Created
September 21, 2014 13:14
-
-
Save taneltm/d3ef395551e78bba6d45 to your computer and use it in GitHub Desktop.
History manager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* History manager. | |
* | |
* It can be used to keep track of application state. | |
* Can be used in places where an Undo/Redo framework doesn't quite fit. | |
* | |
* Can be used with Node.js or as a RequireJS modle. | |
* | |
* @version 0.0.1 | |
* @author TanelTM | |
*/ | |
/** | |
* Usage example: | |
* // Initialize | |
* var history = new HistoryMan(); | |
* | |
* // Add some data | |
* history.add({"route": "#downloads/1"}); | |
* history.add({"route": "#downloads/2"}); | |
* history.add({"route": "#downloads/3"}); | |
* history.add({"route": "#downloads/4"}); | |
* | |
* // Undo | |
* var state = history.getPrevState(); | |
* console.log(state); // > {"route": "#downloads/3"} | |
* | |
* // Redo | |
* var state = history.getPrevState(); | |
* console.log(state); // > {"route": "#downloads/4"} | |
* | |
* // Get specific state | |
* var state = history.getStateAt(1); | |
* console.log(state); // > {"route": "#downloads/2"} | |
* | |
* // Adding a state when the pointer does not point to the last state | |
* // There are currently 4 routes in history. | |
* // The pointer points to the second route: {"route": "#downloads/2"} | |
* history.add({"route": "#about"}); | |
* | |
* // Now the history contains 3 routes in history: | |
* // "#downloads/1", "#downloads/2" and "#about" | |
* | |
* Public functions: | |
* add(state) | |
* getStateAt(pointer) | |
* getCurrentState() | |
* getPrevState() | |
* getNextState() | |
* getPointer() | |
* clear() | |
* clear(pointer) | |
*/ | |
(function(root, factory) { | |
if (typeof exports === 'object') { | |
// Node. Does not work with strict CommonJS, but | |
// only CommonJS-like enviroments that support module.exports, | |
// like Node. | |
module.exports = factory(); | |
} else if (typeof define === 'function' && define.amd) { | |
// AMD. Register as an anonymous module. | |
define(factory); | |
} else { | |
// Browser globals (root is window) | |
root.returnExports = factory(); | |
} | |
}(this, function() { | |
return function() { | |
var stack = []; | |
var pointer = -1; | |
this.getStateAt = function(pt) { | |
if (pt >= stack.length) { | |
return null; | |
} else { | |
pointer = pt; | |
return stack[pt]; | |
} | |
}; | |
this.getCurrentState = function() { | |
return stack[pointer]; | |
}; | |
this.getPrevState = function() { | |
if (pointer <= 0) { | |
return null; | |
} else { | |
pointer--; | |
return stack[pointer]; | |
} | |
}; | |
this.getNextState = function() { | |
if (pointer+1 >= stack.length) { | |
return null; | |
} else { | |
pointer++; | |
return stack[pointer]; | |
} | |
}; | |
this.getPointer = function() { | |
return pointer; | |
}; | |
this.getCount = function() { | |
return stack.length; | |
}; | |
this.clear = function(pt) { | |
if (typeof pt == "undefined") { | |
stack = []; | |
pointer = -1; | |
return pointer; | |
} else if (pt < 0 || pt >= stack.length) { | |
return null; | |
} else { | |
stack.splice(pt, stack.length-pt); | |
if (pointer >= stack.length) { | |
pointer = stack.length-1; | |
} | |
return pointer; | |
} | |
}; | |
this.add = function(object) { | |
this.clear(pointer+1); | |
stack.push(object); | |
return ++pointer; | |
}; | |
}; | |
})); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Simple NodeJS test. | |
* | |
* To run, CD to the project directory and run `node test`. | |
* | |
* @version 0.0.1 | |
* @author TanelTM | |
*/ | |
var assert = require('assert'); | |
var HistoryMan = require('./HistoryMan'); | |
var history = new HistoryMan(); | |
assert.ok( history.getPointer() === -1 ); | |
assert.ok( history.getPrevState() === null ); | |
assert.ok( history.getPointer() === -1 ); | |
assert.ok( history.add("banana") === 0 ); | |
assert.ok( history.add("orange") === 1 ); | |
assert.ok( history.add("apple") === 2 ); | |
assert.ok( history.add("mango") === 3 ); | |
assert.ok( history.getCount() === 4 ); | |
assert.ok( history.getNextState() === null ); | |
assert.ok( history.getPointer() === 3 ); | |
assert.ok( history.getPrevState() === "apple" ); | |
assert.ok( history.getNextState() === "mango" ); | |
assert.ok( history.getPointer() === 3 ); | |
assert.ok( history.getStateAt(0) === "banana" ); | |
assert.ok( history.add("lemon") === 1 ); | |
assert.ok( history.add("kiwi") === 2 ); | |
assert.ok( history.clear(1) === 0 ); | |
assert.ok( history.add("lemon") === 1 ); | |
assert.ok( history.add("kiwi") === 2 ); | |
assert.ok( history.clear() === -1 ); | |
console.log("All tests passed!"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment