Here it is:
function StateMaker(initialStateObj){
var o = initialStateObj;
if(o){
if(typeof o === 'object' && o instanceof Array || typeof o !== 'object'){
throw new Error('initialStateObj must be an Object');
return false;
}
this.initialState = o; this.states = [o]; this.savedStates = [o];
}
else{
this.states = []; this.savedStates = [];
}
this.canUndo = this.canRedo = false; this.undoneStates = [];
this.addState = function(stateObj){
var o = stateObj;
if(typeof o === 'object' && o instanceof Array || typeof o !== 'object'){
throw new Error('stateObj must be an Object');
return false;
}
this.states.push(o); this.undoneStates = []; this.canUndo = this.canRedo = false;
return this;
}
this.undo = function(){
var sl = this.states.length;
if(this.initialState){
if(sl > 1){
this.undoneStates.push(this.states.pop()); this.canRedo = true;
if(this.states.length < 2){
this.canUndo = false;
}
}
else{
this.canUndo = false;
}
}
else if(sl > 0){
this.undoneStates.push(this.states.pop()); this.canRedo = true;
}
else{
this.canUndo = false;
}
return this;
}
this.redo = function(){
if(this.undoneStates.length > 0){
this.states.push(this.undoneStates.pop()); this.canUndo = true;
if(this.undoneStates.length < 1){
this.canRedo = false;
}
}
else{
this.canRedo = false;
}
return this;
}
this.save = function(){
this.savedStates = this.states.slice();
return this;
}
this.isSavedState = function(){
var st = this.states, l = st.length; sv = this.savedStates;
if(l !== sv.length){
return false;
}
for(var i=0; i<l; i++){
var o = st[i], c = sv[i];
for(var p in o){
if(!c[p] || c[p] !== o[p]){
return false;
}
}
}
return true;
}
}
Here are some tests I tried:
var sm = new StateMaker({x:10, y:10, rgb:[255,0,0], a:255});
sm.addState({more:'data', here:1}).save(); console.log(sm.states, sm.isSavedState()); sm.undo().addState({see:'it works'});
console.log(sm.states); sm.undo(); sm.redo(); console.log(sm.states, sm.canUndo, sm.canRedo, sm.savedStates, sm.isSavedState()); sm.save().undo().redo().save(); console.log('test', sm.savedStates);
while(sm.canUndo){
sm.undo();
}
while(sm.canRedo){
sm.redo();
}
console.log(sm.states, sm.canUndo); console.log(sm.isSavedState());
Note: StateMakerIntstance.isSavedState()
tells you whether the save button should become lighter or not, because StateMakerInstance.states
and StateMakerInstance.savedStates
are the same.
The idea is for this to work with Canvas. I basically tried to mimic the Komodo Edit undo, redo, save behavior (without seeing their code), except it will only be based on canvas actions by a user eventually. Is there anything wrong with my logic? If not, you're welcome.