smartxml: wrapping sibling nodes
[fnpeditor.git] / src / smartxml / smartxml.js
index d8b6bf0..28a88ee 100644 (file)
@@ -26,7 +26,10 @@ $.extend(DocumentNode.prototype, {
         this._$ = $(nativeNode);
     },
 
         this._$ = $(nativeNode);
     },
 
-    detach: function() { this._$.detach(); },
+    detach: function() {
+        this._$.detach();
+        return this;
+    },
 
     sameNode: function(otherNode) {
         return otherNode && this.nativeNode === otherNode.nativeNode;
 
     sameNode: function(otherNode) {
         return otherNode && this.nativeNode === otherNode.nativeNode;
@@ -154,6 +157,11 @@ $.extend(ElementNode.prototype, {
         this._$.append(node.nativeNode);
     },
 
         this._$.append(node.nativeNode);
     },
 
+    prepend: function(node) {
+        node = node instanceof DocumentNode ? node : this.document.createElementNode(node);
+        this._$.prepend(node.nativeNode);
+    },
+
     unwrapContent: function() {
         var parent = this.parent();
         if(!parent) {
     unwrapContent: function() {
         var parent = this.parent();
         if(!parent) {
@@ -200,6 +208,10 @@ $.extend(ElementNode.prototype, {
         };
     },
 
         };
     },
 
+    wrapText: function(params) {
+        return this.document._wrapText(_.extend({inside: this}, params));
+    },
+
     toXML: function() {
         var wrapper = $('<div>');
         wrapper.append(this._getXMLDOMToDump());
     toXML: function() {
         var wrapper = $('<div>');
         wrapper.append(this._getXMLDOMToDump());
@@ -304,6 +316,42 @@ $.extend(Document.prototype, Backbone.Events, {
         return this.root.toXML();
     },
 
         return this.root.toXML();
     },
 
+    wrapNodes: function(params) {
+        if(!(params.element1.parent().sameNode(params.element2.parent()))) {
+            throw new Error('Wrapping non-sibling nodes not supported.');
+        }
+
+        var parent = params.element1.parent(),
+            parentContents = parent.contents(),
+            wrapper = this.createElementNode({
+                tagName: params._with.tagName,
+                attrs: params._with.attrs}),
+            idx1 = parent.indexOf(params.element1),
+            idx2 = parent.indexOf(params.element2);
+
+        if(idx1 > idx2) {
+            var tmp = idx1;
+            idx1 = idx2;
+            idx2 = tmp;
+        }
+
+        var insertingMethod, insertingTarget;
+        if(idx1 === 0) {
+            insertingMethod = 'prepend';
+            insertingTarget = parent;
+        } else {
+            insertingMethod = 'after';
+            insertingTarget = parentContents[idx1-1];
+        }
+
+        for(var i = idx1; i <= idx2; i++) {
+            wrapper.append(parentContents[i].detach());
+        }
+
+        insertingTarget[insertingMethod](wrapper);
+        return wrapper;
+    },
+
     _wrapText: function(params) {
         params = _.extend({textNodeIdx: 0}, params);
         if(typeof params.textNodeIdx === 'number') {
     _wrapText: function(params) {
         params = _.extend({textNodeIdx: 0}, params);
         if(typeof params.textNodeIdx === 'number') {
@@ -321,6 +369,10 @@ $.extend(Document.prototype, Backbone.Events, {
             suffixInside = textNode2.getText().substr(0, params.offsetEnd),
             suffixOutside = textNode2.getText().substr(params.offsetEnd)
         ;
             suffixInside = textNode2.getText().substr(0, params.offsetEnd),
             suffixOutside = textNode2.getText().substr(params.offsetEnd)
         ;
+
+        if(!(textNode1.parent().sameNode(textNode2.parent()))) {
+            throw new Error('Wrapping text in non-sibling text nodes not supported.');
+        }
         
         var wrapperElement = this.createElementNode({tagName: params._with.tag, attrs: params._with.attrs});
         textNode1.after(wrapperElement);
         
         var wrapperElement = this.createElementNode({tagName: params._with.tag, attrs: params._with.attrs});
         textNode1.after(wrapperElement);