wip: refactoring method/transformation registration out of wlxml.js to smartxml ...
[fnpeditor.git] / src / smartxml / smartxml.js
index bb47c06..41e8e19 100644 (file)
@@ -15,12 +15,13 @@ var TEXT_NODE = Node.TEXT_NODE;
 var INSERTION = function(implementation) {
     var toret = function(node) {
         var insertion = this.getNodeInsertion(node),
+            nodeWasContained = this.document.containsNode(insertion.ofNode),
             nodeParent;
         if(!(this.document.containsNode(this))) {
             nodeParent = insertion.ofNode.parent();
         }
         implementation.call(this, insertion.ofNode.nativeNode);
-        this.triggerChangeEvent(insertion.insertsNew ? 'nodeAdded' : 'nodeMoved', {node: insertion.ofNode}, nodeParent);
+        this.triggerChangeEvent(insertion.insertsNew ? 'nodeAdded' : 'nodeMoved', {node: insertion.ofNode}, nodeParent, nodeWasContained);
         return insertion.ofNode;
     };
     return toret;
@@ -37,8 +38,6 @@ var DocumentNode = function(nativeNode, document) {
 
 $.extend(DocumentNode.prototype, {
 
-    transformations: new transformations.TransformationStorage(),
-
     transform: function(name, args) {
         var Transformation = this.transformations.get(name),
             transformation;
@@ -180,13 +179,13 @@ $.extend(DocumentNode.prototype, {
         }
     },
 
-    triggerChangeEvent: function(type, metaData, origParent) {
+    triggerChangeEvent: function(type, metaData, origParent, nodeWasContained) {
         var node = (metaData && metaData.node) ? metaData.node : this,
             event = new events.ChangeEvent(type, $.extend({node: node}, metaData || {}));
         if(type === 'nodeDetached' || this.document.containsNode(event.meta.node)) {
             this.document.trigger('change', event);
         }
-        if((type === 'nodeAdded' || type === 'nodeMoved') && !(this.document.containsNode(this))) {
+        if((type === 'nodeAdded' || type === 'nodeMoved') && !this.document.containsNode(this) && nodeWasContained) {
              event = new events.ChangeEvent('nodeDetached', {node: node, parent: origParent});
              this.document.trigger('change', event);
         }
@@ -385,56 +384,56 @@ $.extend(ElementNode.prototype, {
 
 // todo - split+append
 
-ElementNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.setAttr',
-    impl: function(args) {
-        this.setAttr(args.name, args.value);
-    },
-    getChangeRoot: function() {
-        return this.context;
-    }
-}));
-
-ElementNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.setAttr2',
-    impl: function(args) {
-        this.prevAttr = this.getAttr(args.name);
-        this.setAttr(args.name, args.value);
-    },
-    undo: function(args) {
-        this.setAttr(args.name, this.prevAttr);
-    }
-}));
-
-DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.wrapWith',
-    getChangeRoot: function() {
-        return this.context.parent();
-    },
-    impl: function(args) {
-        return this.wrapWith(args);
-    }
-}));
-
-DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.wrapText',
-    getChangeRoot: function() {
-        return this.context;
-    },
-    impl: function(args) {
-        return this.wrapText(args);
-    }
-}));
-
-DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.detach',
-    getChangeRoot: function() {
-        return this.context.parent();
-    },
-    impl: function(args) {
-        return this.detach();
-    }
-}));
+// ElementNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.setAttr',
+//     impl: function(args) {
+//         this.setAttr(args.name, args.value);
+//     },
+//     getChangeRoot: function() {
+//         return this.context;
+//     }
+// }));
+
+// ElementNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.setAttr2',
+//     impl: function(args) {
+//         this.prevAttr = this.getAttr(args.name);
+//         this.setAttr(args.name, args.value);
+//     },
+//     undo: function(args) {
+//         this.setAttr(args.name, this.prevAttr);
+//     }
+// }));
+
+// DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.wrapWith',
+//     getChangeRoot: function() {
+//         return this.context.parent();
+//     },
+//     impl: function(args) {
+//         return this.wrapWith(args);
+//     }
+// }));
+
+// DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.wrapText',
+//     getChangeRoot: function() {
+//         return this.context;
+//     },
+//     impl: function(args) {
+//         return this.wrapText(args);
+//     }
+// }));
+
+// DocumentNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.detach',
+//     getChangeRoot: function() {
+//         return this.context.parent();
+//     },
+//     impl: function(args) {
+//         return this.detach();
+//     }
+// }));
 
 ///
 
