src/cm/media/js/lib/yui/yui3-3.15.0/build/oop/oop.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     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 }, '@VERSION@', {"requires": ["yui-base"]});