1 define(function(require) {
 
   5 var _ = require('libs/underscore'),
 
   6     smartxmlTransformations = require('smartxml/transformations'),
 
   7     metadataKey = 'wlxml.metadata';
 
  10 var Row = function(key, value, metadata) {
 
  12     this.value  = value || '';
 
  13     this.metadata = metadata;
 
  16 _.extend(Row.prototype, {
 
  17     ChangeProperty: smartxmlTransformations.createContextTransformation({
 
  18         impl: function(t, rowIndex, propName, value) {
 
  19             var row = this.getMetadata().at(rowIndex);
 
  20             if(row.getValue() === value) {
 
  23             t.rowIndex = rowIndex;
 
  24             t.propName = propName;
 
  25             t.oldValue = row[propName];
 
  26             row[propName] = value;
 
  27             this.triggerChangeEvent('metadataChanged', {row:row});
 
  30             var row = this.getMetadata().at(t.rowIndex);
 
  31             row[t.propName] = t.oldValue;
 
  32             this.triggerChangeEvent('metadataChanged', {row:row});
 
  36     setKey: function(key) {
 
  37         return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'key', key]);
 
  42     setValue: function(value) {
 
  43         return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'value', value]);
 
  45     getValue: function() {
 
  49         this.metadata.remove(this);
 
  51     getIndex: function() {
 
  52         return this.metadata.indexOf(this);
 
  57 var Metadata = function(node) {
 
  59     Object.defineProperty(this, 'length', {
 
  61             return this._rows.length;
 
  67 _.extend(Metadata.prototype, {
 
  68     Add: smartxmlTransformations.createContextTransformation({
 
  69         impl: function(t, rowDesc) {
 
  70             var metadata = this.getMetadata(),
 
  71                 row = new Row(rowDesc.key, rowDesc.value, metadata);
 
  72             metadata._rows.push(row);
 
  73             t.rowIdx = row.getIndex();
 
  74             this.triggerChangeEvent('metadataAdded', {row: row});
 
  78             this.getMetadata().at(t.rowIdx).remove();
 
  82     Remove: smartxmlTransformations.createContextTransformation({
 
  83         impl: function(t, rowIdx) {
 
  84             var metadata = this.getMetadata();
 
  86             t.row = metadata.at(rowIdx);
 
  87             metadata._rows.splice(rowIdx, 1);
 
  88             this.triggerChangeEvent('metadataRemoved', {row: t.row});
 
  91             var metadata = this.getMetadata(),
 
  92                 row = new Row(t.row.getKey(), t.row.getValue(), metadata);
 
  93             metadata._rows.splice(t.rowIdx, 0, row);
 
  94             this.triggerChangeEvent('metadataAdded', {row: row});
 
  98     _iter: function(method, callback, key) {
 
 100             .filter(function(row) { return !key || row.getKey() === key; })
 
 101             [method](function(row) { return callback(row); });
 
 103     forEach: function(callback, key) {
 
 104         return this._iter('forEach', callback, key);
 
 106     some: function(callback, key) {
 
 107         return this._iter('some', callback, key);
 
 109     add: function(rowDesc, options) {
 
 111         options = _.extend({undoable: true}, options);
 
 112         if(options.undoable) {
 
 113             return this.node.transform(this.Add, [rowDesc]);
 
 115             row = new Row(rowDesc.key, rowDesc.value, this);
 
 116             this._rows.push(row);
 
 121         return this._rows[idx];
 
 123     indexOf: function(row) {
 
 124         var idx = this._rows.indexOf(row);
 
 130     remove: function(row) {
 
 131         var idx = this.indexOf(row);
 
 132         if(typeof idx !== 'undefined') {
 
 133             this.node.transform(this.Remove, [idx]);
 
 136     clone: function(node) {
 
 137         var clone = new Metadata(node);
 
 138         this._rows.forEach(function(row) {
 
 139             clone._rows.push(new Row(row.getKey(), row.getValue(), clone));
 
 149             getMetadata: function() {
 
 150                 if(!this.getData(metadataKey)) {
 
 151                     this.setData(metadataKey, new Metadata(this));
 
 153                 return this.getData(metadataKey);