2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('oop', function (Y, NAME) {
11 Adds object inheritance and manipulation utilities to the YUI instance. This
12 module is required by most YUI components.
19 OP = Object.prototype,
20 CLONE_MARKER = '_~yuim~_',
22 hasOwn = OP.hasOwnProperty,
23 toString = OP.toString;
26 Calls the specified _action_ method on _o_ if it exists. Otherwise, if _o_ is an
27 array, calls the _action_ method on `Y.Array`, or if _o_ is an object, calls the
28 _action_ method on `Y.Object`.
30 If _o_ is an array-like object, it will be coerced to an array.
32 This is intended to be used with array/object iteration methods that share
33 signatures, such as `each()`, `some()`, etc.
36 @param {Object} o Array or object to dispatch to.
37 @param {Function} f Iteration callback.
38 @param {Mixed} f.value Value being iterated.
39 @param {Mixed} f.key Current object key or array index.
40 @param {Mixed} f.object Object or array being iterated.
41 @param {Object} c `this` object to bind the iteration callback to.
42 @param {Boolean} proto If `true`, prototype properties of objects will be
44 @param {String} action Function name to be dispatched on _o_. For example:
47 @return {Mixed} Returns the value returned by the chosen iteration action, which
50 function dispatch(o, f, c, proto, action) {
51 if (o && o[action] && o !== Y) {
52 return o[action].call(o, f, c);
56 return A[action](o, f, c);
58 return A[action](Y.Array(o, 0, true), f, c);
60 return Y.Object[action](o, f, c, proto);
66 Augments the _receiver_ with prototype properties from the _supplier_. The
67 receiver may be a constructor function or an object. The supplier must be a
70 If the _receiver_ is an object, then the _supplier_ constructor will be called
71 immediately after _receiver_ is augmented, with _receiver_ as the `this` object.
73 If the _receiver_ is a constructor function, then all prototype methods of
74 _supplier_ that are copied to _receiver_ will be sequestered, and the
75 _supplier_ constructor will not be called immediately. The first time any
76 sequestered method is called on the _receiver_'s prototype, all sequestered
77 methods will be immediately copied to the _receiver_'s prototype, the
78 _supplier_'s constructor will be executed, and finally the newly unsequestered
79 method that was called will be executed.
81 This sequestering logic sounds like a bunch of complicated voodoo, but it makes
82 it cheap to perform frequent augmentation by ensuring that suppliers'
83 constructors are only called if a supplied method is actually used. If none of
84 the supplied methods is ever used, then there's no need to take the performance
85 hit of calling the _supplier_'s constructor.
88 @param {Function|Object} receiver Object or function to be augmented.
89 @param {Function} supplier Function that supplies the prototype properties with
90 which to augment the _receiver_.
91 @param {Boolean} [overwrite=false] If `true`, properties already on the receiver
92 will be overwritten if found on the supplier's prototype.
93 @param {String[]} [whitelist] An array of property names. If specified,
94 only the whitelisted prototype properties will be applied to the receiver, and
95 all others will be ignored.
96 @param {Array|any} [args] Argument or array of arguments to pass to the
97 supplier's constructor when initializing.
98 @return {Function} Augmented object.
101 Y.augment = function (receiver, supplier, overwrite, whitelist, args) {
102 var rProto = receiver.prototype,
103 sequester = rProto && supplier,
104 sProto = supplier.prototype,
105 to = rProto || receiver,
113 args = args ? Y.Array(args) : [];
120 copy = function (value, key) {
121 if (overwrite || !(key in rProto)) {
122 if (toString.call(value) === '[object Function]') {
123 sequestered[key] = value;
125 newPrototype[key] = replacements[key] = function () {
126 return unsequester(this, value, arguments);
129 newPrototype[key] = value;
134 unsequester = function (instance, fn, fnArgs) {
135 // Unsequester all sequestered functions.
136 for (var key in sequestered) {
137 if (hasOwn.call(sequestered, key)
138 && instance[key] === replacements[key]) {
140 instance[key] = sequestered[key];
144 // Execute the supplier constructor.
145 supplier.apply(instance, args);
147 // Finally, execute the original sequestered function.
148 return fn.apply(instance, fnArgs);
152 Y.Array.each(whitelist, function (name) {
153 if (name in sProto) {
154 copy(sProto[name], name);
158 Y.Object.each(sProto, copy, null, true);
162 Y.mix(to, newPrototype || sProto, overwrite, whitelist);
165 supplier.apply(to, args);
172 * Copies object properties from the supplier to the receiver. If the target has
173 * the property, and the property is an object, the target object will be
174 * augmented with the supplier's value.
177 * @param {Object} receiver Object to receive the augmentation.
178 * @param {Object} supplier Object that supplies the properties with which to
179 * augment the receiver.
180 * @param {Boolean} [overwrite=false] If `true`, properties already on the receiver
181 * will be overwritten if found on the supplier.
182 * @param {String[]} [whitelist] Whitelist. If supplied, only properties in this
183 * list will be applied to the receiver.
184 * @return {Object} Augmented object.
186 Y.aggregate = function(r, s, ov, wl) {
187 return Y.mix(r, s, ov, wl, 0, true);
191 * Utility to set up the prototype, constructor and superclass properties to
192 * support an inheritance strategy that can chain constructors and methods.
193 * Static members will not be inherited.
196 * @param {function} r the object to modify.
197 * @param {function} s the object to inherit.
198 * @param {object} px prototype properties to add/override.
199 * @param {object} sx static properties to add/override.
200 * @return {object} the extended object.
202 Y.extend = function(r, s, px, sx) {
204 Y.error('extend failed, verify dependencies');
207 var sp = s.prototype, rp = Y.Object(sp);
213 // assign constructor property
214 if (s != Object && sp.constructor == OP.constructor) {
218 // add prototype overrides
223 // add object overrides
232 * Executes the supplied function for each item in
233 * a collection. Supports arrays, objects, and
236 * @param {object} o the object to iterate.
237 * @param {function} f the function to execute. This function
238 * receives the value, key, and object as parameters.
239 * @param {object} c the execution context for the function.
240 * @param {boolean} proto if true, prototype properties are
241 * iterated on objects.
242 * @return {YUI} the YUI instance.
244 Y.each = function(o, f, c, proto) {
245 return dispatch(o, f, c, proto, 'each');
249 * Executes the supplied function for each item in
250 * a collection. The operation stops if the function
251 * returns true. Supports arrays, objects, and
254 * @param {object} o the object to iterate.
255 * @param {function} f the function to execute. This function
256 * receives the value, key, and object as parameters.
257 * @param {object} c the execution context for the function.
258 * @param {boolean} proto if true, prototype properties are
259 * iterated on objects.
260 * @return {boolean} true if the function ever returns true,
263 Y.some = function(o, f, c, proto) {
264 return dispatch(o, f, c, proto, 'some');
268 Deep object/array copy. Function clones are actually wrappers around the
269 original function. Array-like objects are treated as arrays. Primitives are
270 returned untouched. Optionally, a function can be provided to handle other data
271 types, filter keys, validate values, etc.
273 **Note:** Cloning a non-trivial object is a reasonably heavy operation, due to
274 the need to recursively iterate down non-primitive properties. Clone should be
275 used only when a deep clone down to leaf level properties is explicitly
276 required. This method will also
278 In many cases (for example, when trying to isolate objects used as hashes for
279 configuration properties), a shallow copy, using `Y.merge()` is normally
280 sufficient. If more than one level of isolation is required, `Y.merge()` can be
281 used selectively at each level which needs to be isolated from the original
282 without going all the way to leaf properties.
285 @param {object} o what to clone.
286 @param {boolean} safe if true, objects will not have prototype items from the
287 source. If false, they will. In this case, the original is initially
288 protected, but the clone is not completely immune from changes to the source
289 object prototype. Also, cloned prototype items that are deleted from the
290 clone will result in the value of the source prototype being exposed. If
291 operating on a non-safe clone, items should be nulled out rather than
293 @param {function} f optional function to apply to each item in a collection; it
294 will be executed prior to applying the value to the new object.
295 Return false to prevent the copy.
296 @param {object} c optional execution context for f.
297 @param {object} owner Owner object passed when clone is iterating an object.
298 Used to set up context for cloned functions.
299 @param {object} cloned hash of previously cloned objects to avoid multiple
301 @return {Array|Object} the cloned object.
303 Y.clone = function(o, safe, f, c, owner, cloned) {
304 var o2, marked, stamp;
306 // Does not attempt to clone:
308 // * Non-typeof-object values, "primitive" values don't need cloning.
310 // * YUI instances, cloning complex object like YUI instances is not
311 // advised, this is like cloning the world.
313 // * DOM nodes (#2528250), common host objects like DOM nodes cannot be
314 // "subclassed" in Firefox and old versions of IE. Trying to use
315 // `Object.create()` or `Y.extend()` on a DOM node will throw an error in
318 // Instad, the passed-in `o` will be return as-is when it matches one of the
320 if (!L.isObject(o) ||
321 Y.instanceOf(o, YUI) ||
322 (o.addEventListener || o.attachEvent)) {
327 marked = cloned || {};
333 // if we do this we need to set the flags too
334 // return new RegExp(o.source);
337 // o2 = Y.bind(o, owner);
345 // #2528250 only one clone of a given object should be created.
346 if (o[CLONE_MARKER]) {
347 return marked[o[CLONE_MARKER]];
352 o2 = (safe) ? {} : Y.Object(o);
354 o[CLONE_MARKER] = stamp;
358 Y.each(o, function(v, k) {
359 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
360 if (k !== CLONE_MARKER) {
361 if (k == 'prototype') {
362 // skip the prototype
363 // } else if (o[k] === o) {
367 Y.clone(v, safe, f, c, owner || o, marked);
374 Y.Object.each(marked, function(v, k) {
375 if (v[CLONE_MARKER]) {
377 delete v[CLONE_MARKER];
379 v[CLONE_MARKER] = null;
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 beginning of the arguments collection the
393 * supplied to the function.
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 include before the arguments the
400 * function is executed with.
401 * @return {function} the wrapped function.
403 Y.bind = function(f, c) {
404 var xargs = arguments.length > 2 ?
405 Y.Array(arguments, 2, true) : null;
407 var fn = L.isString(f) ? c[f] : f,
409 xargs.concat(Y.Array(arguments, 0, true)) : arguments;
410 return fn.apply(c || fn, args);
415 * Returns a function that will execute the supplied function in the
416 * supplied object's context, optionally adding any additional
417 * supplied parameters to the end of the arguments the function
421 * @param {Function|String} f the function to bind, or a function name
422 * to execute on the context object.
423 * @param {object} c the execution context.
424 * @param {any} args* 0..n arguments to append to the end of
425 * arguments collection supplied to the function.
426 * @return {function} the wrapped function.
428 Y.rbind = function(f, c) {
429 var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
431 var fn = L.isString(f) ? c[f] : f,
433 Y.Array(arguments, 0, true).concat(xargs) : arguments;
434 return fn.apply(c || fn, args);
439 }, '3.13.0', {"requires": ["yui-base"]});