comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:493bcb69166c
1 "use strict";
2
3 App.module("ContextModule", function(ContextModule, App, Backbone, Marionette, $, _, Logger) {
4
5 // Define private variables
6 var logger = null;
7
8 ContextModule.addInitializer(function(options){
9
10 // logger = Logger.get("ContextModule.StateBookmark");
11 // logger.setLevel(Logger.DEBUG);
12
13 /**
14 * StateHistory stores a history of a serialized state
15 * and provides an API to switch between these states
16 *
17 * A user simply updates the value of currentSerializedState attribute
18 * and calls undo(), redo() or reset() to move along the history
19 * There is no direct access to undo and redo stacks, but it is possible
20 * to know about them by calling canUndo() and canRedo()
21 *
22 * serialize / unserialize deal with the object of the following structure
23 * {
24 * undoStack: [{recent}, {less recent}, ... {the oldest}]
25 * redoStack: [{next}, {the following}, ... {the last}]
26 * currentSerializedState: {}
27 * }
28 *
29 * attribute compoundChangeDetector is a function that helps decide if the changes between
30 * the given three serialized states can be treated as a single change.
31 * This is needed to avoid too many undo states on simple actions like text typing
32 * compoundChangeDetector returns true if the change between the first, the second
33 * and the third object can be considered as a single compound change
34 * (i.e. there is no need to create an extra undo action)
35 */
36 ContextModule.StateHistory = Backbone.Model.extend({
37 defaults: {
38 maxStackSize: 50,
39 currentSerializedState: undefined,
40 compoundChangeDetector: undefined
41 },
42
43 _NONE: 0,
44 _UNDO: 1,
45 _REDO: 2,
46 _UNSERIALIZE: 3,
47
48 /**
49 * @memberOf App.ContextModule.StateBookmark
50 */
51 initialize: function() {
52 this._undoStack = [];
53 this._redoStack = [];
54 this._currentSerializedStateChangeMode = this._NONE;
55
56 this.on("change:maxStackSize", this._trimStacks, this);
57 this.on("change:currentSerializedState", this._registerNewSerializedState, this);
58 },
59
60 _registerNewSerializedState: function() {
61 var previousSerialisedState = this.previous("currentSerializedState");
62 if (this._currentSerializedStateChangeMode == this._UNDO) {
63 this._redoStack.unshift(previousSerialisedState);
64 } else if (this._currentSerializedStateChangeMode == this._REDO) {
65 this._undoStack.unshift(previousSerialisedState);
66 } else if (this._currentSerializedStateChangeMode == this._UNSERIALIZE) {
67 } else {
68 if (!_.isEqual(previousSerialisedState, this.attributes.currentSerializedState)) {
69 if (this._undoStack.length == 0
70 || !_.isFunction(this.attributes.compoundChangeDetector)
71 || !this.attributes.compoundChangeDetector.call(currentSerializedState, previousSerialisedState, this._undoStack[0]))
72 {
73 this._undoStack.unshift(previousSerialisedState);
74 }
75 this._redoStack = [];
76 }
77 }
78 this._trimStacks();
79 },
80
81 getCurrentSerializedState: function() {
82
83 },
84
85 undo: function() {
86 if (this._undoStack.length) {
87 this._currentSerializedStateChangeMode = this._UNDO;
88 this.set("currentSerializedState", this._undoStack.shift());
89 this._currentSerializedStateChangeMode = this._NONE;
90 } else {
91 throw "Undo was called when undo stack was empty";
92 }
93 },
94
95 redo: function() {
96 if (this._redoStack.length) {
97 this._currentSerializedStateChangeMode = this._REDO;
98 this.set("currentSerializedState", this._redoStack.shift());
99 this._currentSerializedStateChangeMode = this._NONE;
100 } else {
101 throw "Redo was called when undo stack was empty";
102 }
103 },
104
105 reset: function() {
106 var stacksWereNotEmpty = this._undoStack.length || this._redoStack.length;
107 this._undoStack = [];
108 this._redoStack = [];
109 if (stacksWereNotEmpty) {
110 this.trigger("change");
111 }
112 },
113
114 canUndo: function() {
115 return !!this._undoStack.length;
116 },
117
118 canRedo: function() {
119 return !!this._redoStack.length;
120 },
121
122 serialize: function() {
123 // logger.debug("method called: StateHistory::serialize");
124
125 var result = {
126 currentSerializedState: this.attributes.currentSerializedState,
127 undoStack: _.clone(this._undoStack),
128 redoStack: _.clone(this._redoStack),
129 };
130
131 return result;
132 },
133
134 unserialize: function(serializedAttributes) {
135 this._currentSerializedStateChangeMode = this._UNSERIALIZE;
136
137 var fixedSerializedAttributes = serializedAttributes;
138 if (!_.isSimpleObject(serializedAttributes)) {
139 fixedSerializedAttributes = {};
140 }
141
142 this._undoStack = _.isArray(fixedSerializedAttributes.undoStack) ?
143 fixedSerializedAttributes.undoStack : [];
144 this._redoStack = _.isArray(fixedSerializedAttributes.redoStack) ?
145 fixedSerializedAttributes.redoStack : [];
146 this._trimStacks();
147
148 this.set("currentSerializedState", fixedSerializedAttributes.currentSerializedState);
149
150 this._currentSerializedStateChangeMode = this._NONE;
151 },
152
153 _trimStacks: function() {
154 if (this._undoStack.length > this.attributes.maxStackSize) {
155 this._undoStack = this._undoStack.slice(0, this.attributes.maxStackSize);
156 }
157 if (this._redoStack.length > this.attributes.maxStackSize) {
158 this._redoStack = this._redoStack.slice(0, this.attributes.maxStackSize);
159 }
160 }
161 });
162
163 });
164 }, Logger);