silverstripe-framework/thirdparty/tinymce/classes/UndoManager.js
2009-11-21 02:26:09 +00:00

184 lines
4.2 KiB
JavaScript

/**
* $Id: UndoManager.js 1045 2009-03-04 20:03:18Z spocke $
*
* @author Moxiecode
* @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function(tinymce) {
/**#@+
* @class 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.
* @member tinymce.UndoManager
*/
tinymce.create('tinymce.UndoManager', {
index : 0,
data : null,
typing : 0,
/**
* Constructs a new UndoManager instance.
*
* @constructor
* @param {tinymce.Editor} ed Editor instance to undo/redo in.
*/
UndoManager : function(ed) {
var t = this, Dispatcher = tinymce.util.Dispatcher;
t.editor = ed;
t.data = [];
t.onAdd = new Dispatcher(this);
t.onUndo = new Dispatcher(this);
t.onRedo = new Dispatcher(this);
},
/**#@+
* @method
*/
/**
* Adds a new undo level/snapshot to the undo list.
*
* @param {Object} l Optional undo level object to add.
* @return {Object} Undo level that got added or null it a level wasn't needed.
*/
add : function(l) {
var t = this, i, ed = t.editor, b, s = ed.settings, la;
l = l || {};
l.content = l.content || ed.getContent({format : 'raw', no_events : 1});
// Add undo level if needed
l.content = l.content.replace(/^\s*|\s*$/g, '');
la = t.data[t.index > 0 && (t.index == 0 || t.index == t.data.length) ? t.index - 1 : t.index];
if (!l.initial && la && l.content == la.content)
return null;
// Time to compress
if (s.custom_undo_redo_levels) {
if (t.data.length > s.custom_undo_redo_levels) {
for (i = 0; i < t.data.length - 1; i++)
t.data[i] = t.data[i + 1];
t.data.length--;
t.index = t.data.length;
}
}
if (s.custom_undo_redo_restore_selection && !l.initial)
l.bookmark = b = l.bookmark || ed.selection.getBookmark();
if (t.index < t.data.length)
t.index++;
// Only initial marked undo levels should be allowed as first item
// This to workaround a bug with Firefox and the blur event
if (t.data.length === 0 && !l.initial)
return null;
// Add level
t.data.length = t.index + 1;
t.data[t.index++] = l;
if (l.initial)
t.index = 0;
// Set initial bookmark use first real undo level
if (t.data.length == 2 && t.data[0].initial)
t.data[0].bookmark = b;
t.onAdd.dispatch(t, l);
ed.isNotDirty = 0;
//console.dir(t.data);
return l;
},
/**
* Undoes the last action.
*
* @return {Object} Undo level or null if no undo was performed.
*/
undo : function() {
var t = this, ed = t.editor, l = l, i;
if (t.typing) {
t.add();
t.typing = 0;
}
if (t.index > 0) {
// If undo on last index then take snapshot
if (t.index == t.data.length && t.index > 1) {
i = t.index;
t.typing = 0;
if (!t.add())
t.index = i;
--t.index;
}
l = t.data[--t.index];
ed.setContent(l.content, {format : 'raw'});
ed.selection.moveToBookmark(l.bookmark);
t.onUndo.dispatch(t, l);
}
return l;
},
/**
* Redoes the last action.
*
* @return {Object} Redo level or null if no redo was performed.
*/
redo : function() {
var t = this, ed = t.editor, l = null;
if (t.index < t.data.length - 1) {
l = t.data[++t.index];
ed.setContent(l.content, {format : 'raw'});
ed.selection.moveToBookmark(l.bookmark);
t.onRedo.dispatch(t, l);
}
return l;
},
/**
* Removes all undo levels.
*/
clear : function() {
var t = this;
t.data = [];
t.index = 0;
t.typing = 0;
t.add({initial : true});
},
/**
* Returns true/false if the undo manager has any undo levels.
*
* @return {bool} true/false if the undo manager has any undo levels.
*/
hasUndo : function() {
return this.index != 0 || this.typing;
},
/**
* Returns true/false if the undo manager has any redo levels.
*
* @return {bool} true/false if the undo manager has any redo levels.
*/
hasRedo : function() {
return this.index < this.data.length - 1;
}
/**#@-*/
});
})(tinymce);