acd404c702753dca40dac3cf2e5b5a8d982b0782
[fnpeditor.git] / src / wlxml / extensions / metadata / metadata.js
1 define(function(require) {
2     
3 'use strict';
4
5 var _ = require('libs/underscore'),
6     smartxmlTransformations = require('smartxml/transformations'),
7     metadataKey = 'wlxml.metadata';
8
9
10 var Row = function(key, value, metadata) {
11     this.key = key || '';
12     this.value  = value || '';
13     this.metadata = metadata;
14 };
15
16 _.extend(Row.prototype, {
17     ChangeProperty: smartxmlTransformations.createContextTransformation({
18         impl: function(t, rowIndex, propName, value) {
19             var row = this.getMetadata().at(rowIndex);
20             t.rowIndex = rowIndex;
21             t.propName = propName;
22             t.oldValue = row[propName];
23             row[propName] = value;
24             this.triggerChangeEvent('metadataChanged', {row:row});
25         },
26         undo: function(t) {
27             var row = this.getMetadata().at(t.rowIndex);
28             row[t.propName] = t.oldValue;
29             this.triggerChangeEvent('metadataChanged', {row:row});
30         }
31     }),
32
33     setKey: function(key) {
34         return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'key', key]);
35     },
36     getKey: function() {
37         return this.key;
38     },
39     setValue: function(value) {
40         return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'value', value]);
41     },
42     getValue: function() {
43         return this.value;
44     },
45     remove: function() {
46         this.metadata.remove(this);
47     },
48     getIndex: function() {
49         return this.metadata.indexOf(this);
50     }
51 });
52
53
54 var Metadata = function(node) {
55     this._rows = [];
56     Object.defineProperty(this, 'length', {
57         get: function() {
58             return this._rows.length;
59         }
60     });
61     this.node = node;
62 };
63
64 _.extend(Metadata.prototype, {
65     Add: smartxmlTransformations.createContextTransformation({
66         impl: function(t, rowDesc) {
67             var metadata = this.getMetadata(),
68                 row = new Row(rowDesc.key, rowDesc.value, metadata);
69             metadata._rows.push(row);
70             t.rowIdx = row.getIndex();
71             this.triggerChangeEvent('metadataAdded', {row: row});
72             return row;
73         },
74         undo: function(t) {
75             this.getMetadata().at(t.rowIdx).remove();
76         }
77     }),
78
79     Remove: smartxmlTransformations.createContextTransformation({
80         impl: function(t, rowIdx) {
81             var metadata = this.getMetadata();
82             t.rowIdx = rowIdx;
83             t.row = metadata.at(rowIdx);
84             metadata._rows.splice(rowIdx, 1);
85             this.triggerChangeEvent('metadataRemoved', {row: t.row});
86         },
87         undo: function(t) {
88             var metadata = this.getMetadata(),
89                 row = new Row(t.row.getKey(), t.row.getValue(), metadata);
90             metadata._rows.splice(t.rowIdx, 0, row);
91             this.triggerChangeEvent('metadataAdded', {row: row});
92         }
93     }),
94
95     _iter: function(method, callback, key) {
96         return this._rows
97             .filter(function(row) { return !key || row.getKey() === key; })
98             [method](function(row) { return callback(row); });
99     },
100     forEach: function(callback, key) {
101         return this._iter('forEach', callback, key);
102     },
103     some: function(callback, key) {
104         return this._iter('some', callback, key);
105     },
106     add: function(rowDesc, options) {
107         var row;
108         options = _.extend({undoable: true}, options);
109         if(options.undoable) {
110             return this.node.transform(this.Add, [rowDesc]);
111         } else {
112             row = new Row(rowDesc.key, rowDesc.value, this);
113             this._rows.push(row);
114             return row;
115         }
116     },
117     at: function(idx) {
118         return this._rows[idx];
119     },
120     indexOf: function(row) {
121         var idx = this._rows.indexOf(row);
122         if(idx !== -1) {
123             return idx;
124         }
125         return undefined;
126     },
127     remove: function(row) {
128         var idx = this.indexOf(row);
129         if(typeof idx !== 'undefined') {
130             this.node.transform(this.Remove, [idx]);
131         }
132     },
133     clone: function(node) {
134         var clone = new Metadata(node);
135         this._rows.forEach(function(row) {
136             clone._rows.push(new Row(row.getKey(), row.getValue(), clone));
137         });
138         return clone;
139     }
140 });
141
142
143 return {
144     elementNode: {
145         methods: {
146             getMetadata: function() {
147                 if(!this.getData(metadataKey)) {
148                     this.setData(metadataKey, new Metadata(this));
149                 }
150                 return this.getData(metadataKey);
151             }
152         }
153     }
154 };
155
156 });
157