From: Aleksander Ɓukasz Date: Fri, 25 Oct 2013 10:35:59 +0000 (+0200) Subject: smartxml - emitting nodeAdded event on node inserting operations X-Git-Url: https://git.mdrn.pl/fnpeditor.git/commitdiff_plain/180cd85dd5dcdcb29eb1a4626e3c6412558caddb?ds=inline smartxml - emitting nodeAdded event on node inserting operations --- diff --git a/src/smartxml/smartxml.js b/src/smartxml/smartxml.js index 28a88ee..6b02779 100644 --- a/src/smartxml/smartxml.js +++ b/src/smartxml/smartxml.js @@ -40,15 +40,21 @@ $.extend(DocumentNode.prototype, { }, after: function(node) { - node = node instanceof ElementNode ? node : this.document.createElementNode(node); - this._$.after(node.nativeNode); - return node; + var insertion = this.getNodeInsertion(node); + this._$.after(insertion.ofNode.nativeNode); + if(insertion.insertsNew) { + this.triggerChangeEvent('nodeAdded', {node: insertion.ofNode}); + } + return insertion.ofNode; }, before: function(node) { - node = node instanceof ElementNode ? node : this.document.createElementNode(node); - this._$.before(node.nativeNode); - return node; + var insertion = this.getNodeInsertion(node); + this._$.before(insertion.ofNode.nativeNode); + if(insertion.insertsNew) { + this.triggerChangeEvent('nodeAdded', {node: insertion.ofNode}); + } + return insertion.ofNode; }, wrapWith: function(node) { @@ -65,6 +71,18 @@ $.extend(DocumentNode.prototype, { var event = new events.ChangeEvent(type, $.extend({node: this}, metaData || {})); this.document.trigger('change', event); }, + + getNodeInsertion: function(node) { + var insertion = {}; + if(node instanceof DocumentNode) { + insertion.ofNode = node; + insertion.insertsNew = !this.document.containsNode(node); + } else { + insertion.ofNode = this.document.createElementNode(node); + insertion.insertsNew = true; + } + return insertion; + } }); var ElementNode = function(nativeNode, document) { @@ -153,13 +171,21 @@ $.extend(ElementNode.prototype, { }, append: function(node) { - node = node instanceof DocumentNode ? node : this.document.createElementNode(node); - this._$.append(node.nativeNode); + var insertion = this.getNodeInsertion(node); + this._$.append(insertion.ofNode.nativeNode); + if(insertion.insertsNew) { + this.triggerChangeEvent('nodeAdded', {node: insertion.ofNode}); + } + return insertion.ofNode; }, prepend: function(node) { - node = node instanceof DocumentNode ? node : this.document.createElementNode(node); - this._$.prepend(node.nativeNode); + var insertion = this.getNodeInsertion(node); + this._$.prepend(insertion.ofNode.nativeNode); + if(insertion.insertsNew) { + this.triggerChangeEvent('nodeAdded', {node: insertion.ofNode}); + } + return insertion.ofNode; }, unwrapContent: function() { @@ -316,6 +342,10 @@ $.extend(Document.prototype, Backbone.Events, { return this.root.toXML(); }, + containsNode: function(node) { + return node._$.parents().index(this.root._$) !== -1; + }, + wrapNodes: function(params) { if(!(params.element1.parent().sameNode(params.element2.parent()))) { throw new Error('Wrapping non-sibling nodes not supported.'); diff --git a/src/smartxml/smartxml.test.js b/src/smartxml/smartxml.test.js index 0826458..4f9a72a 100644 --- a/src/smartxml/smartxml.test.js +++ b/src/smartxml/smartxml.test.js @@ -368,6 +368,92 @@ describe('smartxml', function() { }); + describe('Events', function() { + it('emits nodeAdded event when appending new node', function() { + var node = elementNodeFromXML('
'), + spy = sinon.spy(); + node.document.on('change', spy); + + var appended = node.append({tagName:'div'}), + event = spy.args[0][0]; + expect(event.type).to.equal('nodeAdded'); + expect(event.meta.node.sameNode(appended)).to.be.true; + }); + + it('doesn\'t emit nodeAdded when appending aready existing node', function() { + var node = elementNodeFromXML('
'), + a = node.contents()[0], + b = node.contents()[1], + spy = sinon.spy(); + node.document.on('change', spy); + a.append(b); + expect(spy.callCount).to.equal(0); + }); + + it('emits nodeAdded event when prepending new node', function() { + var node = elementNodeFromXML('
'), + spy = sinon.spy(); + node.document.on('change', spy); + + var prepended = node.prepend({tagName:'div'}), + event = spy.args[0][0]; + expect(event.type).to.equal('nodeAdded'); + expect(event.meta.node.sameNode(prepended)).to.be.true; + }); + + it('doesn\'t emit nodeAdded when prepending aready existing node', function() { + var node = elementNodeFromXML('
'), + a = node.contents()[0], + b = node.contents()[1], + spy = sinon.spy(); + node.document.on('change', spy); + a.prepend(b); + expect(spy.callCount).to.equal(0); + }); + + it('emits nodeAdded event when inserting node after another', function() { + var node = elementNodeFromXML('
').contents()[0], + spy = sinon.spy(); + node.document.on('change', spy); + + var inserted = node.after({tagName:'div'}), + event = spy.args[0][0]; + expect(event.type).to.equal('nodeAdded'); + expect(event.meta.node.sameNode(inserted)).to.be.true; + }); + + it('doesn\'t emit nodeAdded when inserting aready existing node after another', function() { + var node = elementNodeFromXML('
'), + a = node.contents()[0], + b = node.contents()[1], + spy = sinon.spy(); + node.document.on('change', spy); + b.after(a); + expect(spy.callCount).to.equal(0); + }); + + it('emits nodeAdded event when inserting node before another', function() { + var node = elementNodeFromXML('
').contents()[0], + spy = sinon.spy(); + node.document.on('change', spy); + + var inserted = node.before({tagName:'div'}), + event = spy.args[0][0]; + expect(event.type).to.equal('nodeAdded'); + expect(event.meta.node.sameNode(inserted)).to.be.true; + }); + + it('doesn\'t emit nodeAdded when inserting aready existing node before another', function() { + var node = elementNodeFromXML('
'), + a = node.contents()[0], + b = node.contents()[1], + spy = sinon.spy(); + node.document.on('change', spy); + a.before(b); + expect(spy.callCount).to.equal(0); + }); + }); + describe('Serializing document to WLXML', function() { it('keeps document intact when no changes have been made', function() { var xmlIn = '
Alice
has
a cat!
',