]> git.wh0rd.org Git - tt-rss.git/blob - lib/dojo/Stateful.js.uncompressed.js
merge new hu_HU translation
[tt-rss.git] / lib / dojo / Stateful.js.uncompressed.js
1 define("dojo/Stateful", ["./_base/declare", "./_base/lang", "./_base/array", "dojo/when"], function(declare, lang, array, when){
2         // module:
3         //              dojo/Stateful
4
5 return declare("dojo.Stateful", null, {
6         // summary:
7         //              Base class for objects that provide named properties with optional getter/setter
8         //              control and the ability to watch for property changes
9         //
10         //              The class also provides the functionality to auto-magically manage getters
11         //              and setters for object attributes/properties.
12         //              
13         //              Getters and Setters should follow the format of _xxxGetter or _xxxSetter where 
14         //              the xxx is a name of the attribute to handle.  So an attribute of "foo" 
15         //              would have a custom getter of _fooGetter and a custom setter of _fooSetter.
16         //
17         // example:
18         //      |       var obj = new dojo.Stateful();
19         //      |       obj.watch("foo", function(){
20         //      |               console.log("foo changed to " + this.get("foo"));
21         //      |       });
22         //      |       obj.set("foo","bar");
23
24         // _attrPairNames: Hash
25         //              Used across all instances a hash to cache attribute names and their getter 
26         //              and setter names.
27         _attrPairNames: {},
28
29         _getAttrNames: function(name){
30                 // summary:
31                 //              Helper function for get() and set().
32                 //              Caches attribute name values so we don't do the string ops every time.
33                 // tags:
34                 //              private
35
36                 var apn = this._attrPairNames;
37                 if(apn[name]){ return apn[name]; }
38                 return (apn[name] = {
39                         s: "_" + name + "Setter",
40                         g: "_" + name + "Getter"
41                 });
42         },
43
44         postscript: function(/*Object?*/ params){
45                 // Automatic setting of params during construction
46                 if (params){ this.set(params); }
47         },
48
49         _get: function(name, names){
50                 // summary:
51                 //              Private function that does a get based off a hash of names
52                 // names:
53                 //              Hash of names of custom attributes
54                 return typeof this[names.g] === "function" ? this[names.g]() : this[name];
55         },
56         get: function(/*String*/name){
57                 // summary:
58                 //              Get a property on a Stateful instance.
59                 // name:
60                 //              The property to get.
61                 // returns:
62                 //              The property value on this Stateful instance.
63                 // description:
64                 //              Get a named property on a Stateful object. The property may
65                 //              potentially be retrieved via a getter method in subclasses. In the base class
66                 //              this just retrieves the object's property.
67                 //              For example:
68                 //      |       stateful = new dojo.Stateful({foo: 3});
69                 //      |       stateful.get("foo") // returns 3
70                 //      |       stateful.foo // returns 3
71
72                 return this._get(name, this._getAttrNames(name)); //Any
73         },
74         set: function(/*String*/name, /*Object*/value){
75                 // summary:
76                 //              Set a property on a Stateful instance
77                 // name:
78                 //              The property to set.
79                 // value:
80                 //              The value to set in the property.
81                 // returns:
82                 //              The function returns this dojo.Stateful instance.
83                 // description:
84                 //              Sets named properties on a stateful object and notifies any watchers of
85                 //              the property. A programmatic setter may be defined in subclasses.
86                 //              For example:
87                 //      |       stateful = new dojo.Stateful();
88                 //      |       stateful.watch(function(name, oldValue, value){
89                 //      |               // this will be called on the set below
90                 //      |       }
91                 //      |       stateful.set(foo, 5);
92                 //
93                 //      set() may also be called with a hash of name/value pairs, ex:
94                 //      |       myObj.set({
95                 //      |               foo: "Howdy",
96                 //      |               bar: 3
97                 //      |       })
98                 //      This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
99
100                 // If an object is used, iterate through object
101                 if(typeof name === "object"){
102                         for(var x in name){
103                                 if(name.hasOwnProperty(x) && x !="_watchCallbacks"){
104                                         this.set(x, name[x]);
105                                 }
106                         }
107                         return this;
108                 }
109
110                 var names = this._getAttrNames(name),
111                         oldValue = this._get(name, names),
112                         setter = this[names.s],
113                         result;
114                 if(typeof setter === "function"){
115                         // use the explicit setter
116                         result = setter.apply(this, Array.prototype.slice.call(arguments, 1));
117                 }else{
118                         // no setter so set attribute directly
119                         this[name] = value;
120                 }
121                 if(this._watchCallbacks){
122                         var self = this;
123                         // If setter returned a promise, wait for it to complete, otherwise call watches immediatly
124                         when(result, function(){
125                                 self._watchCallbacks(name, oldValue, value);
126                         });
127                 }
128                 return this; // dojo/Stateful
129         },
130         _changeAttrValue: function(name, value){
131                 // summary:
132                 //              Internal helper for directly changing an attribute value.
133                 //
134                 // name: String
135                 //              The property to set.
136                 // value: Mixed
137                 //              The value to set in the property.
138                 //
139                 // description:
140                 //              Directly change the value of an attribute on an object, bypassing any 
141                 //              accessor setter.  Also handles the calling of watch and emitting events. 
142                 //              It is designed to be used by descendent class when there are two values 
143                 //              of attributes that are linked, but calling .set() is not appropriate.
144
145                 var oldValue = this.get(name);
146                 this[name] = value;
147                 if(this._watchCallbacks){
148                         this._watchCallbacks(name, oldValue, value);
149                 }
150                 return this; // dojo/Stateful
151         },
152         watch: function(/*String?*/name, /*Function*/callback){
153                 // summary:
154                 //              Watches a property for changes
155                 // name:
156                 //              Indicates the property to watch. This is optional (the callback may be the
157                 //              only parameter), and if omitted, all the properties will be watched
158                 // returns:
159                 //              An object handle for the watch. The unwatch method of this object
160                 //              can be used to discontinue watching this property:
161                 //              |       var watchHandle = obj.watch("foo", callback);
162                 //              |       watchHandle.unwatch(); // callback won't be called now
163                 // callback:
164                 //              The function to execute when the property changes. This will be called after
165                 //              the property has been changed. The callback will be called with the |this|
166                 //              set to the instance, the first argument as the name of the property, the
167                 //              second argument as the old value and the third argument as the new value.
168
169                 var callbacks = this._watchCallbacks;
170                 if(!callbacks){
171                         var self = this;
172                         callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
173                                 var notify = function(propertyCallbacks){
174                                         if(propertyCallbacks){
175                                                 propertyCallbacks = propertyCallbacks.slice();
176                                                 for(var i = 0, l = propertyCallbacks.length; i < l; i++){
177                                                         propertyCallbacks[i].call(self, name, oldValue, value);
178                                                 }
179                                         }
180                                 };
181                                 notify(callbacks['_' + name]);
182                                 if(!ignoreCatchall){
183                                         notify(callbacks["*"]); // the catch-all
184                                 }
185                         }; // we use a function instead of an object so it will be ignored by JSON conversion
186                 }
187                 if(!callback && typeof name === "function"){
188                         callback = name;
189                         name = "*";
190                 }else{
191                         // prepend with dash to prevent name conflicts with function (like "name" property)
192                         name = '_' + name;
193                 }
194                 var propertyCallbacks = callbacks[name];
195                 if(typeof propertyCallbacks !== "object"){
196                         propertyCallbacks = callbacks[name] = [];
197                 }
198                 propertyCallbacks.push(callback);
199
200                 // TODO: Remove unwatch in 2.0
201                 var handle = {};
202                 handle.unwatch = handle.remove = function(){
203                         var index = array.indexOf(propertyCallbacks, callback);
204                         if(index > -1){
205                                 propertyCallbacks.splice(index, 1);
206                         }
207                 };
208                 return handle; //Object
209         }
210
211 });
212
213 });