diff options
Diffstat (limited to 'node_modules/montage-user/core/undo-manager.js')
-rw-r--r-- | node_modules/montage-user/core/undo-manager.js | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/node_modules/montage-user/core/undo-manager.js b/node_modules/montage-user/core/undo-manager.js new file mode 100644 index 00000000..cd97ee59 --- /dev/null +++ b/node_modules/montage-user/core/undo-manager.js | |||
@@ -0,0 +1,240 @@ | |||
1 | /* <copyright> | ||
2 | This file contains proprietary software owned by Motorola Mobility, Inc.<br/> | ||
3 | No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> | ||
4 | (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. | ||
5 | </copyright> */ | ||
6 | |||
7 | // Consider proposal at https://rniwa.com/editing/undomanager.html | ||
8 | |||
9 | var Montage = require("montage").Montage; | ||
10 | |||
11 | exports.UndoManager = Montage.create(Montage, { | ||
12 | |||
13 | enabled: { | ||
14 | value: true | ||
15 | }, | ||
16 | |||
17 | _maxUndoCount: { | ||
18 | enumerable: false, | ||
19 | value: null | ||
20 | }, | ||
21 | |||
22 | maxUndoCount: { | ||
23 | get: function() { | ||
24 | return this._maxUndoCount; | ||
25 | }, | ||
26 | set: function(value) { | ||
27 | if (value === this._maxUndoCount) { | ||
28 | return; | ||
29 | } | ||
30 | |||
31 | this._maxUndoCount = value; | ||
32 | |||
33 | if (this._maxUndoCount != null) { | ||
34 | this._trimStacks(); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | }, | ||
39 | |||
40 | _trimStacks: { | ||
41 | enumerable: false, | ||
42 | value: function() { | ||
43 | |||
44 | var undoRemoveCount = this._maxUndoCount - this.undoStack.length, | ||
45 | redoRemoveCount = this._maxUndoCount - this.redoStack.length; | ||
46 | |||
47 | if (undoRemoveCount > 0) { | ||
48 | this.undoStack.splice(0, undoRemoveCount); | ||
49 | } | ||
50 | |||
51 | if (redoRemoveCount > 0) { | ||
52 | this.redoStack.splice(0, redoRemoveCount); | ||
53 | } | ||
54 | } | ||
55 | }, | ||
56 | |||
57 | _undoStack: { | ||
58 | enumerable: false, | ||
59 | value: null | ||
60 | }, | ||
61 | |||
62 | undoStack: { | ||
63 | get: function() { | ||
64 | if (!this._undoStack) { | ||
65 | this._undoStack = []; | ||
66 | } | ||
67 | return this._undoStack | ||
68 | } | ||
69 | }, | ||
70 | |||
71 | redoStack: { | ||
72 | value: [], | ||
73 | distinct: true | ||
74 | }, | ||
75 | |||
76 | add: { | ||
77 | value: function(label, undoFunction, context) { | ||
78 | |||
79 | if (0 === this._maxUndoCount) { | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | var undoEntry = { | ||
84 | label: label, | ||
85 | undoFunction: undoFunction, | ||
86 | context: context, | ||
87 | args: Array.prototype.slice.call(arguments, 3) | ||
88 | }; | ||
89 | |||
90 | // seeing as you can only ever add one entry at a time to either stack, we should never need to make room | ||
91 | // for more than a single entry at this point; there's no need for an expensive trim | ||
92 | if (this.isUndoing) { | ||
93 | |||
94 | // preserve the label of the current action being undone to be the name of the redo | ||
95 | undoEntry.label = this.undoEntry.label; | ||
96 | |||
97 | if (this.redoStack.length === this._maxUndoCount) { | ||
98 | this.redoStack.shift(); | ||
99 | } | ||
100 | |||
101 | this.redoStack.push(undoEntry); | ||
102 | } else { | ||
103 | |||
104 | if (this.undoStack.length === this._maxUndoCount) { | ||
105 | this.undoStack.shift(); | ||
106 | } | ||
107 | |||
108 | this.undoStack.push(undoEntry); | ||
109 | |||
110 | if (!this.isRedoing && this.redoStack.length > 0) { | ||
111 | this.clearRedo(); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | }, | ||
116 | |||
117 | clearUndo: { | ||
118 | value: function() { | ||
119 | this.undoStack.splice(0, this.undoStack.length); | ||
120 | } | ||
121 | }, | ||
122 | |||
123 | clearRedo: { | ||
124 | value: function() { | ||
125 | this.redoStack.splice(0, this.redoStack.length); | ||
126 | } | ||
127 | }, | ||
128 | |||
129 | isUndoing: { | ||
130 | dependencies: ["undoEntry"], | ||
131 | get: function() { | ||
132 | return !!this.undoEntry; | ||
133 | } | ||
134 | }, | ||
135 | |||
136 | isRedoing: { | ||
137 | dependencies: ["redoEntry"], | ||
138 | get: function() { | ||
139 | return !!this.redoEntry; | ||
140 | } | ||
141 | }, | ||
142 | |||
143 | undoEntry: { | ||
144 | enumerable: false, | ||
145 | value: null | ||
146 | }, | ||
147 | |||
148 | redoEntry: { | ||
149 | enumerable: false, | ||
150 | value: null | ||
151 | }, | ||
152 | |||
153 | undo: { | ||
154 | value: function() { | ||
155 | |||
156 | if (this.isUndoing || this.isRedoing) { | ||
157 | throw "UndoManager cannot initiate an undo or redo while undoing."; | ||
158 | } | ||
159 | |||
160 | if (this.undoStack.length === 0) { | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | var entry = this.undoEntry = this.undoStack.pop(); | ||
165 | entry.undoFunction.apply(entry.context, entry.args); | ||
166 | this.undoEntry = null; | ||
167 | } | ||
168 | }, | ||
169 | |||
170 | redo: { | ||
171 | value: function() { | ||
172 | if (this.isUndoing || this.isRedoing) { | ||
173 | throw "UndoManager cannot initiate an undo or redo while redoing."; | ||
174 | } | ||
175 | |||
176 | if (this.redoStack.length === 0) { | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | var entry = this.redoEntry = this.redoStack.pop(); | ||
181 | entry.undoFunction.apply(entry.context, entry.args); | ||
182 | this.redoEntry = null; | ||
183 | } | ||
184 | }, | ||
185 | |||
186 | canUndo: { | ||
187 | dependencies: ["undoStack.count()"], | ||
188 | get: function() { | ||
189 | return !!this.undoStack.length; | ||
190 | } | ||
191 | }, | ||
192 | |||
193 | canRedo: { | ||
194 | dependencies: ["redoStack.count()"], | ||
195 | get: function() { | ||
196 | return !!this.redoStack.length; | ||
197 | } | ||
198 | }, | ||
199 | |||
200 | undoLabel: { | ||
201 | dependencies: ["undoStack.count()"], | ||
202 | get: function() { | ||
203 | var undoCount = this.undoStack.length, | ||
204 | label; | ||
205 | |||
206 | if (undoCount) { | ||
207 | label = this.undoStack[undoCount - 1].label; | ||
208 | } | ||
209 | |||
210 | return label ? "Undo " + label : "Undo"; | ||
211 | }, | ||
212 | set: function(value) { | ||
213 | var undoCount = this.redoStack.length; | ||
214 | if (undoCount) { | ||
215 | this.undoStack[undoCount - 1].label = value; | ||
216 | } | ||
217 | } | ||
218 | }, | ||
219 | |||
220 | redoLabel: { | ||
221 | dependencies: ["redoStack.count()"], | ||
222 | get: function() { | ||
223 | var redoCount = this.redoStack.length, | ||
224 | label; | ||
225 | |||
226 | if (redoCount) { | ||
227 | label = this.redoStack[redoCount - 1].label | ||
228 | } | ||
229 | |||
230 | return label ? "Redo " + label : "Redo"; | ||
231 | }, |