3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 * The YUI module contains the components required for building the YUI seed
9 * file. This includes the script loading mechanism, a simple queue, and
10 * the core utilities for the library.
15 if (typeof YUI != 'undefined') {
20 The YUI global namespace object. If YUI is already defined, the
21 existing YUI object will not be overwritten so that defined
22 namespaces are preserved. It is the constructor for the object
23 the end user interacts with. As indicated below, each instance
24 has full custom event support, but only if the event system
25 is available. This is a self-instantiable factory function. You
26 can invoke it directly like this:
28 YUI().use('*', function(Y) {
32 But it also works like this:
36 Configuring the YUI object:
41 }).use('node', function(Y) {
42 //Node is ready to use
45 See the API docs for the <a href="config.html">Config</a> class
46 for the complete list of supported configuration properties accepted
47 by the YUI constuctor.
53 @param [o]* {Object} 0..n optional configuration objects. these values
54 are store in Y.config. See <a href="config.html">Config</a> for the list of supported
59 var YUI = function() {
64 instanceOf = function(o, type) {
65 return (o && o.hasOwnProperty && (o instanceof type));
67 gconf = (typeof YUI_config !== 'undefined') && YUI_config;
69 if (!(instanceOf(Y, YUI))) {
72 // set up the core environment
76 YUI.GlobalConfig is a master configuration that might span
77 multiple contexts in a non-browser environment. It is applied
78 first to all instances in all contexts.
79 @property GlobalConfig
90 YUI().use('node', function(Y) {
91 //debug files used here
96 }).use('node', function(Y) {
101 if (YUI.GlobalConfig) {
102 Y.applyConfig(YUI.GlobalConfig);
106 YUI_config is a page-level config. It is applied to all
107 instances created on the page. This is applied after
108 YUI.GlobalConfig, and before the instance level configuration
116 //Single global var to include before YUI seed file
121 YUI().use('node', function(Y) {
122 //debug files used here
127 }).use('node', function(Y) {
128 //min files used here
132 Y.applyConfig(gconf);
135 // bind the specified additional modules for this instance
142 // Each instance can accept one or more configuration objects.
143 // These are applied after YUI.GlobalConfig and YUI_Config,
144 // overriding values set in those config files if there is a '
145 // matching property.
147 Y.applyConfig(args[i]);
153 Y.instanceOf = instanceOf;
163 BASE = 'http://yui.yahooapis.com/',
164 DOC_LABEL = 'yui3-js-enabled',
165 CSS_STAMP_EL = 'yui3-css-stamp',
166 NOOP = function() {},
167 SLICE = Array.prototype.slice,
168 APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo
169 'io.xdrResponse': 1, // can call. this should
170 'SWF.eventHandler': 1 }, // be done at build time
171 hasWin = (typeof window != 'undefined'),
172 win = (hasWin) ? window : null,
173 doc = (hasWin) ? win.document : null,
174 docEl = doc && doc.documentElement,
175 docClass = docEl && docEl.className,
177 time = new Date().getTime(),
178 add = function(el, type, fn, capture) {
179 if (el && el.addEventListener) {
180 el.addEventListener(type, fn, capture);
181 } else if (el && el.attachEvent) {
182 el.attachEvent('on' + type, fn);
185 remove = function(el, type, fn, capture) {
186 if (el && el.removeEventListener) {
187 // this can throw an uncaught exception in FF
189 el.removeEventListener(type, fn, capture);
191 } else if (el && el.detachEvent) {
192 el.detachEvent('on' + type, fn);
195 handleLoad = function() {
196 YUI.Env.windowLoaded = true;
197 YUI.Env.DOMReady = true;
199 remove(window, 'load', handleLoad);
202 getLoader = function(Y, o) {
203 var loader = Y.Env._loader;
205 //loader._config(Y.config);
206 loader.ignoreRegistered = false;
209 loader.required = [];
210 loader.loadType = null;
212 loader = new Y.Loader(Y.config);
213 Y.Env._loader = loader;
215 YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, [ 'loader-base', 'loader-rollup', 'loader-yui3' ]));
220 clobber = function(r, s) {
222 if (s.hasOwnProperty(i)) {
228 ALREADY_DONE = { success: true };
230 // Stamp the documentElement (HTML) with a class of "yui-loaded" to
231 // enable styles that need to key off of JS being enabled.
232 if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
236 docClass += DOC_LABEL;
237 docEl.className = docClass;
240 if (VERSION.indexOf('@') > -1) {
241 VERSION = '3.3.0'; // dev time hack for cdn test
246 * Applies a new configuration object to the YUI instance config.
247 * This will merge new group/module definitions, and will also
248 * update the loader cache if necessary. Updating Y.config directly
249 * will not update the cache.
250 * @method applyConfig
251 * @param {Object} o the configuration object.
254 applyConfig: function(o) {
261 config = this.config,
262 mods = config.modules,
263 groups = config.groups,
264 aliases = config.aliases,
265 loader = this.Env._loader;
268 if (o.hasOwnProperty(name)) {
270 if (mods && name == 'modules') {
272 } else if (aliases && name == 'aliases') {
273 clobber(aliases, attr);
274 } else if (groups && name == 'groups') {
275 clobber(groups, attr);
276 } else if (name == 'win') {
277 config[name] = (attr && attr.contentWindow) || attr;
278 config.doc = config[name] ? config[name].document : null;
279 } else if (name == '_yuid') {
293 * Old way to apply a config to the instance (calls `applyConfig` under the hood)
296 * @param {Object} o The config to apply
298 _config: function(o) {
303 * Initialize this YUI instance
315 * The version number of the YUI instance.
323 core: ['get','intl-base'],
324 mods: {}, // flat module map
325 versions: {}, // version module map
327 cdn: BASE + VERSION + '/build/',
328 // bootstrapped: false,
339 // I'll start at the \b(simpleyui).
340 // 1. Look in the test string for "simpleyui" or "yui" or
341 // "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break. That is, it
342 // can't match "foyui" or "i_heart_simpleyui". This can be anywhere in the string.
343 // 2. After #1 must come a forward slash followed by the string matched in #1, so
344 // "yui-base/yui-base" or "simpleyui/simpleyui" or "yui-pants/yui-pants".
345 // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
346 // so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
347 // 4. This is followed by ".js", so "yui/yui.js", "simpleyui/simpleyui-min.js"
348 // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
349 // then capture the junk between the LAST "&" and the string in 1-4. So
350 // "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
351 // will capture "3.3.0/build/"
355 // (?:[^&]*&) followed by 0..n characters followed by an &
356 // * in fact, find as many sets of characters followed by a & as you can
357 // ([^&]*) capture the stuff after the last & in \1
358 // )? but it's ok if all this ?junk&more_junk stuff isn't even there
359 // \b(simpleyui| after a word break find either the string "simpleyui" or
360 // yui(?:-\w+)? the string "yui" optionally followed by a -, then more characters
361 // ) and store the simpleyui or yui-* string in \2
362 // \/\2 then comes a / followed by the simpleyui or yui-* string in \2
363 // (?:-(min|debug))? optionally followed by "-min" or "-debug"
364 // .js and ending in ".js"
365 _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(simpleyui|yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
366 parseBasePath: function(src, pattern) {
367 var match = src.match(pattern),
371 path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
373 // this is to set up the path to the loader. The file
374 // filter for loader should match the yui include.
377 // extract correct path for mixed combo urls
378 // http://yuilibrary.com/projects/yui3/ticket/2528423
380 path += '?' + match[1];
389 getBase: G_ENV && G_ENV.getBase ||
391 var nodes = (doc && doc.getElementsByTagName('script')) || [],
392 path = Env.cdn, parsed,
395 for (i = 0, len = nodes.length; i < len; ++i) {
398 parsed = Y.Env.parseBasePath(src, pattern);
400 filter = parsed.filter;
415 Env._loaded[VERSION] = {};
417 if (G_ENV && Y !== YUI) {
418 Env._yidx = ++G_ENV._yidx;
419 Env._guidp = ('yui_' + VERSION + '_' +
420 Env._yidx + '_' + time).replace(/\./g, '_');
421 } else if (YUI._YUI) {
423 G_ENV = YUI._YUI.Env;
424 Env._yidx += G_ENV._yidx;
425 Env._uidx += G_ENV._uidx;
427 for (prop in G_ENV) {
428 if (!(prop in Env)) {
429 Env[prop] = G_ENV[prop];
443 // configuration defaults
444 Y.config = Y.config || {
451 useBrowserConsole: true,
456 //Register the CSS stamp element
457 if (doc && !doc.getElementById(CSS_STAMP_EL)) {
458 el = doc.createElement('div');
459 el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
460 YUI.Env.cssStampEl = el.firstChild;
461 docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
464 Y.config.lang = Y.config.lang || 'en-US';
466 Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
468 if (!filter || (!('mindebug').indexOf(filter))) {
471 filter = (filter) ? '-' + filter : filter;
472 Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
477 * Finishes the instance setup. Attaches whatever modules were defined
478 * when the yui modules was registered.
482 _setup: function(o) {
486 //extras = Y.config.core || ['get','intl-base'];
487 extras = Y.config.core || [].concat(YUI.Env.core); //Clone it..
489 for (i = 0; i < extras.length; i++) {
490 if (mods[extras[i]]) {
491 core.push(extras[i]);
495 Y._attach(['yui-base']);
502 // Y.log(Y.id + ' initialized', 'info', 'yui');
506 * Executes a method on a YUI instance with
507 * the specified id if the specified method is whitelisted.
509 * @param id {String} the YUI instance id.
510 * @param method {String} the name of the method to exectute.
512 * @param args {Array} the arguments to apply to the method.
513 * @return {Object} the return value from the applied method or null.
515 applyTo: function(id, method, args) {
516 if (!(method in APPLY_TO_AUTH)) {
517 this.log(method + ': applyTo not allowed', 'warn', 'yui');
521 var instance = instances[id], nest, m, i;
523 nest = method.split('.');
525 for (i = 0; i < nest.length; i = i + 1) {
528 this.log('applyTo not found: ' + method, 'warn', 'yui');
531 return m && m.apply(instance, args);
538 Registers a module with the YUI global. The easiest way to create a
539 first-class YUI module is to use the YUI component build tool.
541 http://yuilibrary.com/projects/builder
543 The build system will produce the `YUI.add` wrapper for you module, along
544 with any configuration info required for the module.
546 @param name {String} module name.
547 @param fn {Function} entry point into the module that is used to bind module to the YUI instance.
548 @param {YUI} fn.Y The YUI instance this module is executed in.
549 @param {String} fn.name The name of the module
550 @param version {String} version string.
551 @param details {Object} optional config data:
552 @param details.requires {Array} features that must be present before this module can be attached.
553 @param details.optional {Array} optional features that should be present if loadOptional
554 is defined. Note: modules are not often loaded this way in YUI 3,
555 but this field is still useful to inform the user that certain
556 features in the component will require additional dependencies.
557 @param details.use {Array} features that are included within this module which need to
558 be attached automatically when this module is attached. This
559 supports the YUI 3 rollup system -- a module with submodules
560 defined will need to have the submodules listed in the 'use'
561 config. The YUI component build tool does this for you.
562 @return {YUI} the YUI instance.
565 YUI.add('davglass', function(Y, name) {
566 Y.davglass = function() {
567 alert('Dav was here!');
569 }, '3.4.0', { requires: ['yui-base', 'harley-davidson', 'mt-dew'] });
572 add: function(name, fn, version, details) {
573 details = details || {};
582 i, versions = env.versions;
584 env.mods[name] = mod;
585 versions[version] = versions[version] || {};
586 versions[version][name] = mod;
588 for (i in instances) {
589 if (instances.hasOwnProperty(i)) {
590 loader = instances[i].Env._loader;
592 if (!loader.moduleInfo[name] || loader.moduleInfo[name].temp) {
593 loader.addModule(details, name);
603 * Executes the function associated with each required
604 * module, binding the module to the YUI instance.
605 * @param {Array} r The array of modules to attach
606 * @param {Boolean} [moot=false] Don't throw a warning if the module is not attached
610 _attach: function(r, moot) {
611 var i, name, mod, details, req, use, after,
613 aliases = YUI.Env.aliases,
615 loader = Y.Env._loader,
616 done = Y.Env._attached,
617 len = r.length, loader,
620 //Check for conditional modules (in a second+ instance) and add their requirements
621 //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
622 for (i = 0; i < len; i++) {
626 if (loader && loader.conditions[name]) {
627 Y.Object.each(loader.conditions[name], function(def) {
628 var go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
638 for (i = 0; i < len; i++) {
643 if (aliases && aliases[name]) {
644 Y._attach(aliases[name]);
648 if (loader && loader.moduleInfo[name]) {
649 mod = loader.moduleInfo[name];
653 // Y.log('no js def for: ' + name, 'info', 'yui');
655 //if (!loader || !loader.moduleInfo[name]) {
656 //if ((!loader || !loader.moduleInfo[name]) && !moot) {
658 if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
659 Y.Env._missed.push(name);
660 Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
661 Y.message('NOT loaded: ' + name, 'warn', 'yui');
666 //Don't like this, but in case a mod was asked for once, then we fetch it
667 //We need to remove it from the missed list ^davglass
668 for (j = 0; j < Y.Env._missed.length; j++) {
669 if (Y.Env._missed[j] === name) {
670 Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
671 Y.Env._missed.splice(j, 1);
674 details = mod.details;
675 req = details.requires;
677 after = details.after;
680 for (j = 0; j < req.length; j++) {
682 if (!Y._attach(req)) {
691 for (j = 0; j < after.length; j++) {
692 if (!done[after[j]]) {
693 if (!Y._attach(after, true)) {
705 Y.error('Attach error: ' + name, e, name);
711 for (j = 0; j < use.length; j++) {
713 if (!Y._attach(use)) {
731 * Attaches one or more modules to the YUI instance. When this
732 * is executed, the requirements are analyzed, and one of
733 * several things can happen:
735 * * All requirements are available on the page -- The modules
736 * are attached to the instance. If supplied, the use callback
737 * is executed synchronously.
739 * * Modules are missing, the Get utility is not available OR
740 * the 'bootstrap' config is false -- A warning is issued about
741 * the missing modules and all available modules are attached.
743 * * Modules are missing, the Loader is not available but the Get
744 * utility is and boostrap is not false -- The loader is bootstrapped
745 * before doing the following....
747 * * Modules are missing and the Loader is available -- The loader
748 * expands the dependency tree and fetches missing modules. When
749 * the loader is finshed the callback supplied to use is executed
753 * @param modules* {String|Array} 1-n modules to bind (uses arguments array).
754 * @param [callback] {Function} callback function executed when
755 * the instance has the required functionality. If included, it
756 * must be the last parameter.
757 * @param callback.Y {YUI} The `YUI` instance created for this sandbox
758 * @param callback.data {Object} Object data returned from `Loader`.
761 * // loads and attaches dd and its dependencies
762 * YUI().use('dd', function(Y) {});
764 * // loads and attaches dd and node as well as all of their dependencies (since 3.4.0)
765 * YUI().use(['dd', 'node'], function(Y) {});
767 * // attaches all modules that are available on the page
768 * YUI().use('*', function(Y) {});
770 * // intrinsic YUI gallery support (since 3.1.0)
771 * YUI().use('gallery-yql', function(Y) {});
773 * // intrinsic YUI 2in3 support (since 3.1.0)
774 * YUI().use('yui2-datatable', function(Y) {});
776 * @return {YUI} the YUI instance.
779 var args = SLICE.call(arguments, 0),
780 callback = args[args.length - 1],
788 // The last argument supplied to use can be a load complete callback
789 if (Y.Lang.isFunction(callback)) {
794 if (Y.Lang.isArray(args[0])) {
798 if (Y.config.cacheUse) {
799 while ((name = args[i++])) {
800 if (!Env._attached[name]) {
808 Y.log('already provisioned: ' + args, 'info', 'yui');
810 Y._notify(callback, ALREADY_DONE, args);
816 Y._useQueue = Y._useQueue || new Y.Queue();
817 Y._useQueue.add([args, callback]);
819 Y._use(args, function(Y, response) {
820 Y._notify(callback, response, args);
827 * Notify handler from Loader for attachment/load errors
829 * @param callback {Function} The callback to pass to the `Y.config.loadErrorFn`
830 * @param response {Object} The response returned from Loader
831 * @param args {Array} The aruments passed from Loader
834 _notify: function(callback, response, args) {
835 if (!response.success && this.config.loadErrorFn) {
836 this.config.loadErrorFn.call(this, this, callback, response, args);
837 } else if (callback) {
839 callback(this, response);
841 this.error('use callback error', e, args);
847 * This private method is called from the `use` method queue. To ensure that only one set of loading
848 * logic is performed at a time.
851 * @param args* {String} 1-n modules to bind (uses arguments array).
852 * @param *callback {Function} callback function executed when
853 * the instance has the required functionality. If included, it
854 * must be the last parameter.
856 _use: function(args, callback) {
859 this._attach(['yui-base']);
862 var len, loader, handleBoot, handleRLS,
868 aliases = G_ENV.aliases,
869 queue = G_ENV._loaderQueue,
873 boot = config.bootstrap,
877 fetchCSS = config.fetchCSS,
878 process = function(names, skip) {
887 for (i = 0; i < names.length; i++) {
888 if (aliases[names[i]]) {
889 a = [].concat(a, aliases[names[i]]);
897 YArray.each(names, function(name) {
899 // add this module to full list of things to attach
904 // only attach a module once
909 var m = mods[name], req, use;
913 req = m.details.requires;
916 // CSS files don't register themselves, see if it has
918 if (!G_ENV._loaded[VERSION][name]) {
921 used[name] = true; // probably css
925 // make sure requirements are attached
926 if (req && req.length) {
930 // make sure we grab the submodule dependencies too
931 if (use && use.length) {
937 handleLoader = function(fromLoader) {
938 var response = fromLoader || {
944 data = response.data;
949 origMissing = missing;
953 redo = missing.length;
955 if (missing.sort().join() ==
956 origMissing.sort().join()) {
964 Y._use(missing, function() {
965 Y.log('Nested use callback: ' + data, 'info', 'yui');
966 if (Y._attach(data)) {
967 Y._notify(callback, response, data);
972 // Y.log('attaching from loader: ' + data, 'info', 'yui');
973 ret = Y._attach(data);
976 Y._notify(callback, response, args);
980 if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
981 Y._use.apply(Y, Y._useQueue.next());
986 // Y.log(Y.id + ': use called: ' + a + ' :: ' + callback, 'info', 'yui');
988 // YUI().use('*'); // bind everything available
989 if (firstArg === '*') {
990 ret = Y._attach(Y.Object.keys(mods));
997 if (mods['loader'] && !Y.Loader) {
998 Y.log('Loader was found in meta, but it is not attached. Attaching..', 'info', 'yui');
999 Y._attach(['loader']);
1002 // Y.log('before loader requirements: ' + args, 'info', 'yui');
1004 // use loader to expand dependencies and sort the
1005 // requirements if it is available.
1006 if (boot && Y.Loader && args.length) {
1007 loader = getLoader(Y);
1008 loader.require(args);
1009 loader.ignoreRegistered = true;
1010 loader._boot = true;
1011 loader.calculate(null, (fetchCSS) ? null : 'js');
1012 args = loader.sorted;
1013 loader._boot = false;
1016 // process each requirement and any additional requirements
1017 // the module metadata specifies
1020 len = missing.length;
1023 missing = Y.Object.keys(YArray.hash(missing));
1024 len = missing.length;
1025 Y.log('Modules missing: ' + missing + ', ' + missing.length, 'info', 'yui');
1030 if (boot && len && Y.Loader) {
1031 // Y.log('Using loader to fetch missing deps: ' + missing, 'info', 'yui');
1032 Y.log('Using Loader', 'info', 'yui');
1034 loader = getLoader(Y);
1035 loader.onEnd = handleLoader;
1038 loader.ignoreRegistered = false;
1039 loader.require(args);
1040 loader.insert(null, (fetchCSS) ? null : 'js');
1042 } else if (boot && len && Y.Get && !Env.bootstrapped) {
1046 handleBoot = function() {
1048 queue.running = false;
1049 Env.bootstrapped = true;
1050 G_ENV._bootstrapping = false;
1051 if (Y._attach(['loader'])) {
1052 Y._use(args, callback);
1056 if (G_ENV._bootstrapping) {
1057 Y.log('Waiting for loader', 'info', 'yui');
1058 queue.add(handleBoot);
1060 G_ENV._bootstrapping = true;
1061 Y.log('Fetching loader: ' + config.base + config.loaderPath, 'info', 'yui');
1062 Y.Get.script(config.base + config.loaderPath, {
1068 Y.log('Attaching available dependencies: ' + args, 'info', 'yui');
1069 ret = Y._attach(args);
1080 Adds a namespace object onto the YUI global if called statically.
1082 // creates YUI.your.namespace.here as nested objects
1083 YUI.namespace("your.namespace.here");
1085 If called as a method on a YUI <em>instance</em>, it creates the
1086 namespace on the instance.
1088 // creates Y.property.package
1089 Y.namespace("property.package");
1091 Dots in the input string cause `namespace` to create nested objects for
1092 each token. If any part of the requested namespace already exists, the
1093 current object will be left in place. This allows multiple calls to
1094 `namespace` to preserve existing namespaced properties.
1096 If the first token in the namespace string is "YAHOO", the token is
1099 Be careful with namespace tokens. Reserved words may work in some browsers
1100 and not others. For instance, the following will fail in some browsers
1101 because the supported version of JavaScript reserves the word "long":
1103 Y.namespace("really.long.nested.namespace");
1105 <em>Note: If you pass multiple arguments to create multiple namespaces, only
1106 the last one created is returned from this function.</em>
1109 @param {String} namespace* namespaces to create.
1110 @return {Object} A reference to the last namespace object created.
1112 namespace: function() {
1113 var a = arguments, o, i = 0, j, d, arg;
1115 for (; i < a.length; i++) {
1116 o = this; //Reset base object per argument or it will get reused from the last
1118 if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
1119 d = arg.split(PERIOD);
1120 for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1121 o[d[j]] = o[d[j]] || {};
1125 o[arg] = o[arg] || {};
1126 o = o[arg]; //Reset base object to the new object so it's returned
1132 // this is replaced if the log module is included
1135 // this is replaced if the dump module is included
1136 dump: function (o) { return ''+o; },
1139 * Report an error. The reporting mechanism is controlled by
1140 * the `throwFail` configuration attribute. If throwFail is
1141 * not specified, the message is written to the Logger, otherwise
1142 * a JS error is thrown. If an `errorFn` is specified in the config
1143 * it must return `true` to keep the error from being thrown.
1145 * @param msg {String} the error message.
1146 * @param e {Error|String} Optional JS error that was caught, or an error string.
1147 * @param src Optional additional info (passed to `Y.config.errorFn` and `Y.message`)
1148 * and `throwFail` is specified, this error will be re-thrown.
1149 * @return {YUI} this YUI instance.
1151 error: function(msg, e, src) {
1152 //TODO Add check for window.onerror here
1156 if (Y.config.errorFn) {
1157 ret = Y.config.errorFn.apply(Y, arguments);
1160 if (Y.config.throwFail && !ret) {
1161 throw (e || new Error(msg));
1163 Y.message(msg, 'error', ''+src); // don't scrub this one
1170 * Generate an id that is unique among all YUI instances
1172 * @param pre {String} optional guid prefix.
1173 * @return {String} the guid.
1175 guid: function(pre) {
1176 var id = this.Env._guidp + '_' + (++this.Env._uidx);
1177 return (pre) ? (pre + id) : id;
1181 * Returns a `guid` associated with an object. If the object
1182 * does not have one, a new one is created unless `readOnly`
1185 * @param o {Object} The object to stamp.
1186 * @param readOnly {Boolean} if `true`, a valid guid will only
1187 * be returned if the object has one assigned to it.
1188 * @return {String} The object's guid or null.
1190 stamp: function(o, readOnly) {
1196 // IE generates its own unique ID for dom nodes
1197 // The uniqueID property of a document node returns a new ID
1198 if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1201 uid = (typeof o === 'string') ? o : o._yuid;
1218 * Destroys the YUI instance
1222 destroy: function() {
1227 delete instances[Y.id];
1233 * instanceof check for objects that works around
1234 * memory leak in IE when the item tested is
1236 * @method instanceOf
1237 * @param o {Object} The object to check.
1238 * @param type {Object} The class to check against.
1243 YUI.prototype = proto;
1245 // inheritance utilities are not available yet
1246 for (prop in proto) {
1247 if (proto.hasOwnProperty(prop)) {
1248 YUI[prop] = proto[prop];
1253 Static method on the Global YUI object to apply a config to all YUI instances.
1254 It's main use case is "mashups" where several third party scripts are trying to write to
1255 a global YUI config at the same time. This way they can all call `YUI.applyConfig({})` instead of
1256 overwriting other scripts configs.
1260 @param {Object} o the configuration object.
1266 fullpath: './davglass.js'
1274 fullpath: './foo.js'
1279 YUI().use('davglass', function(Y) {
1280 //Module davglass will be available here..
1284 YUI.applyConfig = function(o) {
1288 //If there is a GlobalConfig, apply it first to set the defaults
1289 if (YUI.GlobalConfig) {
1290 this.prototype.applyConfig.call(this, YUI.GlobalConfig);
1292 //Apply this config to it
1293 this.prototype.applyConfig.call(this, o);
1294 //Reset GlobalConfig to the combined config
1295 YUI.GlobalConfig = this.config;
1298 // set up the environment
1302 // add a window load event at load time so we can capture
1303 // the case where it fires before dynamic loading is
1305 add(window, 'load', handleLoad);
1311 YUI.Env.remove = remove;
1314 // Support the CommonJS method for exporting our single global
1315 if (typeof exports == 'object') {
1323 * The config object contains all of the configuration options for
1324 * the `YUI` instance. This object is supplied by the implementer
1325 * when instantiating a `YUI` instance. Some properties have default
1326 * values if they are not supplied by the implementer. This should
1327 * not be updated directly because some values are cached. Use
1328 * `applyConfig()` to update the config object on a YUI instance that
1329 * has already been configured.
1336 * Allows the YUI seed file to fetch the loader component and library
1337 * metadata to dynamically load additional dependencies.
1339 * @property bootstrap
1345 * Turns on writing Ylog messages to the browser console.
1353 * Log to the browser console if debug is on and the browser has a
1354 * supported console.
1356 * @property useBrowserConsole
1362 * A hash of log sources that should be logged. If specified, only
1363 * log messages from these sources will be logged.
1365 * @property logInclude
1370 * A hash of log sources that should be not be logged. If specified,
1371 * all sources are logged if not on this list.
1373 * @property logExclude
1378 * Set to true if the yui seed file was dynamically loaded in
1379 * order to bootstrap components relying on the window load event
1380 * and the `domready` custom event.
1382 * @property injected
1388 * If `throwFail` is set, `Y.error` will generate or re-throw a JS Error.
1389 * Otherwise the failure is logged.
1391 * @property throwFail
1397 * The window/frame that this instance should operate in.
1401 * @default the window hosting YUI
1405 * The document associated with the 'win' configuration.
1409 * @default the document hosting YUI
1413 * A list of modules that defines the YUI core (overrides the default list).
1417 * @default [ get,features,intl-base,yui-log,yui-later,loader-base, loader-rollup, loader-yui3 ]
1421 * A list of languages in order of preference. This list is matched against
1422 * the list of available languages in modules that the YUI instance uses to
1423 * determine the best possible localization of language sensitive modules.
1424 * Languages are represented using BCP 47 language tags, such as "en-GB" for
1425 * English as used in the United Kingdom, or "zh-Hans-CN" for simplified
1426 * Chinese as used in China. The list can be provided as a comma-separated
1427 * list or as an array.
1430 * @type string|string[]
1434 * The default date format
1435 * @property dateFormat
1437 * @deprecated use configuration in `DataType.Date.format()` instead.
1441 * The default locale
1444 * @deprecated use `config.lang` instead.
1448 * The default interval when polling in milliseconds.
1449 * @property pollInterval
1455 * The number of dynamic nodes to insert by default before
1456 * automatically removing them. This applies to script nodes
1457 * because removing the node will not make the evaluated script
1458 * unavailable. Dynamic CSS is not auto purged, because removing
1459 * a linked style sheet will also remove the style definitions.
1460 * @property purgethreshold
1466 * The default interval when polling in milliseconds.
1467 * @property windowResizeDelay
1473 * Base directory for dynamic loading
1479 * The secure base dir (not implemented)
1480 * For dynamic loading.
1481 * @property secureBase
1486 * The YUI combo service base dir. Ex: `http://yui.yahooapis.com/combo?`
1487 * For dynamic loading.
1488 * @property comboBase
1493 * The root path to prepend to module path for the combo service.
1494 * Ex: 3.0.0b1/build/
1495 * For dynamic loading.
1501 * A filter to apply to result urls. This filter will modify the default
1502 * path for all modules. The default path for the YUI library is the
1503 * minified version of the files (e.g., event-min.js). The filter property
1504 * can be a predefined filter or a custom filter. The valid predefined
1508 * <dd>Selects the debug versions of the library (e.g., event-debug.js).
1509 * This option will automatically include the Logger widget</dd>
1511 * <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
1513 * You can also define a custom filter, which must be an object literal
1514 * containing a search expression and a replace string:
1517 * 'searchExp': "-min\\.js",
1518 * 'replaceStr': "-debug.js"
1521 * For dynamic loading.
1524 * @type string|object
1528 * The `skin` config let's you configure application level skin
1529 * customizations. It contains the following attributes which
1530 * can be specified to override the defaults:
1532 * // The default skin, which is automatically applied if not
1533 * // overriden by a component-specific skin definition.
1534 * // Change this in to apply a different skin globally
1535 * defaultSkin: 'sam',
1537 * // This is combined with the loader base property to get
1538 * // the default root directory for a skin.
1539 * base: 'assets/skins/',
1541 * // Any component-specific overrides can be specified here,
1542 * // making it possible to load different skins for different
1543 * // components. It is possible to load more than one skin
1544 * // for a given component as well.
1546 * slider: ['capsule', 'round']
1549 * For dynamic loading.
1555 * Hash of per-component filter specification. If specified for a given
1556 * component, this overrides the filter config.
1558 * For dynamic loading.
1564 * Use the YUI combo service to reduce the number of http connections
1565 * required to load your dependencies. Turning this off will
1566 * disable combo handling for YUI and all module groups configured
1567 * with a combo service.
1569 * For dynamic loading.
1573 * @default true if 'base' is not supplied, false if it is.
1577 * A list of modules that should never be dynamically loaded
1584 * A list of modules that should always be loaded when required, even if already
1585 * present on the page.
1592 * Node or id for a node that should be used as the insertion point for new
1593 * nodes. For dynamic loading.
1595 * @property insertBefore
1600 * Object literal containing attributes to add to dynamically loaded script
1602 * @property jsAttributes
1607 * Object literal containing attributes to add to dynamically loaded link
1609 * @property cssAttributes
1614 * Number of milliseconds before a timeout occurs when dynamically
1615 * loading nodes. If not set, there is no timeout.
1621 * Callback for the 'CSSComplete' event. When dynamically loading YUI
1622 * components with CSS, this property fires when the CSS is finished
1623 * loading but script loading is still ongoing. This provides an
1624 * opportunity to enhance the presentation of a loading page a little
1625 * bit before the entire loading process is done.
1632 * A hash of module definitions to add to the list of YUI components.
1633 * These components can then be dynamically loaded side by side with
1634 * YUI via the `use()` method. This is a hash, the key is the module
1635 * name, and the value is an object literal specifying the metdata
1636 * for the module. See `Loader.addModule` for the supported module
1637 * metadata fields. Also see groups, which provides a way to
1638 * configure the base and combo spec for a set of modules.
1642 * requires: ['node'],
1643 * fullpath: '/mymod1/mymod1.js'
1646 * requires: ['mymod1'],
1647 * fullpath: '/mymod2/mymod2.js'
1649 * mymod3: '/js/mymod3.js',
1650 * mycssmod: '/css/mycssmod.css'
1659 * Aliases are dynamic groups of modules that can be used as
1664 * davglass: [ 'node', 'yql', 'dd' ],
1665 * mine: [ 'davglass', 'autocomplete']
1667 * }).use('mine', function(Y) {
1668 * //Node, YQL, DD & AutoComplete available here..
1676 * A hash of module group definitions. It for each group you
1677 * can specify a list of modules and the base path and
1678 * combo spec to use when dynamically loading the modules.
1682 * // specify whether or not this group has a combo service
1685 * // The comboSeperator to use with this group's combo handler
1688 * // The maxURLLength for this server
1689 * maxURLLength: 500,
1691 * // the base path for non-combo paths
1692 * base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1694 * // the path to the combo service
1695 * comboBase: 'http://yui.yahooapis.com/combo?',
1697 * // a fragment to prepend to the path attribute when
1698 * // when building combo urls
1699 * root: '2.8.0r4/build/',
1701 * // the module definitions
1704 * path: "yahoo-dom-event/yahoo-dom-event.js"
1707 * path: "animation/animation.js",
1708 * requires: ['yui2_yde']
1719 * The loader 'path' attribute to the loader itself. This is combined
1720 * with the 'base' attribute to dynamically load the loader component
1721 * when boostrapping with the get utility alone.
1723 * @property loaderPath
1725 * @default loader/loader-min.js
1729 * Specifies whether or not YUI().use(...) will attempt to load CSS
1730 * resources at all. Any truthy value will cause CSS dependencies
1731 * to load when fetching script. The special value 'force' will
1732 * cause CSS dependencies to be loaded even if no script is needed.
1734 * @property fetchCSS
1735 * @type boolean|string
1740 * The default gallery version to build gallery module urls
1747 * The default YUI 2 version to build yui2 module urls. This is for
1748 * intrinsic YUI 2 support via the 2in3 project. Also see the '2in3'
1749 * config for pulling different revisions of the wrapped YUI 2
1758 * The 2in3 project is a deployment of the various versions of YUI 2
1759 * deployed as first-class YUI 3 modules. Eventually, the wrapper
1760 * for the modules will change (but the underlying YUI 2 code will
1761 * be the same), and you can select a particular version of
1762 * the wrapper modules via this config.
1770 * Alternative console log function for use in environments without
1771 * a supported native console. The function is executed in the
1772 * YUI instance context.
1779 * A callback to execute when Y.error is called. It receives the
1780 * error message and an javascript error object if Y.error was
1781 * executed because a javascript error was caught. The function
1782 * is executed in the YUI instance context. Returning `true` from this
1783 * function will stop the Error from being thrown.
1791 * A callback to execute when the loader fails to load one or
1792 * more resource. This could be because of a script load
1793 * failure. It can also fail if a javascript module fails
1794 * to register itself, but only when the 'requireRegistration'
1795 * is true. If this function is defined, the use() callback will
1796 * only be called when the loader succeeds, otherwise it always
1797 * executes unless there was a javascript error when attaching
1801 * @property loadErrorFn
1806 * When set to true, the YUI loader will expect that all modules
1807 * it is responsible for loading will be first-class YUI modules
1808 * that register themselves with the YUI global. If this is
1809 * set to true, loader will fail if the module registration fails
1810 * to happen after the script is loaded.
1813 * @property requireRegistration
1819 * Cache serviced use() requests.
1821 * @property cacheUse
1824 * @deprecated no longer used
1828 * Whether or not YUI should use native ES5 functionality when available for
1829 * features like `Y.Array.each()`, `Y.Object()`, etc. When `false`, YUI will
1830 * always use its own fallback implementations instead of relying on ES5
1831 * functionality, even when it's available.
1833 * @method useNativeES5
1838 YUI.add('yui-base', function(Y) {
1843 * @submodule yui-base
1846 * The YUI module contains the components required for building the YUI
1847 * seed file. This includes the script loading mechanism, a simple queue,
1848 * and the core utilities for the library.
1850 * @submodule yui-base
1854 * Provides core language utilites and extensions used throughout YUI.
1860 var L = Y.Lang || (Y.Lang = {}),
1862 STRING_PROTO = String.prototype,
1863 TOSTRING = Object.prototype.toString,
1866 'undefined' : 'undefined',
1867 'number' : 'number',
1868 'boolean' : 'boolean',
1869 'string' : 'string',
1870 '[object Function]': 'function',
1871 '[object RegExp]' : 'regexp',
1872 '[object Array]' : 'array',
1873 '[object Date]' : 'date',
1874 '[object Error]' : 'error'
1877 SUBREGEX = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
1878 TRIMREGEX = /^\s+|\s+$/g,
1879 NATIVE_FN_REGEX = /\{\s*\[(?:native code|function)\]\s*\}/i;
1881 // -- Protected Methods --------------------------------------------------------
1884 Returns `true` if the given function appears to be implemented in native code,
1885 `false` otherwise. Will always return `false` -- even in ES5-capable browsers --
1886 if the `useNativeES5` YUI config option is set to `false`.
1888 This isn't guaranteed to be 100% accurate and won't work for anything other than
1889 functions, but it can be useful for determining whether a function like
1890 `Array.prototype.forEach` is native or a JS shim provided by another library.
1892 There's a great article by @kangax discussing certain flaws with this technique:
1893 <http://perfectionkills.com/detecting-built-in-host-methods/>
1895 While his points are valid, it's still possible to benefit from this function
1896 as long as it's used carefully and sparingly, and in such a way that false
1897 negatives have minimal consequences. It's used internally to avoid using
1898 potentially broken non-native ES5 shims that have been added to the page by
1902 @param {Function} fn Function to test.
1903 @return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
1908 L._isNative = function (fn) {
1909 return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
1912 // -- Public Methods -----------------------------------------------------------
1915 * Determines whether or not the provided item is an array.
1917 * Returns `false` for array-like collections such as the function `arguments`
1918 * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
1919 * test for an array-like collection.
1922 * @param o The object to test.
1923 * @return {boolean} true if o is an array.
1926 L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
1927 return L.type(o) === 'array';
1931 * Determines whether or not the provided item is a boolean.
1934 * @param o The object to test.
1935 * @return {boolean} true if o is a boolean.
1937 L.isBoolean = function(o) {
1938 return typeof o === 'boolean';
1942 * Determines whether or not the supplied item is a date instance.
1945 * @param o The object to test.
1946 * @return {boolean} true if o is a date.
1948 L.isDate = function(o) {
1949 return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
1954 * Determines whether or not the provided item is a function.
1955 * Note: Internet Explorer thinks certain functions are objects:
1959 * var obj = document.createElement("object");
1960 * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1962 * var input = document.createElement("input"); // append to body
1963 * Y.Lang.isFunction(input.focus) // reports false in IE
1967 * You will have to implement additional tests if these functions
1971 * @method isFunction
1973 * @param o The object to test.
1974 * @return {boolean} true if o is a function.
1976 L.isFunction = function(o) {
1977 return L.type(o) === 'function';
1981 * Determines whether or not the provided item is null.
1984 * @param o The object to test.
1985 * @return {boolean} true if o is null.
1987 L.isNull = function(o) {
1992 * Determines whether or not the provided item is a legal number.
1995 * @param o The object to test.
1996 * @return {boolean} true if o is a number.
1998 L.isNumber = function(o) {
1999 return typeof o === 'number' && isFinite(o);
2003 * Determines whether or not the provided item is of type object
2004 * or function. Note that arrays are also objects, so
2005 * <code>Y.Lang.isObject([]) === true</code>.
2008 * @param o The object to test.
2009 * @param failfn {boolean} fail if the input is a function.
2010 * @return {boolean} true if o is an object.
2011 * @see isPlainObject
2013 L.isObject = function(o, failfn) {
2015 return (o && (t === 'object' ||
2016 (!failfn && (t === 'function' || L.isFunction(o))))) || false;
2020 * Determines whether or not the provided item is a string.
2023 * @param o The object to test.
2024 * @return {boolean} true if o is a string.
2026 L.isString = function(o) {
2027 return typeof o === 'string';
2031 * Determines whether or not the provided item is undefined.
2032 * @method isUndefined
2034 * @param o The object to test.
2035 * @return {boolean} true if o is undefined.
2037 L.isUndefined = function(o) {
2038 return typeof o === 'undefined';
2042 * A convenience method for detecting a legitimate non-null value.
2043 * Returns false for null/undefined/NaN, true for other values,
2044 * including 0/false/''
2047 * @param o The item to test.
2048 * @return {boolean} true if it is not null/undefined/NaN || false.
2050 L.isValue = function(o) {
2057 case 'null': // fallthru
2067 * Returns the current time in milliseconds.
2070 * @return {Number} Current time in milliseconds.
2074 L.now = Date.now || function () {
2075 return new Date().getTime();
2079 * Lightweight version of <code>Y.substitute</code>. Uses the same template
2080 * structure as <code>Y.substitute</code>, but doesn't support recursion,
2081 * auto-object coersion, or formats.
2083 * @param {string} s String to be modified.
2084 * @param {object} o Object containing replacement values.
2085 * @return {string} the substitute result.
2089 L.sub = function(s, o) {
2090 return s.replace ? s.replace(SUBREGEX, function (match, key) {
2091 return L.isUndefined(o[key]) ? match : o[key];
2096 * Returns a string without any leading or trailing whitespace. If
2097 * the input is not a string, the input will be returned untouched.
2100 * @param s {string} the string to trim.
2101 * @return {string} the trimmed string.
2103 L.trim = STRING_PROTO.trim ? function(s) {
2104 return s && s.trim ? s.trim() : s;
2107 return s.replace(TRIMREGEX, '');
2114 * Returns a string without any leading whitespace.
2117 * @param s {string} the string to trim.
2118 * @return {string} the trimmed string.
2120 L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
2121 return s.trimLeft();
2123 return s.replace(/^\s+/, '');
2127 * Returns a string without any trailing whitespace.
2130 * @param s {string} the string to trim.
2131 * @return {string} the trimmed string.
2133 L.trimRight = STRING_PROTO.trimRight ? function (s) {
2134 return s.trimRight();
2136 return s.replace(/\s+$/, '');
2140 Returns one of the following strings, representing the type of the item passed
2157 * `typeof HTMLElementCollection` returns function in Safari, but
2158 `Y.Lang.type()` reports "object", which could be a good thing --
2159 but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
2162 @param o the item to test.
2163 @return {string} the detected type.
2166 L.type = function(o) {
2167 return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
2175 Native = Array.prototype,
2177 hasOwn = Object.prototype.hasOwnProperty;
2180 Provides utility methods for working with arrays. Additional array helpers can
2181 be found in the `collection` and `array-extras` modules.
2183 `Y.Array(thing)` returns a native array created from _thing_. Depending on
2184 _thing_'s type, one of the following will happen:
2186 * Arrays are returned unmodified unless a non-zero _startIndex_ is
2188 * Array-like collections (see `Array.test()`) are converted to arrays.
2189 * For everything else, a new array is created with _thing_ as the sole
2192 Note: elements that are also collections, such as `<form>` and `<select>`
2193 elements, are not automatically converted to arrays. To force a conversion,
2194 pass `true` as the value of the _force_ parameter.
2198 @param {Any} thing The thing to arrayify.
2199 @param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2200 collection, a subset of items starting at the specified index will be
2202 @param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2203 array-like collection no matter what.
2204 @return {Array} A native array created from _thing_, according to the rules
2207 function YArray(thing, startIndex, force) {
2210 startIndex || (startIndex = 0);
2212 if (force || YArray.test(thing)) {
2213 // IE throws when trying to slice HTMLElement collections.
2215 return Native.slice.call(thing, startIndex);
2219 for (len = thing.length; startIndex < len; ++startIndex) {
2220 result.push(thing[startIndex]);
2233 Dedupes an array of strings, returning an array that's guaranteed to contain
2234 only one copy of a given string.
2236 This method differs from `Array.unique()` in that it's optimized for use only
2237 with strings, whereas `unique` may be used with other types (but is slower).
2238 Using `dedupe()` with non-string values may result in unexpected behavior.
2241 @param {String[]} array Array of strings to dedupe.
2242 @return {Array} Deduped copy of _array_.
2246 YArray.dedupe = function (array) {
2251 for (i = 0, len = array.length; i < len; ++i) {
2254 if (!hasOwn.call(hash, item)) {
2264 Executes the supplied function on each item in the array. This method wraps
2265 the native ES5 `Array.forEach()` method if available.
2268 @param {Array} array Array to iterate.
2269 @param {Function} fn Function to execute on each item in the array. The function
2270 will receive the following arguments:
2271 @param {Any} fn.item Current array item.
2272 @param {Number} fn.index Current array index.
2273 @param {Array} fn.array Array being iterated.
2274 @param {Object} [thisObj] `this` object to use when calling _fn_.
2275 @return {YUI} The YUI instance.
2278 YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
2279 Native.forEach.call(array || [], fn, thisObj || Y);
2281 } : function (array, fn, thisObj) {
2282 for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2284 fn.call(thisObj || Y, array[i], i, array);
2299 Returns an object using the first array as keys and the second as values. If
2300 the second array is not provided, or if it doesn't contain the same number of
2301 values as the first array, then `true` will be used in place of the missing
2306 Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2307 // => {a: 'foo', b: 'bar', c: true}
2310 @param {String[]} keys Array of strings to use as keys.
2311 @param {Array} [values] Array to use as values.
2312 @return {Object} Hash using the first array as keys and the second as values.
2315 YArray.hash = function (keys, values) {
2317 vlen = (values && values.length) || 0,
2320 for (i = 0, len = keys.length; i < len; ++i) {
2322 hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2330 Returns the index of the first item in the array that's equal (using a strict
2331 equality check) to the specified _value_, or `-1` if the value isn't found.
2333 This method wraps the native ES5 `Array.indexOf()` method if available.
2336 @param {Array} array Array to search.
2337 @param {Any} value Value to search for.
2338 @param {Number} [from=0] The index at which to begin the search.
2339 @return {Number} Index of the item strictly equal to _value_, or `-1` if not
2343 YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
2344 return Native.indexOf.call(array, value, from);
2345 } : function (array, value, from) {
2346 // http://es5.github.com/#x15.4.4.14
2347 var len = array.length;
2350 from = (from > 0 || -1) * Math.floor(Math.abs(from));
2360 for (; from < len; ++from) {
2361 if (from in array && array[from] === value) {
2370 Numeric sort convenience function.
2372 The native `Array.prototype.sort()` function converts values to strings and
2373 sorts them in lexicographic order, which is unsuitable for sorting numeric
2374 values. Provide `Array.numericSort` as a custom sort function when you want
2375 to sort values in numeric order.
2379 [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2380 // => [4, 8, 15, 16, 23, 42]
2383 @param {Number} a First value to compare.
2384 @param {Number} b Second value to compare.
2385 @return {Number} Difference between _a_ and _b_.
2388 YArray.numericSort = function (a, b) {
2393 Executes the supplied function on each item in the array. Returning a truthy
2394 value from the function will stop the processing of remaining items.
2397 @param {Array} array Array to iterate over.
2398 @param {Function} fn Function to execute on each item. The function will receive
2399 the following arguments:
2400 @param {Any} fn.value Current array item.
2401 @param {Number} fn.index Current array index.
2402 @param {Array} fn.array Array being iterated over.
2403 @param {Object} [thisObj] `this` object to use when calling _fn_.
2404 @return {Boolean} `true` if the function returns a truthy value on any of the
2405 items in the array; `false` otherwise.
2408 YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
2409 return Native.some.call(array, fn, thisObj);
2410 } : function (array, fn, thisObj) {
2411 for (var i = 0, len = array.length; i < len; ++i) {
2412 if (i in array && fn.call(thisObj, array[i], i, array)) {
2421 Evaluates _obj_ to determine if it's an array, an array-like collection, or
2422 something else. This is useful when working with the function `arguments`
2423 collection and `HTMLElement` collections.
2425 Note: This implementation doesn't consider elements that are also
2426 collections, such as `<form>` and `<select>`, to be array-like.
2429 @param {Object} obj Object to test.
2430 @return {Number} A number indicating the results of the test:
2432 * 0: Neither an array nor an array-like collection.
2434 * 2: Array-like collection.
2438 YArray.test = function (obj) {
2441 if (Lang.isArray(obj)) {
2443 } else if (Lang.isObject(obj)) {
2445 // indexed, but no tagName (element) or alert (window),
2446 // or functions without apply/call (Safari
2447 // HTMLElementCollection bug).
2448 if ('length' in obj && !obj.tagName && !obj.alert && !obj.apply) {
2457 * The YUI module contains the components required for building the YUI
2458 * seed file. This includes the script loading mechanism, a simple queue,
2459 * and the core utilities for the library.
2461 * @submodule yui-base
2465 * A simple FIFO queue. Items are added to the Queue with add(1..n items) and
2466 * removed using next().
2470 * @param {MIXED} item* 0..n items to seed the queue.
2474 this.add.apply(this, arguments);
2479 * Initialize the queue
2486 * The collection of enqueued items
2496 * Get the next item in the queue. FIFO support
2499 * @return {MIXED} the next item in the queue.
2502 return this._q.shift();
2506 * Get the last in the queue. LIFO support.
2509 * @return {MIXED} the last item in the queue.
2512 return this._q.pop();
2516 * Add 0..n items to the end of the queue.
2519 * @param {MIXED} item* 0..n items.
2520 * @return {object} this queue.
2523 this._q.push.apply(this._q, arguments);
2529 * Returns the current number of queued items.
2532 * @return {Number} The size.
2535 return this._q.length;
2541 YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2544 The YUI module contains the components required for building the YUI seed file.
2545 This includes the script loading mechanism, a simple queue, and the core
2546 utilities for the library.
2552 var CACHED_DELIMITER = '__',
2554 hasOwn = Object.prototype.hasOwnProperty,
2555 isObject = Y.Lang.isObject;
2558 Returns a wrapper for a function which caches the return value of that function,
2559 keyed off of the combined string representation of the argument values provided
2560 when the wrapper is called.
2562 Calling this function again with the same arguments will return the cached value
2563 rather than executing the wrapped function.
2565 Note that since the cache is keyed off of the string representation of arguments
2566 passed to the wrapper function, arguments that aren't strings and don't provide
2567 a meaningful `toString()` method may result in unexpected caching behavior. For
2568 example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2569 string `[object Object]` when used as a cache key.
2572 @param {Function} source The function to memoize.
2573 @param {Object} [cache={}] Object in which to store cached values. You may seed
2574 this object with pre-existing cached values if desired.
2575 @param {any} [refetch] If supplied, this value is compared with the cached value
2576 using a `==` comparison. If the values are equal, the wrapped function is
2577 executed again even though a cached value exists.
2578 @return {Function} Wrapped function.
2581 Y.cached = function (source, cache, refetch) {
2582 cache || (cache = {});
2584 return function (arg) {
2585 var key = arguments.length > 1 ?
2586 Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2589 if (!(key in cache) || (refetch && cache[key] == refetch)) {
2590 cache[key] = source.apply(source, arguments);
2598 Returns the `location` object from the window/frame in which this YUI instance
2599 operates, or `undefined` when executing in a non-browser environment
2602 It is _not_ recommended to hold references to the `window.location` object
2603 outside of the scope of a function in which its properties are being accessed or
2604 its methods are being called. This is because of a nasty bug/issue that exists
2605 in both Safari and MobileSafari browsers:
2606 [WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
2609 @return {location} The `location` object from the window/frame in which this YUI
2613 Y.getLocation = function () {
2614 // It is safer to look this up every time because yui-base is attached to a
2615 // YUI instance before a user's config is applied; i.e. `Y.config.win` does
2616 // not point the correct window object when this file is loaded.
2617 var win = Y.config.win;
2619 // It is not safe to hold a reference to the `location` object outside the
2620 // scope in which it is being used. The WebKit engine used in Safari and
2621 // MobileSafari will "disconnect" the `location` object from the `window`
2622 // when a page is restored from back/forward history cache.
2623 return win && win.location;
2627 Returns a new object containing all of the properties of all the supplied
2628 objects. The properties from later objects will overwrite those in earlier
2631 Passing in a single object will create a shallow copy of it. For a deep copy,
2635 @param {Object} objects* One or more objects to merge.
2636 @return {Object} A new merged object.
2638 Y.merge = function () {
2639 var args = arguments,
2644 for (; i < len; ++i) {
2645 Y.mix(result, args[i], true);
2652 Mixes _supplier_'s properties into _receiver_.
2654 Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
2655 shadowed unless the _overwrite_ parameter is `true`, and will not be merged
2656 unless the _merge_ parameter is `true`.
2658 In the default mode (0), only properties the supplier owns are copied (prototype
2659 properties are not copied). The following copying modes are available:
2661 * `0`: _Default_. Object to object.
2662 * `1`: Prototype to prototype.
2663 * `2`: Prototype to prototype and object to object.
2664 * `3`: Prototype to object.
2665 * `4`: Object to prototype.
2668 @param {Function|Object} receiver The object or function to receive the mixed
2670 @param {Function|Object} supplier The object or function supplying the
2671 properties to be mixed.
2672 @param {Boolean} [overwrite=false] If `true`, properties that already exist
2673 on the receiver will be overwritten with properties from the supplier.
2674 @param {String[]} [whitelist] An array of property names to copy. If
2675 specified, only the whitelisted properties will be copied, and all others
2677 @param {Number} [mode=0] Mix mode to use. See above for available modes.
2678 @param {Boolean} [merge=false] If `true`, objects and arrays that already
2679 exist on the receiver will have the corresponding object/array from the
2680 supplier merged into them, rather than being skipped or overwritten. When
2681 both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2682 @return {Function|Object|YUI} The receiver, or the YUI instance if the
2683 specified receiver is falsy.
2685 Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2686 var alwaysOverwrite, exists, from, i, key, len, to;
2688 // If no supplier is given, we return the receiver. If no receiver is given,
2689 // we return Y. Returning Y doesn't make much sense to me, but it's
2690 // grandfathered in for backcompat reasons.
2691 if (!receiver || !supplier) {
2692 return receiver || Y;
2696 // In mode 2 (prototype to prototype and object to object), we recurse
2697 // once to do the proto to proto mix. The object to object mix will be
2698 // handled later on.
2700 Y.mix(receiver.prototype, supplier.prototype, overwrite,
2701 whitelist, 0, merge);
2704 // Depending on which mode is specified, we may be copying from or to
2705 // the prototypes of the supplier and receiver.
2706 from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2707 to = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2709 // If either the supplier or receiver doesn't actually have a
2710 // prototype property, then we could end up with an undefined `from`
2711 // or `to`. If that happens, we abort and return the receiver.
2720 // If `overwrite` is truthy and `merge` is falsy, then we can skip a
2721 // property existence check on each iteration and save some time.
2722 alwaysOverwrite = overwrite && !merge;
2725 for (i = 0, len = whitelist.length; i < len; ++i) {
2728 // We call `Object.prototype.hasOwnProperty` instead of calling
2729 // `hasOwnProperty` on the object itself, since the object's
2730 // `hasOwnProperty` method may have been overridden or removed.
2731 // Also, some native objects don't implement a `hasOwnProperty`
2733 if (!hasOwn.call(from, key)) {
2737 // The `key in to` check here is (sadly) intentional for backwards
2738 // compatibility reasons. It prevents undesired shadowing of
2739 // prototype members on `to`.
2740 exists = alwaysOverwrite ? false : key in to;
2742 if (merge && exists && isObject(to[key], true)
2743 && isObject(from[key], true)) {
2744 // If we're in merge mode, and the key is present on both
2745 // objects, and the value on both objects is either an object or
2746 // an array (but not a function), then we recurse to merge the
2747 // `from` value into the `to` value instead of overwriting it.
2749 // Note: It's intentional that the whitelist isn't passed to the
2750 // recursive call here. This is legacy behavior that lots of
2751 // code still depends on.
2752 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2753 } else if (overwrite || !exists) {
2754 // We're not in merge mode, so we'll only copy the `from` value
2755 // to the `to` value if we're in overwrite mode or if the
2756 // current key doesn't exist on the `to` object.
2757 to[key] = from[key];
2762 // The code duplication here is for runtime performance reasons.
2763 // Combining whitelist and non-whitelist operations into a single
2764 // loop or breaking the shared logic out into a function both result
2765 // in worse performance, and Y.mix is critical enough that the byte
2766 // tradeoff is worth it.
2767 if (!hasOwn.call(from, key)) {
2771 // The `key in to` check here is (sadly) intentional for backwards
2772 // compatibility reasons. It prevents undesired shadowing of
2773 // prototype members on `to`.
2774 exists = alwaysOverwrite ? false : key in to;
2776 if (merge && exists && isObject(to[key], true)
2777 && isObject(from[key], true)) {
2778 Y.mix(to[key], from[key], overwrite, null, 0, merge);
2779 } else if (overwrite || !exists) {
2780 to[key] = from[key];
2784 // If this is an IE browser with the JScript enumeration bug, force
2785 // enumeration of the buggy properties by making a recursive call with
2786 // the buggy properties as the whitelist.
2787 if (Y.Object._hasEnumBug) {
2788 Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
2795 * The YUI module contains the components required for building the YUI
2796 * seed file. This includes the script loading mechanism, a simple queue,
2797 * and the core utilities for the library.
2799 * @submodule yui-base
2803 * Adds utilities to the YUI instance for working with objects.
2809 hasOwn = Object.prototype.hasOwnProperty,
2811 UNDEFINED, // <-- Note the comma. We're still declaring vars.
2814 * Returns a new object that uses _obj_ as its prototype. This method wraps the
2815 * native ES5 `Object.create()` method if available, but doesn't currently
2816 * pass through `Object.create()`'s second argument (properties) in order to
2817 * ensure compatibility with older browsers.
2820 * @param {Object} obj Prototype object.
2821 * @return {Object} New object using _obj_ as its prototype.
2824 O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
2825 // We currently wrap the native Object.create instead of simply aliasing it
2826 // to ensure consistency with our fallback shim, which currently doesn't
2827 // support Object.create()'s second argument (properties). Once we have a
2828 // safe fallback for the properties arg, we can stop wrapping
2830 return Object.create(obj);
2832 // Reusable constructor function for the Object.create() shim.
2836 return function (obj) {
2843 * Property names that IE doesn't enumerate in for..in loops, even when they
2844 * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
2845 * manually enumerate these properties.
2847 * @property _forceEnum
2852 forceEnum = O._forceEnum = [
2855 'propertyIsEnumerable',
2862 * `true` if this browser has the JScript enumeration bug that prevents
2863 * enumeration of the properties named in the `_forceEnum` array, `false`
2867 * - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
2868 * - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
2870 * @property _hasEnumBug
2875 hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
2878 * `true` if this browser incorrectly considers the `prototype` property of
2879 * functions to be enumerable. Currently known to affect Opera 11.50.
2881 * @property _hasProtoEnumBug
2886 hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
2889 * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
2890 * exists only on _obj_'s prototype. This is essentially a safer version of
2891 * `obj.hasOwnProperty()`.
2894 * @param {Object} obj Object to test.
2895 * @param {String} key Property name to look for.
2896 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2899 owns = O.owns = function (obj, key) {
2900 return !!obj && hasOwn.call(obj, key);
2901 }; // <-- End of var declarations.
2904 * Alias for `owns()`.
2907 * @param {Object} obj Object to test.
2908 * @param {String} key Property name to look for.
2909 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2915 * Returns an array containing the object's enumerable keys. Does not include
2916 * prototype keys or non-enumerable keys.
2918 * Note that keys are returned in enumeration order (that is, in the same order
2919 * that they would be enumerated by a `for-in` loop), which may not be the same
2920 * as the order in which they were defined.
2922 * This method is an alias for the native ES5 `Object.keys()` method if
2927 * Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
2928 * // => ['a', 'b', 'c']
2931 * @param {Object} obj An object.
2932 * @return {String[]} Array of keys.
2935 O.keys = Lang._isNative(Object.keys) ? Object.keys : function (obj) {
2936 if (!Lang.isObject(obj)) {
2937 throw new TypeError('Object.keys called on a non-object');
2943 if (hasProtoEnumBug && typeof obj === 'function') {
2945 if (owns(obj, key) && key !== 'prototype') {
2951 if (owns(obj, key)) {
2958 for (i = 0, len = forceEnum.length; i < len; ++i) {
2961 if (owns(obj, key)) {
2971 * Returns an array containing the values of the object's enumerable keys.
2973 * Note that values are returned in enumeration order (that is, in the same
2974 * order that they would be enumerated by a `for-in` loop), which may not be the
2975 * same as the order in which they were defined.
2979 * Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
2980 * // => ['foo', 'bar', 'baz']
2983 * @param {Object} obj An object.
2984 * @return {Array} Array of values.
2987 O.values = function (obj) {
2988 var keys = O.keys(obj),
2993 for (; i < len; ++i) {
2994 values.push(obj[keys[i]]);
3001 * Returns the number of enumerable keys owned by an object.
3004 * @param {Object} obj An object.
3005 * @return {Number} The object's size.
3008 O.size = function (obj) {
3010 return O.keys(obj).length;
3012 return 0; // Legacy behavior for non-objects.
3017 * Returns `true` if the object owns an enumerable property with the specified
3021 * @param {Object} obj An object.
3022 * @param {any} value The value to search for.
3023 * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
3026 O.hasValue = function (obj, value) {
3027 return Y.Array.indexOf(O.values(obj), value) > -1;
3031 * Executes a function on each enumerable property in _obj_. The function
3032 * receives the value, the key, and the object itself as parameters (in that
3035 * By default, only properties owned by _obj_ are enumerated. To include
3036 * prototype properties, set the _proto_ parameter to `true`.
3039 * @param {Object} obj Object to enumerate.
3040 * @param {Function} fn Function to execute on each enumerable property.
3041 * @param {mixed} fn.value Value of the current property.
3042 * @param {String} fn.key Key of the current property.
3043 * @param {Object} fn.obj Object being enumerated.
3044 * @param {Object} [thisObj] `this` object to use when calling _fn_.
3045 * @param {Boolean} [proto=false] Include prototype properties.
3046 * @return {YUI} the YUI instance.
3050 O.each = function (obj, fn, thisObj, proto) {
3054 if (proto || owns(obj, key)) {
3055 fn.call(thisObj || Y, obj[key], key, obj);
3063 * Executes a function on each enumerable property in _obj_, but halts if the
3064 * function returns a truthy value. The function receives the value, the key,
3065 * and the object itself as paramters (in that order).
3067 * By default, only properties owned by _obj_ are enumerated. To include
3068 * prototype properties, set the _proto_ parameter to `true`.
3071 * @param {Object} obj Object to enumerate.
3072 * @param {Function} fn Function to execute on each enumerable property.
3073 * @param {mixed} fn.value Value of the current property.
3074 * @param {String} fn.key Key of the current property.
3075 * @param {Object} fn.obj Object being enumerated.
3076 * @param {Object} [thisObj] `this` object to use when calling _fn_.
3077 * @param {Boolean} [proto=false] Include prototype properties.
3078 * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
3079 * `false` otherwise.
3082 O.some = function (obj, fn, thisObj, proto) {
3086 if (proto || owns(obj, key)) {
3087 if (fn.call(thisObj || Y, obj[key], key, obj)) {
3097 * Retrieves the sub value at the provided path,
3098 * from the value object provided.
3102 * @param o The object from which to extract the property value.
3103 * @param path {Array} A path array, specifying the object traversal path
3104 * from which to obtain the sub value.
3105 * @return {Any} The value stored in the path, undefined if not found,
3106 * undefined if the source is not an object. Returns the source object
3107 * if an empty path is provided.
3109 O.getValue = function(o, path) {
3110 if (!Lang.isObject(o)) {
3118 for (i = 0; o !== UNDEFINED && i < l; i++) {
3126 * Sets the sub-attribute value at the provided path on the
3127 * value object. Returns the modified value object, or
3128 * undefined if the path is invalid.
3132 * @param o The object on which to set the sub value.
3133 * @param path {Array} A path array, specifying the object traversal path
3134 * at which to set the sub value.
3135 * @param val {Any} The new value for the sub-attribute.
3136 * @return {Object} The modified object, with the new sub value set, or
3137 * undefined, if the path was invalid.
3139 O.setValue = function(o, path, val) {
3142 leafIdx = p.length - 1,
3146 for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
3150 if (ref !== UNDEFINED) {
3161 * Returns `true` if the object has no enumerable properties of its own.
3164 * @param {Object} obj An object.
3165 * @return {Boolean} `true` if the object is empty.
3169 O.isEmpty = function (obj) {
3170 return !O.keys(Object(obj)).length;
3173 * The YUI module contains the components required for building the YUI seed
3174 * file. This includes the script loading mechanism, a simple queue, and the
3175 * core utilities for the library.
3177 * @submodule yui-base
3181 * YUI user agent detection.
3182 * Do not fork for a browser if it can be avoided. Use feature detection when
3183 * you can. Use the user agent as a last resort. For all fields listed
3184 * as @type float, UA stores a version number for the browser engine,
3185 * 0 otherwise. This value may or may not map to the version number of
3186 * the browser using the engine. The value is presented as a float so
3187 * that it can easily be used for boolean evaluation as well as for
3188 * looking for a particular range of versions. Because of this,
3189 * some of the granularity of the version info may be lost. The fields that
3190 * are @type string default to null. The API docs list the values that
3191 * these fields can have.
3197 * Static method on `YUI.Env` for parsing a UA string. Called at instantiation
3198 * to populate `Y.UA`.
3202 * @param {String} [subUA=navigator.userAgent] UA string to parse
3203 * @return {Object} The Y.UA object
3205 YUI.Env.parseUA = function(subUA) {
3207 var numberify = function(s) {
3209 return parseFloat(s.replace(/\./g, function() {
3210 return (c++ == 1) ? '' : '.';
3216 nav = win && win.navigator,
3221 * Internet Explorer version number or 0. Example: 6
3229 * Opera version number or 0. Example: 9.2
3237 * Gecko engine revision number. Will evaluate to 1 if Gecko
3238 * is detected but the revision could not be found. Other browsers
3239 * will be 0. Example: 1.8
3241 * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7
3242 * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3243 * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3244 * Firefox 3.0 <-- 1.9
3245 * Firefox 3.5 <-- 1.91
3254 * AppleWebKit version. KHTML browsers that are not WebKit browsers
3255 * will evaluate to 1, other browsers 0. Example: 418.9
3257 * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3258 * latest available for Mac OSX 10.3.
3259 * Safari 2.0.2: 416 <-- hasOwnProperty introduced
3260 * Safari 2.0.4: 418 <-- preventDefault fixed
3261 * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3262 * different versions of webkit
3263 * Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been
3264 * updated, but not updated
3265 * to the latest patch.
3266 * Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native
3267 * SVG and many major issues fixed).
3268 * Safari 3.0.4 (523.12) 523.12 <-- First Tiger release - automatic
3269 * update from 2.x via the 10.4.11 OS patch.
3270 * Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event.
3271 * yahoo.com user agent hack removed.
3273 * http://en.wikipedia.org/wiki/Safari_version_history
3281 * Safari will be detected as webkit, but this property will also
3282 * be populated with the Safari version number
3290 * Chrome will be detected as webkit, but this property will also
3291 * be populated with the Chrome version number
3299 * The mobile property will be set to a string containing any relevant
3300 * user agent information when a modern mobile browser is detected.
3301 * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3302 * devices with the WebKit-based browser, and Opera Mini.
3311 * Adobe AIR version number or 0. Only populated if webkit is detected.
3318 * Detects Apple iPad's OS version
3325 * Detects Apple iPhone's OS version
3332 * Detects Apples iPod's OS version
3339 * General truthy check for iPad, iPhone or iPod
3347 * Detects Googles Android OS version
3354 * Detects Kindle Silk
3361 * Detects Kindle Silk Acceleration
3368 * Detects Palms WebOS version
3376 * Google Caja version number or 0.
3380 caja: nav && nav.cajaVersion,
3383 * Set to true if the page appears to be in SSL
3391 * The operating system. Currently only detecting windows or macintosh
3400 * The Nodejs Version
3409 ua = subUA || nav && nav.userAgent,
3411 loc = win && win.location,
3413 href = loc && loc.href,
3418 * The User Agent string that was parsed
3419 * @property userAgent
3426 o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3430 if ((/windows|win32/i).test(ua)) {
3432 } else if ((/macintosh|mac_powerpc/i).test(ua)) {
3434 } else if ((/android/i).test(ua)) {
3436 } else if ((/symbos/i).test(ua)) {
3438 } else if ((/linux/i).test(ua)) {
3440 } else if ((/rhino/i).test(ua)) {
3444 // Modern KHTML browsers should qualify as Safari X-Grade
3445 if ((/KHTML/).test(ua)) {
3448 if ((/IEMobile|XBLWP7/).test(ua)) {
3449 o.mobile = 'windows';
3451 if ((/Fennec/).test(ua)) {
3454 // Modern WebKit browsers are at least X-Grade
3455 m = ua.match(/AppleWebKit\/([^\s]*)/);
3457 o.webkit = numberify(m[1]);
3458 o.safari = o.webkit;
3460 // Mobile browser check
3461 if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
3462 o.mobile = 'Apple'; // iPhone or iPod Touch
3464 m = ua.match(/OS ([^\s]*)/);
3466 m = numberify(m[1].replace('_', '.'));
3470 o.ipad = o.ipod = o.iphone = 0;
3472 m = ua.match(/iPad|iPod|iPhone/);
3474 o[m[0].toLowerCase()] = o.ios;
3477 m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3479 // Nokia N-series, webOS, ex: NokiaN95
3482 if (/webOS/.test(ua)) {
3484 m = ua.match(/webOS\/([^\s]*);/);
3486 o.webos = numberify(m[1]);
3489 if (/ Android/.test(ua)) {
3490 if (/Mobile/.test(ua)) {
3491 o.mobile = 'Android';
3493 m = ua.match(/Android ([^\s]*);/);
3495 o.android = numberify(m[1]);
3499 if (/Silk/.test(ua)) {
3500 m = ua.match(/Silk\/([^\s]*)\)/);
3502 o.silk = numberify(m[1]);
3505 o.android = 2.34; //Hack for desktop mode in Kindle
3508 if (/Accelerated=true/.test(ua)) {
3514 m = ua.match(/(Chrome|CrMo)\/([^\s]*)/);
3515 if (m && m[1] && m[2]) {
3516 o.chrome = numberify(m[2]); // Chrome
3517 o.safari = 0; //Reset safari back to 0
3518 if (m[1] === 'CrMo') {
3519 o.mobile = 'chrome';
3522 m = ua.match(/AdobeAIR\/([^\s]*)/);
3524 o.air = m[0]; // Adobe AIR 1.0 or better
3529 if (!o.webkit) { // not webkit
3530 // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3531 if (/Opera/.test(ua)) {
3532 m = ua.match(/Opera[\s\/]([^\s]*)/);
3534 o.opera = numberify(m[1]);
3536 m = ua.match(/Version\/([^\s]*)/);
3538 o.opera = numberify(m[1]); // opera 10+
3541 if (/Opera Mobi/.test(ua)) {
3543 m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
3545 o.opera = numberify(m[1]);
3548 m = ua.match(/Opera Mini[^;]*/);
3551 o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3553 } else { // not opera or webkit
3554 m = ua.match(/MSIE\s([^;]*)/);
3556 o.ie = numberify(m[1]);
3557 } else { // not opera, webkit, or ie
3558 m = ua.match(/Gecko\/([^\s]*)/);
3560 o.gecko = 1; // Gecko detected, look for revision
3561 m = ua.match(/rv:([^\s\)]*)/);
3563 o.gecko = numberify(m[1]);
3571 //It was a parsed UA, do not assign the global value.
3574 if (typeof process == 'object') {
3576 if (process.versions && process.versions.node) {
3578 o.os = process.platform;
3579 o.nodejs = process.versions.node;
3591 Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3594 Performs a simple comparison between two version numbers, accounting for
3595 standard versioning logic such as the fact that "535.8" is a lower version than
3596 "535.24", even though a simple numerical comparison would indicate that it's
3597 greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
3598 considered equivalent.
3600 Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
3601 1 if _a_ is higher than _b_.
3603 Versions may be numbers or strings containing numbers and dots. For example,
3604 both `535` and `"535.8.10"` are acceptable. A version string containing
3605 non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
3607 @method compareVersions
3608 @param {Number|String} a First version number to compare.
3609 @param {Number|String} b Second version number to compare.
3610 @return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
3613 Y.UA.compareVersions = function (a, b) {
3614 var aPart, aParts, bPart, bParts, i, len;
3620 aParts = (a + '').split('.');
3621 bParts = (b + '').split('.');
3623 for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
3624 aPart = parseInt(aParts[i], 10);
3625 bPart = parseInt(bParts[i], 10);
3627 isNaN(aPart) && (aPart = 0);
3628 isNaN(bPart) && (bPart = 0);
3630 if (aPart < bPart) {
3634 if (aPart > bPart) {
3642 "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3643 "app": ["app-base","app-transitions","model","model-list","router","view"],
3644 "attribute": ["attribute-base","attribute-complex"],
3645 "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3646 "base": ["base-base","base-pluginhost","base-build"],
3647 "cache": ["cache-base","cache-offline","cache-plugin"],
3648 "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3649 "controller": ["router"],
3650 "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3651 "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3652 "datatable": ["datatable-core","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
3653 "datatable-deprecated": ["datatable-base-deprecated","datatable-datasource-deprecated","datatable-sort-deprecated","datatable-scroll-deprecated"],
3654 "datatype": ["datatype-number","datatype-date","datatype-xml"],
3655 "datatype-date": ["datatype-date-parse","datatype-date-format"],
3656 "datatype-number": ["datatype-number-parse","datatype-number-format"],
3657 "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3658 "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3659 "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3660 "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3661 "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"],
3662 "event-custom": ["event-custom-base","event-custom-complex"],
3663 "event-gestures": ["event-flick","event-move"],
3664 "handlebars": ["handlebars-compiler"],
3665 "highlight": ["highlight-base","highlight-accentfold"],
3666 "history": ["history-base","history-hash","history-hash-ie","history-html5"],
3667 "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
3668 "json": ["json-parse","json-stringify"],
3669 "loader": ["loader-base","loader-rollup","loader-yui3"],
3670 "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
3671 "pluginhost": ["pluginhost-base","pluginhost-config"],
3672 "querystring": ["querystring-parse","querystring-stringify"],
3673 "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
3674 "resize": ["resize-base","resize-proxy","resize-constrain"],
3675 "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
3676 "text": ["text-accentfold","text-wordbreak"],
3677 "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]