Mercurial > hg > dml-open-vis
diff src/DML/MainVisBundle/Resources/assets/marionette/modules/ContextModule/ContextModule.30-StateHistory.js @ 0:493bcb69166c
added public content
author | Daniel Wolff |
---|---|
date | Tue, 09 Feb 2016 20:54:02 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DML/MainVisBundle/Resources/assets/marionette/modules/ContextModule/ContextModule.30-StateHistory.js Tue Feb 09 20:54:02 2016 +0100 @@ -0,0 +1,164 @@ +"use strict"; + +App.module("ContextModule", function(ContextModule, App, Backbone, Marionette, $, _, Logger) { + + // Define private variables + var logger = null; + + ContextModule.addInitializer(function(options){ + +// logger = Logger.get("ContextModule.StateBookmark"); +// logger.setLevel(Logger.DEBUG); + + /** + * StateHistory stores a history of a serialized state + * and provides an API to switch between these states + * + * A user simply updates the value of currentSerializedState attribute + * and calls undo(), redo() or reset() to move along the history + * There is no direct access to undo and redo stacks, but it is possible + * to know about them by calling canUndo() and canRedo() + * + * serialize / unserialize deal with the object of the following structure + * { + * undoStack: [{recent}, {less recent}, ... {the oldest}] + * redoStack: [{next}, {the following}, ... {the last}] + * currentSerializedState: {} + * } + * + * attribute compoundChangeDetector is a function that helps decide if the changes between + * the given three serialized states can be treated as a single change. + * This is needed to avoid too many undo states on simple actions like text typing + * compoundChangeDetector returns true if the change between the first, the second + * and the third object can be considered as a single compound change + * (i.e. there is no need to create an extra undo action) + */ + ContextModule.StateHistory = Backbone.Model.extend({ + defaults: { + maxStackSize: 50, + currentSerializedState: undefined, + compoundChangeDetector: undefined + }, + + _NONE: 0, + _UNDO: 1, + _REDO: 2, + _UNSERIALIZE: 3, + + /** + * @memberOf App.ContextModule.StateBookmark + */ + initialize: function() { + this._undoStack = []; + this._redoStack = []; + this._currentSerializedStateChangeMode = this._NONE; + + this.on("change:maxStackSize", this._trimStacks, this); + this.on("change:currentSerializedState", this._registerNewSerializedState, this); + }, + + _registerNewSerializedState: function() { + var previousSerialisedState = this.previous("currentSerializedState"); + if (this._currentSerializedStateChangeMode == this._UNDO) { + this._redoStack.unshift(previousSerialisedState); + } else if (this._currentSerializedStateChangeMode == this._REDO) { + this._undoStack.unshift(previousSerialisedState); + } else if (this._currentSerializedStateChangeMode == this._UNSERIALIZE) { + } else { + if (!_.isEqual(previousSerialisedState, this.attributes.currentSerializedState)) { + if (this._undoStack.length == 0 + || !_.isFunction(this.attributes.compoundChangeDetector) + || !this.attributes.compoundChangeDetector.call(currentSerializedState, previousSerialisedState, this._undoStack[0])) + { + this._undoStack.unshift(previousSerialisedState); + } + this._redoStack = []; + } + } + this._trimStacks(); + }, + + getCurrentSerializedState: function() { + + }, + + undo: function() { + if (this._undoStack.length) { + this._currentSerializedStateChangeMode = this._UNDO; + this.set("currentSerializedState", this._undoStack.shift()); + this._currentSerializedStateChangeMode = this._NONE; + } else { + throw "Undo was called when undo stack was empty"; + } + }, + + redo: function() { + if (this._redoStack.length) { + this._currentSerializedStateChangeMode = this._REDO; + this.set("currentSerializedState", this._redoStack.shift()); + this._currentSerializedStateChangeMode = this._NONE; + } else { + throw "Redo was called when undo stack was empty"; + } + }, + + reset: function() { + var stacksWereNotEmpty = this._undoStack.length || this._redoStack.length; + this._undoStack = []; + this._redoStack = []; + if (stacksWereNotEmpty) { + this.trigger("change"); + } + }, + + canUndo: function() { + return !!this._undoStack.length; + }, + + canRedo: function() { + return !!this._redoStack.length; + }, + + serialize: function() { +// logger.debug("method called: StateHistory::serialize"); + + var result = { + currentSerializedState: this.attributes.currentSerializedState, + undoStack: _.clone(this._undoStack), + redoStack: _.clone(this._redoStack), + }; + + return result; + }, + + unserialize: function(serializedAttributes) { + this._currentSerializedStateChangeMode = this._UNSERIALIZE; + + var fixedSerializedAttributes = serializedAttributes; + if (!_.isSimpleObject(serializedAttributes)) { + fixedSerializedAttributes = {}; + } + + this._undoStack = _.isArray(fixedSerializedAttributes.undoStack) ? + fixedSerializedAttributes.undoStack : []; + this._redoStack = _.isArray(fixedSerializedAttributes.redoStack) ? + fixedSerializedAttributes.redoStack : []; + this._trimStacks(); + + this.set("currentSerializedState", fixedSerializedAttributes.currentSerializedState); + + this._currentSerializedStateChangeMode = this._NONE; + }, + + _trimStacks: function() { + if (this._undoStack.length > this.attributes.maxStackSize) { + this._undoStack = this._undoStack.slice(0, this.attributes.maxStackSize); + } + if (this._redoStack.length > this.attributes.maxStackSize) { + this._redoStack = this._redoStack.slice(0, this.attributes.maxStackSize); + } + } + }); + + }); +}, Logger);