NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / yui-core / yui-core.js
blob5028af8499430bb6494e2e2c6446156410a581d7
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 /**
9 The YUI module contains the components required for building the YUI seed file.
10 This includes the script loading mechanism, a simple queue, and the core
11 utilities for the library.
13 @module yui
14 @main yui
15 @submodule yui-base
16 **/
18 /*jshint eqeqeq: false*/
19 if (typeof YUI != 'undefined') {
20     YUI._YUI = YUI;
23 /**
24 The YUI global namespace object. This is the constructor for all YUI instances.
26 This is a self-instantiable factory function, meaning you don't need to precede
27 it with the `new` operator. You can invoke it directly like this:
29     YUI().use('*', function (Y) {
30         // Y is a new YUI instance.
31     });
33 But it also works like this:
35     var Y = YUI();
37 The `YUI` constructor accepts an optional config object, like this:
39     YUI({
40         debug: true,
41         combine: false
42     }).use('node', function (Y) {
43         // Y.Node is ready to use.
44     });
46 See the API docs for the <a href="config.html">Config</a> class for the complete
47 list of supported configuration properties accepted by the YUI constuctor.
49 If a global `YUI` object is already defined, the existing YUI object will not be
50 overwritten, to ensure that defined namespaces are preserved.
52 Each YUI instance has full custom event support, but only if the event system is
53 available.
55 @class YUI
56 @uses EventTarget
57 @constructor
58 @global
59 @param {Object} [config]* Zero or more optional configuration objects. Config
60     values are stored in the `Y.config` property. See the
61     <a href="config.html">Config</a> docs for the list of supported properties.
62 **/
64     /*global YUI*/
65     /*global YUI_config*/
66     var YUI = function() {
67         var i = 0,
68             Y = this,
69             args = arguments,
70             l = args.length,
71             instanceOf = function(o, type) {
72                 return (o && o.hasOwnProperty && (o instanceof type));
73             },
74             gconf = (typeof YUI_config !== 'undefined') && YUI_config;
76         if (!(instanceOf(Y, YUI))) {
77             Y = new YUI();
78         } else {
79             // set up the core environment
80             Y._init();
82             /**
83             Master configuration that might span multiple contexts in a non-
84             browser environment. It is applied first to all instances in all
85             contexts.
87             @example
89                 YUI.GlobalConfig = {
90                     filter: 'debug'
91                 };
93                 YUI().use('node', function (Y) {
94                     // debug files used here
95                 });
97                 YUI({
98                     filter: 'min'
99                 }).use('node', function (Y) {
100                     // min files used here
101                 });
103             @property {Object} GlobalConfig
104             @global
105             @static
106             **/
107             if (YUI.GlobalConfig) {
108                 Y.applyConfig(YUI.GlobalConfig);
109             }
111             /**
112             Page-level config applied to all YUI instances created on the
113             current page. This is applied after `YUI.GlobalConfig` and before
114             any instance-level configuration.
116             @example
118                 // Single global var to include before YUI seed file
119                 YUI_config = {
120                     filter: 'debug'
121                 };
123                 YUI().use('node', function (Y) {
124                     // debug files used here
125                 });
127                 YUI({
128                     filter: 'min'
129                 }).use('node', function (Y) {
130                     // min files used here
131                 });
133             @property {Object} YUI_config
134             @global
135             **/
136             if (gconf) {
137                 Y.applyConfig(gconf);
138             }
140             // bind the specified additional modules for this instance
141             if (!l) {
142                 Y._setup();
143             }
144         }
146         if (l) {
147             // Each instance can accept one or more configuration objects.
148             // These are applied after YUI.GlobalConfig and YUI_Config,
149             // overriding values set in those config files if there is a
150             // matching property.
151             for (; i < l; i++) {
152                 Y.applyConfig(args[i]);
153             }
155             Y._setup();
156         }
158         Y.instanceOf = instanceOf;
160         return Y;
161     };
163 (function() {
165     var proto, prop,
166         VERSION = '3.13.0',
167         PERIOD = '.',
168         BASE = 'http://yui.yahooapis.com/',
169         /*
170             These CSS class names can't be generated by
171             getClassName since it is not available at the
172             time they are being used.
173         */
174         DOC_LABEL = 'yui3-js-enabled',
175         CSS_STAMP_EL = 'yui3-css-stamp',
176         NOOP = function() {},
177         SLICE = Array.prototype.slice,
178         APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
179                           'io.xdrResponse': 1,   // can call. this should
180                           'SWF.eventHandler': 1 }, // be done at build time
181         hasWin = (typeof window != 'undefined'),
182         win = (hasWin) ? window : null,
183         doc = (hasWin) ? win.document : null,
184         docEl = doc && doc.documentElement,
185         docClass = docEl && docEl.className,
186         instances = {},
187         time = new Date().getTime(),
188         add = function(el, type, fn, capture) {
189             if (el && el.addEventListener) {
190                 el.addEventListener(type, fn, capture);
191             } else if (el && el.attachEvent) {
192                 el.attachEvent('on' + type, fn);
193             }
194         },
195         remove = function(el, type, fn, capture) {
196             if (el && el.removeEventListener) {
197                 // this can throw an uncaught exception in FF
198                 try {
199                     el.removeEventListener(type, fn, capture);
200                 } catch (ex) {}
201             } else if (el && el.detachEvent) {
202                 el.detachEvent('on' + type, fn);
203             }
204         },
205         handleLoad = function() {
206             YUI.Env.windowLoaded = true;
207             YUI.Env.DOMReady = true;
208             if (hasWin) {
209                 remove(window, 'load', handleLoad);
210             }
211         },
212         getLoader = function(Y, o) {
213             var loader = Y.Env._loader,
214                 lCore = [ 'loader-base' ],
215                 G_ENV = YUI.Env,
216                 mods = G_ENV.mods;
218             if (loader) {
219                 //loader._config(Y.config);
220                 loader.ignoreRegistered = false;
221                 loader.onEnd = null;
222                 loader.data = null;
223                 loader.required = [];
224                 loader.loadType = null;
225             } else {
226                 loader = new Y.Loader(Y.config);
227                 Y.Env._loader = loader;
228             }
229             if (mods && mods.loader) {
230                 lCore = [].concat(lCore, YUI.Env.loaderExtras);
231             }
232             YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore));
234             return loader;
235         },
237         clobber = function(r, s) {
238             for (var i in s) {
239                 if (s.hasOwnProperty(i)) {
240                     r[i] = s[i];
241                 }
242             }
243         },
245         ALREADY_DONE = { success: true };
247 //  Stamp the documentElement (HTML) with a class of "yui-loaded" to
248 //  enable styles that need to key off of JS being enabled.
249 if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
250     if (docClass) {
251         docClass += ' ';
252     }
253     docClass += DOC_LABEL;
254     docEl.className = docClass;
257 if (VERSION.indexOf('@') > -1) {
258     VERSION = '3.5.0'; // dev time hack for cdn test
261 proto = {
262     /**
263     Applies a new configuration object to the config of this YUI instance. This
264     will merge new group/module definitions, and will also update the loader
265     cache if necessary. Updating `Y.config` directly will not update the cache.
267     @method applyConfig
268     @param {Object} o the configuration object.
269     @since 3.2.0
270     **/
271     applyConfig: function(o) {
273         o = o || NOOP;
275         var attr,
276             name,
277             // detail,
278             config = this.config,
279             mods = config.modules,
280             groups = config.groups,
281             aliases = config.aliases,
282             loader = this.Env._loader;
284         for (name in o) {
285             if (o.hasOwnProperty(name)) {
286                 attr = o[name];
287                 if (mods && name == 'modules') {
288                     clobber(mods, attr);
289                 } else if (aliases && name == 'aliases') {
290                     clobber(aliases, attr);
291                 } else if (groups && name == 'groups') {
292                     clobber(groups, attr);
293                 } else if (name == 'win') {
294                     config[name] = (attr && attr.contentWindow) || attr;
295                     config.doc = config[name] ? config[name].document : null;
296                 } else if (name == '_yuid') {
297                     // preserve the guid
298                 } else {
299                     config[name] = attr;
300                 }
301             }
302         }
304         if (loader) {
305             loader._config(o);
306         }
308     },
310     /**
311     Old way to apply a config to this instance (calls `applyConfig` under the
312     hood).
314     @private
315     @method _config
316     @param {Object} o The config to apply
317     **/
318     _config: function(o) {
319         this.applyConfig(o);
320     },
322     /**
323     Initializes this YUI instance.
325     @private
326     @method _init
327     **/
328     _init: function() {
329         var filter, el,
330             Y = this,
331             G_ENV = YUI.Env,
332             Env = Y.Env,
333             prop;
335         /**
336         The version number of this YUI instance.
338         This value is typically updated by a script when a YUI release is built,
339         so it may not reflect the correct version number when YUI is run from
340         the development source tree.
342         @property {String} version
343         **/
344         Y.version = VERSION;
346         if (!Env) {
347             Y.Env = {
348                 core: ['intl-base'],
349                 loaderExtras: ['loader-rollup', 'loader-yui3'],
350                 mods: {}, // flat module map
351                 versions: {}, // version module map
352                 base: BASE,
353                 cdn: BASE + VERSION + '/build/',
354                 // bootstrapped: false,
355                 _idx: 0,
356                 _used: {},
357                 _attached: {},
358                 _missed: [],
359                 _yidx: 0,
360                 _uidx: 0,
361                 _guidp: 'y',
362                 _loaded: {},
363                 // serviced: {},
364                 // Regex in English:
365                 // I'll start at the \b(yui).
366                 // 1. Look in the test string for "yui" or
367                 //    "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break.  That is, it
368                 //    can't match "foyui" or "i_heart_yui". This can be anywhere in the string.
369                 // 2. After #1 must come a forward slash followed by the string matched in #1, so
370                 //    "yui-base/yui-base" or "yui-pants/yui-pants".
371                 // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
372                 //    so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
373                 // 4. This is followed by ".js", so "yui/yui.js".
374                 // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
375                 //    then capture the junk between the LAST "&" and the string in 1-4.  So
376                 //    "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
377                 //    will capture "3.3.0/build/"
378                 //
379                 // Regex Exploded:
380                 // (?:\?             Find a ?
381                 //   (?:[^&]*&)      followed by 0..n characters followed by an &
382                 //   *               in fact, find as many sets of characters followed by a & as you can
383                 //   ([^&]*)         capture the stuff after the last & in \1
384                 // )?                but it's ok if all this ?junk&more_junk stuff isn't even there
385                 // \b(               after a word break find either the string
386                 //    yui(?:-\w+)?   "yui" optionally followed by a -, then more characters
387                 // )                 and store the yui-* string in \2
388                 // \/\2              then comes a / followed by the yui-* string in \2
389                 // (?:-(min|debug))? optionally followed by "-min" or "-debug"
390                 // .js               and ending in ".js"
391                 _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
392                 parseBasePath: function(src, pattern) {
393                     var match = src.match(pattern),
394                         path, filter;
396                     if (match) {
397                         path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
399                         // this is to set up the path to the loader.  The file
400                         // filter for loader should match the yui include.
401                         filter = match[3];
403                         // extract correct path for mixed combo urls
404                         // http://yuilibrary.com/projects/yui3/ticket/2528423
405                         if (match[1]) {
406                             path += '?' + match[1];
407                         }
408                         path = {
409                             filter: filter,
410                             path: path
411                         };
412                     }
413                     return path;
414                 },
415                 getBase: G_ENV && G_ENV.getBase ||
416                         function(pattern) {
417                             var nodes = (doc && doc.getElementsByTagName('script')) || [],
418                                 path = Env.cdn, parsed,
419                                 i, len, src;
421                             for (i = 0, len = nodes.length; i < len; ++i) {
422                                 src = nodes[i].src;
423                                 if (src) {
424                                     parsed = Y.Env.parseBasePath(src, pattern);
425                                     if (parsed) {
426                                         filter = parsed.filter;
427                                         path = parsed.path;
428                                         break;
429                                     }
430                                 }
431                             }
433                             // use CDN default
434                             return path;
435                         }
437             };
439             Env = Y.Env;
441             Env._loaded[VERSION] = {};
443             if (G_ENV && Y !== YUI) {
444                 Env._yidx = ++G_ENV._yidx;
445                 Env._guidp = ('yui_' + VERSION + '_' +
446                              Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_');
447             } else if (YUI._YUI) {
449                 G_ENV = YUI._YUI.Env;
450                 Env._yidx += G_ENV._yidx;
451                 Env._uidx += G_ENV._uidx;
453                 for (prop in G_ENV) {
454                     if (!(prop in Env)) {
455                         Env[prop] = G_ENV[prop];
456                     }
457                 }
459                 delete YUI._YUI;
460             }
462             Y.id = Y.stamp(Y);
463             instances[Y.id] = Y;
465         }
467         Y.constructor = YUI;
469         // configuration defaults
470         Y.config = Y.config || {
471             bootstrap: true,
472             cacheUse: true,
473             debug: true,
474             doc: doc,
475             fetchCSS: true,
476             throwFail: true,
477             useBrowserConsole: true,
478             useNativeES5: true,
479             win: win,
480             global: Function('return this')()
481         };
483         //Register the CSS stamp element
484         if (doc && !doc.getElementById(CSS_STAMP_EL)) {
485             el = doc.createElement('div');
486             el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
487             YUI.Env.cssStampEl = el.firstChild;
488             if (doc.body) {
489                 doc.body.appendChild(YUI.Env.cssStampEl);
490             } else {
491                 docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
492             }
493         } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) {
494             YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL);
495         }
497         Y.config.lang = Y.config.lang || 'en-US';
499         Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
501         if (!filter || (!('mindebug').indexOf(filter))) {
502             filter = 'min';
503         }
504         filter = (filter) ? '-' + filter : filter;
505         Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
507     },
509     /**
510     Finishes the instance setup. Attaches whatever YUI modules were defined
511     at the time that this instance was created.
513     @method _setup
514     @private
515     **/
516     _setup: function() {
517         var i, Y = this,
518             core = [],
519             mods = YUI.Env.mods,
520             extras = Y.config.core || [].concat(YUI.Env.core); //Clone it..
522         for (i = 0; i < extras.length; i++) {
523             if (mods[extras[i]]) {
524                 core.push(extras[i]);
525             }
526         }
528         Y._attach(['yui-base']);
529         Y._attach(core);
531         if (Y.Loader) {
532             getLoader(Y);
533         }
535     },
537     /**
538     Executes the named method on the specified YUI instance if that method is
539     whitelisted.
541     @method applyTo
542     @param {String} id YUI instance id.
543     @param {String} method Name of the method to execute. For example:
544         'Object.keys'.
545     @param {Array} args Arguments to apply to the method.
546     @return {Mixed} Return value from the applied method, or `null` if the
547         specified instance was not found or the method was not whitelisted.
548     **/
549     applyTo: function(id, method, args) {
550         if (!(method in APPLY_TO_AUTH)) {
551             this.log(method + ': applyTo not allowed', 'warn', 'yui');
552             return null;
553         }
555         var instance = instances[id], nest, m, i;
556         if (instance) {
557             nest = method.split('.');
558             m = instance;
559             for (i = 0; i < nest.length; i = i + 1) {
560                 m = m[nest[i]];
561                 if (!m) {
562                     this.log('applyTo not found: ' + method, 'warn', 'yui');
563                 }
564             }
565             return m && m.apply(instance, args);
566         }
568         return null;
569     },
572 Registers a YUI module and makes it available for use in a `YUI().use()` call or
573 as a dependency for other modules.
575 The easiest way to create a first-class YUI module is to use
576 <a href="http://yui.github.com/shifter/">Shifter</a>, the YUI component build
577 tool.
579 Shifter will automatically wrap your module code in a `YUI.add()` call along
580 with any configuration info required for the module.
582 @example
584     YUI.add('davglass', function (Y) {
585         Y.davglass = function () {
586         };
587     }, '3.4.0', {
588         requires: ['harley-davidson', 'mt-dew']
589     });
591 @method add
592 @param {String} name Module name.
593 @param {Function} fn Function containing module code. This function will be
594     executed whenever the module is attached to a specific YUI instance.
596     @param {YUI} fn.Y The YUI instance to which this module is attached.
597     @param {String} fn.name Name of the module
599 @param {String} version Module version number. This is currently used only for
600     informational purposes, and is not used internally by YUI.
602 @param {Object} [config] Module config.
603     @param {Array} [config.requires] Array of other module names that must be
604         attached before this module can be attached.
605     @param {Array} [config.optional] Array of optional module names that should
606         be attached before this module is attached if they've already been
607         loaded. If the `loadOptional` YUI option is `true`, optional modules
608         that have not yet been loaded will be loaded just as if they were hard
609         requirements.
610     @param {Array} [config.use] Array of module names that are included within
611         or otherwise provided by this module, and which should be attached
612         automatically when this module is attached. This makes it possible to
613         create "virtual rollup" modules that simply attach a collection of other
614         modules or submodules.
616 @return {YUI} This YUI instance.
618     add: function(name, fn, version, details) {
619         details = details || {};
620         var env = YUI.Env,
621             mod = {
622                 name: name,
623                 fn: fn,
624                 version: version,
625                 details: details
626             },
627             //Instance hash so we don't apply it to the same instance twice
628             applied = {},
629             loader, inst,
630             i, versions = env.versions;
632         env.mods[name] = mod;
633         versions[version] = versions[version] || {};
634         versions[version][name] = mod;
636         for (i in instances) {
637             if (instances.hasOwnProperty(i)) {
638                 inst = instances[i];
639                 if (!applied[inst.id]) {
640                     applied[inst.id] = true;
641                     loader = inst.Env._loader;
642                     if (loader) {
643                         if (!loader.moduleInfo[name] || loader.moduleInfo[name].temp) {
644                             loader.addModule(details, name);
645                         }
646                     }
647                 }
648             }
649         }
651         return this;
652     },
654     /**
655     Executes the callback function associated with each required module,
656     attaching the module to this YUI instance.
658     @method _attach
659     @param {Array} r The array of modules to attach
660     @param {Boolean} [moot=false] If `true`, don't throw a warning if the module
661         is not attached.
662     @private
663     **/
664     _attach: function(r, moot) {
665         var i, name, mod, details, req, use, after,
666             mods = YUI.Env.mods,
667             aliases = YUI.Env.aliases,
668             Y = this, j,
669             cache = YUI.Env._renderedMods,
670             loader = Y.Env._loader,
671             done = Y.Env._attached,
672             len = r.length, loader, def, go,
673             c = [];
675         //Check for conditional modules (in a second+ instance) and add their requirements
676         //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
677         for (i = 0; i < len; i++) {
678             name = r[i];
679             mod = mods[name];
680             c.push(name);
681             if (loader && loader.conditions[name]) {
682                 for (j in loader.conditions[name]) {
683                     if (loader.conditions[name].hasOwnProperty(j)) {
684                         def = loader.conditions[name][j];
685                         go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
686                         if (go) {
687                             c.push(def.name);
688                         }
689                     }
690                 }
691             }
692         }
693         r = c;
694         len = r.length;
696         for (i = 0; i < len; i++) {
697             if (!done[r[i]]) {
698                 name = r[i];
699                 mod = mods[name];
701                 if (aliases && aliases[name] && !mod) {
702                     Y._attach(aliases[name]);
703                     continue;
704                 }
705                 if (!mod) {
706                     if (loader && loader.moduleInfo[name]) {
707                         mod = loader.moduleInfo[name];
708                         moot = true;
709                     }
712                     //if (!loader || !loader.moduleInfo[name]) {
713                     //if ((!loader || !loader.moduleInfo[name]) && !moot) {
714                     if (!moot && name) {
715                         if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
716                             Y.Env._missed.push(name);
717                             Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
718                             Y.message('NOT loaded: ' + name, 'warn', 'yui');
719                         }
720                     }
721                 } else {
722                     done[name] = true;
723                     //Don't like this, but in case a mod was asked for once, then we fetch it
724                     //We need to remove it from the missed list ^davglass
725                     for (j = 0; j < Y.Env._missed.length; j++) {
726                         if (Y.Env._missed[j] === name) {
727                             Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
728                             Y.Env._missed.splice(j, 1);
729                         }
730                     }
731                     /*
732                         If it's a temp module, we need to redo it's requirements if it's already loaded
733                         since it may have been loaded by another instance and it's dependencies might
734                         have been redefined inside the fetched file.
735                     */
736                     if (loader && cache && cache[name] && cache[name].temp) {
737                         loader.getRequires(cache[name]);
738                         req = [];
739                         for (j in loader.moduleInfo[name].expanded_map) {
740                             if (loader.moduleInfo[name].expanded_map.hasOwnProperty(j)) {
741                                 req.push(j);
742                             }
743                         }
744                         Y._attach(req);
745                     }
747                     details = mod.details;
748                     req = details.requires;
749                     use = details.use;
750                     after = details.after;
751                     //Force Intl load if there is a language (Loader logic) @todo fix this shit
752                     if (details.lang) {
753                         req = req || [];
754                         req.unshift('intl');
755                     }
757                     if (req) {
758                         for (j = 0; j < req.length; j++) {
759                             if (!done[req[j]]) {
760                                 if (!Y._attach(req)) {
761                                     return false;
762                                 }
763                                 break;
764                             }
765                         }
766                     }
768                     if (after) {
769                         for (j = 0; j < after.length; j++) {
770                             if (!done[after[j]]) {
771                                 if (!Y._attach(after, true)) {
772                                     return false;
773                                 }
774                                 break;
775                             }
776                         }
777                     }
779                     if (mod.fn) {
780                             if (Y.config.throwFail) {
781                                 mod.fn(Y, name);
782                             } else {
783                                 try {
784                                     mod.fn(Y, name);
785                                 } catch (e) {
786                                     Y.error('Attach error: ' + name, e, name);
787                                 return false;
788                             }
789                         }
790                     }
792                     if (use) {
793                         for (j = 0; j < use.length; j++) {
794                             if (!done[use[j]]) {
795                                 if (!Y._attach(use)) {
796                                     return false;
797                                 }
798                                 break;
799                             }
800                         }
801                     }
805                 }
806             }
807         }
809         return true;
810     },
812     /**
813     Delays the `use` callback until another event has taken place such as
814     `window.onload`, `domready`, `contentready`, or `available`.
816     @private
817     @method _delayCallback
818     @param {Function} cb The original `use` callback.
819     @param {String|Object} until Either an event name ('load', 'domready', etc.)
820         or an object containing event/args keys for contentready/available.
821     @return {Function}
822     **/
823     _delayCallback: function(cb, until) {
825         var Y = this,
826             mod = ['event-base'];
828         until = (Y.Lang.isObject(until) ? until : { event: until });
830         if (until.event === 'load') {
831             mod.push('event-synthetic');
832         }
834         return function() {
835             var args = arguments;
836             Y._use(mod, function() {
837                 Y.on(until.event, function() {
838                     args[1].delayUntil = until.event;
839                     cb.apply(Y, args);
840                 }, until.args);
841             });
842         };
843     },
845     /**
846     Attaches one or more modules to this YUI instance. When this is executed,
847     the requirements of the desired modules are analyzed, and one of several
848     things can happen:
851       * All required modules have already been loaded, and just need to be
852         attached to this YUI instance. In this case, the `use()` callback will
853         be executed synchronously after the modules are attached.
855       * One or more modules have not yet been loaded, or the Get utility is not
856         available, or the `bootstrap` config option is `false`. In this case,
857         a warning is issued indicating that modules are missing, but all
858         available modules will still be attached and the `use()` callback will
859         be executed synchronously.
861       * One or more modules are missing and the Loader is not available but the
862         Get utility is, and `bootstrap` is not `false`. In this case, the Get
863         utility will be used to load the Loader, and we will then proceed to
864         the following state:
866       * One or more modules are missing and the Loader is available. In this
867         case, the Loader will be used to resolve the dependency tree for the
868         missing modules and load them and their dependencies. When the Loader is
869         finished loading modules, the `use()` callback will be executed
870         asynchronously.
872     @example
874         // Loads and attaches dd and its dependencies.
875         YUI().use('dd', function (Y) {
876             // ...
877         });
879         // Loads and attaches dd and node as well as all of their dependencies.
880         YUI().use(['dd', 'node'], function (Y) {
881             // ...
882         });
884         // Attaches all modules that have already been loaded.
885         YUI().use('*', function (Y) {
886             // ...
887         });
889         // Attaches a gallery module.
890         YUI().use('gallery-yql', function (Y) {
891             // ...
892         });
894         // Attaches a YUI 2in3 module.
895         YUI().use('yui2-datatable', function (Y) {
896             // ...
897         });
899     @method use
900     @param {String|Array} modules* One or more module names to attach.
901     @param {Function} [callback] Callback function to be executed once all
902         specified modules and their dependencies have been attached.
903     @param {YUI} callback.Y The YUI instance created for this sandbox.
904     @param {Object} callback.status Object containing `success`, `msg` and
905         `data` properties.
906     @chainable
907     **/
908     use: function() {
909         var args = SLICE.call(arguments, 0),
910             callback = args[args.length - 1],
911             Y = this,
912             i = 0,
913             name,
914             Env = Y.Env,
915             provisioned = true;
917         // The last argument supplied to use can be a load complete callback
918         if (Y.Lang.isFunction(callback)) {
919             args.pop();
920             if (Y.config.delayUntil) {
921                 callback = Y._delayCallback(callback, Y.config.delayUntil);
922             }
923         } else {
924             callback = null;
925         }
926         if (Y.Lang.isArray(args[0])) {
927             args = args[0];
928         }
930         if (Y.config.cacheUse) {
931             while ((name = args[i++])) {
932                 if (!Env._attached[name]) {
933                     provisioned = false;
934                     break;
935                 }
936             }
938             if (provisioned) {
939                 if (args.length) {
940                 }
941                 Y._notify(callback, ALREADY_DONE, args);
942                 return Y;
943             }
944         }
946         if (Y._loading) {
947             Y._useQueue = Y._useQueue || new Y.Queue();
948             Y._useQueue.add([args, callback]);
949         } else {
950             Y._use(args, function(Y, response) {
951                 Y._notify(callback, response, args);
952             });
953         }
955         return Y;
956     },
958     /**
959     Handles Loader notifications about attachment/load errors.
961     @method _notify
962     @param {Function} callback Callback to pass to `Y.config.loadErrorFn`.
963     @param {Object} response Response returned from Loader.
964     @param {Array} args Arguments passed from Loader.
965     @private
966     **/
967     _notify: function(callback, response, args) {
968         if (!response.success && this.config.loadErrorFn) {
969             this.config.loadErrorFn.call(this, this, callback, response, args);
970         } else if (callback) {
971             if (this.Env._missed && this.Env._missed.length) {
972                 response.msg = 'Missing modules: ' + this.Env._missed.join();
973                 response.success = false;
974             }
975             if (this.config.throwFail) {
976                 callback(this, response);
977             } else {
978                 try {
979                     callback(this, response);
980                 } catch (e) {
981                     this.error('use callback error', e, args);
982                 }
983             }
984         }
985     },
987     /**
988     Called from the `use` method queue to ensure that only one set of loading
989     logic is performed at a time.
991     @method _use
992     @param {String} args* One or more modules to attach.
993     @param {Function} [callback] Function to call once all required modules have
994         been attached.
995     @private
996     **/
997     _use: function(args, callback) {
999         if (!this.Array) {
1000             this._attach(['yui-base']);
1001         }
1003         var len, loader, handleBoot,
1004             Y = this,
1005             G_ENV = YUI.Env,
1006             mods = G_ENV.mods,
1007             Env = Y.Env,
1008             used = Env._used,
1009             aliases = G_ENV.aliases,
1010             queue = G_ENV._loaderQueue,
1011             firstArg = args[0],
1012             YArray = Y.Array,
1013             config = Y.config,
1014             boot = config.bootstrap,
1015             missing = [],
1016             i,
1017             r = [],
1018             ret = true,
1019             fetchCSS = config.fetchCSS,
1020             process = function(names, skip) {
1022                 var i = 0, a = [], name, len, m, req, use;
1024                 if (!names.length) {
1025                     return;
1026                 }
1028                 if (aliases) {
1029                     len = names.length;
1030                     for (i = 0; i < len; i++) {
1031                         if (aliases[names[i]] && !mods[names[i]]) {
1032                             a = [].concat(a, aliases[names[i]]);
1033                         } else {
1034                             a.push(names[i]);
1035                         }
1036                     }
1037                     names = a;
1038                 }
1040                 len = names.length;
1042                 for (i = 0; i < len; i++) {
1043                     name = names[i];
1044                     if (!skip) {
1045                         r.push(name);
1046                     }
1048                     // only attach a module once
1049                     if (used[name]) {
1050                         continue;
1051                     }
1053                     m = mods[name];
1054                     req = null;
1055                     use = null;
1057                     if (m) {
1058                         used[name] = true;
1059                         req = m.details.requires;
1060                         use = m.details.use;
1061                     } else {
1062                         // CSS files don't register themselves, see if it has
1063                         // been loaded
1064                         if (!G_ENV._loaded[VERSION][name]) {
1065                             missing.push(name);
1066                         } else {
1067                             used[name] = true; // probably css
1068                         }
1069                     }
1071                     // make sure requirements are attached
1072                     if (req && req.length) {
1073                         process(req);
1074                     }
1076                     // make sure we grab the submodule dependencies too
1077                     if (use && use.length) {
1078                         process(use, 1);
1079                     }
1080                 }
1082             },
1084             handleLoader = function(fromLoader) {
1085                 var response = fromLoader || {
1086                         success: true,
1087                         msg: 'not dynamic'
1088                     },
1089                     redo, origMissing,
1090                     ret = true,
1091                     data = response.data;
1093                 Y._loading = false;
1095                 if (data) {
1096                     origMissing = missing;
1097                     missing = [];
1098                     r = [];
1099                     process(data);
1100                     redo = missing.length;
1101                     if (redo) {
1102                         if ([].concat(missing).sort().join() ==
1103                                 origMissing.sort().join()) {
1104                             redo = false;
1105                         }
1106                     }
1107                 }
1109                 if (redo && data) {
1110                     Y._loading = true;
1111                     Y._use(missing, function() {
1112                         if (Y._attach(data)) {
1113                             Y._notify(callback, response, data);
1114                         }
1115                     });
1116                 } else {
1117                     if (data) {
1118                         ret = Y._attach(data);
1119                     }
1120                     if (ret) {
1121                         Y._notify(callback, response, args);
1122                     }
1123                 }
1125                 if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
1126                     Y._use.apply(Y, Y._useQueue.next());
1127                 }
1129             };
1132         // YUI().use('*'); // bind everything available
1133         if (firstArg === '*') {
1134             args = [];
1135             for (i in mods) {
1136                 if (mods.hasOwnProperty(i)) {
1137                     args.push(i);
1138                 }
1139             }
1140             ret = Y._attach(args);
1141             if (ret) {
1142                 handleLoader();
1143             }
1144             return Y;
1145         }
1147         if ((mods.loader || mods['loader-base']) && !Y.Loader) {
1148             Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]);
1149         }
1152         // use loader to expand dependencies and sort the
1153         // requirements if it is available.
1154         if (boot && Y.Loader && args.length) {
1155             loader = getLoader(Y);
1156             loader.require(args);
1157             loader.ignoreRegistered = true;
1158             loader._boot = true;
1159             loader.calculate(null, (fetchCSS) ? null : 'js');
1160             args = loader.sorted;
1161             loader._boot = false;
1162         }
1164         process(args);
1166         len = missing.length;
1169         if (len) {
1170             missing = YArray.dedupe(missing);
1171             len = missing.length;
1172         }
1175         // dynamic load
1176         if (boot && len && Y.Loader) {
1177             Y._loading = true;
1178             loader = getLoader(Y);
1179             loader.onEnd = handleLoader;
1180             loader.context = Y;
1181             loader.data = args;
1182             loader.ignoreRegistered = false;
1183             loader.require(missing);
1184             loader.insert(null, (fetchCSS) ? null : 'js');
1186         } else if (boot && len && Y.Get && !Env.bootstrapped) {
1188             Y._loading = true;
1190             handleBoot = function() {
1191                 Y._loading = false;
1192                 queue.running = false;
1193                 Env.bootstrapped = true;
1194                 G_ENV._bootstrapping = false;
1195                 if (Y._attach(['loader'])) {
1196                     Y._use(args, callback);
1197                 }
1198             };
1200             if (G_ENV._bootstrapping) {
1201                 queue.add(handleBoot);
1202             } else {
1203                 G_ENV._bootstrapping = true;
1204                 Y.Get.script(config.base + config.loaderPath, {
1205                     onEnd: handleBoot
1206                 });
1207             }
1209         } else {
1210             ret = Y._attach(args);
1211             if (ret) {
1212                 handleLoader();
1213             }
1214         }
1216         return Y;
1217     },
1220     /**
1221     Utility method for safely creating namespaces if they don't already exist.
1222     May be called statically on the YUI global object or as a method on a YUI
1223     instance.
1225     When called statically, a namespace will be created on the YUI global
1226     object:
1228         // Create `YUI.your.namespace.here` as nested objects, preserving any
1229         // objects that already exist instead of overwriting them.
1230         YUI.namespace('your.namespace.here');
1232     When called as a method on a YUI instance, a namespace will be created on
1233     that instance:
1235         // Creates `Y.property.package`.
1236         Y.namespace('property.package');
1238     Dots in the input string cause `namespace` to create nested objects for each
1239     token. If any part of the requested namespace already exists, the current
1240     object will be left in place and will not be overwritten. This allows
1241     multiple calls to `namespace` to preserve existing namespaced properties.
1243     If the first token in the namespace string is "YAHOO", that token is
1244     discarded. This is legacy behavior for backwards compatibility with YUI 2.
1246     Be careful with namespace tokens. Reserved words may work in some browsers
1247     and not others. For instance, the following will fail in some browsers
1248     because the supported version of JavaScript reserves the word "long":
1250         Y.namespace('really.long.nested.namespace');
1252     Note: If you pass multiple arguments to create multiple namespaces, only the
1253     last one created is returned from this function.
1255     @method namespace
1256     @param {String} namespace* One or more namespaces to create.
1257     @return {Object} Reference to the last namespace object created.
1258     **/
1259     namespace: function() {
1260         var a = arguments, o, i = 0, j, d, arg;
1262         for (; i < a.length; i++) {
1263             o = this; //Reset base object per argument or it will get reused from the last
1264             arg = a[i];
1265             if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
1266                 d = arg.split(PERIOD);
1267                 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1268                     o[d[j]] = o[d[j]] || {};
1269                     o = o[d[j]];
1270                 }
1271             } else {
1272                 o[arg] = o[arg] || {};
1273                 o = o[arg]; //Reset base object to the new object so it's returned
1274             }
1275         }
1276         return o;
1277     },
1279     // this is replaced if the log module is included
1280     log: NOOP,
1281     message: NOOP,
1282     // this is replaced if the dump module is included
1283     dump: function (o) { return ''+o; },
1285     /**
1286     Reports an error.
1288     The reporting mechanism is controlled by the `throwFail` configuration
1289     attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is
1290     truthy, a JS exception is thrown.
1292     If an `errorFn` is specified in the config it must return `true` to indicate
1293     that the exception was handled and keep it from being thrown.
1295     @method error
1296     @param {String} msg Error message.
1297     @param {Error|String} [e] JavaScript error object or an error string.
1298     @param {String} [src] Source of the error (such as the name of the module in
1299         which the error occurred).
1300     @chainable
1301     **/
1302     error: function(msg, e, src) {
1303         //TODO Add check for window.onerror here
1305         var Y = this, ret;
1307         if (Y.config.errorFn) {
1308             ret = Y.config.errorFn.apply(Y, arguments);
1309         }
1311         if (!ret) {
1312             throw (e || new Error(msg));
1313         } else {
1314             Y.message(msg, 'error', ''+src); // don't scrub this one
1315         }
1317         return Y;
1318     },
1320     /**
1321     Generates an id string that is unique among all YUI instances in this
1322     execution context.
1324     @method guid
1325     @param {String} [pre] Prefix.
1326     @return {String} Unique id.
1327     **/
1328     guid: function(pre) {
1329         var id = this.Env._guidp + '_' + (++this.Env._uidx);
1330         return (pre) ? (pre + id) : id;
1331     },
1333     /**
1334     Returns a unique id associated with the given object and (if *readOnly* is
1335     falsy) stamps the object with that id so it can be identified in the future.
1337     Stamping an object involves adding a `_yuid` property to it that contains
1338     the object's id. One exception to this is that in Internet Explorer, DOM
1339     nodes have a `uniqueID` property that contains a browser-generated unique
1340     id, which will be used instead of a YUI-generated id when available.
1342     @method stamp
1343     @param {Object} o Object to stamp.
1344     @param {Boolean} readOnly If truthy and the given object has not already
1345         been stamped, the object will not be modified and `null` will be
1346         returned.
1347     @return {String} Object's unique id, or `null` if *readOnly* was truthy and
1348         the given object was not already stamped.
1349     **/
1350     stamp: function(o, readOnly) {
1351         var uid;
1352         if (!o) {
1353             return o;
1354         }
1356         // IE generates its own unique ID for dom nodes
1357         // The uniqueID property of a document node returns a new ID
1358         if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1359             uid = o.uniqueID;
1360         } else {
1361             uid = (typeof o === 'string') ? o : o._yuid;
1362         }
1364         if (!uid) {
1365             uid = this.guid();
1366             if (!readOnly) {
1367                 try {
1368                     o._yuid = uid;
1369                 } catch (e) {
1370                     uid = null;
1371                 }
1372             }
1373         }
1374         return uid;
1375     },
1377     /**
1378     Destroys this YUI instance.
1380     @method destroy
1381     @since 3.3.0
1382     **/
1383     destroy: function() {
1384         var Y = this;
1385         if (Y.Event) {
1386             Y.Event._unload();
1387         }
1388         delete instances[Y.id];
1389         delete Y.Env;
1390         delete Y.config;
1391     }
1393     /**
1394     Safe `instanceof` wrapper that works around a memory leak in IE when the
1395     object being tested is `window` or `document`.
1397     Unless you are testing objects that may be `window` or `document`, you
1398     should use the native `instanceof` operator instead of this method.
1400     @method instanceOf
1401     @param {Object} o Object to check.
1402     @param {Object} type Class to check against.
1403     @since 3.3.0
1404     **/
1407     YUI.prototype = proto;
1409     // inheritance utilities are not available yet
1410     for (prop in proto) {
1411         if (proto.hasOwnProperty(prop)) {
1412             YUI[prop] = proto[prop];
1413         }
1414     }
1416     /**
1417     Applies a configuration to all YUI instances in this execution context.
1419     The main use case for this method is in "mashups" where several third-party
1420     scripts need to write to a global YUI config, but cannot share a single
1421     centrally-managed config object. This way they can all call
1422     `YUI.applyConfig({})` instead of overwriting the single global config.
1424     @example
1426         YUI.applyConfig({
1427             modules: {
1428                 davglass: {
1429                     fullpath: './davglass.js'
1430                 }
1431             }
1432         });
1434         YUI.applyConfig({
1435             modules: {
1436                 foo: {
1437                     fullpath: './foo.js'
1438                 }
1439             }
1440         });
1442         YUI().use('davglass', function (Y) {
1443             // Module davglass will be available here.
1444         });
1446     @method applyConfig
1447     @param {Object} o Configuration object to apply.
1448     @static
1449     @since 3.5.0
1450     **/
1451     YUI.applyConfig = function(o) {
1452         if (!o) {
1453             return;
1454         }
1455         //If there is a GlobalConfig, apply it first to set the defaults
1456         if (YUI.GlobalConfig) {
1457             this.prototype.applyConfig.call(this, YUI.GlobalConfig);
1458         }
1459         //Apply this config to it
1460         this.prototype.applyConfig.call(this, o);
1461         //Reset GlobalConfig to the combined config
1462         YUI.GlobalConfig = this.config;
1463     };
1465     // set up the environment
1466     YUI._init();
1468     if (hasWin) {
1469         // add a window load event at load time so we can capture
1470         // the case where it fires before dynamic loading is
1471         // complete.
1472         add(window, 'load', handleLoad);
1473     } else {
1474         handleLoad();
1475     }
1477     YUI.Env.add = add;
1478     YUI.Env.remove = remove;
1480     /*global exports*/
1481     // Support the CommonJS method for exporting our single global
1482     if (typeof exports == 'object') {
1483         exports.YUI = YUI;
1484         /**
1485         * Set a method to be called when `Get.script` is called in Node.js
1486         * `Get` will open the file, then pass it's content and it's path
1487         * to this method before attaching it. Commonly used for code coverage
1488         * instrumentation. <strong>Calling this multiple times will only
1489         * attach the last hook method</strong>. This method is only
1490         * available in Node.js.
1491         * @method setLoadHook
1492         * @static
1493         * @param {Function} fn The function to set
1494         * @param {String} fn.data The content of the file
1495         * @param {String} fn.path The file path of the file
1496         */
1497         YUI.setLoadHook = function(fn) {
1498             YUI._getLoadHook = fn;
1499         };
1500         /**
1501         * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook`
1502         * @method _getLoadHook
1503         * @private
1504         * @param {String} data The content of the file
1505         * @param {String} path The file path of the file
1506         */
1507         YUI._getLoadHook = null;
1508     }
1510     YUI.Env[VERSION] = {};
1511 }());
1515 Config object that contains all of the configuration options for
1516 this `YUI` instance.
1518 This object is supplied by the implementer when instantiating YUI. Some
1519 properties have default values if they are not supplied by the implementer.
1521 This object should not be updated directly because some values are cached. Use
1522 `applyConfig()` to update the config object on a YUI instance that has already
1523 been configured.
1525 @class config
1526 @static
1530 If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata
1531 if they're needed to load additional dependencies and aren't already available.
1533 Setting this to `false` will prevent YUI from automatically loading the Loader
1534 and module metadata, so you will need to manually ensure that they're available
1535 or handle dependency resolution yourself.
1537 @property {Boolean} bootstrap
1538 @default true
1543 @property {Object} aliases
1547 A hash of module group definitions.
1549 For each group you can specify a list of modules and the base path and
1550 combo spec to use when dynamically loading the modules.
1552 @example
1554     groups: {
1555         yui2: {
1556             // specify whether or not this group has a combo service
1557             combine: true,
1559             // The comboSeperator to use with this group's combo handler
1560             comboSep: ';',
1562             // The maxURLLength for this server
1563             maxURLLength: 500,
1565             // the base path for non-combo paths
1566             base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1568             // the path to the combo service
1569             comboBase: 'http://yui.yahooapis.com/combo?',
1571             // a fragment to prepend to the path attribute when
1572             // when building combo urls
1573             root: '2.8.0r4/build/',
1575             // the module definitions
1576             modules:  {
1577                 yui2_yde: {
1578                     path: "yahoo-dom-event/yahoo-dom-event.js"
1579                 },
1580                 yui2_anim: {
1581                     path: "animation/animation.js",
1582                     requires: ['yui2_yde']
1583                 }
1584             }
1585         }
1586     }
1588 @property {Object} groups
1592 Path to the Loader JS file, relative to the `base` path.
1594 This is used to dynamically bootstrap the Loader when it's needed and isn't yet
1595 available.
1597 @property {String} loaderPath
1598 @default "loader/loader-min.js"
1602 If `true`, YUI will attempt to load CSS dependencies and skins. Set this to
1603 `false` to prevent YUI from loading any CSS, or set it to the string `"force"`
1604 to force CSS dependencies to be loaded even if their associated JS modules are
1605 already loaded.
1607 @property {Boolean|String} fetchCSS
1608 @default true
1612 Default gallery version used to build gallery module urls.
1614 @property {String} gallery
1615 @since 3.1.0
1619 Default YUI 2 version used to build YUI 2 module urls.
1621 This is used for intrinsic YUI 2 support via the 2in3 project. Also see the
1622 `2in3` config for pulling different revisions of the wrapped YUI 2 modules.
1624 @property {String} yui2
1625 @default "2.9.0"
1626 @since 3.1.0
1630 Revision number of YUI 2in3 modules that should be used when loading YUI 2in3.
1632 @property {String} 2in3
1633 @default "4"
1634 @since 3.1.0
1638 Alternate console log function that should be used in environments without a
1639 supported native console. This function is executed with the YUI instance as its
1640 `this` object.
1642 @property {Function} logFn
1643 @since 3.1.0
1647 The minimum log level to log messages for. Log levels are defined
1648 incrementally. Messages greater than or equal to the level specified will
1649 be shown. All others will be discarded. The order of log levels in
1650 increasing priority is:
1652     debug
1653     info
1654     warn
1655     error
1657 @property {String} logLevel
1658 @default 'debug'
1659 @since 3.10.0
1663 Callback to execute when `Y.error()` is called. It receives the error message
1664 and a JavaScript error object if one was provided.
1666 This function is executed with the YUI instance as its `this` object.
1668 Returning `true` from this function will prevent an exception from being thrown.
1670 @property {Function} errorFn
1671 @param {String} errorFn.msg Error message
1672 @param {Object} [errorFn.err] Error object (if one was provided).
1673 @since 3.2.0
1677 A callback to execute when Loader fails to load one or more resources.
1679 This could be because of a script load failure. It could also be because a
1680 module fails to register itself when the `requireRegistration` config is `true`.
1682 If this function is defined, the `use()` callback will only be called when the
1683 loader succeeds. Otherwise, `use()` will always executes unless there was a
1684 JavaScript error when attaching a module.
1686 @property {Function} loadErrorFn
1687 @since 3.3.0
1691 If `true`, Loader will expect all loaded scripts to be first-class YUI modules
1692 that register themselves with the YUI global, and will trigger a failure if a
1693 loaded script does not register a YUI module.
1695 @property {Boolean} requireRegistration
1696 @default false
1697 @since 3.3.0
1701 Cache serviced use() requests.
1703 @property {Boolean} cacheUse
1704 @default true
1705 @since 3.3.0
1706 @deprecated No longer used.
1710 Whether or not YUI should use native ES5 functionality when available for
1711 features like `Y.Array.each()`, `Y.Object()`, etc.
1713 When `false`, YUI will always use its own fallback implementations instead of
1714 relying on ES5 functionality, even when ES5 functionality is available.
1716 @property {Boolean} useNativeES5
1717 @default true
1718 @since 3.5.0
1722  * Leverage native JSON stringify if the browser has a native
1723  * implementation.  In general, this is a good idea.  See the Known Issues
1724  * section in the JSON user guide for caveats.  The default value is true
1725  * for browsers with native JSON support.
1727  * @property useNativeJSONStringify
1728  * @type Boolean
1729  * @default true
1730  * @since 3.8.0
1731  */
1733  /**
1734  * Leverage native JSON parse if the browser has a native implementation.
1735  * In general, this is a good idea.  See the Known Issues section in the
1736  * JSON user guide for caveats.  The default value is true for browsers with
1737  * native JSON support.
1739  * @property useNativeJSONParse
1740  * @type Boolean
1741  * @default true
1742  * @since 3.8.0
1743  */
1746 Delay the `use` callback until a specific event has passed (`load`, `domready`, `contentready` or `available`)
1748 @property {Object|String} delayUntil
1749 @since 3.6.0
1750 @example
1752 You can use `load` or `domready` strings by default:
1754     YUI({
1755         delayUntil: 'domready'
1756     }, function (Y) {
1757         // This will not execute until 'domeready' occurs.
1758     });
1760 Or you can delay until a node is available (with `available` or `contentready`):
1762     YUI({
1763         delayUntil: {
1764             event: 'available',
1765             args : '#foo'
1766         }
1767     }, function (Y) {
1768         // This will not execute until a node matching the selector "#foo" is
1769         // available in the DOM.
1770     });
1773 YUI.add('yui-base', function (Y, NAME) {
1776  * YUI stub
1777  * @module yui
1778  * @submodule yui-base
1779  */
1781  * The YUI module contains the components required for building the YUI
1782  * seed file.  This includes the script loading mechanism, a simple queue,
1783  * and the core utilities for the library.
1784  * @module yui
1785  * @submodule yui-base
1786  */
1789  * Provides core language utilites and extensions used throughout YUI.
1791  * @class Lang
1792  * @static
1793  */
1795 var L = Y.Lang || (Y.Lang = {}),
1797 STRING_PROTO = String.prototype,
1798 TOSTRING     = Object.prototype.toString,
1800 TYPES = {
1801     'undefined'        : 'undefined',
1802     'number'           : 'number',
1803     'boolean'          : 'boolean',
1804     'string'           : 'string',
1805     '[object Function]': 'function',
1806     '[object RegExp]'  : 'regexp',
1807     '[object Array]'   : 'array',
1808     '[object Date]'    : 'date',
1809     '[object Error]'   : 'error'
1812 SUBREGEX         = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
1814 WHITESPACE       = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF",
1815 WHITESPACE_CLASS = "[\x09-\x0D\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+",
1816 TRIM_LEFT_REGEX  = new RegExp("^" + WHITESPACE_CLASS),
1817 TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"),
1818 TRIMREGEX        = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"),
1820 NATIVE_FN_REGEX  = /\{\s*\[(?:native code|function)\]\s*\}/i;
1822 // -- Protected Methods --------------------------------------------------------
1825 Returns `true` if the given function appears to be implemented in native code,
1826 `false` otherwise. Will always return `false` -- even in ES5-capable browsers --
1827 if the `useNativeES5` YUI config option is set to `false`.
1829 This isn't guaranteed to be 100% accurate and won't work for anything other than
1830 functions, but it can be useful for determining whether a function like
1831 `Array.prototype.forEach` is native or a JS shim provided by another library.
1833 There's a great article by @kangax discussing certain flaws with this technique:
1834 <http://perfectionkills.com/detecting-built-in-host-methods/>
1836 While his points are valid, it's still possible to benefit from this function
1837 as long as it's used carefully and sparingly, and in such a way that false
1838 negatives have minimal consequences. It's used internally to avoid using
1839 potentially broken non-native ES5 shims that have been added to the page by
1840 other libraries.
1842 @method _isNative
1843 @param {Function} fn Function to test.
1844 @return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
1845 @static
1846 @protected
1847 @since 3.5.0
1849 L._isNative = function (fn) {
1850     return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
1853 // -- Public Methods -----------------------------------------------------------
1856  * Determines whether or not the provided item is an array.
1858  * Returns `false` for array-like collections such as the function `arguments`
1859  * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
1860  * test for an array-like collection.
1862  * @method isArray
1863  * @param o The object to test.
1864  * @return {boolean} true if o is an array.
1865  * @static
1866  */
1867 L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
1868     return L.type(o) === 'array';
1872  * Determines whether or not the provided item is a boolean.
1873  * @method isBoolean
1874  * @static
1875  * @param o The object to test.
1876  * @return {boolean} true if o is a boolean.
1877  */
1878 L.isBoolean = function(o) {
1879     return typeof o === 'boolean';
1883  * Determines whether or not the supplied item is a date instance.
1884  * @method isDate
1885  * @static
1886  * @param o The object to test.
1887  * @return {boolean} true if o is a date.
1888  */
1889 L.isDate = function(o) {
1890     return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
1894  * <p>
1895  * Determines whether or not the provided item is a function.
1896  * Note: Internet Explorer thinks certain functions are objects:
1897  * </p>
1899  * <pre>
1900  * var obj = document.createElement("object");
1901  * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1902  * &nbsp;
1903  * var input = document.createElement("input"); // append to body
1904  * Y.Lang.isFunction(input.focus) // reports false in IE
1905  * </pre>
1907  * <p>
1908  * You will have to implement additional tests if these functions
1909  * matter to you.
1910  * </p>
1912  * @method isFunction
1913  * @static
1914  * @param o The object to test.
1915  * @return {boolean} true if o is a function.
1916  */
1917 L.isFunction = function(o) {
1918     return L.type(o) === 'function';
1922  * Determines whether or not the provided item is null.
1923  * @method isNull
1924  * @static
1925  * @param o The object to test.
1926  * @return {boolean} true if o is null.
1927  */
1928 L.isNull = function(o) {
1929     return o === null;
1933  * Determines whether or not the provided item is a legal number.
1934  * @method isNumber
1935  * @static
1936  * @param o The object to test.
1937  * @return {boolean} true if o is a number.
1938  */
1939 L.isNumber = function(o) {
1940     return typeof o === 'number' && isFinite(o);
1944  * Determines whether or not the provided item is of type object
1945  * or function. Note that arrays are also objects, so
1946  * <code>Y.Lang.isObject([]) === true</code>.
1947  * @method isObject
1948  * @static
1949  * @param o The object to test.
1950  * @param failfn {boolean} fail if the input is a function.
1951  * @return {boolean} true if o is an object.
1952  * @see isPlainObject
1953  */
1954 L.isObject = function(o, failfn) {
1955     var t = typeof o;
1956     return (o && (t === 'object' ||
1957         (!failfn && (t === 'function' || L.isFunction(o))))) || false;
1961  * Determines whether or not the provided value is a regexp.
1962  * @method isRegExp
1963  * @static
1964  * @param value The value or object to test.
1965  * @return {boolean} true if value is a regexp.
1966  */
1967 L.isRegExp = function(value) {
1968     return L.type(value) === 'regexp';
1972  * Determines whether or not the provided item is a string.
1973  * @method isString
1974  * @static
1975  * @param o The object to test.
1976  * @return {boolean} true if o is a string.
1977  */
1978 L.isString = function(o) {
1979     return typeof o === 'string';
1983  * Determines whether or not the provided item is undefined.
1984  * @method isUndefined
1985  * @static
1986  * @param o The object to test.
1987  * @return {boolean} true if o is undefined.
1988  */
1989 L.isUndefined = function(o) {
1990     return typeof o === 'undefined';
1994  * A convenience method for detecting a legitimate non-null value.
1995  * Returns false for null/undefined/NaN, true for other values,
1996  * including 0/false/''
1997  * @method isValue
1998  * @static
1999  * @param o The item to test.
2000  * @return {boolean} true if it is not null/undefined/NaN || false.
2001  */
2002 L.isValue = function(o) {
2003     var t = L.type(o);
2005     switch (t) {
2006         case 'number':
2007             return isFinite(o);
2009         case 'null': // fallthru
2010         case 'undefined':
2011             return false;
2013         default:
2014             return !!t;
2015     }
2019  * Returns the current time in milliseconds.
2021  * @method now
2022  * @return {Number} Current time in milliseconds.
2023  * @static
2024  * @since 3.3.0
2025  */
2026 L.now = Date.now || function () {
2027     return new Date().getTime();
2031  * Lightweight version of <code>Y.substitute</code>. Uses the same template
2032  * structure as <code>Y.substitute</code>, but doesn't support recursion,
2033  * auto-object coersion, or formats.
2034  * @method sub
2035  * @param {string} s String to be modified.
2036  * @param {object} o Object containing replacement values.
2037  * @return {string} the substitute result.
2038  * @static
2039  * @since 3.2.0
2040  */
2041 L.sub = function(s, o) {
2042     return s.replace ? s.replace(SUBREGEX, function (match, key) {
2043         return L.isUndefined(o[key]) ? match : o[key];
2044     }) : s;
2048  * Returns a string without any leading or trailing whitespace.  If
2049  * the input is not a string, the input will be returned untouched.
2050  * @method trim
2051  * @static
2052  * @param s {string} the string to trim.
2053  * @return {string} the trimmed string.
2054  */
2055 L.trim = L._isNative(STRING_PROTO.trim) && !WHITESPACE.trim() ? function(s) {
2056     return s && s.trim ? s.trim() : s;
2057 } : function (s) {
2058     try {
2059         return s.replace(TRIMREGEX, '');
2060     } catch (e) {
2061         return s;
2062     }
2066  * Returns a string without any leading whitespace.
2067  * @method trimLeft
2068  * @static
2069  * @param s {string} the string to trim.
2070  * @return {string} the trimmed string.
2071  */
2072 L.trimLeft = L._isNative(STRING_PROTO.trimLeft) && !WHITESPACE.trimLeft() ? function (s) {
2073     return s.trimLeft();
2074 } : function (s) {
2075     return s.replace(TRIM_LEFT_REGEX, '');
2079  * Returns a string without any trailing whitespace.
2080  * @method trimRight
2081  * @static
2082  * @param s {string} the string to trim.
2083  * @return {string} the trimmed string.
2084  */
2085 L.trimRight = L._isNative(STRING_PROTO.trimRight) && !WHITESPACE.trimRight() ? function (s) {
2086     return s.trimRight();
2087 } : function (s) {
2088     return s.replace(TRIM_RIGHT_REGEX, '');
2092 Returns one of the following strings, representing the type of the item passed
2095  * "array"
2096  * "boolean"
2097  * "date"
2098  * "error"
2099  * "function"
2100  * "null"
2101  * "number"
2102  * "object"
2103  * "regexp"
2104  * "string"
2105  * "undefined"
2107 Known issues:
2109  * `typeof HTMLElementCollection` returns function in Safari, but
2110     `Y.Lang.type()` reports "object", which could be a good thing --
2111     but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
2113 @method type
2114 @param o the item to test.
2115 @return {string} the detected type.
2116 @static
2118 L.type = function(o) {
2119     return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
2122 @module yui
2123 @submodule yui-base
2126 var Lang   = Y.Lang,
2127     Native = Array.prototype,
2129     hasOwn = Object.prototype.hasOwnProperty;
2132 Provides utility methods for working with arrays. Additional array helpers can
2133 be found in the `collection` and `array-extras` modules.
2135 `Y.Array(thing)` returns a native array created from _thing_. Depending on
2136 _thing_'s type, one of the following will happen:
2138   * Arrays are returned unmodified unless a non-zero _startIndex_ is
2139     specified.
2140   * Array-like collections (see `Array.test()`) are converted to arrays.
2141   * For everything else, a new array is created with _thing_ as the sole
2142     item.
2144 Note: elements that are also collections, such as `<form>` and `<select>`
2145 elements, are not automatically converted to arrays. To force a conversion,
2146 pass `true` as the value of the _force_ parameter.
2148 @class Array
2149 @constructor
2150 @param {Any} thing The thing to arrayify.
2151 @param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2152   collection, a subset of items starting at the specified index will be
2153   returned.
2154 @param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2155   array-like collection no matter what.
2156 @return {Array} A native array created from _thing_, according to the rules
2157   described above.
2159 function YArray(thing, startIndex, force) {
2160     var len, result;
2162     /*jshint expr: true*/
2163     startIndex || (startIndex = 0);
2165     if (force || YArray.test(thing)) {
2166         // IE throws when trying to slice HTMLElement collections.
2167         try {
2168             return Native.slice.call(thing, startIndex);
2169         } catch (ex) {
2170             result = [];
2172             for (len = thing.length; startIndex < len; ++startIndex) {
2173                 result.push(thing[startIndex]);
2174             }
2176             return result;
2177         }
2178     }
2180     return [thing];
2183 Y.Array = YArray;
2186 Dedupes an array of strings, returning an array that's guaranteed to contain
2187 only one copy of a given string.
2189 This method differs from `Array.unique()` in that it's optimized for use only
2190 with arrays consisting entirely of strings or entirely of numbers, whereas
2191 `unique` may be used with other value types (but is slower).
2193 Using `dedupe()` with values other than strings or numbers, or with arrays
2194 containing a mix of strings and numbers, may result in unexpected behavior.
2196 @method dedupe
2197 @param {String[]|Number[]} array Array of strings or numbers to dedupe.
2198 @return {Array} Copy of _array_ containing no duplicate values.
2199 @static
2200 @since 3.4.0
2202 YArray.dedupe = Lang._isNative(Object.create) ? function (array) {
2203     var hash    = Object.create(null),
2204         results = [],
2205         i, item, len;
2207     for (i = 0, len = array.length; i < len; ++i) {
2208         item = array[i];
2210         if (!hash[item]) {
2211             hash[item] = 1;
2212             results.push(item);
2213         }
2214     }
2216     return results;
2217 } : function (array) {
2218     var hash    = {},
2219         results = [],
2220         i, item, len;
2222     for (i = 0, len = array.length; i < len; ++i) {
2223         item = array[i];
2225         if (!hasOwn.call(hash, item)) {
2226             hash[item] = 1;
2227             results.push(item);
2228         }
2229     }
2231     return results;
2235 Executes the supplied function on each item in the array. This method wraps
2236 the native ES5 `Array.forEach()` method if available.
2238 @method each
2239 @param {Array} array Array to iterate.
2240 @param {Function} fn Function to execute on each item in the array. The function
2241   will receive the following arguments:
2242     @param {Any} fn.item Current array item.
2243     @param {Number} fn.index Current array index.
2244     @param {Array} fn.array Array being iterated.
2245 @param {Object} [thisObj] `this` object to use when calling _fn_.
2246 @return {YUI} The YUI instance.
2247 @static
2249 YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
2250     Native.forEach.call(array || [], fn, thisObj || Y);
2251     return Y;
2252 } : function (array, fn, thisObj) {
2253     for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2254         if (i in array) {
2255             fn.call(thisObj || Y, array[i], i, array);
2256         }
2257     }
2259     return Y;
2263 Alias for `each()`.
2265 @method forEach
2266 @static
2270 Returns an object using the first array as keys and the second as values. If
2271 the second array is not provided, or if it doesn't contain the same number of
2272 values as the first array, then `true` will be used in place of the missing
2273 values.
2275 @example
2277     Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2278     // => {a: 'foo', b: 'bar', c: true}
2280 @method hash
2281 @param {String[]} keys Array of strings to use as keys.
2282 @param {Array} [values] Array to use as values.
2283 @return {Object} Hash using the first array as keys and the second as values.
2284 @static
2286 YArray.hash = function (keys, values) {
2287     var hash = {},
2288         vlen = (values && values.length) || 0,
2289         i, len;
2291     for (i = 0, len = keys.length; i < len; ++i) {
2292         if (i in keys) {
2293             hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2294         }
2295     }
2297     return hash;
2301 Returns the index of the first item in the array that's equal (using a strict
2302 equality check) to the specified _value_, or `-1` if the value isn't found.
2304 This method wraps the native ES5 `Array.indexOf()` method if available.
2306 @method indexOf
2307 @param {Array} array Array to search.
2308 @param {Any} value Value to search for.
2309 @param {Number} [from=0] The index at which to begin the search.
2310 @return {Number} Index of the item strictly equal to _value_, or `-1` if not
2311     found.
2312 @static
2314 YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
2315     return Native.indexOf.call(array, value, from);
2316 } : function (array, value, from) {
2317     // http://es5.github.com/#x15.4.4.14
2318     var len = array.length;
2320     from = +from || 0;
2321     from = (from > 0 || -1) * Math.floor(Math.abs(from));
2323     if (from < 0) {
2324         from += len;
2326         if (from < 0) {
2327             from = 0;
2328         }
2329     }
2331     for (; from < len; ++from) {
2332         if (from in array && array[from] === value) {
2333             return from;
2334         }
2335     }
2337     return -1;
2341 Numeric sort convenience function.
2343 The native `Array.prototype.sort()` function converts values to strings and
2344 sorts them in lexicographic order, which is unsuitable for sorting numeric
2345 values. Provide `Array.numericSort` as a custom sort function when you want
2346 to sort values in numeric order.
2348 @example
2350     [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2351     // => [4, 8, 15, 16, 23, 42]
2353 @method numericSort
2354 @param {Number} a First value to compare.
2355 @param {Number} b Second value to compare.
2356 @return {Number} Difference between _a_ and _b_.
2357 @static
2359 YArray.numericSort = function (a, b) {
2360     return a - b;
2364 Executes the supplied function on each item in the array. Returning a truthy
2365 value from the function will stop the processing of remaining items.
2367 @method some
2368 @param {Array} array Array to iterate over.
2369 @param {Function} fn Function to execute on each item. The function will receive
2370   the following arguments:
2371     @param {Any} fn.value Current array item.
2372     @param {Number} fn.index Current array index.
2373     @param {Array} fn.array Array being iterated over.
2374 @param {Object} [thisObj] `this` object to use when calling _fn_.
2375 @return {Boolean} `true` if the function returns a truthy value on any of the
2376   items in the array; `false` otherwise.
2377 @static
2379 YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
2380     return Native.some.call(array, fn, thisObj);
2381 } : function (array, fn, thisObj) {
2382     for (var i = 0, len = array.length; i < len; ++i) {
2383         if (i in array && fn.call(thisObj, array[i], i, array)) {
2384             return true;
2385         }
2386     }
2388     return false;
2392 Evaluates _obj_ to determine if it's an array, an array-like collection, or
2393 something else. This is useful when working with the function `arguments`
2394 collection and `HTMLElement` collections.
2396 Note: This implementation doesn't consider elements that are also
2397 collections, such as `<form>` and `<select>`, to be array-like.
2399 @method test
2400 @param {Object} obj Object to test.
2401 @return {Number} A number indicating the results of the test:
2403   * 0: Neither an array nor an array-like collection.
2404   * 1: Real array.
2405   * 2: Array-like collection.
2407 @static
2409 YArray.test = function (obj) {
2410     var result = 0;
2412     if (Lang.isArray(obj)) {
2413         result = 1;
2414     } else if (Lang.isObject(obj)) {
2415         try {
2416             // indexed, but no tagName (element) or scrollTo/document (window. From DOM.isWindow test which we can't use here),
2417             // or functions without apply/call (Safari
2418             // HTMLElementCollection bug).
2419             if ('length' in obj && !obj.tagName && !(obj.scrollTo && obj.document) && !obj.apply) {
2420                 result = 2;
2421             }
2422         } catch (ex) {}
2423     }
2425     return result;
2428  * The YUI module contains the components required for building the YUI
2429  * seed file.  This includes the script loading mechanism, a simple queue,
2430  * and the core utilities for the library.
2431  * @module yui
2432  * @submodule yui-base
2433  */
2436  * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2437  * removed using next().
2439  * @class Queue
2440  * @constructor
2441  * @param {MIXED} item* 0..n items to seed the queue.
2442  */
2443 function Queue() {
2444     this._init();
2445     this.add.apply(this, arguments);
2448 Queue.prototype = {
2449     /**
2450      * Initialize the queue
2451      *
2452      * @method _init
2453      * @protected
2454      */
2455     _init: function() {
2456         /**
2457          * The collection of enqueued items
2458          *
2459          * @property _q
2460          * @type Array
2461          * @protected
2462          */
2463         this._q = [];
2464     },
2466     /**
2467      * Get the next item in the queue. FIFO support
2468      *
2469      * @method next
2470      * @return {MIXED} the next item in the queue.
2471      */
2472     next: function() {
2473         return this._q.shift();
2474     },
2476     /**
2477      * Get the last in the queue. LIFO support.
2478      *
2479      * @method last
2480      * @return {MIXED} the last item in the queue.
2481      */
2482     last: function() {
2483         return this._q.pop();
2484     },
2486     /**
2487      * Add 0..n items to the end of the queue.
2488      *
2489      * @method add
2490      * @param {MIXED} item* 0..n items.
2491      * @return {object} this queue.
2492      */
2493     add: function() {
2494         this._q.push.apply(this._q, arguments);
2496         return this;
2497     },
2499     /**
2500      * Returns the current number of queued items.
2501      *
2502      * @method size
2503      * @return {Number} The size.
2504      */
2505     size: function() {
2506         return this._q.length;
2507     }
2510 Y.Queue = Queue;
2512 YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2515 The YUI module contains the components required for building the YUI seed file.
2516 This includes the script loading mechanism, a simple queue, and the core
2517 utilities for the library.
2519 @module yui
2520 @submodule yui-base
2523 var CACHED_DELIMITER = '__',
2525     hasOwn   = Object.prototype.hasOwnProperty,
2526     isObject = Y.Lang.isObject;
2529 Returns a wrapper for a function which caches the return value of that function,
2530 keyed off of the combined string representation of the argument values provided
2531 when the wrapper is called.
2533 Calling this function again with the same arguments will return the cached value
2534 rather than executing the wrapped function.
2536 Note that since the cache is keyed off of the string representation of arguments
2537 passed to the wrapper function, arguments that aren't strings and don't provide
2538 a meaningful `toString()` method may result in unexpected caching behavior. For
2539 example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2540 string `[object Object]` when used as a cache key.
2542 @method cached
2543 @param {Function} source The function to memoize.
2544 @param {Object} [cache={}] Object in which to store cached values. You may seed
2545   this object with pre-existing cached values if desired.
2546 @param {any} [refetch] If supplied, this value is compared with the cached value
2547   using a `==` comparison. If the values are equal, the wrapped function is
2548   executed again even though a cached value exists.
2549 @return {Function} Wrapped function.
2550 @for YUI
2552 Y.cached = function (source, cache, refetch) {
2553     /*jshint expr: true*/
2554     cache || (cache = {});
2556     return function (arg) {
2557         var key = arguments.length > 1 ?
2558                 Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2559                 String(arg);
2561         /*jshint eqeqeq: false*/
2562         if (!(key in cache) || (refetch && cache[key] == refetch)) {
2563             cache[key] = source.apply(source, arguments);
2564         }
2566         return cache[key];
2567     };
2571 Returns the `location` object from the window/frame in which this YUI instance
2572 operates, or `undefined` when executing in a non-browser environment
2573 (e.g. Node.js).
2575 It is _not_ recommended to hold references to the `window.location` object
2576 outside of the scope of a function in which its properties are being accessed or
2577 its methods are being called. This is because of a nasty bug/issue that exists
2578 in both Safari and MobileSafari browsers:
2579 [WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
2581 @method getLocation
2582 @return {location} The `location` object from the window/frame in which this YUI
2583     instance operates.
2584 @since 3.5.0
2586 Y.getLocation = function () {
2587     // It is safer to look this up every time because yui-base is attached to a
2588     // YUI instance before a user's config is applied; i.e. `Y.config.win` does
2589     // not point the correct window object when this file is loaded.
2590     var win = Y.config.win;
2592     // It is not safe to hold a reference to the `location` object outside the
2593     // scope in which it is being used. The WebKit engine used in Safari and
2594     // MobileSafari will "disconnect" the `location` object from the `window`
2595     // when a page is restored from back/forward history cache.
2596     return win && win.location;
2600 Returns a new object containing all of the properties of all the supplied
2601 objects. The properties from later objects will overwrite those in earlier
2602 objects.
2604 Passing in a single object will create a shallow copy of it. For a deep copy,
2605 use `clone()`.
2607 @method merge
2608 @param {Object} objects* One or more objects to merge.
2609 @return {Object} A new merged object.
2611 Y.merge = function () {
2612     var i      = 0,
2613         len    = arguments.length,
2614         result = {},
2615         key,
2616         obj;
2618     for (; i < len; ++i) {
2619         obj = arguments[i];
2621         for (key in obj) {
2622             if (hasOwn.call(obj, key)) {
2623                 result[key] = obj[key];
2624             }
2625         }
2626     }
2628     return result;
2632 Mixes _supplier_'s properties into _receiver_.
2634 Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
2635 shadowed unless the _overwrite_ parameter is `true`, and will not be merged
2636 unless the _merge_ parameter is `true`.
2638 In the default mode (0), only properties the supplier owns are copied (prototype
2639 properties are not copied). The following copying modes are available:
2641   * `0`: _Default_. Object to object.
2642   * `1`: Prototype to prototype.
2643   * `2`: Prototype to prototype and object to object.
2644   * `3`: Prototype to object.
2645   * `4`: Object to prototype.
2647 @method mix
2648 @param {Function|Object} receiver The object or function to receive the mixed
2649   properties.
2650 @param {Function|Object} supplier The object or function supplying the
2651   properties to be mixed.
2652 @param {Boolean} [overwrite=false] If `true`, properties that already exist
2653   on the receiver will be overwritten with properties from the supplier.
2654 @param {String[]} [whitelist] An array of property names to copy. If
2655   specified, only the whitelisted properties will be copied, and all others
2656   will be ignored.
2657 @param {Number} [mode=0] Mix mode to use. See above for available modes.
2658 @param {Boolean} [merge=false] If `true`, objects and arrays that already
2659   exist on the receiver will have the corresponding object/array from the
2660   supplier merged into them, rather than being skipped or overwritten. When
2661   both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2662 @return {Function|Object|YUI} The receiver, or the YUI instance if the
2663   specified receiver is falsy.
2665 Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2666     var alwaysOverwrite, exists, from, i, key, len, to;
2668     // If no supplier is given, we return the receiver. If no receiver is given,
2669     // we return Y. Returning Y doesn't make much sense to me, but it's
2670     // grandfathered in for backcompat reasons.
2671     if (!receiver || !supplier) {
2672         return receiver || Y;
2673     }
2675     if (mode) {
2676         // In mode 2 (prototype to prototype and object to object), we recurse
2677         // once to do the proto to proto mix. The object to object mix will be
2678         // handled later on.
2679         if (mode === 2) {
2680             Y.mix(receiver.prototype, supplier.prototype, overwrite,
2681                     whitelist, 0, merge);
2682         }
2684         // Depending on which mode is specified, we may be copying from or to
2685         // the prototypes of the supplier and receiver.
2686         from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2687         to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2689         // If either the supplier or receiver doesn't actually have a
2690         // prototype property, then we could end up with an undefined `from`
2691         // or `to`. If that happens, we abort and return the receiver.
2692         if (!from || !to) {
2693             return receiver;
2694         }
2695     } else {
2696         from = supplier;
2697         to   = receiver;
2698     }
2700     // If `overwrite` is truthy and `merge` is falsy, then we can skip a
2701     // property existence check on each iteration and save some time.
2702     alwaysOverwrite = overwrite && !merge;
2704     if (whitelist) {
2705         for (i = 0, len = whitelist.length; i < len; ++i) {
2706             key = whitelist[i];
2708             // We call `Object.prototype.hasOwnProperty` instead of calling
2709             // `hasOwnProperty` on the object itself, since the object's
2710             // `hasOwnProperty` method may have been overridden or removed.
2711             // Also, some native objects don't implement a `hasOwnProperty`
2712             // method.
2713             if (!hasOwn.call(from, key)) {
2714                 continue;
2715             }
2717             // The `key in to` check here is (sadly) intentional for backwards
2718             // compatibility reasons. It prevents undesired shadowing of
2719             // prototype members on `to`.
2720             exists = alwaysOverwrite ? false : key in to;
2722             if (merge && exists && isObject(to[key], true)
2723                     && isObject(from[key], true)) {
2724                 // If we're in merge mode, and the key is present on both
2725                 // objects, and the value on both objects is either an object or
2726                 // an array (but not a function), then we recurse to merge the
2727                 // `from` value into the `to` value instead of overwriting it.
2728                 //
2729                 // Note: It's intentional that the whitelist isn't passed to the
2730                 // recursive call here. This is legacy behavior that lots of
2731                 // code still depends on.
2732                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2733             } else if (overwrite || !exists) {
2734                 // We're not in merge mode, so we'll only copy the `from` value
2735                 // to the `to` value if we're in overwrite mode or if the
2736                 // current key doesn't exist on the `to` object.
2737                 to[key] = from[key];
2738             }
2739         }
2740     } else {
2741         for (key in from) {
2742             // The code duplication here is for runtime performance reasons.
2743             // Combining whitelist and non-whitelist operations into a single
2744             // loop or breaking the shared logic out into a function both result
2745             // in worse performance, and Y.mix is critical enough that the byte
2746             // tradeoff is worth it.
2747             if (!hasOwn.call(from, key)) {
2748                 continue;
2749             }
2751             // The `key in to` check here is (sadly) intentional for backwards
2752             // compatibility reasons. It prevents undesired shadowing of
2753             // prototype members on `to`.
2754             exists = alwaysOverwrite ? false : key in to;
2756             if (merge && exists && isObject(to[key], true)
2757                     && isObject(from[key], true)) {
2758                 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2759             } else if (overwrite || !exists) {
2760                 to[key] = from[key];
2761             }
2762         }
2764         // If this is an IE browser with the JScript enumeration bug, force
2765         // enumeration of the buggy properties by making a recursive call with
2766         // the buggy properties as the whitelist.
2767         if (Y.Object._hasEnumBug) {
2768             Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
2769         }
2770     }
2772     return receiver;
2775  * The YUI module contains the components required for building the YUI
2776  * seed file.  This includes the script loading mechanism, a simple queue,
2777  * and the core utilities for the library.
2778  * @module yui
2779  * @submodule yui-base
2780  */
2783  * Adds utilities to the YUI instance for working with objects.
2785  * @class Object
2786  */
2788 var Lang   = Y.Lang,
2789     hasOwn = Object.prototype.hasOwnProperty,
2791     UNDEFINED, // <-- Note the comma. We're still declaring vars.
2794  * Returns a new object that uses _obj_ as its prototype. This method wraps the
2795  * native ES5 `Object.create()` method if available, but doesn't currently
2796  * pass through `Object.create()`'s second argument (properties) in order to
2797  * ensure compatibility with older browsers.
2799  * @method ()
2800  * @param {Object} obj Prototype object.
2801  * @return {Object} New object using _obj_ as its prototype.
2802  * @static
2803  */
2804 O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
2805     // We currently wrap the native Object.create instead of simply aliasing it
2806     // to ensure consistency with our fallback shim, which currently doesn't
2807     // support Object.create()'s second argument (properties). Once we have a
2808     // safe fallback for the properties arg, we can stop wrapping
2809     // Object.create().
2810     return Object.create(obj);
2811 } : (function () {
2812     // Reusable constructor function for the Object.create() shim.
2813     function F() {}
2815     // The actual shim.
2816     return function (obj) {
2817         F.prototype = obj;
2818         return new F();
2819     };
2820 }()),
2823  * Property names that IE doesn't enumerate in for..in loops, even when they
2824  * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
2825  * manually enumerate these properties.
2827  * @property _forceEnum
2828  * @type String[]
2829  * @protected
2830  * @static
2831  */
2832 forceEnum = O._forceEnum = [
2833     'hasOwnProperty',
2834     'isPrototypeOf',
2835     'propertyIsEnumerable',
2836     'toString',
2837     'toLocaleString',
2838     'valueOf'
2842  * `true` if this browser has the JScript enumeration bug that prevents
2843  * enumeration of the properties named in the `_forceEnum` array, `false`
2844  * otherwise.
2846  * See:
2847  *   - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
2848  *   - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
2850  * @property _hasEnumBug
2851  * @type Boolean
2852  * @protected
2853  * @static
2854  */
2855 hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
2858  * `true` if this browser incorrectly considers the `prototype` property of
2859  * functions to be enumerable. Currently known to affect Opera 11.50 and Android 2.3.x.
2861  * @property _hasProtoEnumBug
2862  * @type Boolean
2863  * @protected
2864  * @static
2865  */
2866 hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
2869  * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
2870  * exists only on _obj_'s prototype. This is essentially a safer version of
2871  * `obj.hasOwnProperty()`.
2873  * @method owns
2874  * @param {Object} obj Object to test.
2875  * @param {String} key Property name to look for.
2876  * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2877  * @static
2878  */
2879 owns = O.owns = function (obj, key) {
2880     return !!obj && hasOwn.call(obj, key);
2881 }; // <-- End of var declarations.
2884  * Alias for `owns()`.
2886  * @method hasKey
2887  * @param {Object} obj Object to test.
2888  * @param {String} key Property name to look for.
2889  * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2890  * @static
2891  */
2892 O.hasKey = owns;
2895  * Returns an array containing the object's enumerable keys. Does not include
2896  * prototype keys or non-enumerable keys.
2898  * Note that keys are returned in enumeration order (that is, in the same order
2899  * that they would be enumerated by a `for-in` loop), which may not be the same
2900  * as the order in which they were defined.
2902  * This method is an alias for the native ES5 `Object.keys()` method if
2903  * available and non-buggy. The Opera 11.50 and Android 2.3.x versions of
2904  * `Object.keys()` have an inconsistency as they consider `prototype` to be
2905  * enumerable, so a non-native shim is used to rectify the difference.
2907  * @example
2909  *     Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
2910  *     // => ['a', 'b', 'c']
2912  * @method keys
2913  * @param {Object} obj An object.
2914  * @return {String[]} Array of keys.
2915  * @static
2916  */
2917 O.keys = Lang._isNative(Object.keys) && !hasProtoEnumBug ? Object.keys : function (obj) {
2918     if (!Lang.isObject(obj)) {
2919         throw new TypeError('Object.keys called on a non-object');
2920     }
2922     var keys = [],
2923         i, key, len;
2925     if (hasProtoEnumBug && typeof obj === 'function') {
2926         for (key in obj) {
2927             if (owns(obj, key) && key !== 'prototype') {
2928                 keys.push(key);
2929             }
2930         }
2931     } else {
2932         for (key in obj) {
2933             if (owns(obj, key)) {
2934                 keys.push(key);
2935             }
2936         }
2937     }
2939     if (hasEnumBug) {
2940         for (i = 0, len = forceEnum.length; i < len; ++i) {
2941             key = forceEnum[i];
2943             if (owns(obj, key)) {
2944                 keys.push(key);
2945             }
2946         }
2947     }
2949     return keys;
2953  * Returns an array containing the values of the object's enumerable keys.
2955  * Note that values are returned in enumeration order (that is, in the same
2956  * order that they would be enumerated by a `for-in` loop), which may not be the
2957  * same as the order in which they were defined.
2959  * @example
2961  *     Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
2962  *     // => ['foo', 'bar', 'baz']
2964  * @method values
2965  * @param {Object} obj An object.
2966  * @return {Array} Array of values.
2967  * @static
2968  */
2969 O.values = function (obj) {
2970     var keys   = O.keys(obj),
2971         i      = 0,
2972         len    = keys.length,
2973         values = [];
2975     for (; i < len; ++i) {
2976         values.push(obj[keys[i]]);
2977     }
2979     return values;
2983  * Returns the number of enumerable keys owned by an object.
2985  * @method size
2986  * @param {Object} obj An object.
2987  * @return {Number} The object's size.
2988  * @static
2989  */
2990 O.size = function (obj) {
2991     try {
2992         return O.keys(obj).length;
2993     } catch (ex) {
2994         return 0; // Legacy behavior for non-objects.
2995     }
2999  * Returns `true` if the object owns an enumerable property with the specified
3000  * value.
3002  * @method hasValue
3003  * @param {Object} obj An object.
3004  * @param {any} value The value to search for.
3005  * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
3006  * @static
3007  */
3008 O.hasValue = function (obj, value) {
3009     return Y.Array.indexOf(O.values(obj), value) > -1;
3013  * Executes a function on each enumerable property in _obj_. The function
3014  * receives the value, the key, and the object itself as parameters (in that
3015  * order).
3017  * By default, only properties owned by _obj_ are enumerated. To include
3018  * prototype properties, set the _proto_ parameter to `true`.
3020  * @method each
3021  * @param {Object} obj Object to enumerate.
3022  * @param {Function} fn Function to execute on each enumerable property.
3023  *   @param {mixed} fn.value Value of the current property.
3024  *   @param {String} fn.key Key of the current property.
3025  *   @param {Object} fn.obj Object being enumerated.
3026  * @param {Object} [thisObj] `this` object to use when calling _fn_.
3027  * @param {Boolean} [proto=false] Include prototype properties.
3028  * @return {YUI} the YUI instance.
3029  * @chainable
3030  * @static
3031  */
3032 O.each = function (obj, fn, thisObj, proto) {
3033     var key;
3035     for (key in obj) {
3036         if (proto || owns(obj, key)) {
3037             fn.call(thisObj || Y, obj[key], key, obj);
3038         }
3039     }
3041     return Y;
3045  * Executes a function on each enumerable property in _obj_, but halts if the
3046  * function returns a truthy value. The function receives the value, the key,
3047  * and the object itself as paramters (in that order).
3049  * By default, only properties owned by _obj_ are enumerated. To include
3050  * prototype properties, set the _proto_ parameter to `true`.
3052  * @method some
3053  * @param {Object} obj Object to enumerate.
3054  * @param {Function} fn Function to execute on each enumerable property.
3055  *   @param {mixed} fn.value Value of the current property.
3056  *   @param {String} fn.key Key of the current property.
3057  *   @param {Object} fn.obj Object being enumerated.
3058  * @param {Object} [thisObj] `this` object to use when calling _fn_.
3059  * @param {Boolean} [proto=false] Include prototype properties.
3060  * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
3061  *   `false` otherwise.
3062  * @static
3063  */
3064 O.some = function (obj, fn, thisObj, proto) {
3065     var key;
3067     for (key in obj) {
3068         if (proto || owns(obj, key)) {
3069             if (fn.call(thisObj || Y, obj[key], key, obj)) {
3070                 return true;
3071             }
3072         }
3073     }
3075     return false;
3079  * Retrieves the sub value at the provided path,
3080  * from the value object provided.
3082  * @method getValue
3083  * @static
3084  * @param o The object from which to extract the property value.
3085  * @param path {Array} A path array, specifying the object traversal path
3086  * from which to obtain the sub value.
3087  * @return {Any} The value stored in the path, undefined if not found,
3088  * undefined if the source is not an object.  Returns the source object
3089  * if an empty path is provided.
3090  */
3091 O.getValue = function(o, path) {
3092     if (!Lang.isObject(o)) {
3093         return UNDEFINED;
3094     }
3096     var i,
3097         p = Y.Array(path),
3098         l = p.length;
3100     for (i = 0; o !== UNDEFINED && i < l; i++) {
3101         o = o[p[i]];
3102     }
3104     return o;
3108  * Sets the sub-attribute value at the provided path on the
3109  * value object.  Returns the modified value object, or
3110  * undefined if the path is invalid.
3112  * @method setValue
3113  * @static
3114  * @param o             The object on which to set the sub value.
3115  * @param path {Array}  A path array, specifying the object traversal path
3116  *                      at which to set the sub value.
3117  * @param val {Any}     The new value for the sub-attribute.
3118  * @return {Object}     The modified object, with the new sub value set, or
3119  *                      undefined, if the path was invalid.
3120  */
3121 O.setValue = function(o, path, val) {
3122     var i,
3123         p = Y.Array(path),
3124         leafIdx = p.length - 1,
3125         ref = o;
3127     if (leafIdx >= 0) {
3128         for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
3129             ref = ref[p[i]];
3130         }
3132         if (ref !== UNDEFINED) {
3133             ref[p[i]] = val;
3134         } else {
3135             return UNDEFINED;
3136         }
3137     }
3139     return o;
3143  * Returns `true` if the object has no enumerable properties of its own.
3145  * @method isEmpty
3146  * @param {Object} obj An object.
3147  * @return {Boolean} `true` if the object is empty.
3148  * @static
3149  * @since 3.2.0
3150  */
3151 O.isEmpty = function (obj) {
3152     return !O.keys(Object(obj)).length;
3155  * The YUI module contains the components required for building the YUI seed
3156  * file.  This includes the script loading mechanism, a simple queue, and the
3157  * core utilities for the library.
3158  * @module yui
3159  * @submodule yui-base
3160  */
3163  * YUI user agent detection.
3164  * Do not fork for a browser if it can be avoided.  Use feature detection when
3165  * you can.  Use the user agent as a last resort.  For all fields listed
3166  * as @type float, UA stores a version number for the browser engine,
3167  * 0 otherwise.  This value may or may not map to the version number of
3168  * the browser using the engine.  The value is presented as a float so
3169  * that it can easily be used for boolean evaluation as well as for
3170  * looking for a particular range of versions.  Because of this,
3171  * some of the granularity of the version info may be lost.  The fields that
3172  * are @type string default to null.  The API docs list the values that
3173  * these fields can have.
3174  * @class UA
3175  * @static
3176  */
3179 * Static method on `YUI.Env` for parsing a UA string.  Called at instantiation
3180 * to populate `Y.UA`.
3182 * @static
3183 * @method parseUA
3184 * @param {String} [subUA=navigator.userAgent] UA string to parse
3185 * @return {Object} The Y.UA object
3187 YUI.Env.parseUA = function(subUA) {
3189     var numberify = function(s) {
3190             var c = 0;
3191             return parseFloat(s.replace(/\./g, function() {
3192                 return (c++ === 1) ? '' : '.';
3193             }));
3194         },
3196         win = Y.config.win,
3198         nav = win && win.navigator,
3200         o = {
3202         /**
3203          * Internet Explorer version number or 0.  Example: 6
3204          * @property ie
3205          * @type float
3206          * @static
3207          */
3208         ie: 0,
3210         /**
3211          * Opera version number or 0.  Example: 9.2
3212          * @property opera
3213          * @type float
3214          * @static
3215          */
3216         opera: 0,
3218         /**
3219          * Gecko engine revision number.  Will evaluate to 1 if Gecko
3220          * is detected but the revision could not be found. Other browsers
3221          * will be 0.  Example: 1.8
3222          * <pre>
3223          * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
3224          * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3225          * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3226          * Firefox 3.0   <-- 1.9
3227          * Firefox 3.5   <-- 1.91
3228          * </pre>
3229          * @property gecko
3230          * @type float
3231          * @static
3232          */
3233         gecko: 0,
3235         /**
3236          * AppleWebKit version.  KHTML browsers that are not WebKit browsers
3237          * will evaluate to 1, other browsers 0.  Example: 418.9
3238          * <pre>
3239          * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3240          *                                   latest available for Mac OSX 10.3.
3241          * Safari 2.0.2:         416     <-- hasOwnProperty introduced
3242          * Safari 2.0.4:         418     <-- preventDefault fixed
3243          * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3244          *                                   different versions of webkit
3245          * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
3246          *                                   updated, but not updated
3247          *                                   to the latest patch.
3248          * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
3249          * SVG and many major issues fixed).
3250          * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
3251          * update from 2.x via the 10.4.11 OS patch.
3252          * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
3253          *                                   yahoo.com user agent hack removed.
3254          * </pre>
3255          * http://en.wikipedia.org/wiki/Safari_version_history
3256          * @property webkit
3257          * @type float
3258          * @static
3259          */
3260         webkit: 0,
3262         /**
3263          * Safari will be detected as webkit, but this property will also
3264          * be populated with the Safari version number
3265          * @property safari
3266          * @type float
3267          * @static
3268          */
3269         safari: 0,
3271         /**
3272          * Chrome will be detected as webkit, but this property will also
3273          * be populated with the Chrome version number
3274          * @property chrome
3275          * @type float
3276          * @static
3277          */
3278         chrome: 0,
3280         /**
3281          * The mobile property will be set to a string containing any relevant
3282          * user agent information when a modern mobile browser is detected.
3283          * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3284          * devices with the WebKit-based browser, and Opera Mini.
3285          * @property mobile
3286          * @type string
3287          * @default null
3288          * @static
3289          */
3290         mobile: null,
3292         /**
3293          * Adobe AIR version number or 0.  Only populated if webkit is detected.
3294          * Example: 1.0
3295          * @property air
3296          * @type float
3297          */
3298         air: 0,
3299         /**
3300          * PhantomJS version number or 0.  Only populated if webkit is detected.
3301          * Example: 1.0
3302          * @property phantomjs
3303          * @type float
3304          */
3305         phantomjs: 0,
3306         /**
3307          * Detects Apple iPad's OS version
3308          * @property ipad
3309          * @type float
3310          * @static
3311          */
3312         ipad: 0,
3313         /**
3314          * Detects Apple iPhone's OS version
3315          * @property iphone
3316          * @type float
3317          * @static
3318          */
3319         iphone: 0,
3320         /**
3321          * Detects Apples iPod's OS version
3322          * @property ipod
3323          * @type float
3324          * @static
3325          */
3326         ipod: 0,
3327         /**
3328          * General truthy check for iPad, iPhone or iPod
3329          * @property ios
3330          * @type Boolean
3331          * @default null
3332          * @static
3333          */
3334         ios: null,
3335         /**
3336          * Detects Googles Android OS version
3337          * @property android
3338          * @type float
3339          * @static
3340          */
3341         android: 0,
3342         /**
3343          * Detects Kindle Silk
3344          * @property silk
3345          * @type float
3346          * @static
3347          */
3348         silk: 0,
3349         /**
3350          * Detects Kindle Silk Acceleration
3351          * @property accel
3352          * @type Boolean
3353          * @static
3354          */
3355         accel: false,
3356         /**
3357          * Detects Palms WebOS version
3358          * @property webos
3359          * @type float
3360          * @static
3361          */
3362         webos: 0,
3364         /**
3365          * Google Caja version number or 0.
3366          * @property caja
3367          * @type float
3368          */
3369         caja: nav && nav.cajaVersion,
3371         /**
3372          * Set to true if the page appears to be in SSL
3373          * @property secure
3374          * @type boolean
3375          * @static
3376          */
3377         secure: false,
3379         /**
3380          * The operating system.  Currently only detecting windows or macintosh
3381          * @property os
3382          * @type string
3383          * @default null
3384          * @static
3385          */
3386         os: null,
3388         /**
3389          * The Nodejs Version
3390          * @property nodejs
3391          * @type float
3392          * @default 0
3393          * @static
3394          */
3395         nodejs: 0,
3396         /**
3397         * Window8/IE10 Application host environment
3398         * @property winjs
3399         * @type Boolean
3400         * @static
3401         */
3402         winjs: !!((typeof Windows !== "undefined") && Windows.System),
3403         /**
3404         * Are touch/msPointer events available on this device
3405         * @property touchEnabled
3406         * @type Boolean
3407         * @static
3408         */
3409         touchEnabled: false
3410     },
3412     ua = subUA || nav && nav.userAgent,
3414     loc = win && win.location,
3416     href = loc && loc.href,
3418     m;
3420     /**
3421     * The User Agent string that was parsed
3422     * @property userAgent
3423     * @type String
3424     * @static
3425     */
3426     o.userAgent = ua;
3429     o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3431     if (ua) {
3433         if ((/windows|win32/i).test(ua)) {
3434             o.os = 'windows';
3435         } else if ((/macintosh|mac_powerpc/i).test(ua)) {
3436             o.os = 'macintosh';
3437         } else if ((/android/i).test(ua)) {
3438             o.os = 'android';
3439         } else if ((/symbos/i).test(ua)) {
3440             o.os = 'symbos';
3441         } else if ((/linux/i).test(ua)) {
3442             o.os = 'linux';
3443         } else if ((/rhino/i).test(ua)) {
3444             o.os = 'rhino';
3445         }
3447         // Modern KHTML browsers should qualify as Safari X-Grade
3448         if ((/KHTML/).test(ua)) {
3449             o.webkit = 1;
3450         }
3451         if ((/IEMobile|XBLWP7/).test(ua)) {
3452             o.mobile = 'windows';
3453         }
3454         if ((/Fennec/).test(ua)) {
3455             o.mobile = 'gecko';
3456         }
3457         // Modern WebKit browsers are at least X-Grade
3458         m = ua.match(/AppleWebKit\/([^\s]*)/);
3459         if (m && m[1]) {
3460             o.webkit = numberify(m[1]);
3461             o.safari = o.webkit;
3463             if (/PhantomJS/.test(ua)) {
3464                 m = ua.match(/PhantomJS\/([^\s]*)/);
3465                 if (m && m[1]) {
3466                     o.phantomjs = numberify(m[1]);
3467                 }
3468             }
3470             // Mobile browser check
3471             if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
3472                 o.mobile = 'Apple'; // iPhone or iPod Touch
3474                 m = ua.match(/OS ([^\s]*)/);
3475                 if (m && m[1]) {
3476                     m = numberify(m[1].replace('_', '.'));
3477                 }
3478                 o.ios = m;
3479                 o.os = 'ios';
3480                 o.ipad = o.ipod = o.iphone = 0;
3482                 m = ua.match(/iPad|iPod|iPhone/);
3483                 if (m && m[0]) {
3484                     o[m[0].toLowerCase()] = o.ios;
3485                 }
3486             } else {
3487                 m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3488                 if (m) {
3489                     // Nokia N-series, webOS, ex: NokiaN95
3490                     o.mobile = m[0];
3491                 }
3492                 if (/webOS/.test(ua)) {
3493                     o.mobile = 'WebOS';
3494                     m = ua.match(/webOS\/([^\s]*);/);
3495                     if (m && m[1]) {
3496                         o.webos = numberify(m[1]);
3497                     }
3498                 }
3499                 if (/ Android/.test(ua)) {
3500                     if (/Mobile/.test(ua)) {
3501                         o.mobile = 'Android';
3502                     }
3503                     m = ua.match(/Android ([^\s]*);/);
3504                     if (m && m[1]) {
3505                         o.android = numberify(m[1]);
3506                     }
3508                 }
3509                 if (/Silk/.test(ua)) {
3510                     m = ua.match(/Silk\/([^\s]*)\)/);
3511                     if (m && m[1]) {
3512                         o.silk = numberify(m[1]);
3513                     }
3514                     if (!o.android) {
3515                         o.android = 2.34; //Hack for desktop mode in Kindle
3516                         o.os = 'Android';
3517                     }
3518                     if (/Accelerated=true/.test(ua)) {
3519                         o.accel = true;
3520                     }
3521                 }
3522             }
3524             m = ua.match(/OPR\/(\d+\.\d+)/);
3526             if (m && m[1]) {
3527                 // Opera 15+ with Blink (pretends to be both Chrome and Safari)
3528                 o.opera = numberify(m[1]);
3529             } else {
3530                 m = ua.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/);
3532                 if (m && m[1] && m[2]) {
3533                     o.chrome = numberify(m[2]); // Chrome
3534                     o.safari = 0; //Reset safari back to 0
3535                     if (m[1] === 'CrMo') {
3536                         o.mobile = 'chrome';
3537                     }
3538                 } else {
3539                     m = ua.match(/AdobeAIR\/([^\s]*)/);
3540                     if (m) {
3541                         o.air = m[0]; // Adobe AIR 1.0 or better
3542                     }
3543                 }
3544             }
3545         }
3547         if (!o.webkit) { // not webkit
3548 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3549             if (/Opera/.test(ua)) {
3550                 m = ua.match(/Opera[\s\/]([^\s]*)/);
3551                 if (m && m[1]) {
3552                     o.opera = numberify(m[1]);
3553                 }
3554                 m = ua.match(/Version\/([^\s]*)/);
3555                 if (m && m[1]) {
3556                     o.opera = numberify(m[1]); // opera 10+
3557                 }
3559                 if (/Opera Mobi/.test(ua)) {
3560                     o.mobile = 'opera';
3561                     m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
3562                     if (m && m[1]) {
3563                         o.opera = numberify(m[1]);
3564                     }
3565                 }
3566                 m = ua.match(/Opera Mini[^;]*/);
3568                 if (m) {
3569                     o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3570                 }
3571             } else { // not opera or webkit
3572                 m = ua.match(/MSIE ([^;]*)|Trident.*; rv:([0-9.]+)/);
3574                 if (m && (m[1] || m[2])) {
3575                     o.ie = numberify(m[1] || m[2]);
3576                 } else { // not opera, webkit, or ie
3577                     m = ua.match(/Gecko\/([^\s]*)/);
3579                     if (m) {
3580                         o.gecko = 1; // Gecko detected, look for revision
3581                         m = ua.match(/rv:([^\s\)]*)/);
3582                         if (m && m[1]) {
3583                             o.gecko = numberify(m[1]);
3584                             if (/Mobile|Tablet/.test(ua)) {
3585                                 o.mobile = "ffos";
3586                             }
3587                         }
3588                     }
3589                 }
3590             }
3591         }
3592     }
3594     //Check for known properties to tell if touch events are enabled on this device or if
3595     //the number of MSPointer touchpoints on this device is greater than 0.
3596     if (win && nav && !(o.chrome && o.chrome < 6)) {
3597         o.touchEnabled = (("ontouchstart" in win) || (("msMaxTouchPoints" in nav) && (nav.msMaxTouchPoints > 0)));
3598     }
3600     //It was a parsed UA, do not assign the global value.
3601     if (!subUA) {
3603         if (typeof process === 'object') {
3605             if (process.versions && process.versions.node) {
3606                 //NodeJS
3607                 o.os = process.platform;
3608                 o.nodejs = numberify(process.versions.node);
3609             }
3610         }
3612         YUI.Env.UA = o;
3614     }
3616     return o;
3620 Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3623 Performs a simple comparison between two version numbers, accounting for
3624 standard versioning logic such as the fact that "535.8" is a lower version than
3625 "535.24", even though a simple numerical comparison would indicate that it's
3626 greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
3627 considered equivalent.
3629 Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
3630 1 if _a_ is higher than _b_.
3632 Versions may be numbers or strings containing numbers and dots. For example,
3633 both `535` and `"535.8.10"` are acceptable. A version string containing
3634 non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
3636 @method compareVersions
3637 @param {Number|String} a First version number to compare.
3638 @param {Number|String} b Second version number to compare.
3639 @return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
3640     higher than _b_.
3642 Y.UA.compareVersions = function (a, b) {
3643     var aPart, aParts, bPart, bParts, i, len;
3645     if (a === b) {
3646         return 0;
3647     }
3649     aParts = (a + '').split('.');
3650     bParts = (b + '').split('.');
3652     for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
3653         aPart = parseInt(aParts[i], 10);
3654         bPart = parseInt(bParts[i], 10);
3656         /*jshint expr: true*/
3657         isNaN(aPart) && (aPart = 0);
3658         isNaN(bPart) && (bPart = 0);
3660         if (aPart < bPart) {
3661             return -1;
3662         }
3664         if (aPart > bPart) {
3665             return 1;
3666         }
3667     }
3669     return 0;
3671 YUI.Env.aliases = {
3672     "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3673     "anim-shape-transform": ["anim-shape"],
3674     "app": ["app-base","app-content","app-transitions","lazy-model-list","model","model-list","model-sync-rest","model-sync-local","router","view","view-node-map"],
3675     "attribute": ["attribute-base","attribute-complex"],
3676     "attribute-events": ["attribute-observable"],
3677     "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3678     "axes": ["axis-numeric","axis-category","axis-time","axis-stacked"],
3679     "axes-base": ["axis-numeric-base","axis-category-base","axis-time-base","axis-stacked-base"],
3680     "base": ["base-base","base-pluginhost","base-build"],
3681     "cache": ["cache-base","cache-offline","cache-plugin"],
3682     "charts": ["charts-base"],
3683     "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3684     "color": ["color-base","color-hsl","color-harmony"],
3685     "controller": ["router"],
3686     "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3687     "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3688     "datatable": ["datatable-core","datatable-table","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
3689     "datatype": ["datatype-date","datatype-number","datatype-xml"],
3690     "datatype-date": ["datatype-date-parse","datatype-date-format","datatype-date-math"],
3691     "datatype-number": ["datatype-number-parse","datatype-number-format"],
3692     "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3693     "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3694     "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3695     "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3696     "event": ["event-base","event-delegate","event-synthetic","event-mousewheel","event-mouseenter","event-key","event-focus","event-resize","event-hover","event-outside","event-touch","event-move","event-flick","event-valuechange","event-tap"],
3697     "event-custom": ["event-custom-base","event-custom-complex"],
3698     "event-gestures": ["event-flick","event-move"],
3699     "handlebars": ["handlebars-compiler"],
3700     "highlight": ["highlight-base","highlight-accentfold"],
3701     "history": ["history-base","history-hash","history-hash-ie","history-html5"],
3702     "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
3703     "json": ["json-parse","json-stringify"],
3704     "loader": ["loader-base","loader-rollup","loader-yui3"],
3705     "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
3706     "pluginhost": ["pluginhost-base","pluginhost-config"],
3707     "querystring": ["querystring-parse","querystring-stringify"],
3708     "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
3709     "resize": ["resize-base","resize-proxy","resize-constrain"],
3710     "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
3711     "template": ["template-base","template-micro"],
3712     "text": ["text-accentfold","text-wordbreak"],
3713     "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]
3717 }, '3.13.0');