'use strict';
var _ = require('libs/underscore'),
+ smartxmlTransformations = require('smartxml/transformations'),
metadataKey = 'wlxml.metadata';
-var Row = function(key, value) {
+
+var Row = function(key, value, metadata) {
this.key = key;
this.value = value;
+ this.metadata = metadata;
};
+
_.extend(Row.prototype, {
+ ChangeProperty: smartxmlTransformations.createContextTransformation({
+ impl: function(t, rowIndex, propName, value) {
+ var row = this.getMetadata().at(rowIndex);
+ t.rowIndex = rowIndex;
+ t.propName = propName;
+ t.oldValue = row[propName];
+ row[propName] = value;
+ this.triggerChangeEvent('metadataChanged', {row:row});
+ },
+ undo: function(t) {
+ var row = this.getMetadata().at(t.rowIndex);
+ row[t.propName] = t.oldValue;
+ this.triggerChangeEvent('metadataChanged', {row:row});
+ }
+ }),
+
setKey: function(key) {
- this.key = key;
+ return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'key', key]);
},
getKey: function() {
return this.key;
},
setValue: function(value) {
- this.value = value;
+ return this.metadata.node.transform(this.ChangeProperty, [this.getIndex(), 'value', value]);
},
getValue: function() {
return this.value;
+ },
+ remove: function() {
+ this.metadata.remove(this);
+ },
+ getIndex: function() {
+ return this.metadata.indexOf(this);
}
});
-// var Metadata = function(node) {
-// this._rows = [];
-// }
-// _.extend(Metadata.prototype, {
-// forEach: function(callback) {
-// this.
-// }
-// })
-
-var methods = {
- getMetadata: function() {
- return this.getData(metadataKey) || [];
- }
+var Metadata = function(node) {
+ this._rows = [];
+ Object.defineProperty(this, 'length', {
+ get: function() {
+ return this._rows.length;
+ }
+ });
+ this.node = node;
};
-var transformations = {
- addMetadata: function(desc) {
- var metadata = this.getData(metadataKey) || [],
- row = new Row(desc.key, desc.value);
- metadata.push(row);
- this.setData(metadataKey, metadata);
- return row;
+_.extend(Metadata.prototype, {
+ Add: smartxmlTransformations.createContextTransformation({
+ impl: function(t, rowDesc) {
+ var metadata = this.getMetadata(),
+ row = new Row(rowDesc.key, rowDesc.value, metadata);
+ metadata._rows.push(row);
+ t.rowIdx = row.getIndex();
+ this.triggerChangeEvent('metadataAdded', {row: row});
+ return row;
+ },
+ undo: function(t) {
+ this.getMetadata().at(t.rowIdx).remove();
+ }
+ }),
+
+ Remove: smartxmlTransformations.createContextTransformation({
+ impl: function(t, rowIdx) {
+ var metadata = this.getMetadata();
+ t.rowIdx = rowIdx;
+ t.row = metadata.at(rowIdx);
+ metadata._rows.splice(rowIdx, 1);
+ this.triggerChangeEvent('metadataRemoved', {row: t.row});
+ },
+ undo: function(t) {
+ var metadata = this.getMetadata();
+ metadata._rows.splice(t.rowIdx, 0, new Row(t.row.getKey(), t.row.getValue(), metadata));
+ }
+ }),
+
+ forEach: function(callback) {
+ return this._rows.forEach(callback);
+ },
+ add: function(rowDesc, options) {
+ var row;
+ options = _.extend({undoable: true}, options);
+ if(options.undoable) {
+ return this.node.transform(this.Add, [rowDesc]);
+ } else {
+ row = new Row(rowDesc.key, rowDesc.value, this);
+ this._rows.push(row);
+ return row;
+ }
+ },
+ at: function(idx) {
+ return this._rows[idx];
+ },
+ indexOf: function(row) {
+ var idx = this._rows.indexOf(row);
+ if(idx !== -1) {
+ return idx;
+ }
+ return undefined;
+ },
+ remove: function(row) {
+ var idx = this.indexOf(row);
+ if(typeof idx !== 'undefined') {
+ this.node.transform(this.Remove, [idx]);
+ }
+ },
+ clone: function(node) {
+ var clone = new Metadata(node);
+ this._rows.forEach(function(row) {
+ clone._rows.push(new Row(row.getKey(), row.getValue(), clone));
+ });
+ return clone;
}
-};
+});
+
return {
elementNode: {
- methods: methods,
- transformations: transformations,
+ methods: {
+ getMetadata: function() {
+ if(!this.getData(metadataKey)) {
+ this.setData(metadataKey, new Metadata(this));
+ }
+ return this.getData(metadataKey);
+ }
+ }
}
};
expect = chai.expect,
$ = require('libs/jquery');
+
var getDocumentFromXML = function(xml, options) {
return wlxml.WLXMLDocumentFromXML(xml, options || {});
};
-describe.only('Metadata API', function() {
+describe('Metadata API', function() {
it('returns empty metadata for node without metadata', function() {
var doc = getDocumentFromXML('<section></section>');
expect(doc.root.getMetadata().length).to.equal(0);
});
it('allows to set metadata on an element node', function() {
- var doc = getDocumentFromXML('<section></section>');
-
- var row = doc.root.addMetadata({key: 'key', value: 'value'}),
+ var doc = getDocumentFromXML('<section></section>'),
metadata = doc.root.getMetadata();
-
+
+ var row = metadata.add({key: 'key', value: 'value'});
expect(metadata.length).to.equal(1);
- expect(metadata[0]).to.equal(row, 'aaa');
-
+ expect(metadata.at(0)).to.equal(row);
expect(row.getKey()).to.equal('key');
expect(row.getValue()).to.equal('value');
});
- // it('allows to remove specific metadata row', function() {
- // var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key><dc:key>value</dc:key></metadata></section>'),
- // metadata = doc.root.getMetadata();
- // expect(metadata.length).to.equal(2);
- // row.remove();
- // expect(metadata.length)
- // expect(metadata[0].getValue()).to.equal('value');
- // });
+ it('allows to remove specific metadata row', function() {
+ var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key><dc:key>value</dc:key></metadata></section>'),
+ metadata = doc.root.getMetadata();
+
+ expect(metadata.length).to.equal(2);
+ metadata.at(0).remove();
+ expect(metadata.length).to.equal(1);
+ expect(metadata.at(0).getValue()).to.equal('value');
+ });
it('reads node\'s metadata from source of its metadata child node', function() {
var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key></metadata></section>'),
metadata = doc.root.getMetadata();
expect(metadata.length).to.equal(1);
- expect(metadata[0].getKey()).to.equal('key');
- expect(metadata[0].getValue()).to.equal('value');
+ expect(metadata.at(0).getKey()).to.equal('key');
+ expect(metadata.at(0).getValue()).to.equal('value');
});
it('serializes node\'s metadata to its metadata child node', function() {
var doc = getDocumentFromXML('<section></section>');
- doc.root.addMetadata({key: 'key', value: 'value'});
+ doc.root.getMetadata().add({key: 'key', value: 'value'});
var metadataNodes = $(doc.toXML()).children('metadata'),
keyNodes = metadataNodes.children();
expect(keyNodes[0].tagName.toLowerCase()).to.equal('dc:key');
expect($(keyNodes[0]).text()).to.equal('value');
});
- it('doesn\'t show metadata node on nodes contents', function() {
- var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key></metadata></section>');
- expect(doc.root.contents()).to.have.length(0);
+
+ describe('Hiding metadata nodes from document api', function() {
+ it('hides metadata nodes from document api', function() {
+ var doc = getDocumentFromXML('<section><div></div><metadata><dc:key>value</dc:key></metadata><div></div></section>'),
+ rootContents = doc.root.contents();
+ expect(rootContents).to.have.length(2);
+ expect(rootContents[0].getTagName()).to.equal('div');
+ expect(rootContents[1].getTagName()).to.equal('div');
+ expect(rootContents[0].next().sameNode(rootContents[1])).to.equal(true);
+ expect(rootContents[1].prev().sameNode(rootContents[0])).to.equal(true);
+ });
+
+ it('merges adjacent text nodes', function() {
+ var doc = getDocumentFromXML('<section>Alice<metadata></metadata> has a cat</section>'),
+ contents = doc.root.contents();
+ expect(contents.length).to.equal(1);
+ expect(contents[0].getText()).to.equal('Alice has a cat');
+ });
});
+ describe('undo', function() {
+ it('undoes adding metadata', function() {
+ var doc = getDocumentFromXML('<section></section>'),
+ metadata = doc.root.getMetadata();
+ metadata.add({key: 'k', value: 'v'});
+ doc.undo();
+ expect(metadata.length).to.equal(0);
+ doc.redo();
+ expect(metadata.length).to.equal(1);
+ expect(metadata.at(0).getValue()).to.equal('v');
+ });
+ it('undoes changing metadata key', function() {
+ var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key></metadata></section>'),
+ metadata = doc.root.getMetadata(),
+ row = metadata.at(0);
+
+ row.setKey('key2');
+ doc.undo();
+ expect(row.getKey()).to.equal('key');
+ doc.redo();
+ expect(row.getKey()).to.equal('key2');
+ });
+ it('undoes changing metadata value', function() {
+ var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key></metadata></section>'),
+ metadata = doc.root.getMetadata(),
+ row = metadata.at(0);
+
+ row.setValue('value2');
+ doc.undo();
+ expect(row.getValue()).to.equal('value');
+ doc.redo();
+ expect(row.getValue()).to.equal('value2');
+ });
+ it('undoes removing metadata', function() {
+ var doc = getDocumentFromXML('<section><metadata><dc:key>value</dc:key></metadata></section>'),
+ metadata = doc.root.getMetadata(),
+ row = metadata.at(0);
+
+ row.remove();
+ doc.undo();
+ expect(metadata.length).to.equal(1, 'undo brought back metadata');
+ doc.redo();
+ expect(metadata.length).to.equal(0, 'redo removed metadata');
+ });
+ });
+
+
+
});