4 * Copyright 2009, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
12 var Dispatcher = tinymce.util.Dispatcher;
15 * 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.
17 * @class tinymce.UndoManager
19 tinymce.UndoManager = function(editor) {
20 var self, index = 0, data = [], beforeBookmark;
22 function getContent() {
23 return tinymce.trim(editor.getContent({format : 'raw', no_events : 1}));
28 * State if the user is currently typing or not. This will add a typing operation into one undo
29 * level instead of one new level for each keystroke.
31 * @field {Boolean} typing
36 * This event will fire each time a new undo level is added to the undo manager.
39 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
40 * @param {Object} level The new level object containing a bookmark and contents.
42 onAdd : new Dispatcher(self),
45 * This event will fire when the user make an undo of a change.
48 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
49 * @param {Object} level The old level object containing a bookmark and contents.
51 onUndo : new Dispatcher(self),
54 * This event will fire when the user make an redo of a change.
57 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
58 * @param {Object} level The old level object containing a bookmark and contents.
60 onRedo : new Dispatcher(self),
63 * Stores away a bookmark to be used when performing an undo action so that the selection is before
64 * the change has been made.
66 * @method beforeChange
68 beforeChange : function() {
69 beforeBookmark = editor.selection.getBookmark(2, true);
73 * Adds a new undo level/snapshot to the undo list.
76 * @param {Object} l Optional undo level object to add.
77 * @return {Object} Undo level that got added or null it a level wasn't needed.
79 add : function(level) {
80 var i, settings = editor.settings, lastLevel;
83 level.content = getContent();
85 // Add undo level if needed
86 lastLevel = data[index];
87 if (lastLevel && lastLevel.content == level.content)
90 // Set before bookmark on previous level
92 data[index].beforeBookmark = beforeBookmark;
95 if (settings.custom_undo_redo_levels) {
96 if (data.length > settings.custom_undo_redo_levels) {
97 for (i = 0; i < data.length - 1; i++)
98 data[i] = data[i + 1];
105 // Get a non intrusive normalized bookmark
106 level.bookmark = editor.selection.getBookmark(2, true);
108 // Crop array if needed
109 if (index < data.length - 1)
110 data.length = index + 1;
113 index = data.length - 1;
115 self.onAdd.dispatch(self, level);
116 editor.isNotDirty = 0;
122 * Undoes the last action.
125 * @return {Object} Undo level or null if no undo was performed.
136 level = data[--index];
138 editor.setContent(level.content, {format : 'raw'});
139 editor.selection.moveToBookmark(level.beforeBookmark);
141 self.onUndo.dispatch(self, level);
148 * Redoes the last action.
151 * @return {Object} Redo level or null if no redo was performed.
156 if (index < data.length - 1) {
157 level = data[++index];
159 editor.setContent(level.content, {format : 'raw'});
160 editor.selection.moveToBookmark(level.bookmark);
162 self.onRedo.dispatch(self, level);
169 * Removes all undo levels.
180 * Returns true/false if the undo manager has any undo levels.
183 * @return {Boolean} true/false if the undo manager has any undo levels.
185 hasUndo : function() {
186 return index > 0 || this.typing;
190 * Returns true/false if the undo manager has any redo levels.
193 * @return {Boolean} true/false if the undo manager has any redo levels.
195 hasRedo : function() {
196 return index < data.length - 1 && !this.typing;