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