X-Git-Url: https://git.mdrn.pl/fnpeditor.git/blobdiff_plain/df1aaa5ae8434788bb67662782fe7e5324ac9786..bc66ee34b72b64bbf916a055bf2742ffc7da08c2:/src/smartxml/core.js diff --git a/src/smartxml/core.js b/src/smartxml/core.js index 44be8d6..3fde430 100644 --- a/src/smartxml/core.js +++ b/src/smartxml/core.js @@ -13,9 +13,15 @@ var INSERTION = function(implementation) { nodeParent, returned; options = options || {}; - if(!(this.document.containsNode(this))) { + if(!(this.document.containsNode(this)) || !insertion.insertsNew) { nodeParent = insertion.ofNode.parent(); } + if(!insertion.insertsNew && insertion.ofNode.isSurroundedByTextNodes()) { + var prev = insertion.ofNode.prev(), + next = insertion.ofNode.next(); + prev.setText(prev.getText()+next.getText()); + next.detach(); + } returned = implementation.call(this, insertion.ofNode); if(!options.silent && returned.sameNode(insertion.ofNode)) { this.triggerChangeEvent(insertion.insertsNew ? 'nodeAdded' : 'nodeMoved', {node: insertion.ofNode}, nodeParent, nodeWasContained); @@ -32,6 +38,10 @@ var documentNodeTransformations = { this._$.detach(); if(existed) { this.triggerChangeEvent('nodeDetached', {parent: parent}); + if(!parent) { + // This was the root of the document + this.document._defineDocumentProperties(null); + } } return this; }, @@ -41,9 +51,12 @@ var documentNodeTransformations = { if(this.isRoot()) { return this.document.replaceRoot(node); } - toret = this.after(node); - this.detach(); - return toret; + if(this.parent()) { + toret = this.after(node); + this.detach(); + return toret; + } + throw new Error('Cannot replace node without a parent.'); }, after: INSERTION(function(node) { @@ -70,8 +83,9 @@ var documentNodeTransformations = { wrapWith: function(node) { var insertion = this.getNodeInsertion(node); - if(this.parent()) { - this.before(insertion.ofNode); + + if(this.parent() || this.isRoot()) { + this.replaceWith(insertion.ofNode); } insertion.ofNode.append(this); return insertion.ofNode; @@ -98,7 +112,7 @@ var elementNodeTransformations = { detach: function() { var next; - if(this.parent() && this.isSurroundedByTextElements()) { + if(this.parent() && this.isSurroundedByTextNodes()) { next = this.next(); this.prev().appendText(next.getText()); next.detach(); @@ -107,26 +121,21 @@ var elementNodeTransformations = { }, setTag: function(tagName) { - var node = this.document.createDocumentNode({tagName: tagName}), - oldTagName = this.getTagName(), - myContents = this._$.contents(); + var node = this.document.createDocumentNode({tagName: tagName}); this.getAttrs().forEach(function(attribute) { - node.setAttr(attribute.name, attribute.value, true); + node.setAttr(attribute.name, attribute.value); }); - node.setData(this.getData()); - if(this.sameNode(this.document.root)) { - this.document._defineDocumentProperties(node._$); - } + this.contents().forEach(function(child) { + node.append(child); + }); - /* TODO: This invalidates old references to this node. Caching instances on nodes would fix this. */ - this._$.replaceWith(node._$); - this._setNativeNode(node._$[0]); - this._$.append(myContents); - this.triggerChangeEvent('nodeTagChange', {oldTagName: oldTagName, newTagName: this.getTagName()}); - }, + node.setData(this.getData()); + this.replaceWith(node); + return node; + }, setAttr: function(name, value, silent) { var oldVal = this.getAttr(name); @@ -307,12 +316,12 @@ var textNodeTransformations = { var newElement = this.document.createDocumentNode({tagName: parentElement.getTagName(), attrs: attrs}); parentElement.after(newElement); + succeedingChildren.reverse().forEach(function(child) { + newElement.prepend(child); + }); if(suffix.length > 0) { - newElement.append({text: suffix}); + newElement.prepend({text: suffix}); } - succeedingChildren.forEach(function(child) { - newElement.append(child); - }); return {first: parentElement, second: newElement}; }, @@ -433,7 +442,7 @@ var documentTransformations = { return insertion.ofNode; }, deleteText: function(params) { - var ptr, prev, next, toDetach, middle, text; + var ptr, next, toDetach, middle, text; if(params.from.node.sameNode(params.to.node)) { ptr = params.from.node; @@ -442,12 +451,20 @@ var documentTransformations = { return; } + // Both edge text nodes need to be edited before anything else happen in case that + // they get merged when detaching content between them. + params.from.node.setText(params.from.node.getText().substr(0, params.from.offset)); + params.to.node.setText(params.to.node.getText().substr(params.to.offset)); + ptr = params.from.node; - ptr.setText(ptr.getText().substr(0, params.from.offset)); next = ptr.next(); + while(next || ptr.parent()) { if(next) { - if(next.sameNode(params.to.node) || (next.nodeType === Node.ELEMENT_NODE && next.containsNode(params.to.node))) { + if(next.sameNode(params.to.node)) { + return; + } + else if(next.nodeType === Node.ELEMENT_NODE && next.containsNode(params.to.node)) { middle = next; break; } else { @@ -461,20 +478,19 @@ var documentTransformations = { } } - ptr = params.to.node; - ptr.setText(ptr.getText().substr(params.to.offset)); - prev = ptr.prev(); - while(prev || ptr.parent()) { - if(ptr.sameNode(middle)) { - break; - } - if(prev) { - toDetach = prev; - prev = prev.prev(); - toDetach.detach(); + if(!this.containsNode(params.to.node)) { + // The end node was merged during detaching nodes above - there is nothing more left to do. + return; + } + + ptr = middle.contents()[0]; + while(ptr && !ptr.sameNode(params.to.node)) { + if(ptr.nodeType === Node.ELEMENT_NODE && ptr.containsNode(params.to.node)) { + ptr = ptr.contents()[0]; + continue; } else { - ptr = ptr.parent(); - prev = ptr.prev(); + ptr = ptr.next(); + ptr.prev().detach(); } } }