X-Git-Url: https://git.mdrn.pl/fnpeditor.git/blobdiff_plain/950632a02425edb79343f6fdeb5b2d7f0a5854d2..580d8a5bddb9f4b5fc1525b018bd500f793d7137:/src/smartxml/smartxml.js diff --git a/src/smartxml/smartxml.js b/src/smartxml/smartxml.js index 9227e0f..505ab85 100644 --- a/src/smartxml/smartxml.js +++ b/src/smartxml/smartxml.js @@ -123,6 +123,9 @@ $.extend(DocumentNode.prototype, { 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)) { + if(type === 'nodeMoved') { + event.meta.parent = origParent; + } this.document.trigger('change', event); } if((type === 'nodeAdded' || type === 'nodeMoved') && !this.document.containsNode(this) && nodeWasContained) { @@ -270,7 +273,7 @@ var registerMethod = function(methodName, method, target) { var Document = function(xml, extensions) { this.undoStack = []; this.redoStack = []; - this._transactionStack = []; + this._currentTransaction = null; this._transformationLevel = 0; this._nodeMethods = {}; @@ -370,13 +373,17 @@ $.extend(Document.prototype, Backbone.Events, { return noSiblingParents; } - var i; - for(i = 0; i < Math.min(parents1.length, parents2.length); i++) { + var stop = Math.min(parents1.length, parents2.length), + i; + for(i = 0; i < stop; i++) { if(parents1[i].sameNode(parents2[i])) { continue; } break; } + if(i === stop) { + i--; + } return {node1: parents1[i], node2: parents2[i]}; }, @@ -469,6 +476,12 @@ $.extend(Document.prototype, Backbone.Events, { transform: function(Transformation, args) { var toret, transformation; + if(!this._currentTransaction) { + return this.transaction(function() { + return this.transform(Transformation, args); + }, this); + } + if(typeof Transformation === 'function') { transformation = new Transformation(this, this, args); } else { @@ -484,11 +497,7 @@ $.extend(Document.prototype, Backbone.Events, { }, function() { if(this._transformationLevel === 1 && !this._undoInProgress) { - if(this._transactionInProgress) { - this._transactionStack.push(transformation); - } else { - this.undoStack.push(transformation); - } + this._currentTransaction.pushTransformation(transformation); } if(!this._undoInProgress && this._transformationLevel === 1) { this.redoStack = []; @@ -503,20 +512,15 @@ $.extend(Document.prototype, Backbone.Events, { } }, undo: function() { - var transformationObject = this.undoStack.pop(), + var transaction = this.undoStack.pop(), doc = this, transformations, stopAt; - if(transformationObject) { + if(transaction) { this._undoInProgress = true; - if(_.isArray(transformationObject)) { - // We will modify this array in a minute so make sure we work on a copy. - transformations = transformationObject.slice(0); - } else { - // Lets normalize single transformation to a transaction containing one transformation. - transformations = [transformationObject]; - } + // We will modify this array in a minute so make sure we work on a copy. + transformations = transaction.transformations.slice(0); if(transformations.length > 1) { // In case of real transactions we don't want to run undo on all of transformations if we don't have to. @@ -539,45 +543,44 @@ $.extend(Document.prototype, Backbone.Events, { }); this._undoInProgress = false; - this.redoStack.push(transformationObject); + this.redoStack.push(transaction); } }, redo: function() { - var transformationObject = this.redoStack.pop(), - transformations; - if(transformationObject) { + var transaction = this.redoStack.pop(); + if(transaction) { this._transformationLevel++; - transformations = _.isArray(transformationObject) ? transformationObject : [transformationObject]; - transformations.forEach(function(t) { + transaction.transformations.forEach(function(t) { t.run({beUndoable: true}); }); this._transformationLevel--; - this.undoStack.push(transformationObject); + this.undoStack.push(transaction); } }, - startTransaction: function() { - if(this._transactionInProgress) { + startTransaction: function(metadata) { + if(this._currentTransaction) { throw new Error('Nested transactions not supported!'); } - this._transactionInProgress = true; + this._currentTransaction = new Transaction([], metadata); }, endTransaction: function() { - if(!this._transactionInProgress) { + if(!this._currentTransaction) { throw new Error('End of transaction requested, but there is no transaction in progress!'); } - this._transactionInProgress = false; - if(this._transactionStack.length) { - this.undoStack.push(this._transactionStack); - this._transactionStack = []; + if(this._currentTransaction.hasTransformations()) { + this.undoStack.push(this._currentTransaction); } + this._currentTransaction = null; }, - transaction: function(callback, context) { - this.startTransaction(); - callback.call(context); + transaction: function(callback, context, metadata) { + var toret; + this.startTransaction(metadata); + toret = callback.call(context); this.endTransaction(); + return toret; }, getNodeByPath: function(path) { @@ -591,14 +594,33 @@ $.extend(Document.prototype, Backbone.Events, { _defineDocumentProperties: function($document) { var doc = this; Object.defineProperty(doc, 'root', {get: function() { + if(!$document) { + return null; + } return doc.createDocumentNode($document[0]); }, configurable: true}); Object.defineProperty(doc, 'dom', {get: function() { + if(!$document) { + return null; + } return $document[0]; }, configurable: true}); } }); +var Transaction = function(transformations, metadata) { + this.transformations = transformations || []; + this.metadata = metadata; +}; +$.extend(Transaction.prototype, { + pushTransformation: function(transformation) { + this.transformations.push(transformation); + }, + hasTransformations: function() { + return this.transformations.length > 0; + } +}); + return { documentFromXML: function(xml) {