140 lines
4.4 KiB
JavaScript
140 lines
4.4 KiB
JavaScript
|
define("dojo/Stateful", ["./_base/kernel", "./_base/declare", "./_base/lang", "./_base/array"], function(dojo, declare, lang, array) {
|
||
|
// module:
|
||
|
// dojo/Stateful
|
||
|
// summary:
|
||
|
// TODOC
|
||
|
|
||
|
return dojo.declare("dojo.Stateful", null, {
|
||
|
// summary:
|
||
|
// Base class for objects that provide named properties with optional getter/setter
|
||
|
// control and the ability to watch for property changes
|
||
|
// example:
|
||
|
// | var obj = new dojo.Stateful();
|
||
|
// | obj.watch("foo", function(){
|
||
|
// | console.log("foo changed to " + this.get("foo"));
|
||
|
// | });
|
||
|
// | obj.set("foo","bar");
|
||
|
postscript: function(mixin){
|
||
|
if(mixin){
|
||
|
lang.mixin(this, mixin);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
get: function(/*String*/name){
|
||
|
// summary:
|
||
|
// Get a property on a Stateful instance.
|
||
|
// name:
|
||
|
// The property to get.
|
||
|
// returns:
|
||
|
// The property value on this Stateful instance.
|
||
|
// description:
|
||
|
// Get a named property on a Stateful object. The property may
|
||
|
// potentially be retrieved via a getter method in subclasses. In the base class
|
||
|
// this just retrieves the object's property.
|
||
|
// For example:
|
||
|
// | stateful = new dojo.Stateful({foo: 3});
|
||
|
// | stateful.get("foo") // returns 3
|
||
|
// | stateful.foo // returns 3
|
||
|
|
||
|
return this[name]; //Any
|
||
|
},
|
||
|
set: function(/*String*/name, /*Object*/value){
|
||
|
// summary:
|
||
|
// Set a property on a Stateful instance
|
||
|
// name:
|
||
|
// The property to set.
|
||
|
// value:
|
||
|
// The value to set in the property.
|
||
|
// returns:
|
||
|
// The function returns this dojo.Stateful instance.
|
||
|
// description:
|
||
|
// Sets named properties on a stateful object and notifies any watchers of
|
||
|
// the property. A programmatic setter may be defined in subclasses.
|
||
|
// For example:
|
||
|
// | stateful = new dojo.Stateful();
|
||
|
// | stateful.watch(function(name, oldValue, value){
|
||
|
// | // this will be called on the set below
|
||
|
// | }
|
||
|
// | stateful.set(foo, 5);
|
||
|
//
|
||
|
// set() may also be called with a hash of name/value pairs, ex:
|
||
|
// | myObj.set({
|
||
|
// | foo: "Howdy",
|
||
|
// | bar: 3
|
||
|
// | })
|
||
|
// This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
|
||
|
if(typeof name === "object"){
|
||
|
for(var x in name){
|
||
|
this.set(x, name[x]);
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
var oldValue = this[name];
|
||
|
this[name] = value;
|
||
|
if(this._watchCallbacks){
|
||
|
this._watchCallbacks(name, oldValue, value);
|
||
|
}
|
||
|
return this; //dojo.Stateful
|
||
|
},
|
||
|
watch: function(/*String?*/name, /*Function*/callback){
|
||
|
// summary:
|
||
|
// Watches a property for changes
|
||
|
// name:
|
||
|
// Indicates the property to watch. This is optional (the callback may be the
|
||
|
// only parameter), and if omitted, all the properties will be watched
|
||
|
// returns:
|
||
|
// An object handle for the watch. The unwatch method of this object
|
||
|
// can be used to discontinue watching this property:
|
||
|
// | var watchHandle = obj.watch("foo", callback);
|
||
|
// | watchHandle.unwatch(); // callback won't be called now
|
||
|
// callback:
|
||
|
// The function to execute when the property changes. This will be called after
|
||
|
// the property has been changed. The callback will be called with the |this|
|
||
|
// set to the instance, the first argument as the name of the property, the
|
||
|
// second argument as the old value and the third argument as the new value.
|
||
|
|
||
|
var callbacks = this._watchCallbacks;
|
||
|
if(!callbacks){
|
||
|
var self = this;
|
||
|
callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
|
||
|
var notify = function(propertyCallbacks){
|
||
|
if(propertyCallbacks){
|
||
|
propertyCallbacks = propertyCallbacks.slice();
|
||
|
for(var i = 0, l = propertyCallbacks.length; i < l; i++){
|
||
|
try{
|
||
|
propertyCallbacks[i].call(self, name, oldValue, value);
|
||
|
}catch(e){
|
||
|
console.error(e);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
notify(callbacks['_' + name]);
|
||
|
if(!ignoreCatchall){
|
||
|
notify(callbacks["*"]); // the catch-all
|
||
|
}
|
||
|
}; // we use a function instead of an object so it will be ignored by JSON conversion
|
||
|
}
|
||
|
if(!callback && typeof name === "function"){
|
||
|
callback = name;
|
||
|
name = "*";
|
||
|
}else{
|
||
|
// prepend with dash to prevent name conflicts with function (like "name" property)
|
||
|
name = '_' + name;
|
||
|
}
|
||
|
var propertyCallbacks = callbacks[name];
|
||
|
if(typeof propertyCallbacks !== "object"){
|
||
|
propertyCallbacks = callbacks[name] = [];
|
||
|
}
|
||
|
propertyCallbacks.push(callback);
|
||
|
return {
|
||
|
unwatch: function(){
|
||
|
propertyCallbacks.splice(array.indexOf(propertyCallbacks, callback), 1);
|
||
|
}
|
||
|
}; //Object
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
});
|