NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / oop / oop-debug.js
blob2d43019985953cbfc983f5f40e82adc85017146d
1 /*
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/
6 */
8 YUI.add('oop', function (Y, NAME) {
10 /**
11 Adds object inheritance and manipulation utilities to the YUI instance. This
12 module is required by most YUI components.
14 @module oop
15 **/
17 var L            = Y.Lang,
18     A            = Y.Array,
19     OP           = Object.prototype,
20     CLONE_MARKER = '_~yuim~_',
22     hasOwn   = OP.hasOwnProperty,
23     toString = OP.toString;
25 /**
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.
35 @method dispatch
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
43     iterated.
44 @param {String} action Function name to be dispatched on _o_. For example:
45     'some', 'each', etc.
46 @private
47 @return {Mixed} Returns the value returned by the chosen iteration action, which
48     varies.
49 **/
50 function dispatch(o, f, c, proto, action) {
51     if (o && o[action] && o !== Y) {
52         return o[action].call(o, f, c);
53     } else {
54         switch (A.test(o)) {
55             case 1:
56                 return A[action](o, f, c);
57             case 2:
58                 return A[action](Y.Array(o, 0, true), f, c);
59             default:
60                 return Y.Object[action](o, f, c, proto);
61         }
62     }
65 /**
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
68 constructor function.
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.
87 @method augment
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.
99 @for YUI
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,
107         copy,
108         newPrototype,
109         replacements,
110         sequestered,
111         unsequester;
113     args = args ? Y.Array(args) : [];
115     if (sequester) {
116         newPrototype = {};
117         replacements = {};
118         sequestered  = {};
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);
127                     };
128                 } else {
129                     newPrototype[key] = value;
130                 }
131             }
132         };
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];
141                 }
142             }
144             // Execute the supplier constructor.
145             supplier.apply(instance, args);
147             // Finally, execute the original sequestered function.
148             return fn.apply(instance, fnArgs);
149         };
151         if (whitelist) {
152             Y.Array.each(whitelist, function (name) {
153                 if (name in sProto) {
154                     copy(sProto[name], name);
155                 }
156             });
157         } else {
158             Y.Object.each(sProto, copy, null, true);
159         }
160     }
162     Y.mix(to, newPrototype || sProto, overwrite, whitelist);
164     if (!sequester) {
165         supplier.apply(to, args);
166     }
168     return receiver;
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.
176  * @method aggregate
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.
185  */
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.
195  * @method extend
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.
201  */
202 Y.extend = function(r, s, px, sx) {
203     if (!s || !r) {
204         Y.error('extend failed, verify dependencies');
205     }
207     var sp = s.prototype, rp = Y.Object(sp);
208     r.prototype = rp;
210     rp.constructor = r;
211     r.superclass = sp;
213     // assign constructor property
214     if (s != Object && sp.constructor == OP.constructor) {
215         sp.constructor = s;
216     }
218     // add prototype overrides
219     if (px) {
220         Y.mix(rp, px, true);
221     }
223     // add object overrides
224     if (sx) {
225         Y.mix(r, sx, true);
226     }
228     return r;
232  * Executes the supplied function for each item in
233  * a collection.  Supports arrays, objects, and
234  * NodeLists
235  * @method each
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.
243  */
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
252  * NodeLists.
253  * @method some
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,
261  * false otherwise.
262  */
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.
284 @method clone
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
292     deleted.
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
300     clones.
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:
307     //
308     // * Non-typeof-object values, "primitive" values don't need cloning.
309     //
310     // * YUI instances, cloning complex object like YUI instances is not
311     //   advised, this is like cloning the world.
312     //
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
316     //   these browsers.
317     //
318     // Instad, the passed-in `o` will be return as-is when it matches one of the
319     // above criteria.
320     if (!L.isObject(o) ||
321             Y.instanceOf(o, YUI) ||
322             (o.addEventListener || o.attachEvent)) {
324         return o;
325     }
327     marked = cloned || {};
329     switch (L.type(o)) {
330         case 'date':
331             return new Date(o);
332         case 'regexp':
333             // if we do this we need to set the flags too
334             // return new RegExp(o.source);
335             return o;
336         case 'function':
337             // o2 = Y.bind(o, owner);
338             // break;
339             return o;
340         case 'array':
341             o2 = [];
342             break;
343         default:
345             // #2528250 only one clone of a given object should be created.
346             if (o[CLONE_MARKER]) {
347                 return marked[o[CLONE_MARKER]];
348             }
350             stamp = Y.guid();
352             o2 = (safe) ? {} : Y.Object(o);
354             o[CLONE_MARKER] = stamp;
355             marked[stamp] = o;
356     }
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) {
364                 //     this[k] = this;
365                 } else {
366                     this[k] =
367                         Y.clone(v, safe, f, c, owner || o, marked);
368                 }
369             }
370         }
371     }, o2);
373     if (!cloned) {
374         Y.Object.each(marked, function(v, k) {
375             if (v[CLONE_MARKER]) {
376                 try {
377                     delete v[CLONE_MARKER];
378                 } catch (e) {
379                     v[CLONE_MARKER] = null;
380                 }
381             }
382         }, this);
383         marked = null;
384     }
386     return o2;
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.
395  * @method bind
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.
402  */
403 Y.bind = function(f, c) {
404     var xargs = arguments.length > 2 ?
405             Y.Array(arguments, 2, true) : null;
406     return function() {
407         var fn = L.isString(f) ? c[f] : f,
408             args = (xargs) ?
409                 xargs.concat(Y.Array(arguments, 0, true)) : arguments;
410         return fn.apply(c || fn, args);
411     };
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
418  * is executed with.
420  * @method rbind
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.
427  */
428 Y.rbind = function(f, c) {
429     var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
430     return function() {
431         var fn = L.isString(f) ? c[f] : f,
432             args = (xargs) ?
433                 Y.Array(arguments, 0, true).concat(xargs) : arguments;
434         return fn.apply(c || fn, args);
435     };
439 }, '3.13.0', {"requires": ["yui-base"]});