|
525
|
1 |
/* |
|
|
2 |
YUI 3.10.3 (build 2fb5187) |
|
|
3 |
Copyright 2013 Yahoo! Inc. All rights reserved. |
|
|
4 |
Licensed under the BSD License. |
|
|
5 |
http://yuilibrary.com/license/ |
|
|
6 |
*/ |
|
|
7 |
|
|
|
8 |
YUI.add('oop', function (Y, NAME) { |
|
|
9 |
|
|
|
10 |
/** |
|
|
11 |
Adds object inheritance and manipulation utilities to the YUI instance. This |
|
|
12 |
module is required by most YUI components. |
|
|
13 |
|
|
|
14 |
@module oop |
|
|
15 |
**/ |
|
|
16 |
|
|
|
17 |
var L = Y.Lang, |
|
|
18 |
A = Y.Array, |
|
|
19 |
OP = Object.prototype, |
|
|
20 |
CLONE_MARKER = '_~yuim~_', |
|
|
21 |
|
|
|
22 |
hasOwn = OP.hasOwnProperty, |
|
|
23 |
toString = OP.toString; |
|
|
24 |
|
|
|
25 |
function dispatch(o, f, c, proto, action) { |
|
|
26 |
if (o && o[action] && o !== Y) { |
|
|
27 |
return o[action].call(o, f, c); |
|
|
28 |
} else { |
|
|
29 |
switch (A.test(o)) { |
|
|
30 |
case 1: |
|
|
31 |
return A[action](o, f, c); |
|
|
32 |
case 2: |
|
|
33 |
return A[action](Y.Array(o, 0, true), f, c); |
|
|
34 |
default: |
|
|
35 |
return Y.Object[action](o, f, c, proto); |
|
|
36 |
} |
|
|
37 |
} |
|
|
38 |
} |
|
|
39 |
|
|
|
40 |
/** |
|
|
41 |
Augments the _receiver_ with prototype properties from the _supplier_. The |
|
|
42 |
receiver may be a constructor function or an object. The supplier must be a |
|
|
43 |
constructor function. |
|
|
44 |
|
|
|
45 |
If the _receiver_ is an object, then the _supplier_ constructor will be called |
|
|
46 |
immediately after _receiver_ is augmented, with _receiver_ as the `this` object. |
|
|
47 |
|
|
|
48 |
If the _receiver_ is a constructor function, then all prototype methods of |
|
|
49 |
_supplier_ that are copied to _receiver_ will be sequestered, and the |
|
|
50 |
_supplier_ constructor will not be called immediately. The first time any |
|
|
51 |
sequestered method is called on the _receiver_'s prototype, all sequestered |
|
|
52 |
methods will be immediately copied to the _receiver_'s prototype, the |
|
|
53 |
_supplier_'s constructor will be executed, and finally the newly unsequestered |
|
|
54 |
method that was called will be executed. |
|
|
55 |
|
|
|
56 |
This sequestering logic sounds like a bunch of complicated voodoo, but it makes |
|
|
57 |
it cheap to perform frequent augmentation by ensuring that suppliers' |
|
|
58 |
constructors are only called if a supplied method is actually used. If none of |
|
|
59 |
the supplied methods is ever used, then there's no need to take the performance |
|
|
60 |
hit of calling the _supplier_'s constructor. |
|
|
61 |
|
|
|
62 |
@method augment |
|
|
63 |
@param {Function|Object} receiver Object or function to be augmented. |
|
|
64 |
@param {Function} supplier Function that supplies the prototype properties with |
|
|
65 |
which to augment the _receiver_. |
|
|
66 |
@param {Boolean} [overwrite=false] If `true`, properties already on the receiver |
|
|
67 |
will be overwritten if found on the supplier's prototype. |
|
|
68 |
@param {String[]} [whitelist] An array of property names. If specified, |
|
|
69 |
only the whitelisted prototype properties will be applied to the receiver, and |
|
|
70 |
all others will be ignored. |
|
|
71 |
@param {Array|any} [args] Argument or array of arguments to pass to the |
|
|
72 |
supplier's constructor when initializing. |
|
|
73 |
@return {Function} Augmented object. |
|
|
74 |
@for YUI |
|
|
75 |
**/ |
|
|
76 |
Y.augment = function (receiver, supplier, overwrite, whitelist, args) { |
|
|
77 |
var rProto = receiver.prototype, |
|
|
78 |
sequester = rProto && supplier, |
|
|
79 |
sProto = supplier.prototype, |
|
|
80 |
to = rProto || receiver, |
|
|
81 |
|
|
|
82 |
copy, |
|
|
83 |
newPrototype, |
|
|
84 |
replacements, |
|
|
85 |
sequestered, |
|
|
86 |
unsequester; |
|
|
87 |
|
|
|
88 |
args = args ? Y.Array(args) : []; |
|
|
89 |
|
|
|
90 |
if (sequester) { |
|
|
91 |
newPrototype = {}; |
|
|
92 |
replacements = {}; |
|
|
93 |
sequestered = {}; |
|
|
94 |
|
|
|
95 |
copy = function (value, key) { |
|
|
96 |
if (overwrite || !(key in rProto)) { |
|
|
97 |
if (toString.call(value) === '[object Function]') { |
|
|
98 |
sequestered[key] = value; |
|
|
99 |
|
|
|
100 |
newPrototype[key] = replacements[key] = function () { |
|
|
101 |
return unsequester(this, value, arguments); |
|
|
102 |
}; |
|
|
103 |
} else { |
|
|
104 |
newPrototype[key] = value; |
|
|
105 |
} |
|
|
106 |
} |
|
|
107 |
}; |
|
|
108 |
|
|
|
109 |
unsequester = function (instance, fn, fnArgs) { |
|
|
110 |
// Unsequester all sequestered functions. |
|
|
111 |
for (var key in sequestered) { |
|
|
112 |
if (hasOwn.call(sequestered, key) |
|
|
113 |
&& instance[key] === replacements[key]) { |
|
|
114 |
|
|
|
115 |
instance[key] = sequestered[key]; |
|
|
116 |
} |
|
|
117 |
} |
|
|
118 |
|
|
|
119 |
// Execute the supplier constructor. |
|
|
120 |
supplier.apply(instance, args); |
|
|
121 |
|
|
|
122 |
// Finally, execute the original sequestered function. |
|
|
123 |
return fn.apply(instance, fnArgs); |
|
|
124 |
}; |
|
|
125 |
|
|
|
126 |
if (whitelist) { |
|
|
127 |
Y.Array.each(whitelist, function (name) { |
|
|
128 |
if (name in sProto) { |
|
|
129 |
copy(sProto[name], name); |
|
|
130 |
} |
|
|
131 |
}); |
|
|
132 |
} else { |
|
|
133 |
Y.Object.each(sProto, copy, null, true); |
|
|
134 |
} |
|
|
135 |
} |
|
|
136 |
|
|
|
137 |
Y.mix(to, newPrototype || sProto, overwrite, whitelist); |
|
|
138 |
|
|
|
139 |
if (!sequester) { |
|
|
140 |
supplier.apply(to, args); |
|
|
141 |
} |
|
|
142 |
|
|
|
143 |
return receiver; |
|
|
144 |
}; |
|
|
145 |
|
|
|
146 |
/** |
|
|
147 |
* Copies object properties from the supplier to the receiver. If the target has |
|
|
148 |
* the property, and the property is an object, the target object will be |
|
|
149 |
* augmented with the supplier's value. |
|
|
150 |
* |
|
|
151 |
* @method aggregate |
|
|
152 |
* @param {Object} receiver Object to receive the augmentation. |
|
|
153 |
* @param {Object} supplier Object that supplies the properties with which to |
|
|
154 |
* augment the receiver. |
|
|
155 |
* @param {Boolean} [overwrite=false] If `true`, properties already on the receiver |
|
|
156 |
* will be overwritten if found on the supplier. |
|
|
157 |
* @param {String[]} [whitelist] Whitelist. If supplied, only properties in this |
|
|
158 |
* list will be applied to the receiver. |
|
|
159 |
* @return {Object} Augmented object. |
|
|
160 |
*/ |
|
|
161 |
Y.aggregate = function(r, s, ov, wl) { |
|
|
162 |
return Y.mix(r, s, ov, wl, 0, true); |
|
|
163 |
}; |
|
|
164 |
|
|
|
165 |
/** |
|
|
166 |
* Utility to set up the prototype, constructor and superclass properties to |
|
|
167 |
* support an inheritance strategy that can chain constructors and methods. |
|
|
168 |
* Static members will not be inherited. |
|
|
169 |
* |
|
|
170 |
* @method extend |
|
|
171 |
* @param {function} r the object to modify. |
|
|
172 |
* @param {function} s the object to inherit. |
|
|
173 |
* @param {object} px prototype properties to add/override. |
|
|
174 |
* @param {object} sx static properties to add/override. |
|
|
175 |
* @return {object} the extended object. |
|
|
176 |
*/ |
|
|
177 |
Y.extend = function(r, s, px, sx) { |
|
|
178 |
if (!s || !r) { |
|
|
179 |
Y.error('extend failed, verify dependencies'); |
|
|
180 |
} |
|
|
181 |
|
|
|
182 |
var sp = s.prototype, rp = Y.Object(sp); |
|
|
183 |
r.prototype = rp; |
|
|
184 |
|
|
|
185 |
rp.constructor = r; |
|
|
186 |
r.superclass = sp; |
|
|
187 |
|
|
|
188 |
// assign constructor property |
|
|
189 |
if (s != Object && sp.constructor == OP.constructor) { |
|
|
190 |
sp.constructor = s; |
|
|
191 |
} |
|
|
192 |
|
|
|
193 |
// add prototype overrides |
|
|
194 |
if (px) { |
|
|
195 |
Y.mix(rp, px, true); |
|
|
196 |
} |
|
|
197 |
|
|
|
198 |
// add object overrides |
|
|
199 |
if (sx) { |
|
|
200 |
Y.mix(r, sx, true); |
|
|
201 |
} |
|
|
202 |
|
|
|
203 |
return r; |
|
|
204 |
}; |
|
|
205 |
|
|
|
206 |
/** |
|
|
207 |
* Executes the supplied function for each item in |
|
|
208 |
* a collection. Supports arrays, objects, and |
|
|
209 |
* NodeLists |
|
|
210 |
* @method each |
|
|
211 |
* @param {object} o the object to iterate. |
|
|
212 |
* @param {function} f the function to execute. This function |
|
|
213 |
* receives the value, key, and object as parameters. |
|
|
214 |
* @param {object} c the execution context for the function. |
|
|
215 |
* @param {boolean} proto if true, prototype properties are |
|
|
216 |
* iterated on objects. |
|
|
217 |
* @return {YUI} the YUI instance. |
|
|
218 |
*/ |
|
|
219 |
Y.each = function(o, f, c, proto) { |
|
|
220 |
return dispatch(o, f, c, proto, 'each'); |
|
|
221 |
}; |
|
|
222 |
|
|
|
223 |
/** |
|
|
224 |
* Executes the supplied function for each item in |
|
|
225 |
* a collection. The operation stops if the function |
|
|
226 |
* returns true. Supports arrays, objects, and |
|
|
227 |
* NodeLists. |
|
|
228 |
* @method some |
|
|
229 |
* @param {object} o the object to iterate. |
|
|
230 |
* @param {function} f the function to execute. This function |
|
|
231 |
* receives the value, key, and object as parameters. |
|
|
232 |
* @param {object} c the execution context for the function. |
|
|
233 |
* @param {boolean} proto if true, prototype properties are |
|
|
234 |
* iterated on objects. |
|
|
235 |
* @return {boolean} true if the function ever returns true, |
|
|
236 |
* false otherwise. |
|
|
237 |
*/ |
|
|
238 |
Y.some = function(o, f, c, proto) { |
|
|
239 |
return dispatch(o, f, c, proto, 'some'); |
|
|
240 |
}; |
|
|
241 |
|
|
|
242 |
/** |
|
|
243 |
Deep object/array copy. Function clones are actually wrappers around the |
|
|
244 |
original function. Array-like objects are treated as arrays. Primitives are |
|
|
245 |
returned untouched. Optionally, a function can be provided to handle other data |
|
|
246 |
types, filter keys, validate values, etc. |
|
|
247 |
|
|
|
248 |
**Note:** Cloning a non-trivial object is a reasonably heavy operation, due to |
|
|
249 |
the need to recursively iterate down non-primitive properties. Clone should be |
|
|
250 |
used only when a deep clone down to leaf level properties is explicitly |
|
|
251 |
required. This method will also |
|
|
252 |
|
|
|
253 |
In many cases (for example, when trying to isolate objects used as hashes for |
|
|
254 |
configuration properties), a shallow copy, using `Y.merge()` is normally |
|
|
255 |
sufficient. If more than one level of isolation is required, `Y.merge()` can be |
|
|
256 |
used selectively at each level which needs to be isolated from the original |
|
|
257 |
without going all the way to leaf properties. |
|
|
258 |
|
|
|
259 |
@method clone |
|
|
260 |
@param {object} o what to clone. |
|
|
261 |
@param {boolean} safe if true, objects will not have prototype items from the |
|
|
262 |
source. If false, they will. In this case, the original is initially |
|
|
263 |
protected, but the clone is not completely immune from changes to the source |
|
|
264 |
object prototype. Also, cloned prototype items that are deleted from the |
|
|
265 |
clone will result in the value of the source prototype being exposed. If |
|
|
266 |
operating on a non-safe clone, items should be nulled out rather than |
|
|
267 |
deleted. |
|
|
268 |
@param {function} f optional function to apply to each item in a collection; it |
|
|
269 |
will be executed prior to applying the value to the new object. |
|
|
270 |
Return false to prevent the copy. |
|
|
271 |
@param {object} c optional execution context for f. |
|
|
272 |
@param {object} owner Owner object passed when clone is iterating an object. |
|
|
273 |
Used to set up context for cloned functions. |
|
|
274 |
@param {object} cloned hash of previously cloned objects to avoid multiple |
|
|
275 |
clones. |
|
|
276 |
@return {Array|Object} the cloned object. |
|
|
277 |
**/ |
|
|
278 |
Y.clone = function(o, safe, f, c, owner, cloned) { |
|
|
279 |
var o2, marked, stamp; |
|
|
280 |
|
|
|
281 |
// Does not attempt to clone: |
|
|
282 |
// |
|
|
283 |
// * Non-typeof-object values, "primitive" values don't need cloning. |
|
|
284 |
// |
|
|
285 |
// * YUI instances, cloning complex object like YUI instances is not |
|
|
286 |
// advised, this is like cloning the world. |
|
|
287 |
// |
|
|
288 |
// * DOM nodes (#2528250), common host objects like DOM nodes cannot be |
|
|
289 |
// "subclassed" in Firefox and old versions of IE. Trying to use |
|
|
290 |
// `Object.create()` or `Y.extend()` on a DOM node will throw an error in |
|
|
291 |
// these browsers. |
|
|
292 |
// |
|
|
293 |
// Instad, the passed-in `o` will be return as-is when it matches one of the |
|
|
294 |
// above criteria. |
|
|
295 |
if (!L.isObject(o) || |
|
|
296 |
Y.instanceOf(o, YUI) || |
|
|
297 |
(o.addEventListener || o.attachEvent)) { |
|
|
298 |
|
|
|
299 |
return o; |
|
|
300 |
} |
|
|
301 |
|
|
|
302 |
marked = cloned || {}; |
|
|
303 |
|
|
|
304 |
switch (L.type(o)) { |
|
|
305 |
case 'date': |
|
|
306 |
return new Date(o); |
|
|
307 |
case 'regexp': |
|
|
308 |
// if we do this we need to set the flags too |
|
|
309 |
// return new RegExp(o.source); |
|
|
310 |
return o; |
|
|
311 |
case 'function': |
|
|
312 |
// o2 = Y.bind(o, owner); |
|
|
313 |
// break; |
|
|
314 |
return o; |
|
|
315 |
case 'array': |
|
|
316 |
o2 = []; |
|
|
317 |
break; |
|
|
318 |
default: |
|
|
319 |
|
|
|
320 |
// #2528250 only one clone of a given object should be created. |
|
|
321 |
if (o[CLONE_MARKER]) { |
|
|
322 |
return marked[o[CLONE_MARKER]]; |
|
|
323 |
} |
|
|
324 |
|
|
|
325 |
stamp = Y.guid(); |
|
|
326 |
|
|
|
327 |
o2 = (safe) ? {} : Y.Object(o); |
|
|
328 |
|
|
|
329 |
o[CLONE_MARKER] = stamp; |
|
|
330 |
marked[stamp] = o; |
|
|
331 |
} |
|
|
332 |
|
|
|
333 |
Y.each(o, function(v, k) { |
|
|
334 |
if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) { |
|
|
335 |
if (k !== CLONE_MARKER) { |
|
|
336 |
if (k == 'prototype') { |
|
|
337 |
// skip the prototype |
|
|
338 |
// } else if (o[k] === o) { |
|
|
339 |
// this[k] = this; |
|
|
340 |
} else { |
|
|
341 |
this[k] = |
|
|
342 |
Y.clone(v, safe, f, c, owner || o, marked); |
|
|
343 |
} |
|
|
344 |
} |
|
|
345 |
} |
|
|
346 |
}, o2); |
|
|
347 |
|
|
|
348 |
if (!cloned) { |
|
|
349 |
Y.Object.each(marked, function(v, k) { |
|
|
350 |
if (v[CLONE_MARKER]) { |
|
|
351 |
try { |
|
|
352 |
delete v[CLONE_MARKER]; |
|
|
353 |
} catch (e) { |
|
|
354 |
v[CLONE_MARKER] = null; |
|
|
355 |
} |
|
|
356 |
} |
|
|
357 |
}, this); |
|
|
358 |
marked = null; |
|
|
359 |
} |
|
|
360 |
|
|
|
361 |
return o2; |
|
|
362 |
}; |
|
|
363 |
|
|
|
364 |
/** |
|
|
365 |
* Returns a function that will execute the supplied function in the |
|
|
366 |
* supplied object's context, optionally adding any additional |
|
|
367 |
* supplied parameters to the beginning of the arguments collection the |
|
|
368 |
* supplied to the function. |
|
|
369 |
* |
|
|
370 |
* @method bind |
|
|
371 |
* @param {Function|String} f the function to bind, or a function name |
|
|
372 |
* to execute on the context object. |
|
|
373 |
* @param {object} c the execution context. |
|
|
374 |
* @param {any} args* 0..n arguments to include before the arguments the |
|
|
375 |
* function is executed with. |
|
|
376 |
* @return {function} the wrapped function. |
|
|
377 |
*/ |
|
|
378 |
Y.bind = function(f, c) { |
|
|
379 |
var xargs = arguments.length > 2 ? |
|
|
380 |
Y.Array(arguments, 2, true) : null; |
|
|
381 |
return function() { |
|
|
382 |
var fn = L.isString(f) ? c[f] : f, |
|
|
383 |
args = (xargs) ? |
|
|
384 |
xargs.concat(Y.Array(arguments, 0, true)) : arguments; |
|
|
385 |
return fn.apply(c || fn, args); |
|
|
386 |
}; |
|
|
387 |
}; |
|
|
388 |
|
|
|
389 |
/** |
|
|
390 |
* Returns a function that will execute the supplied function in the |
|
|
391 |
* supplied object's context, optionally adding any additional |
|
|
392 |
* supplied parameters to the end of the arguments the function |
|
|
393 |
* is executed with. |
|
|
394 |
* |
|
|
395 |
* @method rbind |
|
|
396 |
* @param {Function|String} f the function to bind, or a function name |
|
|
397 |
* to execute on the context object. |
|
|
398 |
* @param {object} c the execution context. |
|
|
399 |
* @param {any} args* 0..n arguments to append to the end of |
|
|
400 |
* arguments collection supplied to the function. |
|
|
401 |
* @return {function} the wrapped function. |
|
|
402 |
*/ |
|
|
403 |
Y.rbind = function(f, c) { |
|
|
404 |
var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null; |
|
|
405 |
return function() { |
|
|
406 |
var fn = L.isString(f) ? c[f] : f, |
|
|
407 |
args = (xargs) ? |
|
|
408 |
Y.Array(arguments, 0, true).concat(xargs) : arguments; |
|
|
409 |
return fn.apply(c || fn, args); |
|
|
410 |
}; |
|
|
411 |
}; |
|
|
412 |
|
|
|
413 |
|
|
|
414 |
}, '3.10.3', {"requires": ["yui-base"]}); |