Skip to content

Instantly share code, notes, and snippets.

@kirbysayshi
Created July 16, 2012 16:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kirbysayshi/3123691 to your computer and use it in GitHub Desktop.
Save kirbysayshi/3123691 to your computer and use it in GitHub Desktop.
Determine which values have changed, and also save/restore values similar to the way canvas.context works.
function Something(){
this.who = 'what';
this.how = 'when';
this.say = 'you there';
this.then = 'yeah';
this.pos = { x: 0, y: 0 }
this.pm = new StackMemory(['who', 'say', 'how', 'pos.x', 'pos.y'], this);
}
var s = new Something();
// remember current values
s.pm.save();
s.how = 'duh duh duh';
s.say = 'I did not';
// the following will NOT work, since you're changing the object reference, not values
//s.pos = { x: 0, y: 10 };
// but of course deeper references work fine
s.pos.x += 10;
// returns the "what's changed?" object:
// {
// sm_count: 0, // how many properties have changed
// sm_props: [], // the property names that have changed (e.g. thing)
// sm_paths: [] // the paths (e.g. obj.another.thing) that have changed
// // and whatever paths have changed will be keys here
// }
console.log( s.pm.diff() );
// restore all of the original values
s.pm.restore();
// nothing has changed
console.log( 'after restore', s.pm.diff(), s );
// see http://jsbin.com/ipufab/latest for live demo
StackMemory = function( trackList, rootCtx ){
this.watchHash = {};
this.rootCtx = rootCtx;
this.trackList = trackList;
this.hashList = [];
this.initializeTrackList( trackList );
}
StackMemory.prototype.diff = function(){
var i, path, watch, previous, state = { sm_count: 0, sm_props: [], sm_paths: [] };
if( !this.hashList.length ){
return state;
}
previous = this.hashList[ this.hashList.length - 1 ];
for( i = 0; i < this.trackList.length; i++ ){
path = this.trackList[ i ];
watch = this.watchHash[ path ];
if( previous[ path ] !== watch.ctx[ watch.name ] ){
state[ path ] = previous[ path ];
state.sm_count += 1;
state.sm_paths.push( path );
state.sm_props.push( watch.name );
}
}
return state;
}
StackMemory.prototype.reread = function(){
var i, path, watch;
for( i = 0; i < this.trackList.length; i++ ){
path = this.trackList[i];
watch = this.watchHash[ path ];
watch.value = watch.ctx[ watch.name ];
}
}
StackMemory.prototype.save = function(){
var state = {}, i, path;
for( i = 0; i < this.trackList.length; i++ ){
path = this.trackList[i];
state[ path ] = this.watchHash[ path ].value;
}
this.hashList.push( state );
}
StackMemory.prototype.restore = function(){
var i, path, watch, current;
current = this.hashList.pop();
for( i = 0; i < this.trackList.length; i++ ){
path = this.trackList[i];
watch = this.watchHash[ path ];
watch.ctx[ watch.name ] = current[ path ];
// technically should .reread here, but faster to just do it manually
watch.value = current[ path ];
}
}
StackMemory.prototype.initializeTrackList = function( trackList ){
var i, j, property, path, propMatches, finalMatch, parentObj;
for(i = 0; i < trackList.length; i++){
path = trackList[i];
propMatches = path.split( '.' );
finalMatch = propMatches[ propMatches.length - 1 ];
parentObj = this.rootCtx;
for(j = 0; j < propMatches.length - 1; j++){
parentObj = parentObj[ propMatches[j] ];
}
this.watchHash[ path ] = {
ctx: parentObj
,value: parentObj[ finalMatch ]
,name: finalMatch
};
}
// nuke current states, because tracking changes will invalidate them
this.hashList.length = 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment