API Docs for: 3.8.0
Show:

File: yui/js/yui-core.js

  1. /**
  2. The YUI module contains the components required for building the YUI seed file.
  3. This includes the script loading mechanism, a simple queue, and the core
  4. utilities for the library.

  5. @module yui
  6. @submodule yui-base
  7. **/

  8. var CACHED_DELIMITER = '__',

  9.     hasOwn   = Object.prototype.hasOwnProperty,
  10.     isObject = Y.Lang.isObject;

  11. /**
  12. Returns a wrapper for a function which caches the return value of that function,
  13. keyed off of the combined string representation of the argument values provided
  14. when the wrapper is called.

  15. Calling this function again with the same arguments will return the cached value
  16. rather than executing the wrapped function.

  17. Note that since the cache is keyed off of the string representation of arguments
  18. passed to the wrapper function, arguments that aren't strings and don't provide
  19. a meaningful `toString()` method may result in unexpected caching behavior. For
  20. example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
  21. string `[object Object]` when used as a cache key.

  22. @method cached
  23. @param {Function} source The function to memoize.
  24. @param {Object} [cache={}] Object in which to store cached values. You may seed
  25.   this object with pre-existing cached values if desired.
  26. @param {any} [refetch] If supplied, this value is compared with the cached value
  27.   using a `==` comparison. If the values are equal, the wrapped function is
  28.   executed again even though a cached value exists.
  29. @return {Function} Wrapped function.
  30. @for YUI
  31. **/
  32. Y.cached = function (source, cache, refetch) {
  33.     cache || (cache = {});

  34.     return function (arg) {
  35.         var key = arguments.length > 1 ?
  36.                 Array.prototype.join.call(arguments, CACHED_DELIMITER) :
  37.                 String(arg);

  38.         if (!(key in cache) || (refetch && cache[key] == refetch)) {
  39.             cache[key] = source.apply(source, arguments);
  40.         }

  41.         return cache[key];
  42.     };
  43. };

  44. /**
  45. Returns the `location` object from the window/frame in which this YUI instance
  46. operates, or `undefined` when executing in a non-browser environment
  47. (e.g. Node.js).

  48. It is _not_ recommended to hold references to the `window.location` object
  49. outside of the scope of a function in which its properties are being accessed or
  50. its methods are being called. This is because of a nasty bug/issue that exists
  51. in both Safari and MobileSafari browsers:
  52. [WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).

  53. @method getLocation
  54. @return {location} The `location` object from the window/frame in which this YUI
  55.     instance operates.
  56. @since 3.5.0
  57. **/
  58. Y.getLocation = function () {
  59.     // It is safer to look this up every time because yui-base is attached to a
  60.     // YUI instance before a user's config is applied; i.e. `Y.config.win` does
  61.     // not point the correct window object when this file is loaded.
  62.     var win = Y.config.win;

  63.     // It is not safe to hold a reference to the `location` object outside the
  64.     // scope in which it is being used. The WebKit engine used in Safari and
  65.     // MobileSafari will "disconnect" the `location` object from the `window`
  66.     // when a page is restored from back/forward history cache.
  67.     return win && win.location;
  68. };

  69. /**
  70. Returns a new object containing all of the properties of all the supplied
  71. objects. The properties from later objects will overwrite those in earlier
  72. objects.

  73. Passing in a single object will create a shallow copy of it. For a deep copy,
  74. use `clone()`.

  75. @method merge
  76. @param {Object} objects* One or more objects to merge.
  77. @return {Object} A new merged object.
  78. **/
  79. Y.merge = function () {
  80.     var i      = 0,
  81.         len    = arguments.length,
  82.         result = {},
  83.         key,
  84.         obj;

  85.     for (; i < len; ++i) {
  86.         obj = arguments[i];

  87.         for (key in obj) {
  88.             if (hasOwn.call(obj, key)) {
  89.                 result[key] = obj[key];
  90.             }
  91.         }
  92.     }

  93.     return result;
  94. };

  95. /**
  96. Mixes _supplier_'s properties into _receiver_.

  97. Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
  98. shadowed unless the _overwrite_ parameter is `true`, and will not be merged
  99. unless the _merge_ parameter is `true`.

  100. In the default mode (0), only properties the supplier owns are copied (prototype
  101. properties are not copied). The following copying modes are available:

  102.   * `0`: _Default_. Object to object.
  103.   * `1`: Prototype to prototype.
  104.   * `2`: Prototype to prototype and object to object.
  105.   * `3`: Prototype to object.
  106.   * `4`: Object to prototype.

  107. @method mix
  108. @param {Function|Object} receiver The object or function to receive the mixed
  109.   properties.
  110. @param {Function|Object} supplier The object or function supplying the
  111.   properties to be mixed.
  112. @param {Boolean} [overwrite=false] If `true`, properties that already exist
  113.   on the receiver will be overwritten with properties from the supplier.
  114. @param {String[]} [whitelist] An array of property names to copy. If
  115.   specified, only the whitelisted properties will be copied, and all others
  116.   will be ignored.
  117. @param {Number} [mode=0] Mix mode to use. See above for available modes.
  118. @param {Boolean} [merge=false] If `true`, objects and arrays that already
  119.   exist on the receiver will have the corresponding object/array from the
  120.   supplier merged into them, rather than being skipped or overwritten. When
  121.   both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
  122. @return {Function|Object|YUI} The receiver, or the YUI instance if the
  123.   specified receiver is falsy.
  124. **/
  125. Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
  126.     var alwaysOverwrite, exists, from, i, key, len, to;

  127.     // If no supplier is given, we return the receiver. If no receiver is given,
  128.     // we return Y. Returning Y doesn't make much sense to me, but it's
  129.     // grandfathered in for backcompat reasons.
  130.     if (!receiver || !supplier) {
  131.         return receiver || Y;
  132.     }

  133.     if (mode) {
  134.         // In mode 2 (prototype to prototype and object to object), we recurse
  135.         // once to do the proto to proto mix. The object to object mix will be
  136.         // handled later on.
  137.         if (mode === 2) {
  138.             Y.mix(receiver.prototype, supplier.prototype, overwrite,
  139.                     whitelist, 0, merge);
  140.         }

  141.         // Depending on which mode is specified, we may be copying from or to
  142.         // the prototypes of the supplier and receiver.
  143.         from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
  144.         to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;

  145.         // If either the supplier or receiver doesn't actually have a
  146.         // prototype property, then we could end up with an undefined `from`
  147.         // or `to`. If that happens, we abort and return the receiver.
  148.         if (!from || !to) {
  149.             return receiver;
  150.         }
  151.     } else {
  152.         from = supplier;
  153.         to   = receiver;
  154.     }

  155.     // If `overwrite` is truthy and `merge` is falsy, then we can skip a
  156.     // property existence check on each iteration and save some time.
  157.     alwaysOverwrite = overwrite && !merge;

  158.     if (whitelist) {
  159.         for (i = 0, len = whitelist.length; i < len; ++i) {
  160.             key = whitelist[i];

  161.             // We call `Object.prototype.hasOwnProperty` instead of calling
  162.             // `hasOwnProperty` on the object itself, since the object's
  163.             // `hasOwnProperty` method may have been overridden or removed.
  164.             // Also, some native objects don't implement a `hasOwnProperty`
  165.             // method.
  166.             if (!hasOwn.call(from, key)) {
  167.                 continue;
  168.             }

  169.             // The `key in to` check here is (sadly) intentional for backwards
  170.             // compatibility reasons. It prevents undesired shadowing of
  171.             // prototype members on `to`.
  172.             exists = alwaysOverwrite ? false : key in to;

  173.             if (merge && exists && isObject(to[key], true)
  174.                     && isObject(from[key], true)) {
  175.                 // If we're in merge mode, and the key is present on both
  176.                 // objects, and the value on both objects is either an object or
  177.                 // an array (but not a function), then we recurse to merge the
  178.                 // `from` value into the `to` value instead of overwriting it.
  179.                 //
  180.                 // Note: It's intentional that the whitelist isn't passed to the
  181.                 // recursive call here. This is legacy behavior that lots of
  182.                 // code still depends on.
  183.                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
  184.             } else if (overwrite || !exists) {
  185.                 // We're not in merge mode, so we'll only copy the `from` value
  186.                 // to the `to` value if we're in overwrite mode or if the
  187.                 // current key doesn't exist on the `to` object.
  188.                 to[key] = from[key];
  189.             }
  190.         }
  191.     } else {
  192.         for (key in from) {
  193.             // The code duplication here is for runtime performance reasons.
  194.             // Combining whitelist and non-whitelist operations into a single
  195.             // loop or breaking the shared logic out into a function both result
  196.             // in worse performance, and Y.mix is critical enough that the byte
  197.             // tradeoff is worth it.
  198.             if (!hasOwn.call(from, key)) {
  199.                 continue;
  200.             }

  201.             // The `key in to` check here is (sadly) intentional for backwards
  202.             // compatibility reasons. It prevents undesired shadowing of
  203.             // prototype members on `to`.
  204.             exists = alwaysOverwrite ? false : key in to;

  205.             if (merge && exists && isObject(to[key], true)
  206.                     && isObject(from[key], true)) {
  207.                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
  208.             } else if (overwrite || !exists) {
  209.                 to[key] = from[key];
  210.             }
  211.         }

  212.         // If this is an IE browser with the JScript enumeration bug, force
  213.         // enumeration of the buggy properties by making a recursive call with
  214.         // the buggy properties as the whitelist.
  215.         if (Y.Object._hasEnumBug) {
  216.             Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
  217.         }
  218.     }

  219.     return receiver;
  220. };

  221.