X-Git-Url: https://git.mdrn.pl/fnpeditor.git/blobdiff_plain/00ec27f6852f1dd85f4d90bbc3f1dbb84a0d7f8c..3c6c8fe1de117ec69a146ea18aedac5d8dc30691:/src/smartxml/smartxml.js diff --git a/src/smartxml/smartxml.js b/src/smartxml/smartxml.js index 6cc3e33..202d9e6 100644 --- a/src/smartxml/smartxml.js +++ b/src/smartxml/smartxml.js @@ -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) { @@ -581,12 +580,15 @@ var Document = function(xml) { this.undoStack = []; 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)) { @@ -609,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) { @@ -758,8 +763,66 @@ $.extend(Document.prototype, Backbone.Events, { return insertion.ofNode; }, + registerMethod: function(methodName, method) { + if(this[methodName]) { + throw new Error('Cannot extend document with method name {methodName}. Name already exists.' + .replace('{methodName}', methodName) + ); + } + this[methodName] = method; + }, + + registerTransformation: function(Transformation) { + return this.transformations.register(Transformation); + }, + + registerNodeMethod: function(methodName, method) { + if(this._nodeMethods[methodName]) { + throw new Error('Cannot extend document with method name {methodName}. Name already exists.' + .replace('{methodName}', methodName) + ); + } + this._nodeMethods[methodName] = method; + }, + + registerNodeTransformation: function(Transformation) { + this._nodeTransformations.register(Transformation); + }, + + registerExtension: function(extension) { + //debugger; + var doc = this, + existingPropertyNames = _.values(this); + + ['document', 'documentNode'].forEach(function(dstName) { + var dstExtension = extension[dstName]; + if(dstExtension) { + if(dstExtension.methods) { + _.pairs(dstExtension.methods).forEach(function(pair) { + var methodName = pair[0], + method = pair[1], + operation; + operation = {document: 'registerMethod', documentNode: 'registerNodeMethod'}[dstName]; + doc[operation](methodName, method); + + }); + } + + if(dstExtension.transformations) { + _.pairs(dstExtension.transformations).forEach(function(pair) { + var name = pair[0], + desc = pair[1], + operation; + operation = {document: 'registerTransformation', documentNode: 'registerNodeTransformation'}[dstName]; + doc[operation](transformations.createContextTransformation(desc, name)); + }); + } + } + }); + }, + transform: function(transformation, args) { - console.log('transform'); + //console.log('transform'); var Transformation, toret; if(typeof transformation === 'string') { Transformation = this.transformations.get(transformation); @@ -774,7 +837,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 { @@ -814,19 +877,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 { @@ -840,7 +903,8 @@ return { Document: Document, DocumentNode: DocumentNode, - ElementNode: ElementNode + ElementNode: ElementNode, + TextNode: TextNode }; }); \ No newline at end of file