|
1 YUI.add('attribute-observable', function (Y, NAME) { |
|
2 |
|
3 /*For log lines*/ |
|
4 /*jshint maxlen:200*/ |
|
5 |
|
6 |
|
7 /** |
|
8 * The attribute module provides an augmentable Attribute implementation, which |
|
9 * adds configurable attributes and attribute change events to the class being |
|
10 * augmented. It also provides a State class, which is used internally by Attribute, |
|
11 * but can also be used independently to provide a name/property/value data structure to |
|
12 * store state. |
|
13 * |
|
14 * @module attribute |
|
15 */ |
|
16 |
|
17 /** |
|
18 * The `attribute-observable` submodule provides augmentable attribute change event support |
|
19 * for AttributeCore based implementations. |
|
20 * |
|
21 * @module attribute |
|
22 * @submodule attribute-observable |
|
23 */ |
|
24 var EventTarget = Y.EventTarget, |
|
25 |
|
26 CHANGE = "Change", |
|
27 BROADCAST = "broadcast"; |
|
28 |
|
29 /** |
|
30 * Provides an augmentable implementation of attribute change events for |
|
31 * AttributeCore. |
|
32 * |
|
33 * @class AttributeObservable |
|
34 * @extensionfor AttributeCore |
|
35 * @uses EventTarget |
|
36 */ |
|
37 function AttributeObservable() { |
|
38 // Perf tweak - avoid creating event literals if not required. |
|
39 this._ATTR_E_FACADE = {}; |
|
40 |
|
41 EventTarget.call(this, {emitFacade:true}); |
|
42 } |
|
43 |
|
44 AttributeObservable._ATTR_CFG = [BROADCAST]; |
|
45 |
|
46 AttributeObservable.prototype = { |
|
47 |
|
48 /** |
|
49 * Sets the value of an attribute. |
|
50 * |
|
51 * @method set |
|
52 * @chainable |
|
53 * |
|
54 * @param {String} name The name of the attribute. If the |
|
55 * current value of the attribute is an Object, dot notation can be used |
|
56 * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>). |
|
57 * |
|
58 * @param {Any} value The value to set the attribute to. |
|
59 * |
|
60 * @param {Object} opts (Optional) Optional event data to be mixed into |
|
61 * the event facade passed to subscribers of the attribute's change event. This |
|
62 * can be used as a flexible way to identify the source of a call to set, allowing |
|
63 * the developer to distinguish between set called internally by the host, vs. |
|
64 * set called externally by the application developer. |
|
65 * |
|
66 * @return {Object} A reference to the host object. |
|
67 */ |
|
68 set : function(name, val, opts) { |
|
69 return this._setAttr(name, val, opts); |
|
70 }, |
|
71 |
|
72 /** |
|
73 * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details. |
|
74 * |
|
75 * @method _set |
|
76 * @protected |
|
77 * @chainable |
|
78 * |
|
79 * @param {String} name The name of the attribute. |
|
80 * @param {Any} val The value to set the attribute to. |
|
81 * @param {Object} opts (Optional) Optional event data to be mixed into |
|
82 * the event facade passed to subscribers of the attribute's change event. |
|
83 * @return {Object} A reference to the host object. |
|
84 */ |
|
85 _set : function(name, val, opts) { |
|
86 return this._setAttr(name, val, opts, true); |
|
87 }, |
|
88 |
|
89 /** |
|
90 * Sets multiple attribute values. |
|
91 * |
|
92 * @method setAttrs |
|
93 * @param {Object} attrs An object with attributes name/value pairs. |
|
94 * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set |
|
95 * @return {Object} A reference to the host object. |
|
96 * @chainable |
|
97 */ |
|
98 setAttrs : function(attrs, opts) { |
|
99 return this._setAttrs(attrs, opts); |
|
100 }, |
|
101 |
|
102 /** |
|
103 * Implementation behind the public setAttrs method, to set multiple attribute values. |
|
104 * |
|
105 * @method _setAttrs |
|
106 * @protected |
|
107 * @param {Object} attrs An object with attributes name/value pairs. |
|
108 * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set |
|
109 * @return {Object} A reference to the host object. |
|
110 * @chainable |
|
111 */ |
|
112 _setAttrs : function(attrs, opts) { |
|
113 var attr; |
|
114 for (attr in attrs) { |
|
115 if ( attrs.hasOwnProperty(attr) ) { |
|
116 this.set(attr, attrs[attr], opts); |
|
117 } |
|
118 } |
|
119 return this; |
|
120 }, |
|
121 |
|
122 /** |
|
123 * Utility method to help setup the event payload and fire the attribute change event. |
|
124 * |
|
125 * @method _fireAttrChange |
|
126 * @private |
|
127 * @param {String} attrName The name of the attribute |
|
128 * @param {String} subAttrName The full path of the property being changed, |
|
129 * if this is a sub-attribute value being change. Otherwise null. |
|
130 * @param {Any} currVal The current value of the attribute |
|
131 * @param {Any} newVal The new value of the attribute |
|
132 * @param {Object} opts Any additional event data to mix into the attribute change event's event facade. |
|
133 * @param {Object} [cfg] The attribute config stored in State, if already available. |
|
134 */ |
|
135 _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts, cfg) { |
|
136 var host = this, |
|
137 eventName = this._getFullType(attrName + CHANGE), |
|
138 state = host._state, |
|
139 facade, |
|
140 broadcast, |
|
141 e; |
|
142 |
|
143 if (!cfg) { |
|
144 cfg = state.data[attrName] || {}; |
|
145 } |
|
146 |
|
147 if (!cfg.published) { |
|
148 |
|
149 // PERF: Using lower level _publish() for |
|
150 // critical path performance |
|
151 e = host._publish(eventName); |
|
152 |
|
153 e.emitFacade = true; |
|
154 e.defaultTargetOnly = true; |
|
155 e.defaultFn = host._defAttrChangeFn; |
|
156 |
|
157 broadcast = cfg.broadcast; |
|
158 if (broadcast !== undefined) { |
|
159 e.broadcast = broadcast; |
|
160 } |
|
161 |
|
162 cfg.published = true; |
|
163 } |
|
164 |
|
165 if (opts) { |
|
166 facade = Y.merge(opts); |
|
167 facade._attrOpts = opts; |
|
168 } else { |
|
169 facade = host._ATTR_E_FACADE; |
|
170 } |
|
171 |
|
172 // Not using the single object signature for fire({type:..., newVal:...}), since |
|
173 // we don't want to override type. Changed to the fire(type, {newVal:...}) signature. |
|
174 |
|
175 facade.attrName = attrName; |
|
176 facade.subAttrName = subAttrName; |
|
177 facade.prevVal = currVal; |
|
178 facade.newVal = newVal; |
|
179 |
|
180 if (host._hasPotentialSubscribers(eventName)) { |
|
181 host.fire(eventName, facade); |
|
182 } else { |
|
183 this._setAttrVal(attrName, subAttrName, currVal, newVal, opts, cfg); |
|
184 } |
|
185 }, |
|
186 |
|
187 /** |
|
188 * Default function for attribute change events. |
|
189 * |
|
190 * @private |
|
191 * @method _defAttrChangeFn |
|
192 * @param {EventFacade} e The event object for attribute change events. |
|
193 * @param {boolean} eventFastPath Whether or not we're using this as a fast path in the case of no listeners or not |
|
194 */ |
|
195 _defAttrChangeFn : function(e, eventFastPath) { |
|
196 |
|
197 var opts = e._attrOpts; |
|
198 if (opts) { |
|
199 delete e._attrOpts; |
|
200 } |
|
201 |
|
202 if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, opts)) { |
|
203 |
|
204 Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute'); |
|
205 |
|
206 if (!eventFastPath) { |
|
207 // Prevent "after" listeners from being invoked since nothing changed. |
|
208 e.stopImmediatePropagation(); |
|
209 } |
|
210 |
|
211 } else { |
|
212 if (!eventFastPath) { |
|
213 e.newVal = this.get(e.attrName); |
|
214 } |
|
215 } |
|
216 } |
|
217 }; |
|
218 |
|
219 // Basic prototype augment - no lazy constructor invocation. |
|
220 Y.mix(AttributeObservable, EventTarget, false, null, 1); |
|
221 |
|
222 Y.AttributeObservable = AttributeObservable; |
|
223 |
|
224 /** |
|
225 The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now |
|
226 an alias for the `AttributeObservable` class extension. Use that class |
|
227 extnesion instead. This alias will be removed in a future version of YUI. |
|
228 |
|
229 @class AttributeEvents |
|
230 @uses EventTarget |
|
231 @deprecated Use `AttributeObservable` instead. |
|
232 @see AttributeObservable |
|
233 **/ |
|
234 Y.AttributeEvents = AttributeObservable; |
|
235 |
|
236 |
|
237 }, '@VERSION@', {"requires": ["event-custom"]}); |