]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/debian/missing-sources/framework/Web/Javascripts/source/tinymce-405/classes/UndoManager.js
baculum: Add missing-sources directory in debian metadata structure
[bacula/bacula] / gui / baculum / debian / missing-sources / framework / Web / Javascripts / source / tinymce-405 / classes / UndoManager.js
1 /**
2  * UndoManager.js
3  *
4  * Copyright, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 /**
12  * This class handles the undo/redo history levels for the editor. Since the build in undo/redo has major drawbacks a custom one was needed.
13  *
14  * @class tinymce.UndoManager
15  */
16 define("tinymce/UndoManager", [
17         "tinymce/Env",
18         "tinymce/util/Tools"
19 ], function(Env, Tools) {
20         var trim = Tools.trim, trimContentRegExp;
21
22         trimContentRegExp = new RegExp([
23                 '<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\\/span>', // Trim bogus spans like caret containers
24                 '<div[^>]+data-mce-bogus[^>]+><\\/div>', // Trim bogus divs like resize handles
25                 '\\s?data-mce-selected="[^"]+"' // Trim temporaty data-mce prefixed attributes like data-mce-selected
26         ].join('|'), 'gi');
27
28         return function(editor) {
29                 var self, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, lock;
30
31                 // Returns a trimmed version of the current editor contents
32                 function getContent() {
33                         return trim(editor.getContent({format: 'raw', no_events: 1}).replace(trimContentRegExp, ''));
34                 }
35
36                 function addNonTypingUndoLevel() {
37                         self.typing = false;
38                         self.add();
39                 }
40
41                 // Add initial undo level when the editor is initialized
42                 editor.on('init', function() {
43                         self.add();
44                 });
45
46                 // Get position before an execCommand is processed
47                 editor.on('BeforeExecCommand', function(e) {
48                         var cmd = e.command;
49
50                         if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint') {
51                                 self.beforeChange();
52                         }
53                 });
54
55                 // Add undo level after an execCommand call was made
56                 editor.on('ExecCommand', function(e) {
57                         var cmd = e.command;
58
59                         if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint') {
60                                 self.add();
61                         }
62                 });
63
64                 editor.on('ObjectResizeStart', function() {
65                         self.beforeChange();
66                 });
67
68                 editor.on('SaveContent ObjectResized', addNonTypingUndoLevel);
69                 editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
70                 editor.dom.bind(editor.getBody(), 'focusout', function() {
71                         if (!editor.removed && self.typing) {
72                                 addNonTypingUndoLevel();
73                         }
74                 });
75
76                 editor.on('KeyUp', function(e) {
77                         var keyCode = e.keyCode;
78
79                         if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 45 || keyCode == 13 || e.ctrlKey) {
80                                 addNonTypingUndoLevel();
81                                 editor.nodeChanged();
82                         }
83
84                         if (keyCode == 46 || keyCode == 8 || (Env.mac && (keyCode == 91 || keyCode == 93))) {
85                                 editor.nodeChanged();
86                         }
87
88                         // Fire a TypingUndo event on the first character entered
89                         if (isFirstTypedCharacter && self.typing) {
90                                 // Make the it dirty if the content was changed after typing the first character
91                                 if (!editor.isDirty()) {
92                                         editor.isNotDirty = !data[0] || getContent() == data[0].content;
93
94                                         // Fire initial change event
95                                         if (!editor.isNotDirty) {
96                                                 editor.fire('change', {level: data[0], lastLevel: null});
97                                         }
98                                 }
99
100                                 editor.fire('TypingUndo');
101                                 isFirstTypedCharacter = false;
102                                 editor.nodeChanged();
103                         }
104                 });
105
106                 editor.on('KeyDown', function(e) {
107                         var keyCode = e.keyCode;
108
109                         // Is caracter positon keys left,right,up,down,home,end,pgdown,pgup,enter
110                         if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 45) {
111                                 if (self.typing) {
112                                         addNonTypingUndoLevel();
113                                 }
114
115                                 return;
116                         }
117
118                         // If key isn't shift,ctrl,alt,capslock,metakey
119                         if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing) {
120                                 self.beforeChange();
121                                 self.typing = true;
122                                 self.add();
123                                 isFirstTypedCharacter = true;
124                         }
125                 });
126
127                 editor.on('MouseDown', function() {
128                         if (self.typing) {
129                                 addNonTypingUndoLevel();
130                         }
131                 });
132
133                 // Add keyboard shortcuts for undo/redo keys
134                 editor.addShortcut('ctrl+z', '', 'Undo');
135                 editor.addShortcut('ctrl+y,ctrl+shift+z', '', 'Redo');
136
137                 editor.on('AddUndo Undo Redo ClearUndos MouseUp', function(e) {
138                         if (!e.isDefaultPrevented()) {
139                                 editor.nodeChanged();
140                         }
141                 });
142
143                 self = {
144                         // Explose for debugging reasons
145                         data: data,
146
147                         /**
148                          * State if the user is currently typing or not. This will add a typing operation into one undo
149                          * level instead of one new level for each keystroke.
150                          *
151                          * @field {Boolean} typing
152                          */
153                         typing: false,
154
155                         /**
156                          * Stores away a bookmark to be used when performing an undo action so that the selection is before
157                          * the change has been made.
158                          *
159                          * @method beforeChange
160                          */
161                         beforeChange: function() {
162                                 if (!lock) {
163                                         beforeBookmark = editor.selection.getBookmark(2, true);
164                                 }
165                         },
166
167                         /**
168                          * Adds a new undo level/snapshot to the undo list.
169                          *
170                          * @method add
171                          * @param {Object} l Optional undo level object to add.
172                          * @return {Object} Undo level that got added or null it a level wasn't needed.
173                          */
174                         add: function(level) {
175                                 var i, settings = editor.settings, lastLevel;
176
177                                 level = level || {};
178                                 level.content = getContent();
179
180                                 if (lock || editor.fire('BeforeAddUndo', {level: level}).isDefaultPrevented()) {
181                                         return null;
182                                 }
183
184                                 // Add undo level if needed
185                                 lastLevel = data[index];
186                                 if (lastLevel && lastLevel.content == level.content) {
187                                         return null;
188                                 }
189
190                                 // Set before bookmark on previous level
191                                 if (data[index]) {
192                                         data[index].beforeBookmark = beforeBookmark;
193                                 }
194
195                                 // Time to compress
196                                 if (settings.custom_undo_redo_levels) {
197                                         if (data.length > settings.custom_undo_redo_levels) {
198                                                 for (i = 0; i < data.length - 1; i++) {
199                                                         data[i] = data[i + 1];
200                                                 }
201
202                                                 data.length--;
203                                                 index = data.length;
204                                         }
205                                 }
206
207                                 // Get a non intrusive normalized bookmark
208                                 level.bookmark = editor.selection.getBookmark(2, true);
209
210                                 // Crop array if needed
211                                 if (index < data.length - 1) {
212                                         data.length = index + 1;
213                                 }
214
215                                 data.push(level);
216                                 index = data.length - 1;
217
218                                 var args = {level: level, lastLevel: lastLevel};
219
220                                 editor.fire('AddUndo', args);
221
222                                 if (index > 0) {
223                                         editor.fire('change', args);
224                                         editor.isNotDirty = false;
225                                 }
226
227                                 return level;
228                         },
229
230                         /**
231                          * Undoes the last action.
232                          *
233                          * @method undo
234                          * @return {Object} Undo level or null if no undo was performed.
235                          */
236                         undo: function() {
237                                 var level;
238
239                                 if (self.typing) {
240                                         self.add();
241                                         self.typing = false;
242                                 }
243
244                                 if (index > 0) {
245                                         level = data[--index];
246
247                                         editor.setContent(level.content, {format: 'raw'});
248                                         editor.selection.moveToBookmark(level.beforeBookmark);
249
250                                         editor.fire('undo', {level: level});
251                                 }
252
253                                 return level;
254                         },
255
256                         /**
257                          * Redoes the last action.
258                          *
259                          * @method redo
260                          * @return {Object} Redo level or null if no redo was performed.
261                          */
262                         redo: function() {
263                                 var level;
264
265                                 if (index < data.length - 1) {
266                                         level = data[++index];
267
268                                         editor.setContent(level.content, {format: 'raw'});
269                                         editor.selection.moveToBookmark(level.bookmark);
270
271                                         editor.fire('redo', {level: level});
272                                 }
273
274                                 return level;
275                         },
276
277                         /**
278                          * Removes all undo levels.
279                          *
280                          * @method clear
281                          */
282                         clear: function() {
283                                 data = [];
284                                 index = 0;
285                                 self.typing = false;
286                                 editor.fire('ClearUndos');
287                         },
288
289                         /**
290                          * Returns true/false if the undo manager has any undo levels.
291                          *
292                          * @method hasUndo
293                          * @return {Boolean} true/false if the undo manager has any undo levels.
294                          */
295                         hasUndo: function() {
296                                 // Has undo levels or typing and content isn't the same as the initial level
297                                 return index > 0 || (self.typing && data[0] && getContent() != data[0].content);
298                         },
299
300                         /**
301                          * Returns true/false if the undo manager has any redo levels.
302                          *
303                          * @method hasRedo
304                          * @return {Boolean} true/false if the undo manager has any redo levels.
305                          */
306                         hasRedo: function() {
307                                 return index < data.length - 1 && !this.typing;
308                         },
309
310                         /**
311                          * Executes the specified function in an undo transation. The selection
312                          * before the modification will be stored to the undo stack and if the DOM changes
313                          * it will add a new undo level. Any methods within the transation that adds undo levels will
314                          * be ignored. So a transation can include calls to execCommand or editor.insertContent.
315                          *
316                          * @method transact
317                          * @param {function} callback Function to execute dom manipulation logic in.
318                          */
319                         transact: function(callback) {
320                                 self.beforeChange();
321
322                                 lock = true;
323                                 callback();
324                                 lock = false;
325
326                                 self.add();
327                         }
328                 };
329
330                 return self;
331         };
332 });