(function(){ var UndoStack = function(){ this.debug = true this.stack = [] this.types = {} this.pointer = -1 } UndoStack.prototype.push = function(action){ this.pointer++ this.stack[this.pointer] = action this.purge() this.debug && console.log("push", action.type) } UndoStack.prototype.purge = function(){ if (this.stack.length-1 == this.pointer) return this.stack.length = this.pointer+1 } UndoStack.prototype.undo = function(){ if (this.pointer == -1) return false var action = this.stack[this.pointer] this.debug && console.log("undo", action.type) this.types[ action.type ].undo(action.undo) this.pointer-- return this.pointer > -1 } UndoStack.prototype.redo = function(){ if (this.pointer == this.stack.length-1) return false this.pointer++ var action = this.stack[this.pointer] this.debug && console.log("redo", action.type) this.types[ action.type ].redo(action.redo) return this.pointer < this.stack.length-1 } UndoStack.prototype.register = function(actions){ if (actions.length) { actions.forEach(this.registerOne.bind(this)) } else { this.registerOne(actions) } } UndoStack.prototype.registerOne = function(action){ if (! action.redo) { action.redo = action.undo } this.types[ action.type ] = action } if ('window' in this) { window.UndoStack = new UndoStack } else { module.exports = new UndoStack } })()