@@ -451,7 +450,7 @@ $.extend(TextNode.prototype, {
     },
 
     setText: function(text) {
-        console.log('smartxml: ' + text);
+        //console.log('smartxml: ' + text);
         this.nativeNode.data = text;
         this.triggerTextChangeEvent();
     },
@@ -525,51 +524,51 @@ $.extend(TextNode.prototype, {
 });
 
 
-TextNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'rng.breakContent',
-    // impl: function(args) {
-    //     var node = this.context,
-    //         newNodes, emptyNode, emptyText;
-    //     newNodes = node.transform('smartxml.split', {offset: args.offset});
-    //     [newNodes.first, newNodes.second].some(function(newNode) {
-    //         if(!(newNode.contents().length)) {
-    //             newNode.transform('smartxml.append', {text: ''});
-    //             return true; // break
-    //         }
-    //     });
-    //     return _.extend(newNodes, {emptyText: emptyText});
-    // },
-    impl: function(args) {
-        var node = this,
-            newNodes, emptyNode, emptyText;
-        newNodes = node.split({offset: args.offset});
-        [newNodes.first, newNodes.second].some(function(newNode) {
-            if(!(newNode.contents().length)) {
-                newNode.append({text: ''});
-                return true; // break
-            }
-        });
-        return _.extend(newNodes, {emptyText: emptyText});
-    },
-    getChangeRoot: function() {
-        return this.context.parent().parent();
-    },
-    isAllowed: function(args) {
-        var parent = this.parent();
-        return !!(parent && parent.parent());
-    }
-}));
-
-
-ElementNode.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.setText',
-    impl: function(args) {
-        this.setText(args.text);
-    },
-    getChangeRoot: function() {
-        return this.context;
-    }
-}));
+// TextNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'rng.breakContent',
+//     // impl: function(args) {
+//     //     var node = this.context,
+//     //         newNodes, emptyNode, emptyText;
+//     //     newNodes = node.transform('smartxml.split', {offset: args.offset});
+//     //     [newNodes.first, newNodes.second].some(function(newNode) {
+//     //         if(!(newNode.contents().length)) {
+//     //             newNode.transform('smartxml.append', {text: ''});
+//     //             return true; // break
+//     //         }
+//     //     });
+//     //     return _.extend(newNodes, {emptyText: emptyText});
+//     // },
+//     impl: function(args) {
+//         var node = this,
+//             newNodes, emptyNode, emptyText;
+//         newNodes = node.split({offset: args.offset});
+//         [newNodes.first, newNodes.second].some(function(newNode) {
+//             if(!(newNode.contents().length)) {
+//                 newNode.append({text: ''});
+//                 return true; // break
+//             }
+//         });
+//         return _.extend(newNodes, {emptyText: emptyText});
+//     },
+//     getChangeRoot: function() {
+//         return this.context.parent().parent();
+//     },
+//     isAllowed: function(args) {
+//         var parent = this.parent();
+//         return !!(parent && parent.parent());
+//     }
+// }));
+
+
+// ElementNode.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.setText',
+//     impl: function(args) {
+//         this.setText(args.text);
+//     },
+//     getChangeRoot: function() {
+//         return this.context;
+//     }
+// }));
 
 
 var parseXML = function(xml) {
@@ -582,13 +581,14 @@ var Document = function(xml) {
     this.redoStack = [];
     this._transformationLevel = 0;
     this.transformations = new transformations.TransformationStorage();
-
+    
+    this._nodeMethods = {};
+    this._nodeTransformations = new transformations.TransformationStorage();
 };
 
 $.extend(Document.prototype, Backbone.Events, {
     ElementNodeFactory: ElementNode,
     TextNodeFactory: TextNode,
-    transformations: new transformations.TransformationStorage(),
 
     createDocumentNode: function(from) {
         if(!(from instanceof Node)) {
@@ -611,7 +611,10 @@ $.extend(Document.prototype, Backbone.Events, {
         } else if(from.nodeType === Node.ELEMENT_NODE) {
             Factory = this.ElementNodeFactory;
         }
-        return new Factory(from, this);
+        var toret = new Factory(from, this);
+        _.extend(toret, this._nodeMethods);
+        toret.transformations = this._nodeTransformations;
+        return toret;
     },
 
     loadXML: function(xml, options) {
@@ -760,8 +763,25 @@ $.extend(Document.prototype, Backbone.Events, {
         return insertion.ofNode;
     },
 
+    registerMethod: function(methodName, method) {
+        this[methodName] = method;
+    },
+
+    registerTransformation: function(Transformation) {
+        return this.transformations.register(Transformation);
+    },
+
+    registerNodeMethod: function(methodName, method) {
+        this._nodeMethods[methodName] = method;
+    },
+
+    registerNodeTransformation: function(Transformation) {
+        this._nodeTransformations.register(Transformation);
+    },
+
+
     transform: function(transformation, args) {
-        console.log('transform');
+        //console.log('transform');
         var Transformation, toret;
         if(typeof transformation === 'string') {
             Transformation = this.transformations.get(transformation);
@@ -776,7 +796,7 @@ $.extend(Document.prototype, Backbone.Events, {
                 this.undoStack.push(transformation);
             }
             this._transformationLevel--;
-            console.log('clearing redo stack');
+            //console.log('clearing redo stack');
             this.redoStack = [];
             return toret;
         } else {
@@ -816,19 +836,19 @@ var defineDocumentProperties = function(doc, $document) {
     }, configurable: true});
 };
 
-Document.prototype.transformations.register(transformations.createContextTransformation({
-    name: 'smartxml.wrapNodes',
-    // init: function() {
+// Document.prototype.transformations.register(transformations.createContextTransformation({
+//     name: 'smartxml.wrapNodes',
+//     // init: function() {
 
-    // },
-    // getChangeRoot: function() {
-    //     return this.context;
-    // },
-    impl: function(args) {
-        this.wrapNodes(args);
-    },
+//     // },
+//     // getChangeRoot: function() {
+//     //     return this.context;
+//     // },
+//     impl: function(args) {
+//         this.wrapNodes(args);
+//     },
 
-}));
+// }));
 
 
 return {