Created
August 7, 2009 07:56
-
-
Save dandean/163773 to your computer and use it in GitHub Desktop.
Experimental mixins for decoupled object property watching
This file contains 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
// This has been taken further here: | |
// http://github.com/dandean/shouter/tree/master | |
/** | |
* mixin Watchable enables sproutcore-style property watching... kinda. | |
* todo: - unwatch | |
* - allow property modification before setting | |
* - revisit naming | |
* - examples with UI elements | |
* - investigate potential performance issues | |
* - _reactTo_$ method for props without specific handlers | |
* - Make Element.addMethods(Watchable) work | |
**/ | |
var Watchable = (function() { | |
var _registry = []; | |
return { | |
/** | |
* Watchable#set(prop, value) -> "undefined" | |
* Sets the property on this object to the specified value, then notifies all watchers. | |
**/ | |
set: function(prop, value) { | |
if (this[prop] != value) { | |
var old = this[prop]; | |
this[prop] = value; | |
_registry.invoke("_react", this, prop, old, this[prop]); | |
} | |
return this; | |
}, | |
/** | |
* Watchable#get(prop) -> object | |
* Gets the value from the object. | |
**/ | |
get: function(prop) { | |
return this[prop]; | |
}, | |
/** | |
* Watchable#watcher(watcher) -> "undefined" | |
* Adds a watcher to noticy when properties change. | |
**/ | |
watcher: function(watcher) { | |
if (!("_react" in watcher)) throw "'watcher' does not extend Watcher class."; | |
_registry.push(watcher); | |
} | |
}; | |
})(); | |
/** | |
* class Watcher | |
* todo: This could probably just be a Mixin instead of a Class. | |
**/ | |
var Watcher = Class.create({ | |
/** | |
* new Watcher(); | |
**/ | |
initialize: function() { }, | |
/** | |
* Calls property-specific handlers when possible. | |
**/ | |
_react: function(source, prop, old, value) { | |
var callback = "_reactTo" + prop.charAt(0).toUpperCase() + prop.substr(1); | |
if (callback in this) this[callback](source, old, value); | |
}, | |
toString: function() { return "[object Watcher]"; } | |
}); | |
// ------------------------ | |
/** | |
* Dummy classes to implement watching... | |
**/ | |
var MyWatchable = Class.create(Watchable, { | |
initialize: function() { }, | |
toString: function() { return "[object MyWatchable]"; } | |
}); | |
var MyWatcher = Class.create(Watcher, { | |
initialize: function(watchable) { | |
watchable.watcher(this); | |
}, | |
/** | |
* Handles when the "test1" property is set | |
**/ | |
_reactToTest1: function(source, old, value) { | |
console.log("test1 property set to #{value} (was #{old}) by:" | |
.interpolate({old: old || "undefined", value: value}), source); | |
}, | |
/** | |
* Handles when the "test2" property is set | |
**/ | |
_reactToTest2: function(source, old, value) { | |
console.log("test2 property set to #{value} (was #{old}) by:" | |
.interpolate({old: old || "undefined", value: value}), source); | |
}, | |
/** | |
* Handles when the "innerHTML" property is set | |
**/ | |
_reactToInnerHTML: function(source, old, value) { | |
console.log("innerHTML property set to #{value} (was #{old}) by:" | |
.interpolate({old: old || "undefined", value: value}), source); | |
}, | |
toString: function() { return "[object MyWatcher]"; } | |
}); | |
// Make it go! | |
var watchable = new MyWatchable(); | |
var watcher = new MyWatcher(watchable); | |
console.info("Set properties. Should see 2 responses..."); | |
watchable.set("test1", "cool").set("test2", 5); | |
// ------------------------ | |
var watcher2 = new MyWatcher(watchable); | |
console.info("Added another watcher. Should now see 4 responses..."); | |
watchable.set("test1", "amazing").set("test2", 6); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment