Javascript Undo Manager

For an online app I was looking for an existing undo manager in Javascript. My first place to shop was at jQuery, and although it looks like one had been created as plugin for jQuery, only an info page is online.

Other resources where either tied to a larger library (Ruby on Rails, tinymce) or too complicated (like jsUndoable).

So that left me to write one myself. And although the principle is not too difficult, it did take me a couple of trial and error rounds before I got it right. Hopefully this code will save others some time.

My Undo Manager registers undo and redo actions simultaneously and stores them as commands (see command pattern) to store set and unset actions.

Source code

Get the Javascript Undo Manager source code at GitHub

Demo

Click on the area to create circles

Documentation

With each new/create action you call UndoManager.register(...) with these parameters:

  • param undoObj: caller of the undo function
  • param undoFunc: function to be called at myUndoManager.undo
  • param undoParamsList: (array) parameter list
  • param undoMsg: message to be used
  • redo params: you can figure these out...

So in an example create function would look like this:

function createPerson (name, id) {
	
	if (id == undefined) {
		// create id...
	}		
	// store name and id...
	
	this.undoManager.register(
		this, this.removePerson, [id], 'Remove person',
		this, this.createPerson, [name, id], 'Create person'
	);

}

To undo this action you write:

myUndoManager.undo()

To redo this undo-ed action:

myUndoManager.redo()

Test if UndoManager has any undo actions:

var hasUndo = myUndoManager.hasUndo()

Test if UndoManager has any redo actions:

var hasRedo = myUndoManager.hasRedo()

To update your interface I recommend to use backbone.js that makes it easy to tie update functions to model updates.

A backbone version of the undo manager is also provided. Create an instance of UndoManager with:

this.undoManager = new UndoManager()

var onUndoChanged = function(undoManager) {
	$('.btnUndo').attr('disabled', !undoManager.hasUndo());
	$('.btnRedo').attr('disabled', !undoManager.hasRedo());
};
this.undoManager.bind('change', onUndoChanged);

If you don't use backbone.js, pass a function to setCallback:

myUndoManager.setCallback(onUndoChanged)

Comments

Leave your comment