PageSourceSearch

https://ceo.edu.gt/theme/yui_combo.php?rollup/3.18.1/yui-moodlesimple.js

js ceo.edu.gt collected 2026-10-05 23:42:40 UTC 1,277,141 bytes, 40,936 lines download raw bytes

1/**
2The YUI module contains the components required for building the YUI seed file.
3This includes the script loading mechanism, a simple queue, and the core
4utilities for the library.
5
6@module yui
7@main yui
8@submodule yui-base
9**/
10
11/*jshint eqeqeq: false*/
12if (typeof YUI != 'undefined') {
13    YUI._YUI = YUI;
14}
15
16/**
17The YUI global namespace object. This is the constructor for all YUI instances.
18
19This is a self-instantiable factory function, meaning you don't need to precede
20it with the `new` operator. You can invoke it directly like this:
21
22    YUI().use('*', function (Y) {
23        // Y is a new YUI instance.
24    });
25
26But it also works like this:
27
28    var Y = YUI();
29
30The `YUI` constructor accepts an optional config object, like this:
31
32    YUI({
33        debug: true,
34        combine: false
35    }).use('node', function (Y) {
36        // Y.Node is ready to use.
37    });
38
39See the API docs for the <a href="config.html">Config</a> class for the complete
40list of supported configuration properties accepted by the YUI constuctor.
41
42If a global `YUI` object is already defined, the existing YUI object will not be
43overwritten, to ensure that defined namespaces are preserved.
44
45Each YUI instance has full custom event support, but only if the event system is
46available.
47
48@class YUI
49@uses EventTarget
50@constructor
51@global
52@param {Object} [config]* Zero or more optional configuration objects. Config
53    values are stored in the `Y.config` property. See the
54    <a href="config.html">Config</a> docs for the list of supported properties.
55**/
56
57    /*global YUI*/
58    /*global YUI_config*/
59    var YUI = function() {
60        var i = 0,
61            Y = this,
62            args = arguments,
63            l = args.length,
64            instanceOf = function(o, type) {
65                return (o && o.hasOwnProperty && (o instanceof type));
66            },
67            gconf = (typeof YUI_config !== 'undefined') && YUI_config;
68
69        if (!(instanceOf(Y, YUI))) {
70            Y = new YUI();
71        } else {
72            // set up the core environment
73            Y._init();
74
75            /**
76            Master configuration that might span multiple contexts in a non-
77            browser environment. It is applied first to all instances in all
78            contexts.
79
80            @example
81
82                YUI.GlobalConfig = {
83                    filter: 'debug'
84                };
85
86                YUI().use('node', function (Y) {
87                    // debug files used here
88                });
89
90                YUI({
91                    filter: 'min'
92                }).use('node', function (Y) {
93                    // min files used here
94                });
95
96            @property {Object} GlobalConfig
97            @global
98            @static
99            **/
100            if (YUI.GlobalConfig) {
101                Y.applyConfig(YUI.GlobalConfig);
102            }
103
104            /**
105            Page-level config applied to all YUI instances created on the
106            current page. This is applied after `YUI.GlobalConfig` and before
107            any instance-level configuration.
108
109            @example
110
111                // Single global var to include before YUI seed file
112                YUI_config = {
113                    filter: 'debug'
114                };
115
116                YUI().use('node', function (Y) {
117                    // debug files used here
118                });
119
120                YUI({
121                    filter: 'min'
122                }).use('node', function (Y) {
123                    // min files used here
124                });
125
126            @property {Object} YUI_config
127            @global
128            **/
129            if (gconf) {
130                Y.applyConfig(gconf);
131            }
132
133            // bind the specified additional modules for this instance
134            if (!l) {
135                Y._afterConfig();
136                Y._setup();
137            }
138        }
139
140        if (l) {
141            // Each instance can accept one or more configuration objects.
142            // These are applied after YUI.GlobalConfig and YUI_Config,
143            // overriding values set in those config files if there is a
144            // matching property.
145            for (; i < l; i++) {
146                Y.applyConfig(args[i]);
147            }
148
149            Y._afterConfig();
150            Y._setup();
151        }
152
153        Y.instanceOf = instanceOf;
154
155        return Y;
156    };
157
158(function() {
159
160    var proto, prop,
161        VERSION = '3.18.1',
162        PERIOD = '.',
163        BASE = 'http://yui.yahooapis.com/',
164        /*
165            These CSS class names can't be generated by
166            getClassName since it is not available at the
167            time they are being used.
168        */
169        DOC_LABEL = 'yui3-js-enabled',
170        CSS_STAMP_EL = 'yui3-css-stamp',
171        NOOP = function() {},
172        SLICE = Array.prototype.slice,
173        APPLY_TO_AUTH = { 'io.xdrReady': 1,   // the functions applyTo
174                          'io.xdrResponse': 1,   // can call. this should
175                          'SWF.eventHandler': 1 }, // be done at build time
176        hasWin = (typeof window != 'undefined'),
177        win = (hasWin) ? window : null,
178        doc = (hasWin) ? win.document : null,
179        docEl = doc && doc.documentElement,
180        docClass = docEl && docEl.className,
181        instances = {},
182        time = new Date().getTime(),
183        add = function(el, type, fn, capture) {
184            if (el && el.addEventListener) {
185                el.addEventListener(type, fn, capture);
186            } else if (el && el.attachEvent) {
187                el.attachEvent('on' + type, fn);
188            }
189        },
190        remove = function(el, type, fn, capture) {
191            if (el && el.removeEventListener) {
192                // this can throw an uncaught exception in FF
193                try {
194                    el.removeEventListener(type, fn, capture);
195                } catch (ex) {}
196            } else if (el && el.detachEvent) {
197                el.detachEvent('on' + type, fn);
198            }
199        },
200        handleReady = function() {
201            YUI.Env.DOMReady = true;
202            if (hasWin) {
203                remove(doc, 'DOMContentLoaded', handleReady);
204            }
205        },
206        handleLoad = function() {
207            YUI.Env.windowLoaded = true;
208            YUI.Env.DOMReady = true;
209            if (hasWin) {
210                remove(window, 'load', handleLoad);
211            }
212        },
213        getLoader = function(Y, o) {
214            var loader = Y.Env._loader,
215                lCore = [ 'loader-base' ],
216                G_ENV = YUI.Env,
217                mods = G_ENV.mods;
218
219            if (loader) {
220                //loader._config(Y.config);
221                loader.ignoreRegistered = false;
222                loader.onEnd = null;
223                loader.data = null;
224                loader.required = [];
225                loader.loadType = null;
226            } else {
227                loader = new Y.Loader(Y.config);
228                Y.Env._loader = loader;
229            }
230            if (mods && mods.loader) {
231                lCore = [].concat(lCore, YUI.Env.loaderExtras);
232            }
233            YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore));
234
235            return loader;
236        },
237
238        clobber = function(r, s) {
239            for (var i in s) {
240                if (s.hasOwnProperty(i)) {
241                    r[i] = s[i];
242                }
243            }
244        },
245
246        ALREADY_DONE = { success: true };
247
248//  Stamp the documentElement (HTML) with a class of "yui-loaded" to
249//  enable styles that need to key off of JS being enabled.
250if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
251    if (docClass) {
252        docClass += ' ';
253    }
254    docClass += DOC_LABEL;
255    docEl.className = docClass;
256}
257
258if (VERSION.indexOf('@') > -1) {
259    VERSION = '3.5.0'; // dev time hack for cdn test
260}
261
262proto = {
263    /**
264    Applies a new configuration object to the config of this YUI instance. This
265    will merge new group/module definitions, and will also update the loader
266    cache if necessary. Updating `Y.config` directly will not update the cache.
267
268    @method applyConfig
269    @param {Object} o the configuration object.
270    @since 3.2.0
271    **/
272    applyConfig: function(o) {
273
274        o = o || NOOP;
275
276        var attr,
277            name,
278            // detail,
279            config = this.config,
280            mods = config.modules,
281            groups = config.groups,
282            aliases = config.aliases,
283            loader = this.Env._loader;
284
285        for (name in o) {
286            if (o.hasOwnProperty(name)) {
287                attr = o[name];
288                if (mods && name == 'modules') {
289                    clobber(mods, attr);
290                } else if (aliases && name == 'aliases') {
291                    clobber(aliases, attr);
292                } else if (groups && name == 'groups') {
293                    clobber(groups, attr);
294                } else if (name == 'win') {
295                    config[name] = (attr && attr.contentWindow) || attr;
296                    config.doc = config[name] ? config[name].document : null;
297                } else if (name == '_yuid') {
298                    // preserve the guid
299                } else {
300                    config[name] = attr;
301                }
302            }
303        }
304
305        if (loader) {
306            loader._config(o);
307        }
308
309    },
310
311    /**
312    Old way to apply a config to this instance (calls `applyConfig` under the
313    hood).
314
315    @private
316    @method _config
317    @param {Object} o The config to apply
318    **/
319    _config: function(o) {
320        this.applyConfig(o);
321    },
322
323    /**
324    Initializes this YUI instance.
325
326    @private
327    @method _init
328    **/
329    _init: function() {
330        var filter, el,
331            Y = this,
332            G_ENV = YUI.Env,
333            Env = Y.Env,
334            prop;
335
336        /**
337        The version number of this YUI instance.
338
339        This value is typically updated by a script when a YUI release is built,
340        so it may not reflect the correct version number when YUI is run from
341        the development source tree.
342
343        @property {String} version
344        **/
345        Y.version = VERSION;
346
347        if (!Env) {
348            Y.Env = {
349                core: ['get', 'features', 'intl-base', 'yui-log', 'yui-later', 'loader-base', 'loader-rollup', 'loader-yui3'],
350                loaderExtras: ['loader-rollup', 'loader-yui3'],
351                mods: {}, // flat module map
352                versions: {}, // version module map
353                base: BASE,
354                cdn: BASE + VERSION + '/',
355                // bootstrapped: false,
356                _idx: 0,
357                _used: {},
358                _attached: {},
359                _exported: {},
360                _missed: [],
361                _yidx: 0,
362                _uidx: 0,
363                _guidp: 'y',
364                _loaded: {},
365                // serviced: {},
366                // Regex in English:
367                // I'll start at the \b(yui).
368                // 1. Look in the test string for "yui" or
369                //    "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break.  That is, it
370                //    can't match "foyui" or "i_heart_yui". This can be anywhere in the string.
371                // 2. After #1 must come a forward slash followed by the string matched in #1, so
372                //    "yui-base/yui-base" or "yui-pants/yui-pants".
373                // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
374                //    so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
375                // 4. This is followed by ".js", so "yui/yui.js".
376                // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
377                //    then capture the junk between the LAST "&" and the string in 1-4.  So
378                //    "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
379                //    will capture "3.3.0/build/"
380                //
381                // Regex Exploded:
382                // (?:\?             Find a ?
383                //   (?:[^&]*&)      followed by 0..n characters followed by an &
384                //   *               in fact, find as many sets of characters followed by a & as you can
385                //   ([^&]*)         capture the stuff after the last & in \1
386                // )?                but it's ok if all this ?junk&more_junk stuff isn't even there
387                // \b(               after a word break find either the string
388                //    yui(?:-\w+)?   "yui" optionally followed by a -, then more characters
389                // )                 and store the yui-* string in \2
390                // \/\2              then comes a / followed by the yui-* string in \2
391                // (?:-(min|debug))? optionally followed by "-min" or "-debug"
392                // .js               and ending in ".js"
393                _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
394                parseBasePath: function(src, pattern) {
395                    var match = src.match(pattern),
396                        path, filter;
397
398                    if (match) {
399                        path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
400
401                        // this is to set up the path to the loader.  The file
402                        // filter for loader should match the yui include.
403                        filter = match[3];
404
405                        // extract correct path for mixed combo urls
406                        // http://yuilibrary.com/projects/yui3/ticket/2528423
407                        if (match[1]) {
408                            path += '?' + match[1];
409                        }
410                        path = {
411                            filter: filter,
412                            path: path
413                        };
414                    }
415                    return path;
416                },
417                getBase: G_ENV && G_ENV.getBase ||
418                        function(pattern) {
419                            var nodes = (doc && doc.getElementsByTagName('script')) || [],
420                                path = Env.cdn, parsed,
421                                i, len, src;
422
423                            for (i = 0, len = nodes.length; i < len; ++i) {
424                                src = nodes[i].src;
425                                if (src) {
426                                    parsed = Y.Env.parseBasePath(src, pattern);
427                                    if (parsed) {
428                                        filter = parsed.filter;
429                                        path = parsed.path;
430                                        break;
431                                    }
432                                }
433                            }
434
435                            // use CDN default
436                            return path;
437                        }
438
439            };
440
441            Env = Y.Env;
442
443            Env._loaded[VERSION] = {};
444
445            if (G_ENV && Y !== YUI) {
446                Env._yidx = ++G_ENV._yidx;
447                Env._guidp = ('yui_' + VERSION + '_' +
448                             Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_');
449            } else if (YUI._YUI) {
450
451                G_ENV = YUI._YUI.Env;
452                Env._yidx += G_ENV._yidx;
453                Env._uidx += G_ENV._uidx;
454
455                for (prop in G_ENV) {
456                    if (!(prop in Env)) {
457                        Env[prop] = G_ENV[prop];
458                    }
459                }
460
461                delete YUI._YUI;
462            }
463
464            Y.id = Y.stamp(Y);
465            instances[Y.id] = Y;
466
467        }
468
469        Y.constructor = YUI;
470
471        // configuration defaults
472        Y.config = Y.config || {
473            bootstrap: true,
474            cacheUse: true,
475            debug: true,
476            doc: doc,
477            fetchCSS: true,
478            throwFail: true,
479            useBrowserConsole: true,
480            useNativeES5: true,
481            win: win
482        };
483
484        //Register the CSS stamp element
485        if (doc && !doc.getElementById(CSS_STAMP_EL)) {
486            el = doc.createElement('div');
487            el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
488            YUI.Env.cssStampEl = el.firstChild;
489            if (doc.body) {
490                doc.body.appendChild(YUI.Env.cssStampEl);
491            } else {
492                docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
493            }
494        } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) {
495            YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL);
496        }
497
498        Y.config.lang = Y.config.lang || 'en-US';
499
500        Y.config.base = YUI.config.base ||
501                (YUI.config.defaultBase && YUI.config.root && YUI.config.defaultBase + YUI.config.root) ||
502                Y.Env.getBase(Y.Env._BASE_RE);
503
504        if (!filter || (!('mindebug').indexOf(filter))) {
505            filter = 'min';
506        }
507        filter = (filter) ? '-' + filter : filter;
508        Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
509
510    },
511
512    /**
513    This method is called after all other configuration has been applied to
514    the YUI instance.
515
516    @method _afterConfig
517    @private
518    **/
519    _afterConfig: function () {
520        var Y = this;
521
522        // We need to set up Y.config.global after the rest of the configuration
523        // so that setting it in user configuration prevents the library from
524        // using eval(). This is critical for Content Security Policy enabled
525        // sites and other environments like Chrome extensions
526        if (!Y.config.hasOwnProperty('global')) {
527            Y.config.global = Function('return this')();
528        }
529    },
530
531    /**
532    Finishes the instance setup. Attaches whatever YUI modules were defined
533    at the time that this instance was created.
534
535    @method _setup
536    @private
537    **/
538    _setup: function() {
539        var i, Y = this,
540            core = [],
541            mods = YUI.Env.mods,
542            extendedCore = Y.config.extendedCore || [],
543            extras = Y.config.core || [].concat(YUI.Env.core).concat(extendedCore); //Clone it..
544   
545        for (i = 0; i < extras.length; i++) {
546            if (mods[extras[i]]) {
547                core.push(extras[i]);
548            }
549        }
550
551        Y._attach(['yui-base']);
552        Y._attach(core);
553
554        if (Y.Loader) {
555            getLoader(Y);
556        }
557
558    },
559
560    /**
561    Executes the named method on the specified YUI instance if that method is
562    whitelisted.
563
564    @method applyTo
565    @param {String} id YUI instance id.
566    @param {String} method Name of the method to execute. For example:
567        'Object.keys'.
568    @param {Array} args Arguments to apply to the method.
569    @return {Mixed} Return value from the applied method, or `null` if the
570        specified instance was not found or the method was not whitelisted.
571    **/
572    applyTo: function(id, method, args) {
573        if (!(method in APPLY_TO_AUTH)) {
574            this.log(method + ': applyTo not allowed', 'warn', 'yui');
575            return null;
576        }
577
578        var instance = instances[id], nest, m, i;
579        if (instance) {
580            nest = method.split('.');
581            m = instance;
582            for (i = 0; i < nest.length; i = i + 1) {
583                m = m[nest[i]];
584                if (!m) {
585                    this.log('applyTo not found: ' + method, 'warn', 'yui');
586                }
587            }
588            return m && m.apply(instance, args);
589        }
590
591        return null;
592    },
593
594/**
595Registers a YUI module and makes it available for use in a `YUI().use()` call or
596as a dependency for other modules.
597
598The easiest way to create a first-class YUI module is to use
599<a href="http://yui.github.com/shifter/">Shifter</a>, the YUI component build
600tool.
601
602Shifter will automatically wrap your module code in a `YUI.add()` call along
603with any configuration info required for the module.
604
605@example
606
607    YUI.add('davglass', function (Y) {
608        Y.davglass = function () {
609        };
610    }, '3.4.0', {
611        requires: ['harley-davidson', 'mt-dew']
612    });
613
614@method add
615@param {String} name Module name.
616@param {Function} fn Function containing module code. This function will be
617    executed whenever the module is attached to a specific YUI instance.
618
619    @param {YUI} fn.Y The YUI instance to which this module is attached.
620    @param {String} fn.name Name of the module
621
622@param {String} version Module version number. This is currently used only for
623    informational purposes, and is not used internally by YUI.
624
625@param {Object} [details] Module config.
626    @param {Array} [details.requires] Array of other module names that must be
627        attached before this module can be attached.
628    @param {Array} [details.optional] Array of optional module names that should
629        be attached before this module is attached if they've already been
630        loaded. If the `loadOptional` YUI option is `true`, optional modules
631        that have not yet been loaded will be loaded just as if they were hard
632        requirements.
633    @param {Array} [details.use] Array of module names that are included within
634        or otherwise provided by this module, and which should be attached
635        automatically when this module is attached. This makes it possible to
636        create "virtual rollup" modules that simply attach a collection of other
637        modules or submodules.
638
639@return {YUI} This YUI instance.
640**/
641    add: function(name, fn, version, details) {
642        details = details || {};
643        var env = YUI.Env,
644            mod = {
645                name: name,
646                fn: fn,
647                version: version,
648                details: details
649            },
650            //Instance hash so we don't apply it to the same instance twice
651            applied = {},
652            loader, inst, modInfo,
653            i, versions = env.versions;
654
655        env.mods[name] = mod;
656        versions[version] = versions[version] || {};
657        versions[version][name] = mod;
658
659        for (i in instances) {
660            if (instances.hasOwnProperty(i)) {
661                inst = instances[i];
662                if (!applied[inst.id]) {
663                    applied[inst.id] = true;
664                    loader = inst.Env._loader;
665                    if (loader) {
666                        modInfo = loader.getModuleInfo(name);
667                        if (!modInfo || modInfo.temp) {
668                            loader.addModule(details, name);
669                        }
670                    }
671                }
672            }
673        }
674
675        return this;
676    },
677
678    /**
679    Executes the callback function associated with each required module,
680    attaching the module to this YUI instance.
681
682    @method _attach
683    @param {Array} r The array of modules to attach
684    @param {Boolean} [moot=false] If `true`, don't throw a warning if the module
685        is not attached.
686    @private
687    **/
688    _attach: function(r, moot) {
689        var i, name, mod, details, req, use, after,
690            mods = YUI.Env.mods,
691            aliases = YUI.Env.aliases,
692            Y = this, j,
693            cache = YUI.Env._renderedMods,
694            loader = Y.Env._loader,
695            done = Y.Env._attached,
696            exported = Y.Env._exported,
697            len = r.length, loader, def, go,
698            c = [],
699            modArgs, esCompat, reqlen, modInfo,
700            condition,
701            __exports__, __imports__;
702
703        //Check for conditional modules (in a second+ instance) and add their requirements
704        //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
705        for (i = 0; i < len; i++) {
706            name = r[i];
707            mod = mods[name];
708            c.push(name);
709            if (loader && loader.conditions[name]) {
710                for (j in loader.conditions[name]) {
711                    if (loader.conditions[name].hasOwnProperty(j)) {
712                        def = loader.conditions[name][j];
713                        go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
714                        if (go) {
715                            c.push(def.name);
716                        }
717                    }
718                }
719            }
720        }
721        r = c;
722        len = r.length;
723
724        for (i = 0; i < len; i++) {
725            if (!done[r[i]]) {
726                name = r[i];
727                mod = mods[name];
728
729                if (aliases && aliases[name] && !mod) {
730                    Y._attach(aliases[name]);
731                    continue;
732                }
733                if (!mod) {
734                    modInfo = loader && loader.getModuleInfo(name);
735                    if (modInfo) {
736                        mod = modInfo;
737                        moot = true;
738                    }
739
740
741                    //if (!loader || !loader.moduleInfo[name]) {
742                    //if ((!loader || !loader.moduleInfo[name]) && !moot) {
743                    if (!moot && name) {
744                        if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
745                            Y.Env._missed.push(name);
746                            Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
747                            Y.message('NOT loaded: ' + name, 'warn', 'yui');
748                        }
749                    }
750                } else {
751                    done[name] = true;
752                    //Don't like this, but in case a mod was asked for once, then we fetch it
753                    //We need to remove it from the missed list ^davglass
754                    for (j = 0; j < Y.Env._missed.length; j++) {
755                        if (Y.Env._missed[j] === name) {
756                            Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
757                            Y.Env._missed.splice(j, 1);
758                        }
759                    }
760
761                    // Optional dependencies normally work by modifying the
762                    // dependency list of a module. If the dependency's test
763                    // passes it is added to the list. If not, it's not loaded.
764                    // This following check ensures that optional dependencies
765                    // are not attached when they were already loaded into the
766                    // page (when bundling for example)
767                    if (loader && !loader._canBeAttached(name)) {
768                        return true;
769                    }
770
771                    /*
772                        If it's a temp module, we need to redo it's requirements if it's already loaded
773                        since it may have been loaded by another instance and it's dependencies might
774                        have been redefined inside the fetched file.
775                    */
776                    if (loader && cache && cache[name] && cache[name].temp) {
777                        loader.getRequires(cache[name]);
778                        req = [];
779                        modInfo = loader.getModuleInfo(name);
780                        for (j in modInfo.expanded_map) {
781                            if (modInfo.expanded_map.hasOwnProperty(j)) {
782                                req.push(j);
783                            }
784                        }
785                        Y._attach(req);
786                    }
787
788                    details = mod.details;
789                    req = details.requires;
790                    esCompat = details.es;
791                    use = details.use;
792                    after = details.after;
793                    //Force Intl load if there is a language (Loader logic) @todo fix this shit
794                    if (details.lang) {
795                        req = req || [];
796                        req.unshift('intl');
797                    }
798
799                    if (req) {
800                        reqlen = req.length;
801                        for (j = 0; j < reqlen; j++) {
802                            if (!done[req[j]]) {
803                                if (!Y._attach(req)) {
804                                    return false;
805                                }
806                                break;
807                            }
808                        }
809                    }
810
811                    if (after) {
812                        for (j = 0; j < after.length; j++) {
813                            if (!done[after[j]]) {
814                                if (!Y._attach(after, true)) {
815                                    return false;
816                                }
817                                break;
818                            }
819                        }
820                    }
821
822                    if (mod.fn) {
823                        modArgs = [Y, name];
824                        if (esCompat) {
825                            __imports__ = {};
826                            __exports__ = {};
827                            // passing `exports` and `imports` onto the module function
828                            modArgs.push(__imports__, __exports__);
829                            if (req) {
830                                reqlen = req.length;
831                                for (j = 0; j < reqlen; j++) {
832                                    __imports__[req[j]] = exported.hasOwnProperty(req[j]) ? exported[req[j]] : Y;
833                                }
834                            }
835                        }
836                        if (Y.config.throwFail) {
837                            __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs);
838                        } else {
839                            try {
840                                __exports__ = mod.fn.apply(esCompat ? undefined : mod, modArgs);
841                            } catch (e) {
842                                Y.error('Attach error: ' + name, e, name);
843                                return false;
844                            }
845                        }
846                        if (esCompat) {
847                            // store the `exports` in case others `es` modules requires it
848                            exported[name] = __exports__;
849
850                            // If an ES module is conditionally loaded and set
851                            // to be used "instead" another module, replace the
852                            // trigger module's content with the conditionally
853                            // loaded one so the values returned by require()
854                            // still makes sense
855                            condition = mod.details.condition;
856                            if (condition && condition.when === 'instead') {
857                                exported[condition.trigger] = __exports__;
858                            }
859                        }
860                    }
861
862                    if (use) {
863                        for (j = 0; j < use.length; j++) {
864                            if (!done[use[j]]) {
865                                if (!Y._attach(use)) {
866                                    return false;
867                                }
868                                break;
869                            }
870                        }
871                    }
872
873
874
875                }
876            }
877        }
878
879        return true;
880    },
881
882    /**
883    Delays the `use` callback until another event has taken place such as
884    `window.onload`, `domready`, `contentready`, or `available`.
885
886    @private
887    @method _delayCallback
888    @param {Function} cb The original `use` callback.
889    @param {String|Object} until Either an event name ('load', 'domready', etc.)
890        or an object containing event/args keys for contentready/available.
891    @return {Function}
892    **/
893    _delayCallback: function(cb, until) {
894
895        var Y = this,
896            mod = ['event-base'];
897
898        until = (Y.Lang.isObject(until) ? until : { event: until });
899
900        if (until.event === 'load') {
901            mod.push('event-synthetic');
902        }
903
904        return function() {
905            var args = arguments;
906            Y._use(mod, function() {
907                Y.on(until.event, function() {
908                    args[1].delayUntil = until.event;
909                    cb.apply(Y, args);
910                }, until.args);
911            });
912        };
913    },
914
915    /**
916    Attaches one or more modules to this YUI instance. When this is executed,
917    the requirements of the desired modules are analyzed, and one of several
918    things can happen:
919
920
921      * All required modules have already been loaded, and just need to be
922        attached to this YUI instance. In this case, the `use()` callback will
923        be executed synchronously after the modules are attached.
924
925      * One or more modules have not yet been loaded, or the Get utility is not
926        available, or the `bootstrap` config option is `false`. In this case,
927        a warning is issued indicating that modules are missing, but all
928        available modules will still be attached and the `use()` callback will
929        be executed synchronously.
930
931      * One or more modules are missing and the Loader is not available but the
932        Get utility is, and `bootstrap` is not `false`. In this case, the Get
933        utility will be used to load the Loader, and we will then proceed to
934        the following state:
935
936      * One or more modules are missing and the Loader is available. In this
937        case, the Loader will be used to resolve the dependency tree for the
938        missing modules and load them and their dependencies. When the Loader is
939        finished loading modules, the `use()` callback will be executed
940        asynchronously.
941
942    @example
943
944        // Loads and attaches dd and its dependencies.
945        YUI().use('dd', function (Y) {
946            // ...
947        });
948
949        // Loads and attaches dd and node as well as all of their dependencies.
950        YUI().use(['dd', 'node'], function (Y) {
951            // ...
952        });
953
954        // Attaches all modules that have already been loaded.
955        YUI().use('*', function (Y) {
956            // ...
957        });
958
959        // Attaches a gallery module.
960        YUI().use('gallery-yql', function (Y) {
961            // ...
962        });
963
964        // Attaches a YUI 2in3 module.
965        YUI().use('yui2-datatable', function (Y) {
966            // ...
967        });
968
969    @method use
970    @param {String|Array} modules* One or more module names to attach.
971    @param {Function} [callback] Callback function to be executed once all
972        specified modules and their dependencies have been attached.
973    @param {YUI} callback.Y The YUI instance created for this sandbox.
974    @param {Object} callback.status Object containing `success`, `msg` and
975        `data` properties.
976    @chainable
977    **/
978    use: function() {
979        var args = SLICE.call(arguments, 0),
980            callback = args[args.length - 1],
981            Y = this,
982            i = 0,
983            name,
984            Env = Y.Env,
985            provisioned = true;
986
987        // The last argument supplied to use can be a load complete callback
988        if (Y.Lang.isFunction(callback)) {
989            args.pop();
990            if (Y.config.delayUntil) {
991                callback = Y._delayCallback(callback, Y.config.delayUntil);
992            }
993        } else {
994            callback = null;
995        }
996        if (Y.Lang.isArray(args[0])) {
997            args = args[0];
998        }
999
1000        if (Y.config.cacheUse) {
1001            while ((name = args[i++])) {
1002                if (!Env._attached[name]) {
1003                    provisioned = false;
1004                    break;
1005                }
1006            }
1007
1008            if (provisioned) {
1009                if (args.length) {
1010                }
1011                Y._notify(callback, ALREADY_DONE, args);
1012                return Y;
1013            }
1014        }
1015
1016        if (Y._loading) {
1017            Y._useQueue = Y._useQueue || new Y.Queue();
1018            Y._useQueue.add([args, callback]);
1019        } else {
1020            Y._use(args, function(Y, response) {
1021                Y._notify(callback, response, args);
1022            });
1023        }
1024
1025        return Y;
1026    },
1027
1028    /**
1029    Sugar for loading both legacy and ES6-based YUI modules.
1030
1031    @method require
1032    @param {String} [modules*] List of module names to import or a single
1033        module name.
1034    @param {Function} callback Callback that gets called once all the modules
1035        were loaded. Each parameter of the callback is the export value of the
1036        corresponding module in the list. If the module is a legacy YUI module,
1037        the YUI instance is used instead of the module exports.
1038    @example
1039    ```
1040    YUI().require(['es6-set'], function (Y, imports) {
1041        var Set = imports.Set,
1042            set = new Set();
1043    });
1044    ```
1045    **/
1046    require: function () {
1047        var args = SLICE.call(arguments),
1048            callback;
1049
1050        if (typeof args[args.length - 1] === 'function') {
1051            callback = args.pop();
1052
1053            // only add the callback if one was provided
1054            // YUI().require('foo'); is valid
1055            args.push(function (Y) {
1056                var i, length = args.length,
1057                    exported = Y.Env._exported,
1058                    __imports__ = {};
1059
1060                // Get only the imports requested as arguments
1061                for (i = 0; i < length; i++) {
1062                    if (exported.hasOwnProperty(args[i])) {
1063                        __imports__[args[i]] = exported[args[i]];
1064                    }
1065                }
1066
1067                // Using `undefined` because:
1068                // - Using `Y.config.global` would force the value of `this` to be
1069                //   the global object even in strict mode
1070                // - Using `Y` goes against the goal of moving away from a shared
1071                //   object and start thinking in terms of imported and exported
1072                //   objects
1073                callback.call(undefined, Y, __imports__);
1074            });
1075        }
1076        // Do not return the Y object. This makes it hard to follow this
1077        // traditional pattern:
1078        //   var Y = YUI().use(...);
1079        // This is a good idea in the light of ES6 modules, to avoid working
1080        // in the global scope.
1081        // This also leaves the door open for returning a promise, once the
1082        // YUI loader is based on the ES6 loader which uses
1083        // loader.import(...).then(...)
1084        this.use.apply(this, args);
1085    },
1086
1087    /**
1088    Handles Loader notifications about attachment/load errors.
1089
1090    @method _notify
1091    @param {Function} callback Callback to pass to `Y.config.loadErrorFn`.
1092    @param {Object} response Response returned from Loader.
1093    @param {Array} args Arguments passed from Loader.
1094    @private
1095    **/
1096    _notify: function(callback, response, args) {
1097        if (!response.success && this.config.loadErrorFn) {
1098            this.config.loadErrorFn.call(this, this, callback, response, args);
1099        } else if (callback) {
1100            if (this.Env._missed && this.Env._missed.length) {
1101                response.msg = 'Missing modules: ' + this.Env._missed.join();
1102                response.success = false;
1103            }
1104            if (this.config.throwFail) {
1105                callback(this, response);
1106            } else {
1107                try {
1108                    callback(this, response);
1109                } catch (e) {
1110                    this.error('use callback error', e, args);
1111                }
1112            }
1113        }
1114    },
1115
1116    /**
1117    Called from the `use` method queue to ensure that only one set of loading
1118    logic is performed at a time.
1119
1120    @method _use
1121    @param {String} args* One or more modules to attach.
1122    @param {Function} [callback] Function to call once all required modules have
1123        been attached.
1124    @private
1125    **/
1126    _use: function(args, callback) {
1127
1128        if (!this.Array) {
1129            this._attach(['yui-base']);
1130        }
1131
1132        var len, loader, handleBoot,
1133            Y = this,
1134            G_ENV = YUI.Env,
1135            mods = G_ENV.mods,
1136            Env = Y.Env,
1137            used = Env._used,
1138            aliases = G_ENV.aliases,
1139            queue = G_ENV._loaderQueue,
1140            firstArg = args[0],
1141            YArray = Y.Array,
1142            config = Y.config,
1143            boot = config.bootstrap,
1144            missing = [],
1145            i,
1146            r = [],
1147            ret = true,
1148            fetchCSS = config.fetchCSS,
1149            process = function(names, skip) {
1150
1151                var i = 0, a = [], name, len, m, req, use;
1152
1153                if (!names.length) {
1154                    return;
1155                }
1156
1157                if (aliases) {
1158                    len = names.length;
1159                    for (i = 0; i < len; i++) {
1160                        if (aliases[names[i]] && !mods[names[i]]) {
1161                            a = [].concat(a, aliases[names[i]]);
1162                        } else {
1163                            a.push(names[i]);
1164                        }
1165                    }
1166                    names = a;
1167                }
1168
1169                len = names.length;
1170
1171                for (i = 0; i < len; i++) {
1172                    name = names[i];
1173                    if (!skip) {
1174                        r.push(name);
1175                    }
1176
1177                    // only attach a module once
1178                    if (used[name]) {
1179                        continue;
1180                    }
1181
1182                    m = mods[name];
1183                    req = null;
1184                    use = null;
1185
1186                    if (m) {
1187                        used[name] = true;
1188                        req = m.details.requires;
1189                        use = m.details.use;
1190                    } else {
1191                        // CSS files don't register themselves, see if it has
1192                        // been loaded
1193                        if (!G_ENV._loaded[VERSION][name]) {
1194                            missing.push(name);
1195                        } else {
1196                            used[name] = true; // probably css
1197                        }
1198                    }
1199
1200                    // make sure requirements are attached
1201                    if (req && req.length) {
1202                        process(req);
1203                    }
1204
1205                    // make sure we grab the submodule dependencies too
1206                    if (use && use.length) {
1207                        process(use, 1);
1208                    }
1209                }
1210
1211            },
1212
1213            handleLoader = function(fromLoader) {
1214                var response = fromLoader || {
1215                        success: true,
1216                        msg: 'not dynamic'
1217                    },
1218                    redo, origMissing,
1219                    ret = true,
1220                    data = response.data;
1221
1222                Y._loading = false;
1223
1224                if (data) {
1225                    origMissing = missing;
1226                    missing = [];
1227                    r = [];
1228                    process(data);
1229                    redo = missing.length;
1230                    if (redo) {
1231                        if ([].concat(missing).sort().join() ==
1232                                origMissing.sort().join()) {
1233                            redo = false;
1234                        }
1235                    }
1236                }
1237
1238                if (redo && data) {
1239                    Y._loading = true;
1240                    Y._use(missing, function() {
1241                        if (Y._attach(data)) {
1242                            Y._notify(callback, response, data);
1243                        }
1244                    });
1245                } else {
1246                    if (data) {
1247                        ret = Y._attach(data);
1248                    }
1249                    if (ret) {
1250                        Y._notify(callback, response, args);
1251                    }
1252                }
1253
1254                if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
1255                    Y._use.apply(Y, Y._useQueue.next());
1256                }
1257
1258            };
1259
1260
1261        // YUI().use('*'); // bind everything available
1262        if (firstArg === '*') {
1263            args = [];
1264            for (i in mods) {
1265                if (mods.hasOwnProperty(i)) {
1266                    args.push(i);
1267                }
1268            }
1269            ret = Y._attach(args);
1270            if (ret) {
1271                handleLoader();
1272            }
1273            return Y;
1274        }
1275
1276        if ((mods.loader || mods['loader-base']) && !Y.Loader) {
1277            Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]);
1278        }
1279
1280
1281        // use loader to expand dependencies and sort the
1282        // requirements if it is available.
1283        if (boot && Y.Loader && args.length) {
1284            loader = getLoader(Y);
1285            loader.require(args);
1286            loader.ignoreRegistered = true;
1287            loader._boot = true;
1288            loader.calculate(null, (fetchCSS) ? null : 'js');
1289            args = loader.sorted;
1290            loader._boot = false;
1291        }
1292
1293        process(args);
1294
1295        len = missing.length;
1296
1297
1298        if (len) {
1299            missing = YArray.dedupe(missing);
1300            len = missing.length;
1301        }
1302
1303
1304        // dynamic load
1305        if (boot && len && Y.Loader) {
1306            Y._loading = true;
1307            loader = getLoader(Y);
1308            loader.onEnd = handleLoader;
1309            loader.context = Y;
1310            loader.data = args;
1311            loader.ignoreRegistered = false;
1312            loader.require(missing);
1313            loader.insert(null, (fetchCSS) ? null : 'js');
1314
1315        } else if (boot && len && Y.Get && !Env.bootstrapped) {
1316
1317            Y._loading = true;
1318
1319            handleBoot = function() {
1320                Y._loading = false;
1321                queue.running = false;
1322                Env.bootstrapped = true;
1323                G_ENV._bootstrapping = false;
1324                if (Y._attach(['loader'])) {
1325                    Y._use(args, callback);
1326                }
1327            };
1328
1329            if (G_ENV._bootstrapping) {
1330                queue.add(handleBoot);
1331            } else {
1332                G_ENV._bootstrapping = true;
1333                Y.Get.script(config.base + config.loaderPath, {
1334                    onEnd: handleBoot
1335                });
1336            }
1337
1338        } else {
1339            ret = Y._attach(args);
1340            if (ret) {
1341                handleLoader();
1342            }
1343        }
1344
1345        return Y;
1346    },
1347
1348
1349    /**
1350    Utility method for safely creating namespaces if they don't already exist.
1351    May be called statically on the YUI global object or as a method on a YUI
1352    instance.
1353
1354    When called statically, a namespace will be created on the YUI global
1355    object:
1356
1357        // Create `YUI.your.namespace.here` as nested objects, preserving any
1358        // objects that already exist instead of overwriting them.
1359        YUI.namespace('your.namespace.here');
1360
1361    When called as a method on a YUI instance, a namespace will be created on
1362    that instance:
1363
1364        // Creates `Y.property.package`.
1365        Y.namespace('property.package');
1366
1367    Dots in the input string cause `namespace` to create nested objects for each
1368    token. If any part of the requested namespace already exists, the current
1369    object will be left in place and will not be overwritten. This allows
1370    multiple calls to `namespace` to preserve existing namespaced properties.
1371
1372    If the first token in the namespace string is "YAHOO", that token is
1373    discarded. This is legacy behavior for backwards compatibility with YUI 2.
1374
1375    Be careful with namespace tokens. Reserved words may work in some browsers
1376    and not others. For instance, the following will fail in some browsers
1377    because the supported version of JavaScript reserves the word "long":
1378
1379        Y.namespace('really.long.nested.namespace');
1380
1381    Note: If you pass multiple arguments to create multiple namespaces, only the
1382    last one created is returned from this function.
1383
1384    @method namespace
1385    @param {String} namespace* One or more namespaces to create.
1386    @return {Object} Reference to the last namespace object created.
1387    **/
1388    namespace: function() {
1389        var a = arguments, o, i = 0, j, d, arg;
1390
1391        for (; i < a.length; i++) {
1392            o = this; //Reset base object per argument or it will get reused from the last
1393            arg = a[i];
1394            if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
1395                d = arg.split(PERIOD);
1396                for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1397                    o[d[j]] = o[d[j]] || {};
1398                    o = o[d[j]];
1399                }
1400            } else {
1401                o[arg] = o[arg] || {};
1402                o = o[arg]; //Reset base object to the new object so it's returned
1403            }
1404        }
1405        return o;
1406    },
1407
1408    // this is replaced if the log module is included
1409    log: NOOP,
1410    message: NOOP,
1411    // this is replaced if the dump module is included
1412    dump: function (o) { return ''+o; },
1413
1414    /**
1415    Reports an error.
1416
1417    The reporting mechanism is controlled by the `throwFail` configuration
1418    attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is
1419    truthy, a JS exception is thrown.
1420
1421    If an `errorFn` is specified in the config it must return `true` to indicate
1422    that the exception was handled and keep it from being thrown.
1423
1424    @method error
1425    @param {String} msg Error message.
1426    @param {Error|String} [e] JavaScript error object or an error string.
1427    @param {String} [src] Source of the error (such as the name of the module in
1428        which the error occurred).
1429    @chainable
1430    **/
1431    error: function(msg, e, src) {
1432        //TODO Add check for window.onerror here
1433
1434        var Y = this, ret;
1435
1436        if (Y.config.errorFn) {
1437            ret = Y.config.errorFn.apply(Y, arguments);
1438        }
1439
1440        if (!ret) {
1441            throw (e || new Error(msg));
1442        } else {
1443            Y.message(msg, 'error', ''+src); // don't scrub this one
1444        }
1445
1446        return Y;
1447    },
1448
1449    /**
1450    Generates an id string that is unique among all YUI instances in this
1451    execution context.
1452
1453    @method guid
1454    @param {String} [pre] Prefix.
1455    @return {String} Unique id.
1456    **/
1457    guid: function(pre) {
1458        var id = this.Env._guidp + '_' + (++this.Env._uidx);
1459        return (pre) ? (pre + id) : id;
1460    },
1461
1462    /**
1463    Returns a unique id associated with the given object and (if *readOnly* is
1464    falsy) stamps the object with that id so it can be identified in the future.
1465
1466    Stamping an object involves adding a `_yuid` property to it that contains
1467    the object's id. One exception to this is that in Internet Explorer, DOM
1468    nodes have a `uniqueID` property that contains a browser-generated unique
1469    id, which will be used instead of a YUI-generated id when available.
1470
1471    @method stamp
1472    @param {Object} o Object to stamp.
1473    @param {Boolean} readOnly If truthy and the given object has not already
1474        been stamped, the object will not be modified and `null` will be
1475        returned.
1476    @return {String} Object's unique id, or `null` if *readOnly* was truthy and
1477        the given object was not already stamped.
1478    **/
1479    stamp: function(o, readOnly) {
1480        var uid;
1481        if (!o) {
1482            return o;
1483        }
1484
1485        // IE generates its own unique ID for dom nodes
1486        // The uniqueID property of a document node returns a new ID
1487        if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1488            uid = o.uniqueID;
1489        } else {
1490            uid = (typeof o === 'string') ? o : o._yuid;
1491        }
1492
1493        if (!uid) {
1494            uid = this.guid();
1495            if (!readOnly) {
1496                try {
1497                    o._yuid = uid;
1498                } catch (e) {
1499                    uid = null;
1500                }
1501            }
1502        }
1503        return uid;
1504    },
1505
1506    /**
1507    Destroys this YUI instance.
1508
1509    @method destroy
1510    @since 3.3.0
1511    **/
1512    destroy: function() {
1513        var Y = this;
1514        if (Y.Event) {
1515            Y.Event._unload();
1516        }
1517        delete instances[Y.id];
1518        delete Y.Env;
1519        delete Y.config;
1520    }
1521
1522    /**
1523    Safe `instanceof` wrapper that works around a memory leak in IE when the
1524    object being tested is `window` or `document`.
1525
1526    Unless you are testing objects that may be `window` or `document`, you
1527    should use the native `instanceof` operator instead of this method.
1528
1529    @method instanceOf
1530    @param {Object} o Object to check.
1531    @param {Object} type Class to check against.
1532    @since 3.3.0
1533    **/
1534};
1535
1536    YUI.prototype = proto;
1537
1538    // inheritance utilities are not available yet
1539    for (prop in proto) {
1540        if (proto.hasOwnProperty(prop)) {
1541            YUI[prop] = proto[prop];
1542        }
1543    }
1544
1545    /**
1546    Applies a configuration to all YUI instances in this execution context.
1547
1548    The main use case for this method is in "mashups" where several third-party
1549    scripts need to write to a global YUI config, but cannot share a single
1550    centrally-managed config object. This way they can all call
1551    `YUI.applyConfig({})` instead of overwriting the single global config.
1552
1553    @example
1554
1555        YUI.applyConfig({
1556            modules: {
1557                davglass: {
1558                    fullpath: './davglass.js'
1559                }
1560            }
1561        });
1562
1563        YUI.applyConfig({
1564            modules: {
1565                foo: {
1566                    fullpath: './foo.js'
1567                }
1568            }
1569        });
1570
1571        YUI().use('davglass', function (Y) {
1572            // Module davglass will be available here.
1573        });
1574
1575    @method applyConfig
1576    @param {Object} o Configuration object to apply.
1577    @static
1578    @since 3.5.0
1579    **/
1580    YUI.applyConfig = function(o) {
1581        if (!o) {
1582            return;
1583        }
1584        //If there is a GlobalConfig, apply it first to set the defaults
1585        if (YUI.GlobalConfig) {
1586            this.prototype.applyConfig.call(this, YUI.GlobalConfig);
1587        }
1588        //Apply this config to it
1589        this.prototype.applyConfig.call(this, o);
1590        //Reset GlobalConfig to the combined config
1591        YUI.GlobalConfig = this.config;
1592    };
1593
1594    // set up the environment
1595    YUI._init();
1596
1597    if (hasWin) {
1598        add(doc, 'DOMContentLoaded', handleReady);
1599
1600        // add a window load event at load time so we can capture
1601        // the case where it fires before dynamic loading is
1602        // complete.
1603        add(window, 'load', handleLoad);
1604    } else {
1605        handleReady();
1606        handleLoad();
1607    }
1608
1609    YUI.Env.add = add;
1610    YUI.Env.remove = remove;
1611
1612    /*global exports*/
1613    // Support the CommonJS method for exporting our single global
1614    if (typeof exports == 'object') {
1615        exports.YUI = YUI;
1616        /**
1617        * Set a method to be called when `Get.script` is called in Node.js
1618        * `Get` will open the file, then pass it's content and it's path
1619        * to this method before attaching it. Commonly used for code coverage
1620        * instrumentation. <strong>Calling this multiple times will only
1621        * attach the last hook method</strong>. This method is only
1622        * available in Node.js.
1623        * @method setLoadHook
1624        * @static
1625        * @param {Function} fn The function to set
1626        * @param {String} fn.data The content of the file
1627        * @param {String} fn.path The file path of the file
1628        */
1629        YUI.setLoadHook = function(fn) {
1630            YUI._getLoadHook = fn;
1631        };
1632        /**
1633        * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook`
1634        * @method _getLoadHook
1635        * @private
1636        * @param {String} data The content of the file
1637        * @param {String} path The file path of the file
1638        */
1639        YUI._getLoadHook = null;
1640    }
1641
1642    YUI.Env[VERSION] = {};
1643}());
1644
1645
1646/**
1647Config object that contains all of the configuration options for
1648this `YUI` instance.
1649
1650This object is supplied by the implementer when instantiating YUI. Some
1651properties have default values if they are not supplied by the implementer.
1652
1653This object should not be updated directly because some values are cached. Use
1654`applyConfig()` to update the config object on a YUI instance that has already
1655been configured.
1656
1657@class config
1658@static
1659**/
1660
1661/**
1662If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata
1663if they're needed to load additional dependencies and aren't already available.
1664
1665Setting this to `false` will prevent YUI from automatically loading the Loader
1666and module metadata, so you will need to manually ensure that they're available
1667or handle dependency resolution yourself.
1668
1669@property {Boolean} bootstrap
1670@default true
1671**/
1672
1673/**
1674
1675@property {Object} filters
1676**/
1677
1678/**
1679If `true`, YUI will use a combo handler to load multiple modules in as few
1680requests as possible.
1681
1682The YUI CDN (which YUI uses by default) supports combo handling, but other
1683servers may not. If the server from which you're loading YUI does not support
1684combo handling, set this to `false`.
1685
1686Providing a value for the `base` config property will cause `combine` to default
1687to `false` instead of `true`.
1688
1689@property {Boolean} combine
1690@default true
1691*/
1692
1693/**
1694Array of module names that should never be dynamically loaded.
1695
1696@property {String[]} ignore
1697**/
1698
1699/**
1700Array of module names that should always be loaded when required, even if
1701already present on the page.
1702
1703@property {String[]} force
1704**/
1705
1706/**
1707DOM element or id that should be used as the insertion point for dynamically
1708added `<script>` and `<link>` nodes.
1709
1710@property {HTMLElement|String} insertBefore
1711**/
1712
1713/**
1714Object hash containing attributes to add to dynamically added `<script>` nodes.
1715
1716@property {Object} jsAttributes
1717**/
1718
1719/**
1720Object hash containing attributes to add to dynamically added `<link>` nodes.
1721
1722@property {Object} cssAttributes
1723**/
1724
1725/**
1726Timeout in milliseconds before a dynamic JS or CSS request will be considered a
1727failure. If not set, no timeout will be enforced.
1728
1729@property {Number} timeout
1730**/
1731
1732/**
1733A hash of module definitions to add to the list of available YUI modules. These
1734modules can then be dynamically loaded via the `use()` method.
1735
1736This is a hash in which keys are module names and values are objects containing
1737module metadata.
1738
1739See `Loader.addModule()` for the supported module metadata fields. Also see
1740`groups`, which provides a way to configure the base and combo spec for a set of
1741modules.
1742
1743@example
1744
1745    modules: {
1746        mymod1: {
1747            requires: ['node'],
1748            fullpath: '/mymod1/mymod1.js'
1749        },
1750
1751        mymod2: {
1752            requires: ['mymod1'],
1753            fullpath: '/mymod2/mymod2.js'
1754        },
1755
1756        mymod3: '/js/mymod3.js',
1757        mycssmod: '/css/mycssmod.css'
1758    }
1759
1760@property {Object} modules
1761**/
1762
1763/**
1764Aliases are dynamic groups of modules that can be used as shortcuts.
1765
1766@example
1767
1768    YUI({
1769        aliases: {
1770            davglass: [ 'node', 'yql', 'dd' ],
1771            mine: [ 'davglass', 'autocomplete']
1772        }
1773    }).use('mine', function (Y) {
1774        // Node, YQL, DD & AutoComplete available here.
1775    });
1776
1777@property {Object} aliases
1778**/
1779
1780/**
1781A hash of module group definitions.
1782
1783For each group you can specify a list of modules and the base path and
1784combo spec to use when dynamically loading the modules.
1785
1786@example
1787
1788    groups: {
1789        yui2: {
1790            // specify whether or not this group has a combo service
1791            combine: true,
1792
1793            // The comboSeperator to use with this group's combo handler
1794            comboSep: ';',
1795
1796            // The maxURLLength for this server
1797            maxURLLength: 500,
1798
1799            // the base path for non-combo paths
1800            base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1801
1802            // the path to the combo service
1803            comboBase: 'http://yui.yahooapis.com/combo?',
1804
1805            // a fragment to prepend to the path attribute when
1806            // when building combo urls
1807            root: '2.8.0r4/build/',
1808
1809            // the module definitions
1810            modules:  {
1811                yui2_yde: {
1812                    path: "yahoo-dom-event/yahoo-dom-event.js"
1813                },
1814                yui2_anim: {
1815                    path: "animation/animation.js",
1816                    requires: ['yui2_yde']
1817                }
1818            }
1819        }
1820    }
1821
1822@property {Object} groups
1823**/
1824
1825/**
1826Path to the Loader JS file, relative to the `base` path.
1827
1828This is used to dynamically bootstrap the Loader when it's needed and isn't yet
1829available.
1830
1831@property {String} loaderPath
1832@default "loader/loader-min.js"
1833**/
1834
1835/**
1836If `true`, YUI will attempt to load CSS dependencies and skins. Set this to
1837`false` to prevent YUI from loading any CSS, or set it to the string `"force"`
1838to force CSS dependencies to be loaded even if their associated JS modules are
1839already loaded.
1840
1841@property {Boolean|String} fetchCSS
1842@default true
1843**/
1844
1845/**
1846Default gallery version used to build gallery module urls.
1847
1848@property {String} gallery
1849@since 3.1.0
1850**/
1851
1852/**
1853Default YUI 2 version used to build YUI 2 module urls.
1854
1855This is used for intrinsic YUI 2 support via the 2in3 project. Also see the
1856`2in3` config for pulling different revisions of the wrapped YUI 2 modules.
1857
1858@property {String} yui2
1859@default "2.9.0"
1860@since 3.1.0
1861**/
1862
1863/**
1864Revision number of YUI 2in3 modules that should be used when loading YUI 2in3.
1865
1866@property {String} 2in3
1867@default "4"
1868@since 3.1.0
1869**/
1870
1871/**
1872Alternate console log function that should be used in environments without a
1873supported native console. This function is executed with the YUI instance as its
1874`this` object.
1875
1876@property {Function} logFn
1877@since 3.1.0
1878**/
1879
1880/**
1881The minimum log level to log messages for. Log levels are defined
1882incrementally. Messages greater than or equal to the level specified will
1883be shown. All others will be discarded. The order of log levels in
1884increasing priority is:
1885
1886    debug
1887    info
1888    warn
1889    error
1890
1891@property {String} logLevel
1892@default 'debug'
1893@since 3.10.0
1894**/
1895
1896/**
1897Callback to execute when `Y.error()` is called. It receives the error message
1898and a JavaScript error object if one was provided.
1899
1900This function is executed with the YUI instance as its `this` object.
1901
1902Returning `true` from this function will prevent an exception from being thrown.
1903
1904@property {Function} errorFn
1905@param {String} errorFn.msg Error message
1906@param {Object} [errorFn.err] Error object (if one was provided).
1907@since 3.2.0
1908**/
1909
1910/**
1911A callback to execute when Loader fails to load one or more resources.
1912
1913This could be because of a script load failure. It could also be because a
1914module fails to register itself when the `requireRegistration` config is `true`.
1915
1916If this function is defined, the `use()` callback will only be called when the
1917loader succeeds. Otherwise, `use()` will always executes unless there was a
1918JavaScript error when attaching a module.
1919
1920@property {Function} loadErrorFn
1921@since 3.3.0
1922**/
1923
1924/**
1925If `true`, Loader will expect all loaded scripts to be first-class YUI modules
1926that register themselves with the YUI global, and will trigger a failure if a
1927loaded script does not register a YUI module.
1928
1929@property {Boolean} requireRegistration
1930@default false
1931@since 3.3.0
1932**/
1933
1934/**
1935Cache serviced use() requests.
1936
1937@property {Boolean} cacheUse
1938@default true
1939@since 3.3.0
1940@deprecated No longer used.
1941**/
1942
1943/**
1944Whether or not YUI should use native ES5 functionality when available for
1945features like `Y.Array.each()`, `Y.Object()`, etc.
1946
1947When `false`, YUI will always use its own fallback implementations instead of
1948relying on ES5 functionality, even when ES5 functionality is available.
1949
1950@property {Boolean} useNativeES5
1951@default true
1952@since 3.5.0
1953**/
1954
1955/**
1956 * Leverage native JSON stringify if the browser has a native
1957 * implementation.  In general, this is a good idea.  See the Known Issues
1958 * section in the JSON user guide for caveats.  The default value is true
1959 * for browsers with native JSON support.
1960 *
1961 * @property useNativeJSONStringify
1962 * @type Boolean
1963 * @default true
1964 * @since 3.8.0
1965 */
1966
1967 /**
1968 * Leverage native JSON parse if the browser has a native implementation.
1969 * In general, this is a good idea.  See the Known Issues section in the
1970 * JSON user guide for caveats.  The default value is true for browsers with
1971 * native JSON support.
1972 *
1973 * @property useNativeJSONParse
1974 * @type Boolean
1975 * @default true
1976 * @since 3.8.0
1977 */
1978
1979/**
1980Delay the `use` callback until a specific event has passed (`load`, `domready`, `contentready` or `available`)
1981
1982@property {Object|String} delayUntil
1983@since 3.6.0
1984@example
1985
1986You can use `load` or `domready` strings by default:
1987
1988    YUI({
1989        delayUntil: 'domready'
1990    }, function (Y) {
1991        // This will not execute until 'domeready' occurs.
1992    });
1993
1994Or you can delay until a node is available (with `available` or `contentready`):
1995
1996    YUI({
1997        delayUntil: {
1998            event: 'available',
1999            args : '#foo'
2000        }
2001    }, function (Y) {
2002        // This will not execute until a node matching the selector "#foo" is
2003        // available in the DOM.
2004    });
2005
2006**/
2007YUI.add('yui-base', function (Y, NAME) {
2008
2009/*
2010 * YUI stub
2011 * @module yui
2012 * @submodule yui-base
2013 */
2014/**
2015 * The YUI module contains the components required for building the YUI
2016 * seed file.  This includes the script loading mechanism, a simple queue,
2017 * and the core utilities for the library.
2018 * @module yui
2019 * @submodule yui-base
2020 */
2021
2022/**
2023 * Provides core language utilites and extensions used throughout YUI.
2024 *
2025 * @class Lang
2026 * @static
2027 */
2028
2029var L = Y.Lang || (Y.Lang = {}),
2030
2031STRING_PROTO = String.prototype,
2032TOSTRING     = Object.prototype.toString,
2033
2034TYPES = {
2035    'undefined'        : 'undefined',
2036    'number'           : 'number',
2037    'boolean'          : 'boolean',
2038    'string'           : 'string',
2039    '[object Function]': 'function',
2040    '[object RegExp]'  : 'regexp',
2041    '[object Array]'   : 'array',
2042    '[object Date]'    : 'date',
2043    '[object Error]'   : 'error'
2044},
2045
2046SUBREGEX         = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
2047
2048WHITESPACE       = "\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",
2049WHITESPACE_CLASS = "[\x09-\x0D\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+",
2050TRIM_LEFT_REGEX  = new RegExp("^" + WHITESPACE_CLASS),
2051TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"),
2052TRIMREGEX        = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"),
2053
2054NATIVE_FN_REGEX  = /\{\s*\[(?:native code|function)\]\s*\}/i;
2055
2056// -- Protected Methods --------------------------------------------------------
2057
2058/**
2059Returns `true` if the given function appears to be implemented in native code,
2060`false` otherwise. Will always return `false` -- even in ES5-capable browsers --
2061if the `useNativeES5` YUI config option is set to `false`.
2062
2063This isn't guaranteed to be 100% accurate and won't work for anything other than
2064functions, but it can be useful for determining whether a function like
2065`Array.prototype.forEach` is native or a JS shim provided by another library.
2066
2067There's a great article by @kangax discussing certain flaws with this technique:
2068<http://perfectionkills.com/detecting-built-in-host-methods/>
2069
2070While his points are valid, it's still possible to benefit from this function
2071as long as it's used carefully and sparingly, and in such a way that false
2072negatives have minimal consequences. It's used internally to avoid using
2073potentially broken non-native ES5 shims that have been added to the page b
2073y
2074other libraries.
2075
2076@method _isNative
2077@param {Function} fn Function to test.
2078@return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
2079@static
2080@protected
2081@since 3.5.0
2082**/
2083L._isNative = function (fn) {
2084    return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
2085};
2086
2087// -- Public Methods -----------------------------------------------------------
2088
2089/**
2090 * Determines whether or not the provided item is an array.
2091 *
2092 * Returns `false` for array-like collections such as the function `arguments`
2093 * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
2094 * test for an array-like collection.
2095 *
2096 * @method isArray
2097 * @param o The object to test.
2098 * @return {boolean} true if o is an array.
2099 * @static
2100 */
2101L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
2102    return L.type(o) === 'array';
2103};
2104
2105/**
2106 * Determines whether or not the provided item is a boolean.
2107 * @method isBoolean
2108 * @static
2109 * @param o The object to test.
2110 * @return {boolean} true if o is a boolean.
2111 */
2112L.isBoolean = function(o) {
2113    return typeof o === 'boolean';
2114};
2115
2116/**
2117 * Determines whether or not the supplied item is a date instance.
2118 * @method isDate
2119 * @static
2120 * @param o The object to test.
2121 * @return {boolean} true if o is a date.
2122 */
2123L.isDate = function(o) {
2124    return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
2125};
2126
2127/**
2128 * <p>
2129 * Determines whether or not the provided item is a function.
2130 * Note: Internet Explorer thinks certain functions are objects:
2131 * </p>
2132 *
2133 * <pre>
2134 * var obj = document.createElement("object");
2135 * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
2136 * &nbsp;
2137 * var input = document.createElement("input"); // append to body
2138 * Y.Lang.isFunction(input.focus) // reports false in IE
2139 * </pre>
2140 *
2141 * <p>
2142 * You will have to implement additional tests if these functions
2143 * matter to you.
2144 * </p>
2145 *
2146 * @method isFunction
2147 * @static
2148 * @param o The object to test.
2149 * @return {boolean} true if o is a function.
2150 */
2151L.isFunction = function(o) {
2152    return L.type(o) === 'function';
2153};
2154
2155/**
2156 * Determines whether or not the provided item is null.
2157 * @method isNull
2158 * @static
2159 * @param o The object to test.
2160 * @return {boolean} true if o is null.
2161 */
2162L.isNull = function(o) {
2163    return o === null;
2164};
2165
2166/**
2167 * Determines whether or not the provided item is a legal number.
2168 * @method isNumber
2169 * @static
2170 * @param o The object to test.
2171 * @return {boolean} true if o is a number.
2172 */
2173L.isNumber = function(o) {
2174    return typeof o === 'number' && isFinite(o);
2175};
2176
2177/**
2178 * Determines whether or not the provided item is of type object
2179 * or function. Note that arrays are also objects, so
2180 * <code>Y.Lang.isObject([]) === true</code>.
2181 * @method isObject
2182 * @static
2183 * @param o The object to test.
2184 * @param failfn {boolean} fail if the input is a function.
2185 * @return {boolean} true if o is an object.
2186 * @see isPlainObject
2187 */
2188L.isObject = function(o, failfn) {
2189    var t = typeof o;
2190    return (o && (t === 'object' ||
2191        (!failfn && (t === 'function' || L.isFunction(o))))) || false;
2192};
2193
2194/**
2195 * Determines whether or not the provided value is a regexp.
2196 * @method isRegExp
2197 * @static
2198 * @param value The value or object to test.
2199 * @return {boolean} true if value is a regexp.
2200 */
2201L.isRegExp = function(value) {
2202    return L.type(value) === 'regexp';
2203};
2204
2205/**
2206 * Determines whether or not the provided item is a string.
2207 * @method isString
2208 * @static
2209 * @param o The object to test.
2210 * @return {boolean} true if o is a string.
2211 */
2212L.isString = function(o) {
2213    return typeof o === 'string';
2214};
2215
2216/**
2217 * Determines whether or not the provided item is undefined.
2218 * @method isUndefined
2219 * @static
2220 * @param o The object to test.
2221 * @return {boolean} true if o is undefined.
2222 */
2223L.isUndefined = function(o) {
2224    return typeof o === 'undefined';
2225};
2226
2227/**
2228 * A convenience method for detecting a legitimate non-null value.
2229 * Returns false for null/undefined/NaN, true for other values,
2230 * including 0/false/''
2231 * @method isValue
2232 * @static
2233 * @param o The item to test.
2234 * @return {boolean} true if it is not null/undefined/NaN || false.
2235 */
2236L.isValue = function(o) {
2237    var t = L.type(o);
2238
2239    switch (t) {
2240        case 'number':
2241            return isFinite(o);
2242
2243        case 'null': // fallthru
2244        case 'undefined':
2245            return false;
2246
2247        default:
2248            return !!t;
2249    }
2250};
2251
2252/**
2253 * Returns the current time in milliseconds.
2254 *
2255 * @method now
2256 * @return {Number} Current time in milliseconds.
2257 * @static
2258 * @since 3.3.0
2259 */
2260L.now = Date.now || function () {
2261    return new Date().getTime();
2262};
2263
2264/**
2265 * Performs `{placeholder}` substitution on a string. The object passed as the
2266 * second parameter provides values to replace the `{placeholder}`s.
2267 * `{placeholder}` token names must match property names of the object. For example,
2268 *
2269 *`var greeting = Y.Lang.sub("Hello, {who}!", { who: "World" });`
2270 *
2271 * `{placeholder}` tokens that are undefined on the object map will be left
2272 * in tact (leaving unsightly `{placeholder}`'s in the output string).
2273 *
2274 * @method sub
2275 * @param {string} s String to be modified.
2276 * @param {object} o Object containing replacement values.
2277 * @return {string} the substitute result.
2278 * @static
2279 * @since 3.2.0
2280 */
2281L.sub = function(s, o) {
2282
2283    /**
2284    Finds the value of `key` in given object.
2285    If the key has a 'dot' notation e.g. 'foo.bar.baz', the function will
2286    try to resolve this path if it doesn't exist as a property
2287    @example
2288        value({ 'a.b': 1, a: { b: 2 } }, 'a.b'); // 1
2289        value({ a: { b: 2 } }          , 'a.b'); // 2
2290    @param {Object} obj A key/value pairs object
2291    @param {String} key
2292    @return {Any}
2293    @private
2294    **/
2295    function value(obj, key) {
2296
2297        var subkey;
2298
2299        if ( typeof obj[key] !== 'undefined' ) {
2300            return obj[key];
2301        }
2302
2303        key    = key.split('.');         // given 'a.b.c'
2304        subkey = key.slice(1).join('.'); // 'b.c'
2305        key    = key[0];                 // 'a'
2306
2307        // special case for null as typeof returns object and we don't want that.
2308        if ( subkey && typeof obj[key] === 'object' && obj[key] !== null ) {
2309            return value(obj[key], subkey);
2310        }
2311    }
2312
2313    return s.replace ? s.replace(SUBREGEX, function (match, key) {
2314        var val = key.indexOf('.')>-1 ? value(o, key) : o[key];
2315        return typeof val === 'undefined' ? match : val;
2316    }) : s;
2317};
2318
2319/**
2320 * Returns a string without any leading or trailing whitespace.  If
2321 * the input is not a string, the input will be returned untouched.
2322 * @method trim
2323 * @static
2324 * @param s {string} the string to trim.
2325 * @return {string} the trimmed string.
2326 */
2327L.trim = L._isNative(STRING_PROTO.trim) && !WHITESPACE.trim() ? function(s) {
2328    return s && s.trim ? s.trim() : s;
2329} : function (s) {
2330    try {
2331        return s.replace(TRIMREGEX, '');
2332    } catch (e) {
2333        return s;
2334    }
2335};
2336
2337/**
2338 * Returns a string without any leading whitespace.
2339 * @method trimLeft
2340 * @static
2341 * @param s {string} the string to trim.
2342 * @return {string} the trimmed string.
2343 */
2344L.trimLeft = L._isNative(STRING_PROTO.trimLeft) && !WHITESPACE.trimLeft() ? function (s) {
2345    return s.trimLeft();
2346} : function (s) {
2347    return s.replace(TRIM_LEFT_REGEX, '');
2348};
2349
2350/**
2351 * Returns a string without any trailing whitespace.
2352 * @method trimRight
2353 * @static
2354 * @param s {string} the string to trim.
2355 * @return {string} the trimmed string.
2356 */
2357L.trimRight = L._isNative(STRING_PROTO.trimRight) && !WHITESPACE.trimRight() ? function (s) {
2358    return s.trimRight();
2359} : function (s) {
2360    return s.replace(TRIM_RIGHT_REGEX, '');
2361};
2362
2363/**
2364Returns one of the following strings, representing the type of the item passed
2365in:
2366
2367 * "array"
2368 * "boolean"
2369 * "date"
2370 * "error"
2371 * "function"
2372 * "null"
2373 * "number"
2374 * "object"
2375 * "regexp"
2376 * "string"
2377 * "undefined"
2378
2379Known issues:
2380
2381 * `typeof HTMLElementCollection` returns function in Safari, but
2382    `Y.Lang.type()` reports "object", which could be a good thing --
2383    but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
2384
2385@method type
2386@param o the item to test.
2387@return {string} the detected type.
2388@static
2389**/
2390L.type = function(o) {
2391    return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
2392};
2393/**
2394@module yui
2395@submodule yui-base
2396*/
2397
2398var Lang   = Y.Lang,
2399    Native = Array.prototype,
2400
2401    hasOwn = Object.prototype.hasOwnProperty;
2402
2403/**
2404Provides utility methods for working with arrays. Additional array helpers can
2405be found in the `collection` and `array-extras` modules.
2406
2407`Y.Array(thing)` returns a native array created from _thing_. Depending on
2408_thing_'s type, one of the following will happen:
2409
2410  * Arrays are returned unmodified unless a non-zero _startIndex_ is
2411    specified.
2412  * Array-like collections (see `Array.test()`) are converted to arrays.
2413  * For everything else, a new array is created with _thing_ as the sole
2414    item.
2415
2416Note: elements that are also collections, such as `<form>` and `<select>`
2417elements, are not automatically converted to arrays. To force a conversion,
2418pass `true` as the value of the _force_ parameter.
2419
2420@class Array
2421@constructor
2422@param {Any} thing The thing to arrayify.
2423@param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2424  collection, a subset of items starting at the specified index will be
2425  returned.
2426@param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2427  array-like collection no matter what.
2428@return {Array} A native array created from _thing_, according to the rules
2429  described above.
2430**/
2431function YArray(thing, startIndex, force) {
2432    var len, result;
2433
2434    /*jshint expr: true*/
2435    startIndex || (startIndex = 0);
2436
2437    if (force || YArray.test(thing)) {
2438        // IE throws when trying to slice HTMLElement collections.
2439        try {
2440            return Native.slice.call(thing, startIndex);
2441        } catch (ex) {
2442            result = [];
2443
2444            for (len = thing.length; startIndex < len; ++startIndex) {
2445                result.push(thing[startIndex]);
2446            }
2447
2448            return result;
2449        }
2450    }
2451
2452    return [thing];
2453}
2454
2455Y.Array = YArray;
2456
2457/**
2458Dedupes an array of strings, returning an array that's guaranteed to contain
2459only one copy of a given string.
2460
2461This method differs from `Array.unique()` in that it's optimized for use only
2462with arrays consisting entirely of strings or entirely of numbers, whereas
2463`unique` may be used with other value types (but is slower).
2464
2465Using `dedupe()` with values other than strings or numbers, or with arrays
2466containing a mix of strings and numbers, may result in unexpected behavior.
2467
2468@method dedupe
2469@param {String[]|Number[]} array Array of strings or numbers to dedupe.
2470@return {Array} Copy of _array_ containing no duplicate values.
2471@static
2472@since 3.4.0
2473**/
2474YArray.dedupe = Lang._isNative(Object.create) ? function (array) {
2475    var hash    = Object.create(null),
2476        results = [],
2477        i, item, len;
2478
2479    for (i = 0, len = array.length; i < len; ++i) {
2480        item = array[i];
2481
2482        if (!hash[item]) {
2483            hash[item] = 1;
2484            results.push(item);
2485        }
2486    }
2487
2488    return results;
2489} : function (array) {
2490    var hash    = {},
2491        results = [],
2492        i, item, len;
2493
2494    for (i = 0, len = array.length; i < len; ++i) {
2495        item = array[i];
2496
2497        if (!hasOwn.call(hash, item)) {
2498            hash[item] = 1;
2499            results.push(item);
2500        }
2501    }
2502
2503    return results;
2504};
2505
2506/**
2507Executes the supplied function on each item in the array. This method wraps
2508the native ES5 `Array.forEach()` method if available.
2509
2510@method each
2511@param {Array} array Array to iterate.
2512@param {Function} fn Function to execute on each item in the array. The function
2513  will receive the following arguments:
2514    @param {Any} fn.item Current array item.
2515    @param {Number} fn.index Current array index.
2516    @param {Array} fn.array Array being iterated.
2517@param {Object} [thisObj] `this` object to use when calling _fn_.
2518@return {YUI} The YUI instance.
2519@static
2520**/
2521YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
2522    Native.forEach.call(array || [], fn, thisObj || Y);
2523    return Y;
2524} : function (array, fn, thisObj) {
2525    for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2526        if (i in array) {
2527            fn.call(thisObj || Y, array[i], i, array);
2528        }
2529    }
2530
2531    return Y;
2532};
2533
2534/**
2535Alias for `each()`.
2536
2537@method forEach
2538@static
2539**/
2540
2541/**
2542Returns an object using the first array as keys and the second as values. If
2543the second array is not provided, or if it doesn't contain the same number of
2544values as the first array, then `true` will be used in place of the missing
2545values.
2546
2547@example
2548
2549    Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2550    // => {a: 'foo', b: 'bar', c: true}
2551
2552@method hash
2553@param {String[]} keys Array of strings to use as keys.
2554@param {Array} [values] Array to use as values.
2555@return {Object} Hash using the first array as keys and the second as values.
2556@static
2557**/
2558YArray.hash = function (keys, values) {
2559    var hash = {},
2560        vlen = (values && values.length) || 0,
2561        i, len;
2562
2563    for (i = 0, len = keys.length; i < len; ++i) {
2564        if (i in keys) {
2565            hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2566        }
2567    }
2568
2569    return hash;
2570};
2571
2572/**
2573Returns the index of the first item in the array that's equal (using a strict
2574equality check) to the specified _value_, or `-1` if the value isn't found.
2575
2576This method wraps the native ES5 `Array.indexOf()` method if available.
2577
2578@method indexOf
2579@param {Array} array Array to search.
2580@param {Any} value Value to search for.
2581@param {Number} [from=0] The index at which to begin the search.
2582@return {Number} Index of the item strictly equal to _value_, or `-1` if not
2583    found.
2584@static
2585**/
2586YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
2587    return Native.indexOf.call(array, value, from);
2588} : function (array, value, from) {
2589    // http://es5.github.com/#x15.4.4.14
2590    var len = array.length;
2591
2592    from = +from || 0;
2593    from = (from > 0 || -1) * Math.floor(Math.abs(from));
2594
2595    if (from < 0) {
2596        from += len;
2597
2598        if (from < 0) {
2599            from = 0;
2600        }
2601    }
2602
2603    for (; from < len; ++from) {
2604        if (from in array && array[from] === value) {
2605            return from;
2606        }
2607    }
2608
2609    return -1;
2610};
2611
2612/**
2613Numeric sort convenience function.
2614
2615The native `Array.prototype.sort()` function converts values to strings and
2616sorts them in lexicographic order, which is unsuitable for sorting numeric
2617values. Provide `Array.numericSort` as a custom sort function when you want
2618to sort values in numeric order.
2619
2620@example
2621
2622    [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2623    // => [4, 8, 15, 16, 23, 42]
2624
2625@method numericSort
2626@param {Number} a First value to compare.
2627@param {Number} b Second value to compare.
2628@return {Number} Difference between _a_ and _b_.
2629@static
2630**/
2631YArray.numericSort = function (a, b) {
2632    return a - b;
2633};
2634
2635/**
2636Executes the supplied function on each item in the array. Returning a truthy
2637value from the function will stop the processing of remaining items.
2638
2639@method some
2640@param {Array} array Array to iterate over.
2641@param {Function} fn Function to execute on each item. The function will receive
2642  the following arguments:
2643    @param {Any} fn.value Current array item.
2644    @param {Number} fn.index Current array index.
2645    @param {Array} fn.array Array being iterated over.
2646@param {Object} [thisObj] `this` object to use when calling _fn_.
2647@return {Boolean} `true` if the function returns a truthy value on any of the
2648  items in the array; `false` otherwise.
2649@static
2650**/
2651YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
2652    return Native.some.call(array, fn, thisObj);
2653} : function (array, fn, thisObj) {
2654    for (var i = 0, len = array.length; i < len; ++i) {
2655        if (i in array && fn.call(thisObj, array[i], i, array)) {
2656            return true;
2657        }
2658    }
2659
2660    return false;
2661};
2662
2663/**
2664Evaluates _obj_ to determine if it's an array, an array-like collection, or
2665something else. This is useful when working with the function `arguments`
2666collection and `HTMLElement` collections.
2667
2668Note: This implementation doesn't consider elements that are also
2669collections, such as `<form>` and `<select>`, to be array-like.
2670
2671@method test
2672@param {Object} obj Object to test.
2673@return {Number} A number indicating the results of the test:
2674
2675  * 0: Neither an array nor an array-like collection.
2676  * 1: Real array.
2677  * 2: Array-like collection.
2678
2679@static
2680**/
2681YArray.test = function (obj) {
2682    var result = 0;
2683
2684    if (Lang.isArray(obj)) {
2685        result = 1;
2686    } else if (Lang.isObject(obj)) {
2687        try {
2688            // indexed, but no tagName (element) or scrollTo/document (window. From DOM.isWindow test which we can't use here),
2689            // or functions without apply/call (Safari
2690            // HTMLElementCollection bug).
2691            if ('length' in obj && !obj.tagName && !(obj.scrollTo && obj.document) && !obj.apply) {
2692                result = 2;
2693            }
2694        } catch (ex) {}
2695    }
2696
2697    return result;
2698};
2699/**
2700 * The YUI module contains the components required for building the YUI
2701 * seed file.  This includes the script loading mechanism, a simple queue,
2702 * and the core utilities for the library.
2703 * @module yui
2704 * @submodule yui-base
2705 */
2706
2707/**
2708 * A simple FIFO queue.  Items are added to the Queue with add(1..n items) and
2709 * removed using next().
2710 *
2711 * @class Queue
2712 * @constructor
2713 * @param {MIXED} item* 0..n items to seed the queue.
2714 */
2715function Queue() {
2716    this._init();
2717    this.add.apply(this, arguments);
2718}
2719
2720Queue.prototype = {
2721    /**
2722     * Initialize the queue
2723     *
2724     * @method _init
2725     * @protected
2726     */
2727    _init: function() {
2728        /**
2729         * The collection of enqueued items
2730         *
2731         * @property _q
2732         * @type Array
2733         * @protected
2734         */
2735        this._q = [];
2736    },
2737
2738    /**
2739     * Get the next item in the queue. FIFO support
2740     *
2741     * @method next
2742     * @return {MIXED} the next item in the queue.
2743     */
2744    next: function() {
2745        return this._q.shift();
2746    },
2747
2748    /**
2749     * Get the last in the queue. LIFO support.
2750     *
2751     * @method last
2752     * @return {MIXED} the last item in the queue.
2753     */
2754    last: function() {
2755        return this._q.pop();
2756    },
2757
2758    /**
2759     * Add 0..n items to the end of the queue.
2760     *
2761     * @method add
2762     * @param {MIXED} item* 0..n items.
2763     * @return {object} this queue.
2764     */
2765    add: function() {
2766        this._q.push.apply(this._q, arguments);
2767
2768        return this;
2769    },
2770
2771    /**
2772     * Returns the current number of queued items.
2773     *
2774     * @method size
2775     * @return {Number} The size.
2776     */
2777    size: function() {
2778        return this._q.length;
2779    }
2780};
2781
2782Y.Queue = Queue;
2783
2784YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2785
2786/**
2787The YUI module contains the components required for building the YUI seed file.
2788This includes the script loading mechanism, a simple queue, and the core
2789utilities for the library.
2790
2791@module yui
2792@submodule yui-base
2793**/
2794
2795var CACHED_DELIMITER = '__',
2796
2797    hasOwn   = Object.prototype.hasOwnProperty,
2798    isObject = Y.Lang.isObject;
2799
2800/**
2801Returns a wrapper for a function which caches the return value of that function,
2802keyed off of the combined string representation of the argument values provided
2803when the wrapper is called.
2804
2805Calling this function again with the same arguments will return the cached value
2806rather than executing the wrapped function.
2807
2808Note that since the cache is keyed off of the string representation of arguments
2809passed to the wrapper function, arguments that aren't strings and don't provide
2810a meaningful `toString()` method may result in unexpected caching behavior. For
2811example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2812string `[object Object]` when used as a cache key.
2813
2814@method cached
2815@param {Function} source The function to memoize.
2816@param {Object} [cache={}] Object in which to store cached values. You may seed
2817  this object with pre-existing cached values if desired.
2818@param {any} [refetch] If supplied, this value is compared with the cached value
2819  using a `==` comparison. If the values are equal, the wrapped function is
2820  executed again even though a cached value exists.
2821@return {Function} Wrapped function.
2822@for YUI
2823**/
2824Y.cached = function (source, cache, refetch) {
2825    /*jshint expr: true*/
2826    cache || (cache = {});
2827
2828    return function (arg) {
2829        var key = arguments.length > 1 ?
2830                Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2831                String(arg);
2832
2833        /*jshint eqeqeq: false*/
2834        if (!(key in cache) || (refetch && cache[key] == refetch)) {
2835            cache[key] = source.apply(source, arguments);
2836        }
2837
2838        return cache[key];
2839    };
2840};
2841
2842/**
2843Returns the `location` object from the window/frame in which this YUI instance
2844operates, or `undefined` when executing in a non-browser environment
2845(e.g. Node.js).
2846
2847It is _not_ recommended to hold references to the `window.location` object
2848outside of the scope of a function in which its properties are being accessed or
2849its methods are being called. This is because of a nasty bug/issue that exists
2850in both Safari and MobileSafari browsers:
2851[WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
2852
2853@method getLocation
2854@return {location} The `location` object from the window/frame in which this YUI
2855    instance operates.
2856@since 3.5.0
2857**/
2858Y.getLocation = function () {
2859    // It is safer to look this up every time because yui-base is attached to a
2860    // YUI instance before a user's config is applied; i.e. `Y.config.win` does
2861    // not point the correct window object when this file is loaded.
2862    var win = Y.config.win;
2863
2864    // It is not safe to hold a reference to the `location` object outside the
2865    // scope in which it is being used. The WebKit engine used in Safari and
2866    // MobileSafari will "disconnect" the `location` object from the `window`
2867    // when a page is restored from back/forward history cache.
2868    return win && win.location;
2869};
2870
2871/**
2872Returns a new object containing all of the properties of all the supplied
2873objects. The properties from later objects will overwrite those in earlier
2874objects.
2875
2876Passing in a single object will create a shallow copy of it. For a deep copy,
2877use `clone()`.
2878
2879@method merge
2880@param {Object} objects* One or more objects to merge.
2881@return {Object} A new merged object.
2882**/
2883Y.merge = function () {
2884    var i      = 0,
2885        len    = arguments.length,
2886        result = {},
2887        key,
2888        obj;
2889
2890    for (; i < len; ++i) {
2891        obj = arguments[i];
2892
2893        for (key in obj) {
2894            if (hasOwn.call(obj, key)) {
2895                result[key] = obj[key];
2896            }
2897        }
2898    }
2899
2900    return result;
2901};
2902
2903/**
2904Mixes _supplier_'s properties into _receiver_.
2905
2906Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
2907shadowed unless the _overwrite_ parameter is `true`, and will not be merged
2908unless the _merge_ parameter is `true`.
2909
2910In the default mode (0), only properties the supplier owns are copied (prototype
2911properties are not copied). The following copying modes are available:
2912
2913  * `0`: _Default_. Object to object.
2914  * `1`: Prototype to prototype.
2915  * `2`: Prototype to prototype and object to object.
2916  * `3`: Prototype to object.
2917  * `4`: Object to prototype.
2918
2919@method mix
2920@param {Function|Object} receiver The object or function to receive the mixed
2921  properties.
2922@param {Function|Object} supplier The object or function supplying the
2923  properties to be mixed.
2924@param {Boolean} [overwrite=false] If `true`, properties that already exist
2925  on the receiver will be overwritten with properties from the supplier.
2926@param {String[]} [whitelist] An array of property names to copy. If
2927  specified, only the whitelisted properties will be copied, and all others
2928  will be ignored.
2929@param {Number} [mode=0] Mix mode to use. See above for available modes.
2930@param {Boolean} [merge=false] If `true`, objects and arrays that already
2931  exist on the receiver will have the corresponding object/array from the
2932  supplier merged into them, rather than being skipped or overwritten. When
2933  both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2934@return {Function|Object|YUI} The receiver, or the YUI instance if the
2935  specified receiver is falsy.
2936**/
2937Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2938    var alwaysOverwrite, exists, from, i, key, len, to;
2939
2940    // If no supplier is given, we return the receiver. If no receiver is given,
2941    // we return Y. Returning Y doesn't make much sense to me, but it's
2942    // grandfathered in for backcompat reasons.
2943    if (!receiver || !supplier) {
2944        return receiver || Y;
2945    }
2946
2947    if (mode) {
2948        // In mode 2 (prototype to prototype and object to object), we recurse
2949        // once to do the proto to proto mix. The object to object mix will be
2950        // handled later on.
2951        if (mode === 2) {
2952            Y.mix(receiver.prototype, supplier.prototype, overwrite,
2953                    whitelist, 0, merge);
2954        }
2955
2956        // Depending on which mode is specified, we may be copying from or to
2957        // the prototypes of the supplier and receiver.
2958        from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2959        to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2960
2961        // If either the supplier or receiver doesn't actually have a
2962        // prototype property, then we could end up with an undefined `from`
2963        // or `to`. If that happens, we abort and return the receiver.
2964        if (!from || !to) {
2965            return receiver;
2966        }
2967    } else {
2968        from = supplier;
2969        to   = receiver;
2970    }
2971
2972    // If `overwrite` is truthy and `merge` is falsy, then we can skip a
2973    // property existence check on each iteration and save some time.
2974    alwaysOverwrite = overwrite && !merge;
2975
2976    if (whitelist) {
2977        for (i = 0, len = whitelist.length; i < len; ++i) {
2978            key = whitelist[i];
2979
2980            // We call `Object.prototype.hasOwnProperty` instead of calling
2981            // `hasOwnProperty` on the object itself, since the object's
2982            // `hasOwnProperty` method may have been overridden or removed.
2983            // Also, some native objects don't implement a `hasOwnProperty`
2984            // method.
2985            if (!hasOwn.call(from, key)) {
2986                continue;
2987            }
2988
2989            // The `key in to` check here is (sadly) intentional for backwards
2990            // compatibility reasons. It prevents undesired shadowing of
2991            // prototype members on `to`.
2992            exists = alwaysOverwrite ? false : key in to;
2993
2994            if (merge && exists && isObject(to[key], true)
2995                    && isObject(from[key], true)) {
2996                // If we're in merge mode, and the key is present on both
2997                // objects, and the value on both objects is either an object or
2998                // an array (but not a function), then we recurse to merge the
2999                // `from` value into the `to` value instead of overwriting it.
3000                //
3001                // Note: It's intentional that the whitelist isn't passed to the
3002                // recursive call here. This is legacy behavior that lots of
3003                // code still depends on.
3004                Y.mix(to[key], from[key], overwrite, null, 0, merge);
3005            } else if (overwrite || !exists) {
3006                // We're not in merge mode, so we'll only copy the `from` value
3007                // to the `to` value if we're in overwrite mode or if the
3008                // current key doesn't exist on the `to` object.
3009                to[key] = from[key];
3010            }
3011        }
3012    } else {
3013        for (key in from) {
3014            // The code duplication here is for runtime performance reasons.
3015            // Combining whitelist and non-whitelist operations into a single
3016            // loop or breaking the shared logic out into a function both result
3017            // in worse performance, and Y.mix is critical enough that the byte
3018            // tradeoff is worth it.
3019            if (!hasOwn.call(from, key)) {
3020                continue;
3021            }
3022
3023            // The `key in to` check here is (sadly) intentional for backwards
3024            // compatibility reasons. It prevents undesired shadowing of
3025            // prototype members on `to`.
3026            exists = alwaysOverwrite ? false : key in to;
3027
3028            if (merge && exists && isObject(to[key], true)
3029                    && isObject(from[key], true)) {
3030                Y.mix(to[key], from[key], overwrite, null, 0, merge);
3031            } else if (overwrite || !exists) {
3032                to[key] = from[key];
3033            }
3034        }
3035
3036        // If this is an IE browser with the JScript enumeration bug, force
3037        // enumeration of the buggy properties by making a recursive call with
3038        // the buggy properties as the whitelist.
3039        if (Y.Object._hasEnumBug) {
3040            Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
3041        }
3042    }
3043
3044    return receiver;
3045};
3046/**
3047 * The YUI module contains the components required for building the YUI
3048 * seed file.  This includes the script loading mechanism, a simple queue,
3049 * and the core utilities for the library.
3050 * @module yui
3051 * @submodule yui-base
3052 */
3053
3054/**
3055 * Adds utilities to the YUI instance for working with objects.
3056 *
3057 * @class Object
3058 */
3059
3060var Lang   = Y.Lang,
3061    hasOwn = Object.prototype.hasOwnProperty,
3062
3063    UNDEFINED, // <-- Note the comma. We're still declaring vars.
3064
3065/**
3066 * Returns a new object that uses _obj_ as its prototype. This method wraps the
3067 * native ES5 `Object.create()` method if available, but doesn't currently
3068 * pass through `Object.create()`'s second argument (properties) in order to
3069 * ensure compatibility with older browsers.
3070 *
3071 * @method ()
3072 * @param {Object} obj Prototype object.
3073 * @return {Object} New object using _obj_ as its prototype.
3074 * @static
3075 */
3076O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
3077    // We currently wrap the native Object.create instead of simply aliasing it
3078    // to ensure consistency with our fallback shim, which currently doesn't
3079    // support Object.create()'s second argument (properties). Once we have a
3080    // safe fallback for the properties arg, we can stop wrapping
3081    // Object.create().
3082    return Object.create(obj);
3083} : (function () {
3084    // Reusable constructor function for the Object.create() shim.
3085    function F() {}
3086
3087    // The actual shim.
3088    return function (obj) {
3089        F.prototype = obj;
3090        return new F();
3091    };
3092}()),
3093
3094/**
3095 * Property names that IE doesn't enumerate in for..in loops, even when they
3096 * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
3097 * manually enumerate these properties.
3098 *
3099 * @property _forceEnum
3100 * @type String[]
3101 * @protected
3102 * @static
3103 */
3104forceEnum = O._forceEnum = [
3105    'hasOwnProperty',
3106    'isPrototypeOf',
3107    'propertyIsEnumerable',
3108    'toString',
3109    'toLocaleString',
3110    'valueOf'
3111],
3112
3113/**
3114 * `true` if this browser has the JScript enumeration bug that prevents
3115 * enumeration of the properties named in the `_forceEnum` array, `false`
3116 * otherwise.
3117 *
3118 * See:
3119 *   - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
3120 *   - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
3121 *
3122 * @property _hasEnumBug
3123 * @type Boolean
3124 * @protected
3125 * @static
3126 */
3127hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
3128
3129/**
3130 * `true` if this browser incorrectly considers the `prototype` property of
3131 * functions to be enumerable. Currently known to affect Opera 11.50 and Android 2.3.x.
3132 *
3133 * @property _hasProtoEnumBug
3134 * @type Boolean
3135 * @protected
3136 * @static
3137 */
3138hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
3139
3140/**
3141 * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
3142 * exists only on _obj_'s prototype. This is essentially a safer version of
3143 * `obj.hasOwnProperty()`.
3144 *
3145 * @method owns
3146 * @param {Object} obj Object to test.
3147 * @param {String} key Property name to look for.
3148 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
3149 * @static
3150 */
3151owns = O.owns = function (obj, key) {
3152    return !!obj && hasOwn.call(obj, key);
3153}; // <-- End of var declarations.
3154
3155/**
3156 * Alias for `owns()`.
3157 *
3158 * @method hasKey
3159 * @param {Object} obj Object to test.
3160 * @param {String} key Property name to look for.
3161 * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
3162 * @static
3163 */
3164O.hasKey = owns;
3165
3166/**
3167 * Returns an array containing the object's enumerable keys. Does not include
3168 * prototype keys or non-enumerable keys.
3169 *
3170 * Note that keys are returned in enumeration order (that is, in the same order
3171 * that they would be enumerated by a `for-in` loop), which may not be the same
3172 * as the order in which they were defined.
3173 *
3174 * This method is an alias for the native ES5 `Object.keys()` method if
3175 * available and non-buggy. The Opera 11.50 and Android 2.3.x versions of
3176 * `Object.keys()` have an inconsistency as they consider `prototype` to be
3177 * enumerable, so a non-native shim is used to rectify the difference.
3178 *
3179 * @example
3180 *
3181 *     Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
3182 *     // => ['a', 'b', 'c']
3183 *
3184 * @method keys
3185 * @param {Object} obj An object.
3186 * @return {String[]} Array of keys.
3187 * @static
3188 */
3189O.keys = Lang._isNative(Object.keys) && !hasProtoEnumBug ? Object.keys : function (obj) {
3190    if (!Lang.isObject(obj)) {
3191        throw new TypeError('Object.keys called on a non-object');
3192    }
3193
3194    var keys = [],
3195        i, key, len;
3196
3197    if (hasProtoEnumBug && typeof obj === 'function') {
3198        for (key in obj) {
3199            if (owns(obj, key) && key !== 'prototype') {
3200                keys.push(key);
3201            }
3202        }
3203    } else {
3204        for (key in obj) {
3205            if (owns(obj, key)) {
3206                keys.push(key);
3207            }
3208        }
3209    }
3210
3211    if (hasEnumBug) {
3212        for (i = 0, len = forceEnum.length; i < len; ++i) {
3213            key = forceEnum[i];
3214
3215            if (owns(obj, key)) {
3216                keys.push(key);
3217            }
3218        }
3219    }
3220
3221    return keys;
3222};
3223
3224/**
3225 * Returns an array containing the values of the object's enumerable keys.
3226 *
3227 * Note that values are returned in enumeration order (that is, in the same
3228 * order that they would be enumerated by a `for-in` loop), which may not be the
3229 * same as the order in which they were defined.
3230 *
3231 * @example
3232 *
3233 *     Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
3234 *     // => ['foo', 'bar', 'baz']
3235 *
3236 * @method values
3237 * @param {Object} obj An object.
3238 * @return {Array} Array of values.
3239 * @static
3240 */
3241O.values = function (obj) {
3242    var keys   = O.keys(obj),
3243        i      = 0,
3244        len    = keys.length,
3245        values = [];
3246
3247    for (; i < len; ++i) {
3248        values.push(obj[keys[i]]);
3249    }
3250
3251    return values;
3252};
3253
3254/**
3255 * Returns the number of enumerable keys owned by an object.
3256 *
3257 * @method size
3258 * @param {Object} obj An object.
3259 * @return {Number} The object's size.
3260 * @static
3261 */
3262O.size = function (obj) {
3263    try {
3264        return O.keys(obj).length;
3265    } catch (ex) {
3266        return 0; // Legacy behavior for non-objects.
3267    }
3268};
3269
3270/**
3271 * Returns `true` if the object owns an enumerable property with the specified
3272 * value.
3273 *
3274 * @method hasValue
3275 * @param {Object} obj An object.
3276 * @param {any} value The value to search for.
3277 * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
3278 * @static
3279 */
3280O.hasValue = function (obj, value) {
3281    return Y.Array.indexOf(O.values(obj), value) > -1;
3282};
3283
3284/**
3285 * Executes a function on each enumerable property in _obj_. The function
3286 * receives the value, the key, and the object itself as parameters (in that
3287 * order).
3288 *
3289 * By default, only properties owned by _obj_ are enumerated. To include
3290 * prototype properties, set the _proto_ parameter to `true`.
3291 *
3292 * @method each
3293 * @param {Object} obj Object to enumerate.
3294 * @param {Function} fn Function to execute on each enumerable property.
3295 *   @param {mixed} fn.value Value of the current property.
3296 *   @param {String} fn.key Key of the current property.
3297 *   @param {Object} fn.obj Object being enumerated.
3298 * @param {Object} [thisObj] `this` object to use when calling _fn_.
3299 * @param {Boolean} [proto=false] Include prototype properties.
3300 * @return {YUI} the YUI instance.
3301 * @chainable
3302 * @static
3303 */
3304O.each = function (obj, fn, thisObj, proto) {
3305    var key;
3306
3307    for (key in obj) {
3308        if (proto || owns(obj, key)) {
3309            fn.call(thisObj || Y, obj[key], key, obj);
3310        }
3311    }
3312
3313    return Y;
3314};
3315
3316/**
3317 * Executes a function on each enumerable property in _obj_, but halts if the
3318 * function returns a truthy value. The function receives the value, the key,
3319 * and the object itself as paramters (in that order).
3320 *
3321 * By default, only properties owned by _obj_ are enumerated. To include
3322 * prototype properties, set the _proto_ parameter to `true`.
3323 *
3324 * @method some
3325 * @param {Object} obj Object to enumerate.
3326 * @param {Function} fn Function to execute on each enumerable property.
3327 *   @param {mixed} fn.value Value of the current property.
3328 *   @param {String} fn.key Key of the current property.
3329 *   @param {Object} fn.obj Object being enumerated.
3330 * @param {Object} [thisObj] `this` object to use when calling _fn_.
3331 * @param {Boolean} [proto=false] Include prototype properties.
3332 * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
3333 *   `false` otherwise.
3334 * @static
3335 */
3336O.some = function (obj, fn, thisObj, proto) {
3337    var key;
3338
3339    for (key in obj) {
3340        if (proto || owns(obj, key)) {
3341            if (fn.call(thisObj || Y, obj[key], key, obj)) {
3342                return true;
3343            }
3344        }
3345    }
3346
3347    return false;
3348};
3349
3350/**
3351 * Retrieves the sub value at the provided path,
3352 * from the value object provided.
3353 *
3354 * @method getValue
3355 * @static
3356 * @param o The object from which to extract the property value.
3357 * @param path {Array} A path array, specifying the object traversal path
3358 * from which to obtain the sub value.
3359 * @return {Any} The value stored in the path, undefined if not found,
3360 * undefined if the source is not an object.  Returns the source object
3361 * if an empty path is provided.
3362 */
3363O.getValue = function(o, path) {
3364    if (!Lang.isObject(o)) {
3365        return UNDEFINED;
3366    }
3367
3368    var i,
3369        p = Y.Array(path),
3370        l = p.length;
3371
3372    for (i = 0; o !== UNDEFINED && i < l; i++) {
3373        o = o[p[i]];
3374    }
3375
3376    return o;
3377};
3378
3379/**
3380 * Sets the sub-attribute value at the provided path on the
3381 * value object.  Returns the modified value object, or
3382 * undefined if the path is invalid.
3383 *
3384 * @method setValue
3385 * @static
3386 * @param o             The object on which to set the sub value.
3387 * @param path {Array}  A path array, specifying the object traversal path
3388 *                      at which to set the sub value.
3389 * @param val {Any}     The new value for the sub-attribute.
3390 * @return {Object}     The modified object, with the new sub value set, or
3391 *                      undefined, if the path was invalid.
3392 */
3393O.setValue = function(o, path, val) {
3394    var i,
3395        p = Y.Array(path),
3396        leafIdx = p.length - 1,
3397        ref = o;
3398
3399    if (leafIdx >= 0) {
3400        for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
3401            ref = ref[p[i]];
3402        }
3403
3404        if (ref !== UNDEFINED) {
3405            ref[p[i]] = val;
3406        } else {
3407            return UNDEFINED;
3408        }
3409    }
3410
3411    return o;
3412};
3413
3414/**
3415 * Returns `true` if the object has no enumerable properties of its own.
3416 *
3417 * @method isEmpty
3418 * @param {Object} obj An object.
3419 * @return {Boolean} `true` if the object is empty.
3420 * @static
3421 * @since 3.2.0
3422 */
3423O.isEmpty = function (obj) {
3424    return !O.keys(Object(obj)).length;
3425};
3426/**
3427 * The YUI module contains the components required for building the YUI seed
3428 * file.  This includes the script loading mechanism, a simple queue, and the
3429 * core utilities for the library.
3430 * @module yui
3431 * @submodule yui-base
3432 */
3433
3434/**
3435 * YUI user agent detection.
3436 * Do not fork for a browser if it can be avoided.  Use feature detection when
3437 * you can.  Use the user agent as a last resort.  For all fields listed
3438 * as @type float, UA stores a version number for the browser engine,
3439 * 0 otherwise.  This value may or may not map to the version number of
3440 * the browser using the engine.  The value is presented as a float so
3441 * that it can easily be used for boolean evaluation as well as for
3442 * looking for a particular range of versions.  Because of this,
3443 * some of the granularity of the version info may be lost.  The fields that
3444 * are @type string default to null.  The API docs list the values that
3445 * these fields can have.
3446 * @class UA
3447 * @static
3448 */
3449
3450/**
3451* Static method on `YUI.Env` for parsing a UA string.  Called at instantiation
3452* to populate `Y.UA`.
3453*
3454* @static
3455* @method parseUA
3456* @param {String} [subUA=navigator.userAgent] UA string to parse
3457* @return {Object} The Y.UA object
3458*/
3459YUI.Env.parseUA = function(subUA) {
3460
3461    var numberify = function(s) {
3462            var c = 0;
3463            return parseFloat(s.replace(/\./g, function() {
3464                return (c++ === 1) ? '' : '.';
3465            }));
3466        },
3467
3468        win = Y.config.win,
3469
3470        nav = win && win.navigator,
3471
3472        o = {
3473
3474        /**
3475         * Internet Explorer version number or 0.  Example: 6
3476         * @property ie
3477         * @type float
3478         * @static
3479         */
3480        ie: 0,
3481
3482        /**
3483         * Opera version number or 0.  Example: 9.2
3484         * @property opera
3485         * @type float
3486         * @static
3487         */
3488        opera: 0,
3489
3490        /**
3491         * Gecko engine revision number.  Will evaluate to 1 if Gecko
3492         * is detected but the revision could not be found. Other browsers
3493         * will be 0.  Example: 1.8
3494         * <pre>
3495         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
3496         * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3497         * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3498         * Firefox 3.0   <-- 1.9
3499         * Firefox 3.5   <-- 1.91
3500         * </pre>
3501         * @property gecko
3502         * @type float
3503         * @static
3504         */
3505        gecko: 0,
3506
3507        /**
3508         * AppleWebKit version.  KHTML browsers that are not WebKit browsers
3509         * will evaluate to 1, other browsers 0.  Example: 418.9
3510         * <pre>
3511         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3512         *                                   latest available for Mac OSX 10.3.
3513         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
3514         * Safari 2.0.4:         418     <-- preventDefault fixed
3515         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3516         *                                   different versions of webkit
3517         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
3518         *                                   updated, but not updated
3519         *                                   to the latest patch.
3520         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native
3521         * SVG and many major issues fixed).
3522         * Safari 3.0.4 (523.12) 523.12  <-- First Tiger release - automatic
3523         * update from 2.x via the 10.4.11 OS patch.
3524         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
3525         *                                   yahoo.com user agent hack removed.
3526         * </pre>
3527         * http://en.wikipedia.org/wiki/Safari_version_history
3528         * @property webkit
3529         * @type float
3530         * @static
3531         */
3532        webkit: 0,
3533
3534        /**
3535         * Safari will be detected as webkit, but this property will also
3536         * be populated with the Safari version number
3537         * @property safari
3538         * @type float
3539         * @static
3540         */
3541        safari: 0,
3542
3543        /**
3544         * Chrome will be detected as webkit, but this property will also
3545         * be populated with the Chrome version number
3546         * @property chrome
3547         * @type float
3548         * @static
3549         */
3550        chrome: 0,
3551
3552        /**
3553         * The mobile property will be set to a string containing any relevant
3554         * user agent information when a modern mobile browser is detected.
3555         * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3556         * devices with the WebKit-based browser, and Opera Mini.
3557         * @property mobile
3558         * @type string
3559         * @default null
3560         * @static
3561         */
3562        mobile: null,
3563
3564        /**
3565         * Adobe AIR version number or 0.  Only populated if webkit is detected.
3566         * Example: 1.0
3567         * @property air
3568         * @type float
3569         */
3570        air: 0,
3571        /**
3572         * PhantomJS version number or 0.  Only populated if webkit is detected.
3573         * Example: 1.0
3574         * @property phantomjs
3575         * @type float
3576         */
3577        phantomjs: 0,
3578        /**
3579         * Detects Apple iPad's OS version
3580         * @property ipad
3581         * @type float
3582         * @static
3583         */
3584        ipad: 0,
3585        /**
3586         * Detects Apple iPhone's OS version
3587         * @property iphone
3588         * @type float
3589         * @static
3590         */
3591        iphone: 0,
3592        /**
3593         * Detects Apples iPod's OS version
3594         * @property ipod
3595         * @type float
3596         * @static
3597         */
3598        ipod: 0,
3599        /**
3600         * General truthy check for iPad, iPhone or iPod
3601         * @property ios
3602         * @type Boolean
3603         * @default null
3604         * @static
3605         */
3606        ios: null,
3607        /**
3608         * Detects Googles Android OS version
3609         * @property android
3610         * @type float
3611         * @static
3612         */
3613        android: 0,
3614        /**
3615         * Detects Kindle Silk
3616         * @property silk
3617         * @type float
3618         * @static
3619         */
3620        silk: 0,
3621        /**
3622         * Detects Ubuntu version
3623         * @property ubuntu
3624         * @type float
3625         * @static
3626         */
3627        ubuntu: 0,
3628        /**
3629         * Detects Kindle Silk Acceleration
3630         * @property accel
3631         * @type Boolean
3632         * @static
3633         */
3634        accel: false,
3635        /**
3636         * Detects Palms WebOS version
3637         * @property webos
3638         * @type float
3639         * @static
3640         */
3641        webos: 0,
3642
3643        /**
3644         * Google Caja version number or 0.
3645         * @property caja
3646         * @type float
3647         */
3648        caja: nav && nav.cajaVersion,
3649
3650        /**
3651         * Set to true if the page appears to be in SSL
3652         * @property secure
3653         * @type boolean
3654         * @static
3655         */
3656        secure: false,
3657
3658        /**
3659         * The operating system.
3660         *
3661         * Possible values are `windows`, `macintosh`, `android`, `symbos`, `linux`, `rhino` and `ios`.
3662         *
3663         * @property os
3664         * @type string
3665         * @default null
3666         * @static
3667         */
3668        os: null,
3669
3670        /**
3671         * The Nodejs Version
3672         * @property nodejs
3673         * @type float
3674         * @default 0
3675         * @static
3676         */
3677        nodejs: 0,
3678        /**
3679        * Window8/IE10 Application host environment
3680        * @property winjs
3681        * @type Boolean
3682        * @static
3683        */
3684        winjs: !!((typeof Windows !== "undefined") && Windows.System),
3685        /**
3686        * Are touch/msPointer events available on this device
3687        * @property touchEnabled
3688        * @type Boolean
3689        * @static
3690        */
3691        touchEnabled: false
3692    },
3693
3694    ua = subUA || nav && nav.userAgent,
3695
3696    loc = win && win.location,
3697
3698    href = loc && loc.href,
3699
3700    m;
3701
3702    /**
3703    * The User Agent string that was parsed
3704    * @property userAgent
3705    * @type String
3706    * @static
3707    */
3708    o.userAgent = ua;
3709
3710
3711    o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3712
3713    if (ua) {
3714
3715        if ((/windows|win32/i).test(ua)) {
3716            o.os = 'windows';
3717        } else if ((/macintosh|mac_powerpc/i).test(ua)) {
3718            o.os = 'macintosh';
3719        } else if ((/android/i).test(ua)) {
3720            o.os = 'android';
3721        } else if ((/symbos/i).test(ua)) {
3722            o.os = 'symbos';
3723        } else if ((/linux/i).test(ua)) {
3724            o.os = 'linux';
3725        } else if ((/rhino/i).test(ua)) {
3726            o.os = 'rhino';
3727        }
3728
3729        // Modern KHTML browsers should qualify as Safari X-Grade
3730        if ((/KHTML/).test(ua)) {
3731            o.webkit = 1;
3732        }
3733        if ((/IEMobile|XBLWP7/).test(ua)) {
3734            o.mobile = 'windows';
3735        }
3736        if ((/Fennec/).test(ua)) {
3737            o.mobile = 'gecko';
3738        }
3739        // Modern WebKit browsers are at least X-Grade
3740        m = ua.match(/AppleWebKit\/([^\s]*)/);
3741        if (m && m[1]) {
3742            o.webkit = numberify(m[1]);
3743            o.safari = o.webkit;
3744
3745            if (/PhantomJS/.test(ua)) {
3746                m = ua.match(/PhantomJS\/([^\s]*)/);
3747                if (m && m[1]) {
3748                    o.phantomjs = numberify(m[1]);
3749                }
3750            }
3751
3752            // Mobile browser check
3753            if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
3754                o.mobile = 'Apple'; // iPhone or iPod Touch
3755
3756                m = ua.match(/OS ([^\s]*)/);
3757                if (m && m[1]) {
3758                    m = numberify(m[1].replace('_', '.'));
3759                }
3760                o.ios = m;
3761                o.os = 'ios';
3762                o.ipad = o.ipod = o.iphone = 0;
3763
3764                m = ua.match(/iPad|iPod|iPhone/);
3765                if (m && m[0]) {
3766                    o[m[0].toLowerCase()] = o.ios;
3767                }
3768            } else {
3769                m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3770                if (m) {
3771                    // Nokia N-series, webOS, ex: NokiaN95
3772                    o.mobile = m[0];
3773                }
3774                if (/webOS/.test(ua)) {
3775                    o.mobile = 'WebOS';
3776                    m = ua.match(/webOS\/([^\s]*);/);
3777                    if (m && m[1]) {
3778                        o.webos = numberify(m[1]);
3779                    }
3780                }
3781                if (/ Android/.test(ua)) {
3782                    o.mobile = 'Android';
3783                    m = ua.match(/Android ([^\s]*);/);
3784                    if (m && m[1]) {
3785                        o.android = numberify(m[1]);
3786                    }
3787
3788                }
3789                if (/Silk/.test(ua)) {
3790                    m = ua.match(/Silk\/([^\s]*)/);
3791                    if (m && m[1]) {
3792                        o.silk = numberify(m[1]);
3793                    }
3794                    if (!o.android) {
3795                        o.android = 2.34; //Hack for desktop mode in Kindle
3796                        o.os = 'Android';
3797                    }
3798                    if (/Accelerated=true/.test(ua)) {
3799                        o.accel = true;
3800                    }
3801                }
3802            }
3803
3804            m = ua.match(/OPR\/(\d+\.\d+)/);
3805
3806            if (m && m[1]) {
3807                // Opera 15+ with Blink (pretends to be both Chrome and Safari)
3808                o.opera = numberify(m[1]);
3809            } else {
3810                m = ua.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/);
3811
3812                if (m && m[1] && m[2]) {
3813                    o.chrome = numberify(m[2]); // Chrome
3814                    o.safari = 0; //Reset safari back to 0
3815                    if (m[1] === 'CrMo') {
3816                        o.mobile = 'chrome';
3817                    }
3818                } else {
3819                    m = ua.match(/AdobeAIR\/([^\s]*)/);
3820                    if (m) {
3821                        o.air = m[0]; // Adobe AIR 1.0 or better
3822                    }
3823                }
3824            }
3825        }
3826
3827        m = ua.match(/Ubuntu\ (\d+\.\d+)/);
3828        if (m && m[1]) {
3829
3830            o.os = 'linux';
3831            o.ubuntu = numberify(m[1]);
3832
3833            m = ua.match(/\ WebKit\/([^\s]*)/);
3834            if (m && m[1]) {
3835                o.webkit = numberify(m[1]);
3836            }
3837            m = ua.match(/\ Chromium\/([^\s]*)/);
3838            if (m && m[1]) {
3839                o.chrome = numberify(m[1]);
3840            }
3841            if (/ Mobile$/.test(ua)) {
3842                o.mobile = 'Ubuntu';
3843            }
3844        }
3845
3846        if (!o.webkit) { // not webkit
3847// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3848            if (/Opera/.test(ua)) {
3849                m = ua.match(/Opera[\s\/]([^\s]*)/);
3850                if (m && m[1]) {
3851                    o.opera = numberify(m[1]);
3852                }
3853                m = ua.match(/Version\/([^\s]*)/);
3854                if (m && m[1]) {
3855                    o.opera = numberify(m[1]); // opera 10+
3856                }
3857
3858                if (/Opera Mobi/.test(ua)) {
3859                    o.mobile = 'opera';
3860                    m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
3861                    if (m && m[1]) {
3862                        o.opera = numberify(m[1]);
3863                    }
3864                }
3865                m = ua.match(/Opera Mini[^;]*/);
3866
3867                if (m) {
3868                    o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3869                }
3870            } else { // not opera or webkit
3871                m = ua.match(/MSIE ([^;]*)|Trident.*; rv:([0-9.]+)/);
3872
3873                if (m && (m[1] || m[2])) {
3874                    o.ie = numberify(m[1] || m[2]);
3875                } else { // not opera, webkit, or ie
3876                    m = ua.match(/Gecko\/([^\s]*)/);
3877
3878                    if (m) {
3879                        o.gecko = 1; // Gecko detected, look for revision
3880                        m = ua.match(/rv:([^\s\)]*)/);
3881                        if (m && m[1]) {
3882                            o.gecko = numberify(m[1]);
3883                            if (/Mobile|Tablet/.test(ua)) {
3884                                o.mobile = "ffos";
3885                            }
3886                        }
3887                    }
3888                }
3889            }
3890        }
3891    }
3892
3893    //Check for known properties to tell if touch events are enabled on this device or if
3894    //the number of MSPointer touchpoints on this device is greater than 0.
3895    if (win && nav && !(o.chrome && o.chrome < 6)) {
3896        o.touchEnabled = (("ontouchstart" in win) || (("msMaxTouchPoints" in nav) && (nav.msMaxTouchPoints > 0)));
3897    }
3898
3899    //It was a parsed UA, do not assign the global value.
3900    if (!subUA) {
3901
3902        if (typeof process === 'object') {
3903
3904            if (process.versions && process.versions.node) {
3905                //NodeJS
3906                o.os = process.platform;
3907                o.nodejs = numberify(process.versions.node);
3908            }
3909        }
3910
3911        YUI.Env.UA = o;
3912
3913    }
3914
3915    return o;
3916};
3917
3918
3919Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3920
3921/**
3922Performs a simple comparison between two version numbers, accounting for
3923standard versioning logic such as the fact that "535.8" is a lower version than
3924"535.24", even though a simple numerical comparison would indicate that it's
3925greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
3926considered equivalent.
3927
3928Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
39291 if _a_ is higher than _b_.
3930
3931Versions may be numbers or strings containing numbers and dots. For example,
3932both `535` and `"535.8.10"` are acceptable. A version string containing
3933non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
3934
3935@method compareVersions
3936@param {Number|String} a First version number to compare.
3937@param {Number|String} b Second version number to compare.
3938@return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
3939    higher than _b_.
3940**/
3941Y.UA.compareVersions = function (a, b) {
3942    var aPart, aParts, bPart, bParts, i, len;
3943
3944    if (a === b) {
3945        return 0;
3946    }
3947
3948    aParts = (a + '').split('.');
3949    bParts = (b + '').split('.');
3950
3951    for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
3952        aPart = parseInt(aParts[i], 10);
3953        bPart = parseInt(bParts[i], 10);
3954
3955        /*jshint expr: true*/
3956        isNaN(aPart) && (aPart = 0);
3957        isNaN(bPart) && (bPart = 0);
3958
3959        if (aPart < bPart) {
3960            return -1;
3961        }
3962
3963        if (aPart > bPart) {
3964            return 1;
3965        }
3966    }
3967
3968    return 0;
3969};
3970YUI.Env.aliases = {
3971    "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3972    "anim-shape-transform": ["anim-shape"],
3973    "app": ["app-base","app-content","app-transitions","lazy-model-list","model","model-list","model-sync-rest","model-sync-local","router","view","view-node-map"],
3974    "attribute": ["attribute-base","attribute-complex"],
3975    "attribute-events": ["attribute-observable"],
3976    "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3977    "axes": ["axis-numeric","axis-category","axis-time","axis-stacked"],
3978    "axes-base": ["axis-numeric-base","axis-category-base","axis-time-base","axis-stacked-base"],
3979    "base": ["base-base","base-pluginhost","base-build"],
3980    "cache": ["cache-base","cache-offline","cache-plugin"],
3981    "charts": ["charts-base"],
3982    "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3983    "color": ["color-base","color-hsl","color-harmony"],
3984    "controller": ["router"],
3985    "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3986    "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3987    "datatable": ["datatable-core","datatable-table","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
3988    "datatype": ["datatype-date","datatype-number","datatype-xml"],
3989    "datatype-date": ["datatype-date-parse","datatype-date-format","datatype-date-math"],
3990    "datatype-number": ["datatype-number-parse","datatype-number-format"],
3991    "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3992    "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3993    "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3994    "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3995    "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"],
3996    "event-custom": ["event-custom-base","event-custom-complex"],
3997    "event-gestures": ["event-flick","event-move"],
3998    "handlebars": ["handlebars-compiler"],
3999    "highlight": ["highlight-base","highlight-accentfold"],
4000    "history": ["history-base","history-hash","history-html5"],
4001    "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
4002    "json": ["json-parse","json-stringify"],
4003    "loader": ["loader-base","loader-rollup","loader-yui3"],
4004    "loader-pathogen-encoder": ["loader-base","loader-rollup","loader-yui3","loader-pathogen-combo
4004handler"],
4005    "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
4006    "pluginhost": ["pluginhost-base","pluginhost-config"],
4007    "querystring": ["querystring-parse","querystring-stringify"],
4008    "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
4009    "resize": ["resize-base","resize-proxy","resize-constrain"],
4010    "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
4011    "template": ["template-base","template-micro"],
4012    "text": ["text-accentfold","text-wordbreak"],
4013    "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]
4014};
4015
4016
4017}, '3.18.1', {
4018    "use": [
4019        "yui-base",
4020        "get",
4021        "features",
4022        "intl-base",
4023        "yui-log",
4024        "yui-later",
4025        "loader-base",
4026        "loader-rollup",
4027        "loader-yui3"
4028    ]
4029});
4030YUI.add('get', function (Y, NAME) {
4031
4032/*jslint boss:true, expr:true, laxbreak: true */
4033
4034/**
4035Provides dynamic loading of remote JavaScript and CSS resources.
4036
4037@module get
4038@class Get
4039@static
4040**/
4041
4042var Lang = Y.Lang,
4043
4044    CUSTOM_ATTRS, // defined lazily in Y.Get.Transaction._createNode()
4045
4046    Get, Transaction;
4047
4048Y.Get = Get = {
4049    // -- Public Properties ----------------------------------------------------
4050
4051    /**
4052    Default options for CSS requests. Options specified here will override
4053    global defaults for CSS requests.
4054
4055    See the `options` property for all available options.
4056
4057    @property cssOptions
4058    @type Object
4059    @static
4060    @since 3.5.0
4061    **/
4062    cssOptions: {
4063        attributes: {
4064            rel: 'stylesheet'
4065        },
4066
4067        doc         : Y.config.linkDoc || Y.config.doc,
4068        pollInterval: 50
4069    },
4070
4071    /**
4072    Default options for JS requests. Options specified here will override global
4073    defaults for JS requests.
4074
4075    See the `options` property for all available options.
4076
4077    @property jsOptions
4078    @type Object
4079    @static
4080    @since 3.5.0
4081    **/
4082    jsOptions: {
4083        autopurge: true,
4084        doc      : Y.config.scriptDoc || Y.config.doc
4085    },
4086
4087    /**
4088    Default options to use for all requests.
4089
4090    Note that while all available options are documented here for ease of
4091    discovery, some options (like callback functions) only make sense at the
4092    transaction level.
4093
4094    Callback functions specified via the options object or the `options`
4095    parameter of the `css()`, `js()`, or `load()` methods will receive the
4096    transaction object as a parameter. See `Y.Get.Transaction` for details on
4097    the properties and methods available on transactions.
4098
4099    @static
4100    @since 3.5.0
4101    @property {Object} options
4102
4103    @property {Boolean} [options.async=false] Whether or not to load scripts
4104        asynchronously, meaning they're requested in parallel and execution
4105        order is not guaranteed. Has no effect on CSS, since CSS is always
4106        loaded asynchronously.
4107
4108    @property {Object} [options.attributes] HTML attribute name/value pairs that
4109        should be added to inserted nodes. By default, the `charset` attribute
4110        will be set to "utf-8" and nodes will be given an auto-generated `id`
4111        attribute, but you can override these with your own values if desired.
4112
4113    @property {Boolean} [options.autopurge] Whether or not to automatically
4114        purge inserted nodes after the purge threshold is reached. This is
4115        `true` by default for JavaScript, but `false` for CSS since purging a
4116        CSS node will also remove any styling applied by the referenced file.
4117
4118    @property {Object} [options.context] `this` object to use when calling
4119        callback functions. Defaults to the transaction object.
4120
4121    @property {Mixed} [options.data] Arbitrary data object to pass to "on*"
4122        callbacks.
4123
4124    @property {Document} [options.doc] Document into which nodes should be
4125        inserted. By default, the current document is used.
4126
4127    @property {HTMLElement|String} [options.insertBefore] HTML element or id
4128        string of an element before which all generated nodes should be
4129        inserted. If not specified, Get will automatically determine the best
4130        place to insert nodes for maximum compatibility.
4131
4132    @property {Function} [options.onEnd] Callback to execute after a transaction
4133        is complete, regardless of whether it succeeded or failed.
4134
4135    @property {Function} [options.onFailure] Callback to execute after a
4136        transaction fails, times out, or is aborted.
4137
4138    @property {Function} [options.onProgress] Callback to execute after each
4139        individual request in a transaction either succeeds or fails.
4140
4141    @property {Function} [options.onSuccess] Callback to execute after a
4142        transaction completes successfully with no errors. Note that in browsers
4143        that don't support the `error` event on CSS `<link>` nodes, a failed CSS
4144        request may still be reported as a success because in these browsers
4145        it can be difficult or impossible to distinguish between success and
4146        failure for CSS resources.
4147
4148    @property {Function} [options.onTimeout] Callback to execute after a
4149        transaction times out.
4150
4151    @property {Number} [options.pollInterval=50] Polling interval (in
4152        milliseconds) for detecting CSS load completion in browsers that don't
4153        support the `load` event on `<link>` nodes. This isn't used for
4154        JavaScript.
4155
4156    @property {Number} [options.purgethreshold=20] Number of nodes to insert
4157        before triggering an automatic purge when `autopurge` is `true`.
4158
4159    @property {Number} [options.timeout] Number of milliseconds to wait before
4160        aborting a transaction. When a timeout occurs, the `onTimeout` callback
4161        is called, followed by `onFailure` and finally `onEnd`. By default,
4162        there is no timeout.
4163
4164    @property {String} [options.type] Resource type ("css" or "js"). This option
4165        is set automatically by the `css()` and `js()` functions and will be
4166        ignored there, but may be useful when using the `load()` function. If
4167        not specified, the type will be inferred from the URL, defaulting to
4168        "js" if the URL doesn't contain a recognizable file extension.
4169    **/
4170    options: {
4171        attributes: {
4172            charset: 'utf-8'
4173        },
4174
4175        purgethreshold: 20
4176    },
4177
4178    // -- Protected Properties -------------------------------------------------
4179
4180    /**
4181    Regex that matches a CSS URL. Used to guess the file type when it's not
4182    specified.
4183
4184    @property REGEX_CSS
4185    @type RegExp
4186    @final
4187    @protected
4188    @static
4189    @since 3.5.0
4190    **/
4191    REGEX_CSS: /\.css(?:[?;].*)?$/i,
4192
4193    /**
4194    Regex that matches a JS URL. Used to guess the file type when it's not
4195    specified.
4196
4197    @property REGEX_JS
4198    @type RegExp
4199    @final
4200    @protected
4201    @static
4202    @since 3.5.0
4203    **/
4204    REGEX_JS : /\.js(?:[?;].*)?$/i,
4205
4206    /**
4207    Contains information about the current environment, such as what script and
4208    link injection features it supports.
4209
4210    This object is created and populated the first time the `_getEnv()` method
4211    is called.
4212
4213    @property _env
4214    @type Object
4215    @protected
4216    @static
4217    @since 3.5.0
4218    **/
4219
4220    /**
4221    Mapping of document _yuid strings to <head> or <base> node references so we
4222    don't have to look the node up each time we want to insert a request node.
4223
4224    @property _insertCache
4225    @type Object
4226    @protected
4227    @static
4228    @since 3.5.0
4229    **/
4230    _insertCache: {},
4231
4232    /**
4233    Information about the currently pending transaction, if any.
4234
4235    This is actually an object with two properties: `callback`, containing the
4236    optional callback passed to `css()`, `load()`, or `js()`; and `transaction`,
4237    containing the actual transaction instance.
4238
4239    @property _pending
4240    @type Object
4241    @protected
4242    @static
4243    @since 3.5.0
4244    **/
4245    _pending: null,
4246
4247    /**
4248    HTML nodes eligible to be purged next time autopurge is triggered.
4249
4250    @property _purgeNodes
4251    @type HTMLElement[]
4252    @protected
4253    @static
4254    @since 3.5.0
4255    **/
4256    _purgeNodes: [],
4257
4258    /**
4259    Queued transactions and associated callbacks.
4260
4261    @property _queue
4262    @type Object[]
4263    @protected
4264    @static
4265    @since 3.5.0
4266    **/
4267    _queue: [],
4268
4269    // -- Public Methods -------------------------------------------------------
4270
4271    /**
4272    Aborts the specified transaction.
4273
4274    This will cause the transaction's `onFailure` callback to be called and
4275    will prevent any new script and link nodes from being added to the document,
4276    but any resources that have already been requested will continue loading
4277    (there's no safe way to prevent this, unfortunately).
4278
4279    *Note:* This method is deprecated as of 3.5.0, and will be removed in a
4280    future version of YUI. Use the transaction-level `abort()` method instead.
4281
4282    @method abort
4283    @param {Get.Transaction} transaction Transaction to abort.
4284    @deprecated Use the `abort()` method on the transaction instead.
4285    @static
4286    **/
4287    abort: function (transaction) {
4288        var i, id, item, len, pending;
4289
4290
4291        if (!transaction.abort) {
4292            id          = transaction;
4293            pending     = this._pending;
4294            transaction = null;
4295
4296            if (pending && pending.transaction.id === id) {
4297                transaction   = pending.transaction;
4298                this._pending = null;
4299            } else {
4300                for (i = 0, len = this._queue.length; i < len; ++i) {
4301                    item = this._queue[i].transaction;
4302
4303                    if (item.id === id) {
4304                        transaction = item;
4305                        this._queue.splice(i, 1);
4306                        break;
4307                    }
4308                }
4309            }
4310        }
4311
4312        transaction && transaction.abort();
4313    },
4314
4315    /**
4316    Loads one or more CSS files.
4317
4318    The _urls_ parameter may be provided as a URL string, a request object,
4319    or an array of URL strings and/or request objects.
4320
4321    A request object is just an object that contains a `url` property and zero
4322    or more options that should apply specifically to that request.
4323    Request-specific options take priority over transaction-level options and
4324    default options.
4325
4326    URLs may be relative or absolute, and do not have to have the same origin
4327    as the current page.
4328
4329    The `options` parameter may be omitted completely and a callback passed in
4330    its place, if desired.
4331
4332    @example
4333
4334        // Load a single CSS file and log a message on completion.
4335        Y.Get.css('foo.css', function (err) {
4336            if (err) {
4337            } else {
4338            }
4339        });
4340
4341        // Load multiple CSS files and log a message when all have finished
4342        // loading.
4343        var urls = ['foo.css', 'http://example.com/bar.css', 'baz/quux.css'];
4344
4345        Y.Get.css(urls, function (err) {
4346            if (err) {
4347            } else {
4348            }
4349        });
4350
4351        // Specify transaction-level options, which will apply to all requests
4352        // within the transaction.
4353        Y.Get.css(urls, {
4354            attributes: {'class': 'my-css'},
4355            timeout   : 5000
4356        });
4357
4358        // Specify per-request options, which override transaction-level and
4359        // default options.
4360        Y.Get.css([
4361            {url: 'foo.css', attributes: {id: 'foo'}},
4362            {url: 'bar.css', attributes: {id: 'bar', charset: 'iso-8859-1'}}
4363        ]);
4364
4365    @method css
4366    @param {String|Object|Array}
4366 urls URL string, request object, or array
4367        of URLs and/or request objects to load.
4368    @param {Object} [options] Options for this transaction. See the
4369        `Y.Get.options` property for a complete list of available options.
4370    @param {Function} [callback] Callback function to be called on completion.
4371        This is a general callback and will be called before any more granular
4372        callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
4373        object.
4374
4375        @param {Array|null} callback.err Array of errors that occurred during
4376            the transaction, or `null` on success.
4377        @param {Get.Transaction} callback.transaction Transaction object.
4378
4379    @return {Get.Transaction} Transaction object.
4380    @static
4381    **/
4382    css: function (urls, options, callback) {
4383        return this._load('css', urls, options, callback);
4384    },
4385
4386    /**
4387    Loads one or more JavaScript resources.
4388
4389    The _urls_ parameter may be provided as a URL string, a request object,
4390    or an array of URL strings and/or request objects.
4391
4392    A request object is just an object that contains a `url` property and zero
4393    or more options that should apply specifically to that request.
4394    Request-specific options take priority over transaction-level options and
4395    default options.
4396
4397    URLs may be relative or absolute, and do not have to have the same origin
4398    as the current page.
4399
4400    The `options` parameter may be omitted completely and a callback passed in
4401    its place, if desired.
4402
4403    Scripts will be executed in the order they're specified unless the `async`
4404    option is `true`, in which case they'll be loaded in parallel and executed
4405    in whatever order they finish loading.
4406
4407    @example
4408
4409        // Load a single JS file and log a message on completion.
4410        Y.Get.js('foo.js', function (err) {
4411            if (err) {
4412            } else {
4413            }
4414        });
4415
4416        // Load multiple JS files, execute them in order, and log a message when
4417        // all have finished loading.
4418        var urls = ['foo.js', 'http://example.com/bar.js', 'baz/quux.js'];
4419
4420        Y.Get.js(urls, function (err) {
4421            if (err) {
4422            } else {
4423            }
4424        });
4425
4426        // Specify transaction-level options, which will apply to all requests
4427        // within the transaction.
4428        Y.Get.js(urls, {
4429            attributes: {'class': 'my-js'},
4430            timeout   : 5000
4431        });
4432
4433        // Specify per-request options, which override transaction-level and
4434        // default options.
4435        Y.Get.js([
4436            {url: 'foo.js', attributes: {id: 'foo'}},
4437            {url: 'bar.js', attributes: {id: 'bar', charset: 'iso-8859-1'}}
4438        ]);
4439
4440    @method js
4441    @param {String|Object|Array} urls URL string, request object, or array
4442        of URLs and/or request objects to load.
4443    @param {Object} [options] Options for this transaction. See the
4444        `Y.Get.options` property for a complete list of available options.
4445    @param {Function} [callback] Callback function to be called on completion.
4446        This is a general callback and will be called before any more granular
4447        callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
4448        object.
4449
4450        @param {Array|null} callback.err Array of errors that occurred during
4451            the transaction, or `null` on success.
4452        @param {Get.Transaction} callback.transaction Transaction object.
4453
4454    @return {Get.Transaction} Transaction object.
4455    @since 3.5.0
4456    @static
4457    **/
4458    js: function (urls, options, callback) {
4459        return this._load('js', urls, options, callback);
4460    },
4461
4462    /**
4463    Loads one or more CSS and/or JavaScript resources in the same transaction.
4464
4465    Use this method when you want to load both CSS and JavaScript in a single
4466    transaction and be notified when all requested URLs have finished loading,
4467    regardless of type.
4468
4469    Behavior and options are the same as for the `css()` and `js()` methods. If
4470    a resource type isn't specified in per-request options or transaction-level
4471    options, Get will guess the file type based on the URL's extension (`.css`
4472    or `.js`, with or without a following query string). If the file type can't
4473    be guessed from the URL, a warning will be logged and Get will assume the
4474    URL is a JavaScript resource.
4475
4476    @example
4477
4478        // Load both CSS and JS files in a single transaction, and log a message
4479        // when all files have finished loading.
4480        Y.Get.load(['foo.css', 'bar.js', 'baz.css'], function (err) {
4481            if (err) {
4482            } else {
4483            }
4484        });
4485
4486    @method load
4487    @param {String|Object|Array}
4487 urls URL string, request object, or array
4488        of URLs and/or request objects to load.
4489    @param {Object} [options] Options for this transaction. See the
4490        `Y.Get.options` property for a complete list of available options.
4491    @param {Function} [callback] Callback function to be called on completion.
4492        This is a general callback and will be called before any more granular
4493        callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
4494        object.
4495
4496        @param {Array|null} err Array of errors that occurred during the
4497            transaction, or `null` on success.
4498        @param {Get.Transaction} Transaction object.
4499
4500    @return {Get.Transaction} Transaction object.
4501    @since 3.5.0
4502    @static
4503    **/
4504    load: function (urls, options, callback) {
4505        return this._load(null, urls, options, callback);
4506    },
4507
4508    // -- Protected Methods ----------------------------------------------------
4509
4510    /**
4511    Triggers an automatic purge if the purge threshold has been reached.
4512
4513    @method _autoPurge
4514    @param {Number} threshold Purge threshold to use, in milliseconds.
4515    @protected
4516    @since 3.5.0
4517    @static
4518    **/
4519    _autoPurge: function (threshold) {
4520        if (threshold && this._purgeNodes.length >= threshold) {
4521            this._purge(this._purgeNodes);
4522        }
4523    },
4524
4525    /**
4526    Populates the `_env` property with information about the current
4527    environment.
4528
4529    @method _getEnv
4530    @return {Object} Environment information.
4531    @protected
4532    @since 3.5.0
4533    @static
4534    **/
4535    _getEnv: function () {
4536        var doc = Y.config.doc,
4537            ua  = Y.UA;
4538
4539        // Note: some of these checks require browser sniffs since it's not
4540        // feasible to load test files on every pageview just to perform a
4541        // feature test. I'm sorry if this makes you sad.
4542        return (this._env = {
4543
4544            // True if this is a browser that supports disabling async mode on
4545            // dynamically created script nodes. See
4546            // https://developer.mozilla.org/En/HTML/Element/Script#Attributes
4547
4548            // IE10 doesn't return true for the MDN feature test, so setting it explicitly,
4549            // because it is async by default, and allows you to disable async by setting it to false
4550            async: (doc && doc.createElement('script').async === true) || (ua.ie >= 10),
4551
4552            // True if this browser fires an event when a dynamically injected
4553            // link node fails to load. This is currently true for Firefox 9+
4554            // and WebKit 535.24+
4555            cssFail: ua.gecko >= 9 || ua.compareVersions(ua.webkit, 535.24) >= 0,
4556
4557            // True if this browser fires an event when a dynamically injected
4558            // link node finishes loading. This is currently true for IE, Opera,
4559            // Firefox 9+, and WebKit 535.24+. Note that IE versions <9 fire the
4560            // DOM 0 "onload" event, but not "load". All versions of IE fire
4561            // "onload".
4562            // davglass: Seems that Chrome on Android needs this to be false.
4563            cssLoad: (
4564                    (!ua.gecko && !ua.webkit) || ua.gecko >= 9 ||
4565                    ua.compareVersions(ua.webkit, 535.24) >= 0
4566                ) && !(ua.chrome && ua.chrome <= 18),
4567
4568            // True if this browser preserves script execution order while
4569            // loading scripts in parallel as long as the script node's `async`
4570            // attribute is set to false to explicitly disable async execution.
4571            preservesScriptOrder: !!(ua.gecko || ua.opera || (ua.ie && ua.ie >= 10))
4572        });
4573    },
4574
4575    _getTransaction: function (urls, options) {
4576        var requests = [],
4577            i, len, req, url;
4578
4579        if (!Lang.isArray(urls)) {
4580            urls = [urls];
4581        }
4582
4583        options = Y.merge(this.options, options);
4584
4585        // Clone the attributes object so we don't end up modifying it by ref.
4586        options.attributes = Y.merge(this.options.attributes,
4587                options.attributes);
4588
4589        for (i = 0, len = urls.length; i < len; ++i) {
4590            url = urls[i];
4591            req = {attributes: {}};
4592
4593            // If `url` is a string, we create a URL object for it, then mix in
4594            // global options and request-specific options. If it's an object
4595            // with a "url" property, we assume it's a request object c
4595ontaining
4596            // URL-specific options.
4597            if (typeof url === 'string') {
4598                req.url = url;
4599            } else if (url.url) {
4600                // URL-specific options override both global defaults and
4601                // request-specific options.
4602                Y.mix(req, url, false, null, 0, true);
4603                url = url.url; // Make url a string so we can use it later.
4604            } else {
4605                continue;
4606            }
4607
4608            Y.mix(req, options, false, null, 0, true);
4609
4610            // If we didn't get an explicit type for this URL either in the
4611            // request options or the URL-specific options, try to determine
4612            // one from the file extension.
4613            if (!req.type) {
4614                if (this.REGEX_CSS.test(url)) {
4615                    req.type = 'css';
4616                } else {
4617                    if (!this.REGEX_JS.test(url)) {
4618                    }
4619
4620                    req.type = 'js';
4621                }
4622            }
4623
4624            // Mix in type-specific default options, but don't overwrite any
4625            // options that have already been set.
4626            Y.mix(req, req.type === 'js' ? this.jsOptions : this.cssOptions,
4627                false, null, 0, true);
4628
4629            // Give the node an id attribute if it doesn't already have one.
4630            req.attributes.id || (req.attributes.id = Y.guid());
4631
4632            // Backcompat for <3.5.0 behavior.
4633            if (req.win) {
4634                req.doc = req.win.document;
4635            } else {
4636                req.win = req.doc.defaultView || req.doc.parentWindow;
4637            }
4638
4639            if (req.charset) {
4640                req.attributes.charset = req.charset;
4641            }
4642
4643            requests.push(req);
4644        }
4645
4646        return new Transaction(requests, options);
4647    },
4648
4649    _load: function (type, urls, options, callback) {
4650        var transaction;
4651
4652        // Allow callback as third param.
4653        if (typeof options === 'function') {
4654            callback = options;
4655            options  = {};
4656        }
4657
4658        options || (options = {});
4659        options.type = type;
4660
4661        options._onFinish = Get._onTransactionFinish;
4662
4663        if (!this._env) {
4664            this._getEnv();
4665        }
4666
4667        transaction = this._getTransaction(urls, options);
4668
4669        this._queue.push({
4670            callback   : callback,
4671            transaction: transaction
4672        });
4673
4674        this._next();
4675
4676        return transaction;
4677    },
4678
4679    _onTransactionFinish : function() {
4680        Get._pending = null;
4681        Get._next();
4682    },
4683
4684    _next: function () {
4685        var item;
4686
4687        if (this._pending) {
4688            return;
4689        }
4690
4691        item = this._queue.shift();
4692
4693        if (item) {
4694            this._pending = item;
4695            item.transaction.execute(item.callback);
4696        }
4697    },
4698
4699    _purge: function (nodes) {
4700        var purgeNodes    = this._purgeNodes,
4701            isTransaction = nodes !== purgeNodes,
4702            index, node;
4703
4704        while (node = nodes.pop()) { // assignment
4705            // Don't purge nodes that haven't finished loading (or errored out),
4706            // since this can hang the transaction.
4707            if (!node._yuiget_finished) {
4708                continue;
4709            }
4710
4711            node.parentNode && node.parentNode.removeChild(node);
4712
4713            // If this is a transaction-level purge and this node also exists in
4714            // the Get-level _purgeNodes array, we need to remove it from
4715            // _purgeNodes to avoid creating a memory leak. The indexOf lookup
4716            // sucks, but until we get WeakMaps, this is the least troublesome
4717            // way to do this (we can't just hold onto node ids because they may
4718            // not be in the same document).
4719            if (isTransaction) {
4720                index = Y.Array.indexOf(purgeNodes, node);
4721
4722                if (index > -1) {
4723                    purgeNodes.splice(index, 1);
4724                }
4725            }
4726        }
4727    }
4728};
4729
4730/**
4731Alias for `js()`.
4732
4733@method script
4734@static
4735**/
4736Get.script = Get.js;
4737
4738/**
4739Represents a Get transaction, which may contain requests for one or more JS or
4740CSS files.
4741
4742This class should not be instantiated manually. Instances will be created and
4743returned as needed by Y.Get's `css()`, `js()`, and `load()` methods.
4744
4745@class Get.Transaction
4746@constructor
4747@since 3.5.0
4748**/
4749Get.Transaction = Transaction = function (requests, options) {
4750    var self = this;
4751
4752    self.id       = Transaction._lastId += 1;
4753    self.data     = options.data;
4754    self.errors   = [];
4755    self.nodes    = [];
4756    self.options  = options;
4757    self.requests = requests;
4758
4759    self._callbacks = []; // callbacks to call after execution finishes
4760    self._queue     = [];
4761    self._reqsWaiting   = 0;
4762
4763    // Deprecated pre-3.5.0 properties.
4764    self.tId = self.id; // Use `id` instead.
4765    self.win = options.win || Y.config.win;
4766};
4767
4768/**
4769Arbitrary data object associated with this transaction.
4770
4771This object comes from the options passed to `Get.css()`, `Get.js()`, or
4772`Get.load()`, and will be `undefined` if no data object was specified.
4773
4774@property {Object} data
4775**/
4776
4777/**
4778Array of errors that have occurred during this transaction, if any. Each error
4779object has the following properties:
4780`errors.error`: Error message.
4781`errors.request`: Request object related to the error.
4782
4783@since 3.5.0
4784@property {Object[]} errors
4785**/
4786
4787/**
4788Numeric id for this transaction, unique among all transactions within the same
4789YUI sandbox in the current pageview.
4790
4791@property {Number} id
4792@since 3.5.0
4793**/
4794
4795/**
4796HTMLElement nodes (native ones, not YUI Node instances) that have been inserted
4797during the current transaction.
4798
4799@property {HTMLElement[]} nodes
4800**/
4801
4802/**
4803Options associated with this transaction.
4804
4805See `Get.options` for the full list of available options.
4806
4807@property {Object} options
4808@since 3.5.0
4809**/
4810
4811/**
4812Request objects contained in this transaction. Each request object represents
4813one CSS or JS URL that will be (or has been) requested and loaded into the page.
4814
4815@property {Object} requests
4816@since 3.5.0
4817**/
4818
4819/**
4820Id of the most recent transaction.
4821
4822@property _lastId
4823@type Number
4824@protected
4825@static
4826**/
4827Transaction._lastId = 0;
4828
4829Transaction.prototype = {
4830    // -- Public Properties ----------------------------------------------------
4831
4832    /**
4833    Current state of this transaction. One of "new", "executing", or "done".
4834
4835    @property _state
4836    @type String
4837    @protected
4838    **/
4839    _state: 'new', // "new", "executing", or "done"
4840
4841    // -- Public Methods -------------------------------------------------------
4842
4843    /**
4844    Aborts this transaction.
4845
4846    This will cause the transaction's `onFailure` callback to be called and
4847    will prevent any new script and link nodes from being added to the document,
4848    but any resources that have already been requested will continue loading
4849    (there's no safe way to prevent this, unfortunately).
4850
4851    @method abort
4852    @param {String} [msg="Aborted."] Optional message to use in the `errors`
4853        array describing why the transaction was aborted.
4854    **/
4855    abort: function (msg) {
4856        this._pending    = null;
4857        this._pendingCSS = null;
4858        this._pollTimer  = clearTimeout(this._pollTimer);
4859        this._queue      = [];
4860        this._reqsWaiting    = 0;
4861
4862        this.errors.push({error: msg || 'Aborted'});
4863        this._finish();
4864    },
4865
4866    /**
4867    Begins execting the transaction.
4868
4869    There's usually no reason to call this manually, since Get will call it
4870    automatically when other pending transactions have finished. If you really
4871    want to execute your transaction before Get does, you can, but be aware that
4872    this transaction's scripts may end up executing before the scripts in other
4873    pending transactions.
4874
4875    If the transaction is already executing, the specified callback (if any)
4876    will be queued and called after execution finishes. If the transaction has
4877    already finished, the callback will be called immediately (the transaction
4878    will not be executed again).
4879
4880    @method execute
4881    @param {Function} callback Callback function to execute after all requests
4882        in the transaction are complete, or after the transaction is aborted.
4883    **/
4884    execute: function (callback) {
4885        var self     = this,
4886            requests = self.requests,
4887            state    = self._state,
4888            i, len, queue, req;
4889
4890        if (state === 'done') {
4891            callback && callback(self.errors.length ? self.errors : null, self);
4892            return;
4893        } else {
4894            callback && self._callbacks.push(callback);
4895
4896            if (state === 'executing') {
4897                return;
4898            }
4899        }
4900
4901        self._state = 'executing';
4902        self._queue = queue = [];
4903
4904        if (self.options.timeout) {
4905            self._timeout = setTimeout(function () {
4906                self.abort('Timeout');
4907            }, self.options.timeout);
4908        }
4909
4910        self._reqsWaiting = requests.length;
4911
4912        for (i = 0, len = requests.length; i < len; ++i) {
4913            req = requests[i];
4914
4915            if (req.async || req.type === 'css') {
4916                // No need to queue CSS or fully async JS.
4917                self._insert(req);
4918            } else {
4919                queue.push(req);
4920            }
4921        }
4922
4923        self._next();
4924    },
4925
4926    /**
4927    Manually purges any `<script>` or `<link>` nodes this transaction has
4928    created.
4929
4930    Be careful when purging a transaction that contains CSS requests, since
4931    removing `<link>` nodes will also remove any styles they applied.
4932
4933    @method purge
4934    **/
4935    purge: function () {
4936        Get._purge(this.nodes);
4937    },
4938
4939    // -- Protected Methods ----------------------------------------------------
4940    _createNode: function (name, attrs, doc) {
4941        var node = doc.createElement(name),
4942            attr, testEl;
4943
4944        if (!CUSTOM_ATTRS) {
4945            // IE6 and IE7 expect property names rather than attribute names for
4946            // certain attributes. Rather than sniffing, we do a quick feature
4947            // test the first time _createNode() runs to determine whether we
4948            // need to provide a workaround.
4949            testEl = doc.createElement('div');
4950            testEl.setAttribute('class', 'a');
4951
4952            CUSTOM_ATTRS = testEl.className === 'a' ? {} : {
4953                'for'  : 'htmlFor',
4954                'class': 'className'
4955            };
4956        }
4957
4958        for (attr in attrs) {
4959            if (attrs.hasOwnProperty(attr)) {
4960                node.setAttribute(CUSTOM_ATTRS[attr] || attr, attrs[attr]);
4961            }
4962        }
4963
4964        return node;
4965    },
4966
4967    _finish: function () {
4968        var errors  = this.errors.length ? this.errors : null,
4969            options = this.options,
4970            thisObj = options.context || this,
4971            data, i, len;
4972
4973        if (this._state === 'done') {
4974            return;
4975        }
4976
4977        this._state = 'done';
4978
4979        for (i = 0, len = this._callbacks.length; i < len; ++i) {
4980            this._callbacks[i].call(thisObj, errors, this);
4981        }
4982
4983        data = this._getEventData();
4984
4985        if (errors) {
4986            if (options.onTimeout && errors[errors.length - 1].error === 'Timeout') {
4987                options.onTimeout.call(thisObj, data);
4988            }
4989
4990            if (options.onFailure) {
4991                options.onFailure.call(thisObj, data);
4992            }
4993        } else if (options.onSuccess) {
4994            options.onSuccess.call(thisObj, data);
4995        }
4996
4997        if (options.onEnd) {
4998            options.onEnd.call(thisObj, data);
4999        }
5000
5001        if (options._onFinish) {
5002            options._onFinish();
5003        }
5004    },
5005
5006    _getEventData: function (req) {
5007        if (req) {
5008            // This merge is necessary for backcompat. I hate it.
5009            return Y.merge(this, {
5010                abort  : this.abort, // have to copy these because the prototype isn't preserved
5011                purge  : this.purge,
5012                request: req,
5013                url    : req.url,
5014                win    : req.win
5015            });
5016        } else {
5017            return this;
5018        }
5019    },
5020
5021    _getInsertBefore: function (req) {
5022        var doc = req.doc,
5023            el  = req.insertBefore,
5024            cache, docStamp;
5025
5026        if (el) {
5027            return typeof el === 'string' ? doc.getElementById(el) : el;
5028        }
5029
5030        cache    = Get._insertCache;
5031        docStamp = Y.stamp(doc);
5032
5033        if ((el = cache[docStamp])) { // assignment
5034            return el;
5035        }
5036
5037        // Inserting before a <base> tag apparently works around an IE bug
5038        // (according to a comment from pre-3.5.0 Y.Get), but I'm not sure what
5039        // bug that is, exactly. Better safe than sorry?
5040        if ((el = doc.getElementsByTagName('base')[0])) { // assignment
5041            return (cache[docStamp] = el);
5042        }
5043
5044        // Look for a <head> element.
5045        el = doc.head || doc.getElementsByTagName('head')[0];
5046
5047        if (el) {
5048            // Create a marker node at the end of <head> to use as an insertion
5049            // point. Inserting before this node will ensure that all our CSS
5050            // gets inserted in the correct order, to maintain style precedence.
5051            el.appendChild(doc.createTextNode(''));
5052            return (cache[docStamp] = el.lastChild);
5053        }
5054
5055        // If all else fails, just insert before the first script node on the
5056        // page, which is virtually guaranteed to exist.
5057        return (cache[docStamp] = doc.getElementsByTagName('script')[0]);
5058    },
5059
5060    _insert: function (req) {
5061        var env          = Get._env,
5062            insertBefore = this._getInsertBefore(req),
5063            isScript     = req.type === 'js',
5064            node         = req.node,
5065            self         = this,
5066            ua           = Y.UA,
5067            cssTimeout, nodeType;
5068
5069        if (!node) {
5070            if (isScript) {
5071                nodeType = 'script';
5072            } else if (!env.cssLoad && ua.gecko) {
5073                nodeType = 'style';
5074            } else {
5075                nodeType = 'link';
5076            }
5077
5078            node = req.node = this._createNode(nodeType, req.attributes,
5079                req.doc);
5080        }
5081
5082        function onError() {
5083            self._progress('Failed to load ' + req.url, req);
5084        }
5085
5086        function onLoad() {
5087            if (cssTimeout) {
5088                clearTimeout(cssTimeout);
5089            }
5090
5091            self._progress(null, req);
5092        }
5093
5094        // Deal with script asynchronicity.
5095        if (isScript) {
5096            node.setAttribute('src', req.url);
5097
5098            if (req.async) {
5099                // Explicitly indicate that we want the browser to execute this
5100                // script asynchronously. This is necessary for older browsers
5101                // like Firefox <4.
5102                node.async = true;
5103            } else {
5104                if (env.async) {
5105                    // This browser treats injected scripts as async by default
5106                    // (standard HTML5 behavior) but asynchronous loading isn't
5107                    // desired, so tell the browser not to mark this script as
5108                    // async.
5109                    node.async = false;
5110                }
5111
5112                // If this browser doesn't preserve script execution order based
5113                // on insertion order, we'll need to avoid inserting other
5114                // scripts until this one finishes loading.
5115                if (!env.preservesScriptOrder) {
5116                    this._pending = req;
5117                }
5118            }
5119        } else {
5120            if (!env.cssLoad && ua.gecko) {
5121                // In Firefox <9, we can import the requested URL into a <style>
5122                // node and poll for the existence of node.sheet.cssRules. This
5123                // gives us a reliable way to determine CSS load completion that
5124                // also works for cross-domain stylesheets.
5125                //
5126                // Props to Zach Leatherman for calling my attention to this
5127                // technique.
5128                node.innerHTML = (req.attributes.charset ?
5129                    '@charset "' + req.attributes.charset + '";' : '') +
5130                    '@import "' + req.url + '";';
5131            } else {
5132                node.setAttribute('href', req.url);
5133            }
5134        }
5135
5136        // Inject the node.
5137        if (isScript && ua.ie && (ua.ie < 9 || (document.documentMode && document.documentMode < 9))) {
5138            // Script on IE < 9, and IE 9+ when in IE 8 or older modes, including quirks mode.
5139            node.onreadystatechange = function () {
5140                if (/loaded|complete/.test(node.readyState)) {
5141                    node.onreadystatechange = null;
5142                    onLoad();
5143                }
5144            };
5145        } else if (!isScript && !env.cssLoad) {
5146            // CSS on Firefox <9 or WebKit.
5147            this._poll(req);
5148        } else {
5149            // Script or CSS on everything else. Using DOM 0 events because that
5150            // evens the playing field with older IEs.
5151
5152            if (ua.ie >= 10) {
5153
5154                // We currently need to introduce a timeout for IE10, since it
5155                // calls onerror/onload synchronously for 304s - messing up existing
5156                // program flow.
5157
5158                // Remove this block if the following bug gets fixed by GA
5159                /*jshint maxlen: 1500 */
5160                // https://connect.microsoft.com/IE/feedback/details/763871/dynamically-loaded-scripts-with-304s-responses-interrupt-the-currently-executing-js-thread-onload
5161                node.onerror = function() { setTimeout(onError, 0); };
5162                node.onload  = function() { setTimeout(onLoad, 0); };
5163            } else {
5164                node.onerror = onError;
5165                node.onload  = onLoad;
5166            }
5167
5168            // If this browser doesn't fire an event when CSS fails to load,
5169            // fail after a timeout to avoid blocking the transaction queue.
5170            if (!env.cssFail && !isScript) {
5171                cssTimeout = setTimeout(onError, req.timeout || 3000);
5172            }
5173        }
5174
5175        this.nodes.push(node);
5176        insertBefore.parentNode.insertBefore(node, insertBefore);
5177    },
5178
5179    _next: function () {
5180        if (this._pending) {
5181            return;
5182        }
5183
5184        // If there are requests in the queue, insert the next queued request.
5185        // Otherwise, if we're waiting on already-inserted requests to finish,
5186        // wait longer. If there are no queued requests and we're not waiting
5187        // for anything to load, then we're done!
5188        if (this._queue.length) {
5189            this._insert(this._queue.shift());
5190        } else if (!this._reqsWaiting) {
5191            this._finish();
5192        }
5193    },
5194
5195    _poll: function (newReq) {
5196        var self       = this,
5197            pendingCSS = self._pendingCSS,
5198            isWebKit   = Y.UA.webkit,
5199            i, hasRules, j, nodeHref, req, sheets;
5200
5201        if (newReq) {
5202            pendingCSS || (pendingCSS = self._pendingCSS = []);
5203            pendingCSS.push(newReq);
5204
5205            if (self._pollTimer) {
5206                // A poll timeout is already pending, so no need to create a
5207                // new one.
5208                return;
5209            }
5210        }
5211
5212        self._pollTimer = null;
5213
5214        // Note: in both the WebKit and Gecko hacks below, a CSS URL that 404s
5215        // will still be treated as a success. There's no good workaround for
5216        // this.
5217
5218        for (i = 0; i < pendingCSS.length; ++i) {
5219            req = pendingCSS[i];
5220
5221            if (isWebKit) {
5222                // Look for a stylesheet matching the pending URL.
5223                sheets   = req.doc.styleSheets;
5224                j        = sheets.length;
5225                nodeHref = req.node.href;
5226
5227                while (--j >= 0) {
5228                    if (sheets[j].href === nodeHref) {
5229                        pendingCSS.splice(i, 1);
5230                        i -= 1;
5231                        self._progress(null, req);
5232                        break;
5233                    }
5234                }
5235            } else {
5236                // Many thanks to Zach Leatherman for calling my attention to
5237                // the @import-based cross-domain technique used here, and to
5238                // Oleg Slobodskoi for an earlier same-domain implementation.
5239                //
5240                // See Zach's blog for more details:
5241                // http://www.zachleat.com/web/2010/07/29/load-css-dynamically/
5242                try {
5243                    // We don't really need to store this value since we never
5244                    // use it again, but if we don't store it, Closure Compiler
5245                    // assumes the code is useless and removes it.
5246                    hasRules = !!req.node.sheet.cssRules;
5247
5248                    // If we get here, the stylesheet has loaded.
5249                    pendingCSS.splice(i, 1);
5250                    i -= 1;
5251                    self._progress(null, req);
5252                } catch (ex) {
5253                    // An exception means the stylesheet is still loading.
5254                }
5255            }
5256        }
5257
5258        if (pendingCSS.length) {
5259            self._pollTimer = setTimeout(function () {
5260                self._poll.call(self);
5261            }, self.options.pollInterval);
5262        }
5263    },
5264
5265    _progress: function (err, req) {
5266        var options = this.options;
5267
5268        if (err) {
5269            req.error = err;
5270
5271            this.errors.push({
5272                error  : err,
5273                request: req
5274            });
5275
5276        }
5277
5278        req.node._yuiget_finished = req.finished = true;
5279
5280        if (options.onProgress) {
5281            options.onProgress.call(options.context || this,
5282                this._getEventData(req));
5283        }
5284
5285        if (req.autopurge) {
5286            // Pre-3.5.0 Get always excludes the most recent node from an
5287            // autopurge. I find this odd, but I'm keeping that behavior for
5288            // the sake of backcompat.
5289            Get._autoPurge(this.options.purgethreshold);
5290            Get._purgeNodes.push(req.node);
5291        }
5292
5293        if (this._pending === req) {
5294            this._pending = null;
5295        }
5296
5297        this._reqsWaiting -= 1;
5298
5299        this._next();
5300    }
5301};
5302
5303
5304}, '3.18.1', {"requires": ["yui-base"]});
5305YUI.add('features', function (Y, NAME) {
5306
5307var feature_tests = {};
5308
5309/**
5310Contains the core of YUI's feature test architecture.
5311@module features
5312*/
5313
5314/**
5315* Feature detection
5316* @class Features
5317* @static
5318*/
5319
5320Y.mix(Y.namespace('Features'), {
5321
5322    /**
5323    * Object hash of all registered feature tests
5324    * @property tests
5325    * @type Object
5326    */
5327    tests: feature_tests,
5328
5329    /**
5330    * Add a test to the system
5331    *
5332    *   ```
5333    *   Y.Features.add("load", "1", {});
5334    *   ```
5335    *
5336    * @method add
5337    * @param {String} cat The category, right now only 'load' is supported
5338    * @param {String}
5338 name The number sequence of the test, how it's reported in the URL or config: 1, 2, 3
5339    * @param {Object} o Object containing test properties
5340    * @param {String} o.name The name of the test
5341    * @param {Function} o.test The test function to execute, the only argument to the function is the `Y` instance
5342    * @param {String} o.trigger The module that triggers this test.
5343    */
5344    add: function(cat, name, o) {
5345        feature_tests[cat] = feature_tests[cat] || {};
5346        feature_tests[cat][name] = o;
5347    },
5348    /**
5349    * Execute all tests of a given category and return the serialized results
5350    *
5351    *   ```
5352    *   caps=1:1;2:1;3:0
5353    *   ```
5354    * @method all
5355    * @param {String} cat The category to execute
5356    * @param {Array} args The arguments to pass to the test function
5357    * @return {String} A semi-colon separated string of tests and their success/failure: 1:1;2:1;3:0
5358    */
5359    all: function(cat, args) {
5360        var cat_o = feature_tests[cat],
5361            // results = {};
5362            result = [];
5363        if (cat_o) {
5364            Y.Object.each(cat_o, function(v, k) {
5365                result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0));
5366            });
5367        }
5368
5369        return (result.length) ? result.join(';') : '';
5370    },
5371    /**
5372    * Run a specific test and return a Boolean response.
5373    *
5374    *   ```
5375    *   Y.Features.test("load", "1");
5376    *   ```
5377    *
5378    * @method test
5379    * @param {String} cat The category of the test to run
5380    * @param {String} name The name of the test to run
5381    * @param {Array} args The arguments to pass to the test function
5382    * @return {Boolean} True or false if the test passed/failed.
5383    */
5384    test: function(cat, name, args) {
5385        args = args || [];
5386        var result, ua, test,
5387            cat_o = feature_tests[cat],
5388            feature = cat_o && cat_o[name];
5389
5390        if (!feature) {
5391        } else {
5392
5393            result = feature.result;
5394
5395            if (Y.Lang.isUndefined(result)) {
5396
5397                ua = feature.ua;
5398                if (ua) {
5399                    result = (Y.UA[ua]);
5400                }
5401
5402                test = feature.test;
5403                if (test && ((!ua) || result)) {
5404                    result = test.apply(Y, args);
5405                }
5406
5407                feature.result = result;
5408            }
5409        }
5410
5411        return result;
5412    }
5413});
5414
5415// Y.Features.add("load", "1", {});
5416// Y.Features.test("load", "1");
5417// caps=1:1;2:0;3:1;
5418
5419/* This file is auto-generated by (yogi loader --yes --mix --start ../) */
5420/*jshint maxlen:900, eqeqeq: false */
5421var add = Y.Features.add;
5422// app-transitions-native
5423add('load', '0', {
5424    "name": "app-transitions-native",
5425    "test": function (Y) {
5426    var doc  = Y.config.doc,
5427        node = doc ? doc.documentElement : null;
5428
5429    if (node && node.style) {
5430        return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
5431    }
5432
5433    return false;
5434},
5435    "trigger": "app-transitions"
5436});
5437// autocomplete-list-keys
5438add('load', '1', {
5439    "name": "autocomplete-list-keys",
5440    "test": function (Y) {
5441    // Only add keyboard support to autocomplete-list if this doesn't appear to
5442    // be an iOS or Android-based mobile device.
5443    //
5444    // There's currently no feasible way to actually detect whether a device has
5445    // a hardware keyboard, so this sniff will have to do. It can easily be
5446    // overridden by manually loading the autocomplete-list-keys module.
5447    //
5448    // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
5449    // doesn't fire the keyboard events used by AutoCompleteList, so there's
5450    // no point loading the -keys module even when a bluetooth keyboard may be
5451    // available.
5452    return !(Y.UA.ios || Y.UA.android);
5453},
5454    "trigger": "autocomplete-list"
5455});
5456// dd-gestures
5457add('load', '2', {
5458    "name": "dd-gestures",
5459    "trigger": "dd-drag",
5460    "ua": "touchEnabled"
5461});
5462// dom-style-ie
5463add('load', '3', {
5464    "name": "dom-style-ie",
5465    "test": function (Y) {
5466
5467    var testFeature = Y.Features.test,
5468        addFeature = Y.Features.add,
5469        WINDOW = Y.config.win,
5470        DOCUMENT = Y.config.doc,
5471        DOCUMENT_ELEMENT = 'documentElement',
5472        ret = false;
5473
5474    addFeature('style', 'computedStyle', {
5475        test: function() {
5476            return WINDOW && 'getComputedStyle' in WINDOW;
5477        }
5478    });
5479
5480    addFeature('style', 'opacity', {
5481        test: function() {
5482            return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
5483        }
5484    });
5485
5486    ret =  (!testFeature('style', 'opacity') &&
5487            !testFeature('style', 'computedStyle'));
5488
5489    return ret;
5490},
5491    "trigger": "dom-style"
5492});
5493// editor-para-ie
5494add('load', '4', {
5495    "name": "editor-para-ie",
5496    "trigger": "editor-para",
5497    "ua": "ie",
5498    "when": "instead"
5499});
5500// event-base-ie
5501add('load', '5', {
5502    "name": "event-base-ie",
5503    "test": function(Y) {
5504    var imp = Y.config.doc && Y.config.doc.implementation;
5505    return (imp && (!imp.hasFeature('Events', '2.0')));
5506},
5507    "trigger": "node-base"
5508});
5509// graphics-canvas
5510add('load', '6', {
5511    "name": "graphics-canvas",
5512    "test": function(Y) {
5513    var DOCUMENT = Y.config.doc,
5514        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
5515		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
5516        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
5517    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
5518},
5519    "trigger": "graphics"
5520});
5521// graphics-canvas-default
5522add('load', '7', {
5523    "name": "graphics-canvas-default",
5524    "test": function(Y) {
5525    var DOCUMENT = Y.config.doc,
5526        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
5527		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
5528        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
5529    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
5530},
5531    "trigger": "graphics"
5532});
5533// graphics-svg
5534add('load', '8', {
5535    "name": "graphics-svg",
5536    "test": function(Y) {
5537    var DOCUMENT = Y.config.doc,
5538        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
5539		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
5540        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
5541
5542    return svg && (useSVG || !canvas);
5543},
5544    "trigger": "graphics"
5545});
5546// graphics-svg-default
5547add('load', '9', {
5548    "name": "graphics-svg-default",
5549    "test": function(Y) {
5550    var DOCUMENT = Y.config.doc,
5551        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
5552		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
5553        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
5554
5555    return svg && (useSVG || !canvas);
5556},
5557    "trigger": "graphics"
5558});
5559// graphics-vml
5560add('load', '10', {
5561    "name": "graphics-vml",
5562    "test": function(Y) {
5563    var DOCUMENT = Y.config.doc,
5564		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
5565    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
5566},
5567    "trigger": "graphics"
5568});
5569// graphics-vml-default
5570add('load', '11', {
5571    "name": "graphics-vml-default",
5572    "test": function(Y) {
5573    var DOCUMENT = Y.config.doc,
5574		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
5575    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
5576},
5577    "trigger": "graphics"
5578});
5579// history-hash-ie
5580add('load', '12', {
5581    "name": "history-hash-ie",
5582    "test": function (Y) {
5583    var docMode = Y.config.doc && Y.config.doc.documentMode;
5584
5585    return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
5586            !docMode || docMode < 8);
5587},
5588    "trigger": "history-hash"
5589});
5590// io-nodejs
5591add('load', '13', {
5592    "name": "io-nodejs",
5593    "trigger": "io-base",
5594    "ua": "nodejs"
5595});
5596// json-parse-shim
5597add('load', '14', {
5598    "name": "json-parse-shim",
5599    "test": function (Y) {
5600    var _JSON = Y.config.global.JSON,
5601        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
5602        nativeSupport = Y.config.useNativeJSONParse !== false && !!Native;
5603
5604    function workingNative( k, v ) {
5605        return k === "ok" ? true : v;
5606    }
5607
5608    // Double check basic functionality.  This is mainly to catch early broken
5609    // implementations of the JSON API in Firefox 3.1 beta1 and beta2
5610    if ( nativeSupport ) {
5611        try {
5612            nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
5613        }
5614        catch ( e ) {
5615            nativeSupport = false;
5616        }
5617    }
5618
5619    return !nativeSupport;
5620},
5621    "trigger": "json-parse"
5622});
5623// json-stringify-shim
5624add('load', '15', {
5625    "name": "json-stringify-shim",
5626    "test": function (Y) {
5627    var _JSON = Y.config.global.JSON,
5628        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
5629        nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native;
5630
5631    // Double check basic native functionality.  This is primarily to catch broken
5632    // early JSON API implementations in Firefox 3.1 beta1 and beta2.
5633    if ( nativeSupport ) {
5634        try {
5635            nativeSupport = ( '0' === Native.stringify(0) );
5636        } catch ( e ) {
5637            nativeSupport = false;
5638        }
5639    }
5640
5641
5642    return !nativeSupport;
5643},
5644    "trigger": "json-stringify"
5645});
5646// scrollview-base-ie
5647add('load', '16', {
5648    "name": "scrollview-base-ie",
5649    "trigger": "scrollview-base",
5650    "ua": "ie"
5651});
5652// selector-css2
5653add('load', '17', {
5654    "name": "selector-css2",
5655    "test": function (Y) {
5656    var DOCUMENT = Y.config.doc,
5657        ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
5658
5659    return ret;
5660},
5661    "trigger": "selector"
5662});
5663// transition-timer
5664add('load', '18', {
5665    "name": "transition-timer",
5666    "test": function (Y) {
5667    var DOCUMENT = Y.config.doc,
5668        node = (DOCUMENT) ? DOCUMENT.documentElement: null,
5669        ret = true;
5670
5671    if (node && node.style) {
5672        ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
5673    }
5674
5675    return ret;
5676},
5677    "trigger": "transition"
5678});
5679// widget-base-ie
5680add('load', '19', {
5681    "name": "widget-base-ie",
5682    "trigger": "widget-base",
5683    "ua": "ie"
5684});
5685// yql-jsonp
5686add('load', '20', {
5687    "name": "yql-jsonp",
5688    "test": function (Y) {
5689    /* Only load the JSONP module when not in nodejs or winjs
5690    TODO Make the winjs module a CORS module
5691    */
5692    return (!Y.UA.nodejs && !Y.UA.winjs);
5693},
5694    "trigger": "yql"
5695});
5696// yql-nodejs
5697add('load', '21', {
5698    "name": "yql-nodejs",
5699    "trigger": "yql",
5700    "ua": "nodejs"
5701});
5702// yql-winjs
5703add('load', '22', {
5704    "name": "yql-winjs",
5705    "trigger": "yql",
5706    "ua": "winjs"
5707});
5708
5709}, '3.18.1', {"requires": ["yui-base"]});
5710YUI.add('intl-base', function (Y, NAME) {
5711
5712/**
5713 * The Intl utility provides a central location for managing sets of
5714 * localized resources (strings and formatting patterns).
5715 *
5716 * @class Intl
5717 * @uses EventTarget
5718 * @static
5719 */
5720
5721var SPLIT_REGEX = /[, ]/;
5722
5723Y.mix(Y.namespace('Intl'), {
5724
5725 /**
5726    * Returns the language among those available that
5727    * best matches the preferred language list, using the Lookup
5728    * algorithm of BCP 47.
5729    * If none of the available languages meets the user's preferences,
5730    * then "" is returned.
5731    * Extended language ranges are not supported.
5732    *
5733    * @method lookupBestLang
5734    * @param {String[] | String} preferredLanguages The list of preferred
5735    * languages in descending preference order, represented as BCP 47
5736    * language tags. A string array or a comma-separated list.
5737    * @param {String[]} availableLanguages The list of languages
5738    * that the application supports, represented as BCP 47 language
5739    * tags.
5740    *
5741    * @return {String} The available language that best matches the
5742    * preferred language list, or "".
5743    * @since 3.1.0
5744    */
5745    lookupBestLang: function(preferredLanguages, availableLanguages) {
5746
5747        var i, language, result, index;
5748
5749        // check whether the list of available languages contains language;
5750        // if so return it
5751        function scan(language) {
5752            var i;
5753            for (i = 0; i < availableLanguages.length; i += 1) {
5754                if (language.toLowerCase() ===
5755                            availableLanguages[i].toLowerCase()) {
5756                    return availableLanguages[i];
5757                }
5758            }
5759        }
5760
5761        if (Y.Lang.isString(preferredLanguages)) {
5762            preferredLanguages = preferredLanguages.split(SPLIT_REGEX);
5763        }
5764
5765        for (i = 0; i < preferredLanguages.length; i += 1) {
5766            language = preferredLanguages[i];
5767            if (!language || language === '*') {
5768                continue;
5769            }
5770            // check the fallback sequence for one language
5771            while (language.length > 0) {
5772                result = scan(language);
5773                if (result) {
5774                    return result;
5775                } else {
5776                    index = language.lastIndexOf('-');
5777                    if (index >= 0) {
5778                        language = language.substring(0, index);
5779                        // one-character subtags get cut along with the
5780                        // following subtag
5781                        if (index >
5781= 2 && language.charAt(index - 2) === '-') {
5782                            language = language.substring(0, index - 2);
5783                        }
5784                    } else {
5785                        // nothing available for this language
5786                        break;
5787                    }
5788                }
5789            }
5790        }
5791
5792        return '';
5793    }
5794});
5795
5796
5797}, '3.18.1', {"requires": ["yui-base"]});
5798YUI.add('yui-log', function (Y, NAME) {
5799
5800/**
5801 * Provides console log capability and exposes a custom event for
5802 * console implementations. This module is a `core` YUI module,
5803 * <a href="../classes/YUI.html#method_log">it's documentation is located under the YUI class</a>.
5804 *
5805 * @module yui
5806 * @submodule yui-log
5807 */
5808
5809var INSTANCE = Y,
5810    LOGEVENT = 'yui:log',
5811    UNDEFINED = 'undefined',
5812    LEVELS = { debug: 1,
5813               info: 2,
5814               warn: 4,
5815               error: 8 };
5816
5817/**
5818 * If the 'debug' config is true, a 'yui:log' event will be
5819 * dispatched, which the Console widget and anything else
5820 * can consume.  If the 'useBrowserConsole' config is true, it will
5821 * write to the browser console if available.  YUI-specific log
5822 * messages will only be present in the -debug versions of the
5823 * JS files.  The build system is supposed to remove log statements
5824 * from the raw and minified versions of the files.
5825 *
5826 * @method log
5827 * @for YUI
5828 * @param  {String}  msg  The message to log.
5829 * @param  {String}  cat  The log category for the message.  Default
5830 *                        categories are "info", "warn", "error", "debug".
5831 *                        Custom categories can be used as well. (opt).
5832 * @param  {String}  src  The source of the the message (opt).
5833 * @param  {boolean} silent If true, the log event won't fire.
5834 * @return {YUI}      YUI instance.
5835 */
5836INSTANCE.log = function(msg, cat, src, silent) {
5837    var bail, excl, incl, m, f, minlevel,
5838        Y = INSTANCE,
5839        c = Y.config,
5840        publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
5841    // suppress log message if the config is off or the event stack
5842    // or the event call stack contains a consumer of the yui:log event
5843    if (c.debug) {
5844        // apply source filters
5845        src = src || "";
5846        if (typeof src !== "undefined") {
5847            excl = c.logExclude;
5848            incl = c.logInclude;
5849            if (incl && !(src in incl)) {
5850                bail = 1;
5851            } else if (incl && (src in incl)) {
5852                bail = !incl[src];
5853            } else if (excl && (src in excl)) {
5854                bail = excl[src];
5855            }
5856
5857            // Set a default category of info if the category was not defined.
5858            if ((typeof cat === 'undefined')) {
5859                cat = 'info';
5860            }
5861
5862            // Determine the current minlevel as defined in configuration
5863            Y.config.logLevel = Y.config.logLevel || 'debug';
5864            minlevel = LEVELS[Y.config.logLevel.toLowerCase()];
5865
5866            if (cat in LEVELS && LEVELS[cat] < minlevel) {
5867                // Skip this message if the we don't meet the defined minlevel
5868                bail = 1;
5869            }
5870        }
5871        if (!bail) {
5872            if (c.useBrowserConsole) {
5873                m = (src) ? src + ': ' + msg : msg;
5874                if (Y.Lang.isFunction(c.logFn)) {
5875                    c.logFn.call(Y, msg, cat, src);
5876                } else if (typeof console !== UNDEFINED && console.log) {
5877                    f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
5878                    console[f](m);
5879                } else if (typeof opera !== UNDEFINED) {
5880                    opera.postError(m);
5881                }
5882            }
5883
5884            if (publisher && !silent) {
5885
5886                if (publisher === Y && (!publisher.getEvent(LOGEVENT))) {
5887                    publisher.publish(LOGEVENT, {
5888                        broadcast: 2
5889                    });
5890                }
5891
5892                publisher.fire(LOGEVENT, {
5893                    msg: msg,
5894                    cat: cat,
5895                    src: src
5896                });
5897            }
5898        }
5899    }
5900
5901    return Y;
5902};
5903
5904/**
5905 * Write a system message.  This message will be preserved in the
5906 * minified and raw versions of the YUI files, unlike log statements.
5907 * @method message
5908 * @for YUI
5909 * @param  {String}  msg  The message to log.
5910 * @param  {String}  cat  The log category for the message.  Default
5911 *                        categories are "info", "warn", "error", "debug".
5912 *                        Custom categories can be used as well. (opt).
5913 * @param  {String}  src  The source of the the message (opt).
5914 * @param  {boolean} silent If true, the log event won't fire.
5915 * @return {YUI}      YUI instance.
5916 */
5917INSTANCE.message = function() {
5918    return INSTANCE.log.apply(INSTANCE, arguments);
5919};
5920
5921
5922}, '3.18.1', {"requires": ["yui-base"]});
5923YUI.add('yui-later', function (Y, NAME) {
5924
5925/**
5926 * Provides a setTimeout/setInterval wrapper. This module is a `core` YUI module,
5927 * <a href="../classes/YUI.html#method_later">
5927it's documentation is located under the YUI class</a>.
5928 *
5929 * @module yui
5930 * @submodule yui-later
5931 */
5932
5933var NO_ARGS = [];
5934
5935/**
5936 * Executes the supplied function in the context of the supplied
5937 * object 'when' milliseconds later.  Executes the function a
5938 * single time unless periodic is set to true.
5939 * @for YUI
5940 * @method later
5941 * @param when {Number} the number of milliseconds to wait until the fn
5942 * is executed.
5943 * @param o the context object.
5944 * @param fn {Function|String} the function to execute or the name of
5945 * the method in the 'o' object to execute.
5946 * @param data [Array] data that is provided to the function.  This
5947 * accepts either a single item or an array.  If an array is provided,
5948 * the function is executed with one parameter for each array item.
5949 * If you need to pass a single array parameter, it needs to be wrapped
5950 * in an array [myarray].
5951 *
5952 * Note: native methods in IE may not have the call and apply methods.
5953 * In this case, it will work, but you are limited to four arguments.
5954 *
5955 * @param periodic {boolean} if true, executes continuously at supplied
5956 * interval until canceled.
5957 * @return {object} a timer object. Call the cancel() method on this
5958 * object to stop the timer.
5959 */
5960Y.later = function(when, o, fn, data, periodic) {
5961    when = when || 0;
5962    data = (!Y.Lang.isUndefined(data)) ? Y.Array(data) : NO_ARGS;
5963    o = o || Y.config.win || Y;
5964
5965    var cancelled = false,
5966        method = (o && Y.Lang.isString(fn)) ? o[fn] : fn,
5967        wrapper = function() {
5968            // IE 8- may execute a setInterval callback one last time
5969            // after clearInterval was called, so in order to preserve
5970            // the cancel() === no more runny-run, we have to jump through
5971            // an extra hoop.
5972            if (!cancelled) {
5973                if (!method.apply) {
5974                    method(data[0], data[1], data[2], data[3]);
5975                } else {
5976                    method.apply(o, data || NO_ARGS);
5977                }
5978            }
5979        },
5980        id = (periodic) ? setInterval(wrapper, when) : setTimeout(wrapper, when);
5981
5982    return {
5983        id: id,
5984        interval: periodic,
5985        cancel: function() {
5986            cancelled = true;
5987            if (this.interval) {
5988                clearInterval(id);
5989            } else {
5990                clearTimeout(id);
5991            }
5992        }
5993    };
5994};
5995
5996Y.Lang.later = Y.later;
5997
5998
5999
6000}, '3.18.1', {"requires": ["yui-base"]});
6001YUI.add('loader-base', function (Y, NAME) {
6002
6003/**
6004 * The YUI loader core
6005 * @module loader
6006 * @submodule loader-base
6007 */
6008
6009(function() {
6010    var VERSION = Y.version,
6011        BUILD = '/build/',
6012        ROOT = VERSION + '/',
6013        CDN_BASE = Y.Env.base,
6014        GALLERY_VERSION = 'gallery-2014.07.31-18-26',
6015        TNT = '2in3',
6016        TNT_VERSION = '4',
6017        YUI2_VERSION = '2.9.0',
6018        COMBO_BASE = CDN_BASE + 'combo?',
6019        META = {
6020            version: VERSION,
6021            root: ROOT,
6022            base: Y.Env.base,
6023            comboBase: COMBO_BASE,
6024            skin: {
6025                defaultSkin: 'sam',
6026                base: 'assets/skins/',
6027                path: 'skin.css',
6028                after: [
6029                    'cssreset',
6030                    'cssfonts',
6031                    'cssgrids',
6032                    'cssbase',
6033                    'cssreset-context',
6034                    'cssfonts-context'
6035                ]
6036            },
6037            groups: {},
6038            patterns: {}
6039        },
6040        groups = META.groups,
6041        yui2Update = function(tnt, yui2, config) {
6042            var root = TNT + '.' +
6043                    (tnt || TNT_VERSION) + '/' +
6044                    (yui2 || YUI2_VERSION) + BUILD,
6045                base = (config && config.base) ? config.base : CDN_BASE,
6046                combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
6047
6048            groups.yui2.base = base + root;
6049            groups.yui2.root = root;
6050            groups.yui2.comboBase = combo;
6051        },
6052        galleryUpdate = function(tag, config) {
6053            var root = (tag || GALLERY_VERSION) + BUILD,
6054                base = (config && config.base) ? config.base : CDN_BASE,
6055                combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
6056
6057            groups.gallery.base = base + root;
6058            groups.gallery.root = root;
6059            groups.gallery.comboBase = combo;
6060        };
6061
6062
6063    groups[VERSION] = {};
6064
6065    groups.gallery = {
6066        ext: false,
6067        combine: true,
6068        comboBase: COMBO_BASE,
6069        update: galleryUpdate,
6070        patterns: {
6071            'gallery-': {},
6072            'lang/gallery-': {},
6073            'gallerycss-': {
6074                type: 'css'
6075            }
6076        }
6077    };
6078
6079    groups.yui2 = {
6080        combine: true,
6081        ext: false,
6082        comboBase: COMBO_BASE,
6083        update: yui2Update,
6084        patterns: {
6085            'yui2-': {
6086                configFn: function(me) {
6087                    if (/-skin|reset|fonts|grids|base/.test(me.name)) {
6088                        me.type = 'css';
6089                        me.path = me.path.replace(/\.js/, '.css');
6090                        // this makes skins in builds earlier than
6091                        // 2.6.0 work as long as combine is false
6092                        me.path = me.path.replace(/\/yui2-skin/,
6093                                            '/assets/skins/sam/yui2-skin');
6094                    }
6095                }
6096            }
6097        }
6098    };
6099
6100    galleryUpdate();
6101    yui2Update();
6102
6103    if (YUI.Env[VERSION]) {
6104        Y.mix(META, YUI.Env[VERSION], false, [
6105            'modules',
6106            'groups',
6107            'skin'
6108        ], 0, true);
6109    }
6110
6111    YUI.Env[VERSION] = META;
6112}());
6113/*jslint forin: true, maxlen: 350 */
6114
6115/**
6116 * Loader dynamically loads script and css files.  It includes the dependency
6117 * information for the version of the library in use, and will automatically pull in
6118 * dependencies for the modules requested. It can also load the
6119 * files from the Yahoo! CDN, and it can utilize the combo service provided on
6120 * this network to reduce the number of http connections required to download
6121 * YUI files.
6122 *
6123 * @module loader
6124 * @main loader
6125 * @submodule loader-base
6126 */
6127
6128var NOT_FOUND = {},
6129    NO_REQUIREMENTS = [],
6130    MAX_URL_LENGTH = 1024,
6131    GLOBAL_ENV = YUI.Env,
6132    GLOBAL_LOADED = GLOBAL_ENV._loaded,
6133    CSS = 'css',
6134    JS = 'js',
6135    INTL = 'intl',
6136    DEFAULT_SKIN = 'sam',
6137    VERSION = Y.version,
6138    ROOT_LANG = '',
6139    YObject = Y.Object,
6140    oeach = YObject.each,
6141    yArray = Y.Array,
6142    _queue = GLOBAL_ENV._loaderQueue,
6143    META = GLOBAL_ENV[VERSION],
6144    SKIN_PREFIX = 'skin-',
6145    L = Y.Lang,
6146    ON_PAGE = GLOBAL_ENV.mods,
6147    modulekey,
6148    _path = function(dir, file, type, nomin) {
6149        var path = dir + '/' + file;
6150        if (!nomin) {
6151            path += '-min';
6152        }
6153        path += '.' + (type || CSS);
6154
6155        return path;
6156    };
6157
6158
6159    if (!YUI.Env._cssLoaded) {
6160        YUI.Env._cssLoaded = {};
6161    }
6162
6163
6164/**
6165 * The component metadata is stored in Y.Env.meta.
6166 * Part of the loader module.
6167 * @property meta
6168 * @for YUI
6169 */
6170Y.Env.meta = META;
6171
6172/**
6173 * Loader dynamically loads script and css files.  It includes the dependency
6174 * info for the version of the library in use, and will automatically pull in
6175 * dependencies for the modules requested. It can load the
6176 * files from the Yahoo! CDN, and it can utilize the combo service provided on
6177 * this network to reduce the number of http connections required to download
6178 * YUI files. You can also specify an external, custom combo service to host
6179 * your modules as well.
6180
6181        var Y = YUI();
6182        var loader = new Y.Loader({
6183            filter: 'debug',
6184            base: '../../',
6185            root: 'build/',
6186            combine: true,
6187            require: ['node', 'dd', 'console']
6188        });
6189        var out = loader.resolve(true);
6190
6191 * If the Loader needs to be patched before it is used for the first time, it
6192 * should be done through the `doBeforeLoader` hook. Simply make the patch
6193 * available via configuration before YUI is loaded:
6194
6195        YUI_config = YUI_config || {};
6196        YUI_config.doBeforeLoader = function (config) {
6197            var resolve = this.context.Loader.prototype.resolve;
6198            this.context.Loader.prototype.resolve = function () {
6199                // do something here
6200                return resolve.apply(this, arguments);
6201            };
6202        };
6203
6204 * @constructor
6205 * @class Loader
6206 * @param {Object} config an optional set of configuration options.
6207 * @param {String} config.base The base dir which to fetch this module from
6208 * @param {String} config.comboBase The Combo service base path. Ex: `http://yui.yahooapis.com/combo?`
6209 * @param {String} config.root The root path to prepend to module names for the combo service. Ex: `2.5.2/build/`
6210 * @param {String|Object} config.filter A filter to apply to result urls. <a href="#property_filter">See filter property</a>
6211 * @param {Object} config.filters Per-component filter specification.  If specified for a given component, this overrides the filter config.
6212 * @param {Boolean} config.combine Use a combo service to reduce the number of http connections required to load your dependencies
6213 * @param {Boolean} [config.async=true] Fetch files in async
6214 * @param {Array} config.ignore: A list of modules that should never be dynamically loaded
6215 * @param {Array} config.force A list of modules that should always be loaded when required, even if already present on the page
6216 * @param {HTMLElement|String} config.insertBefore Node or id for a node that should be used as the insertion point for new nodes
6217 * @param {Object} config.jsAttributes Object literal containing attributes to add to script nodes
6218 * @param {Object} config.cssAttributes Object literal containing attributes to add to link nodes
6219 * @param {Number} config.timeout The number of milliseconds before a timeout occurs when dynamically loading nodes.  If not set, there is no timeout
6220 * @param {Object} config.context Execution context for all callbacks
6221 * @param {Function} config.onSuccess Callback for the 'success' event
6222 * @param {Function} config.onFailure Callback for the 'failure' event
6223 * @param {Function} config.onTimeout Callback for the 'timeout' event
6224 * @param {Function} config.onProgress Callback executed each time a script or css file is loaded
6225 * @param {Object} config.modules A list of module definitions.  See <a href="#method_addModule">Loader.addModule</a> for the supported module metadata
6226 * @param {Object} config.groups A list of group definitions.  Each group can contain specific definitions for `base`, `comboBase`, `combine`, and accepts a list of `modules`.
6227 * @param {String} config.2in3 The version of the YUI 2 in 3 wrapper to use.  The intrinsic support for YUI 2 modules in YUI 3 relies on versions of the YUI 2 components inside YUI 3 module wrappers.  These wrappers change over time to accomodate the issues that arise from running YUI 2 in a YUI 3 sandbox.
6228 * @param {String} config.yui2 When using the 2in3 project, you can select the version of YUI 2 to use.  V
6228alid values are `2.2.2`, `2.3.1`, `2.4.1`, `2.5.2`, `2.6.0`, `2.7.0`, `2.8.0`, `2.8.1` and `2.9.0` [default] -- plus all versions of YUI 2 going forward.
6229 * @param {Function} config.doBeforeLoader An optional hook that allows for the patching of the loader instance. The `Y` instance is available as `this.context` and the only argument to the function is the Loader configuration object.
6230 */
6231Y.Loader = function(o) {
6232
6233    var self = this;
6234
6235    //Catch no config passed.
6236    o = o || {};
6237
6238    modulekey = META.md5;
6239
6240    /**
6241     * Internal callback to handle multiple internal insert() calls
6242     * so that css is inserted prior to js
6243     * @property _internalCallback
6244     * @private
6245     */
6246    // self._internalCallback = null;
6247
6248    /**
6249     * Callback that will be executed when the loader is finished
6250     * with an insert
6251     * @method onSuccess
6252     * @type function
6253     */
6254    // self.onSuccess = null;
6255
6256    /**
6257     * Callback that will be executed if there is a failure
6258     * @method onFailure
6259     * @type function
6260     */
6261    // self.onFailure = null;
6262
6263    /**
6264     * Callback executed each time a script or css file is loaded
6265     * @method onProgress
6266     * @type function
6267     */
6268    // self.onProgress = null;
6269
6270    /**
6271     * Callback that will be executed if a timeout occurs
6272     * @method onTimeout
6273     * @type function
6274     */
6275    // self.onTimeout = null;
6276
6277    /**
6278     * The execution context for all callbacks
6279     * @property context
6280     * @default {YUI} the YUI instance
6281     */
6282    self.context = Y;
6283
6284    // Hook that allows the patching of loader
6285    if (o.doBeforeLoader) {
6286        o.doBeforeLoader.apply(self, arguments);
6287    }
6288
6289    /**
6290     * Data that is passed to all callbacks
6291     * @property data
6292     */
6293    // self.data = null;
6294
6295    /**
6296     * Node reference or id where new nodes should be inserted before
6297     * @property insertBefore
6298     * @type string|HTMLElement
6299     */
6300    // self.insertBefore = null;
6301
6302    /**
6303     * The charset attribute for inserted nodes
6304     * @property charset
6305     * @type string
6306     * @deprecated , use cssAttributes or jsAttributes.
6307     */
6308    // self.charset = null;
6309
6310    /**
6311     * An object literal containing attributes to add to link nodes
6312     * @property cssAttributes
6313     * @type object
6314     */
6315    // self.cssAttributes = null;
6316
6317    /**
6318     * An object literal containing attributes to add to script nodes
6319     * @property jsAttributes
6320     * @type object
6321     */
6322    // self.jsAttributes = null;
6323
6324    /**
6325     * The base directory.
6326     * @property base
6327     * @type string
6328     * @default http://yui.yahooapis.com/[YUI VERSION]/build/
6329     */
6330    self.base = Y.Env.meta.base + Y.Env.meta.root;
6331
6332    /**
6333     * Base path for the combo service
6334     * @property comboBase
6335     * @type string
6336     * @default http://yui.yahooapis.com/combo?
6337     */
6338    self.comboBase = Y.Env.meta.comboBase;
6339
6340    /*
6341     * Base path for language packs.
6342     */
6343    // self.langBase = Y.Env.meta.langBase;
6344    // self.lang = "";
6345
6346    /**
6347     * If configured, the loader will attempt to use the combo
6348     * service for YUI resources and configured external resources.
6349     * @property combine
6350     * @type boolean
6351     * @default true if a base dir isn't in the config
6352     */
6353    self.combine = o.base &&
6354        (o.base.indexOf(self.comboBase.substr(0, 20)) > -1);
6355
6356    /**
6357    * The default seperator to use between files in a combo URL
6358    * @property comboSep
6359    * @type {String}
6360    * @default Ampersand
6361    */
6362    self.comboSep = '&';
6363    /**
6364     * Max url length for combo urls.  The default is 1024. This is the URL
6365     * limit for the Yahoo! hosted combo servers.  If consuming
6366     * a different combo service that has a different URL limit
6367     * it is possible to override this default by supplying
6368     * the maxURLLength config option.  The config option will
6369     * only take effect if lower than the default.
6370     *
6371     * @property maxURLLength
6372     * @type int
6373     */
6374    self.maxURLLength = MAX_URL_LENGTH;
6375
6376    /**
6377     * Ignore modules registered on the YUI global
6378     * @property ignoreRegistered
6379     * @default false
6380     */
6381    self.ignoreRegistered = o.ignoreRegistered;
6382
6383    /**
6384     * Root path to prepend to module path for the combo
6385     * service
6386     * @property root
6387     * @type string
6388     * @default [YUI VERSION]/build/
6389     */
6390    self.root = Y.Env.meta.root;
6391
6392    /**
6393     * Timeout value in milliseconds.  If set, self value will be used by
6394     * the get utility.  the timeout event will fire if
6395     * a timeout occurs.
6396     * @property timeout
6397     * @type int
6398     */
6399    self.timeout = 0;
6400
6401    /**
6402     * A list of modules that should not be loaded, even if
6403     * they turn up in the dependency tree
6404     * @property ignore
6405     * @type string[]
6406     */
6407    // self.ignore = null;
6408
6409    /**
6410     * A list of modules that should always be loaded, even
6411     * if they have already been inserted into the page.
6412     * @property force
6413     * @type string[]
6414     */
6415    // self.force = null;
6416
6417    self.forceMap = {};
6418
6419    /**
6420     * Should we allow rollups
6421     * @property allowRollup
6422     * @type boolean
6423     * @default false
6424     */
6425    self.allowRollup = false;
6426
6427    /**
6428     * A filter to apply to result urls.  This filter will modify the default
6429     * path for all modules.  The default path for the YUI library is the
6430     * minified version of the files (e.g., event-min.js).  The filter property
6431     * can be a predefined filter or a custom filter.  The valid predefined
6432     * filters are:
6433     * <dl>
6434     *  <dt>DEBUG</dt>
6435     *  <dd>Selects the debug versions of the library (e.g., event-debug.js).
6436     *      This option will automatically include the Logger widget</dd>
6437     *  <dt>RAW</dt>
6438     *  <dd>Selects the non-minified version of the library (e.g., event.js).
6439     *  </dd>
6440     * </dl>
6441     * You can also define a custom filter, which must be an object literal
6442     * containing a search expression and a replace string:
6443     *
6444     *      myFilter: {
6445     *          'searchExp': "-min\\.js",
6446     *          'replaceStr': "-debug.js"
6447     *      }
6448     *
6449     * @property filter
6450     * @type string| {searchExp: string, replaceStr: string}
6451     */
6452    // self.filter = null;
6453
6454    /**
6455     * per-component filter specification.  If specified for a given
6456     * component, this overrides the filter config.
6457     * @property filters
6458     * @type object
6459     */
6460    self.filters = {};
6461
6462    /**
6463     * The list of requested modules
6464     * @property required
6465     * @type {string: boolean}
6466     */
6467    self.required = {};
6468
6469    /**
6470     * If a module name is predefined when requested, it is checked againsts
6471     * the patterns provided in this property.  If there is a match, the
6472     * module is added with the default configuration.
6473     *
6474     * At the moment only supporting module prefixes, but anticipate
6475     * supporting at least regular expressions.
6476     * @property patterns
6477     * @type Object
6478     */
6479    // self.patterns = Y.merge(Y.Env.meta.patterns);
6480    self.patterns = {};
6481
6482    /**
6483     * Internal loader instance metadata. Use accessor `getModuleInfo()` instead.
6484     */
6485    self.moduleInfo = {};
6486
6487    self.groups = Y.merge(Y.Env.meta.groups);
6488
6489    /**
6490     * Provides the information used to skin the skinnable components.
6491     * The following skin definition would result in 'skin1' and 'skin2'
6492     * being loaded for calendar (if calendar was requested), and
6493     * 'sam' for all other skinnable components:
6494     *
6495     *      skin: {
6496     *          // The default skin, which is automatically applied if not
6497     *          // overriden by a component-specific skin definition.
6498     *          // Change this in to apply a different skin globally
6499     *          defaultSkin: 'sam',
6500     *
6501     *          // This is combined with the loader base property to get
6502     *          // the default root directory for a skin. ex:
6503     *          // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
6504     *          base: 'assets/skins/',
6505     *
6506     *          // Any component-specific overrides can be specified here,
6507     *          // making it possible to load different skins for different
6508     *          // components.  It is possible to load more than one skin
6509     *          // for a given component as well.
6510     *          overrides: {
6511     *              calendar: ['skin1', 'skin2']
6512     *          }
6513     *      }
6514     * @property skin
6515     * @type {Object}
6516     */
6517    self.skin = Y.merge(Y.Env.meta.skin);
6518
6519    /*
6520     * Map of conditional modules
6521     * @since 3.2.0
6522     */
6523    self.conditions = {};
6524
6525    // map of modules with a hash of modules that meet the requirement
6526    // self.provides = {};
6527
6528    self.config = o;
6529    self._internal = true;
6530
6531    self._populateConditionsCache();
6532
6533    /**
6534     * Set when beginning to compute the dependency tree.
6535     * Composed of what YUI reports to be loaded combined
6536     * with what has been loaded by any instance on the page
6537     * with the version number specified in the metadata.
6538     * @property loaded
6539     * @type {string: boolean}
6540     */
6541    self.loaded = GLOBAL_LOADED[VERSION];
6542
6543
6544    /**
6545    * Should Loader fetch scripts in `async`, defaults to `true`
6546    * @property async
6547    */
6548
6549    self.async = true;
6550
6551    self._inspectPage();
6552
6553    self._internal = false;
6554
6555    self._config(o);
6556
6557    self.forceMap = (self.force) ? Y.Array.hash(self.force) : {};
6558
6559    self.testresults = null;
6560
6561    if (Y.config.tests) {
6562        self.testresults = Y.config.tests;
6563    }
6564
6565    /**
6566     * List of rollup files found in the library metadata
6567     * @property rollups
6568     */
6569    // self.rollups = null;
6570
6571    /**
6572     * Whether or not to load optional dependencies for
6573     * the requested modules
6574     * @property loadOptional
6575     * @type boolean
6576     * @default false
6577     */
6578    // self.loadOptional = false;
6579
6580    /**
6581     * All of the derived dependencies in sorted order, which
6582     * will be populated when either calculate() or insert()
6583     * is called
6584     * @property sorted
6585     * @type string[]
6586     */
6587    self.sorted = [];
6588
6589    /*
6590     * A list of modules to attach to the YUI instance when complete.
6591     * If not supplied, the sorted list of dependencies are applied.
6592     * @property attaching
6593     */
6594    // self.attaching = null;
6595
6596    /**
6597     * Flag to indicate the dependency tree needs to be recomputed
6598     * if insert is called again.
6599     * @property dirty
6600     * @type boolean
6601     * @default true
6602     */
6603    self.dirty = true;
6604
6605    /**
6606     * List of modules inserted by the utility
6607     * @property inserted
6608     * @type {string: boolean}
6609     */
6610    self.inserted = {};
6611
6612    /**
6613     * List of skipped modules during insert() because the module
6614     * was not defined
6615     * @property skipped
6616     */
6617    self.skipped = {};
6618
6619    // Y.on('yui:load', self.loadNext, self);
6620
6621    self.tested = {};
6622
6623    /*
6624     * Cached sorted calculate results
6625     * @property results
6626     * @since 3.2.0
6627     */
6628    //self.results = {};
6629
6630    if (self.ignoreRegistered) {
6631        //Clear inpage already processed modules.
6632        self._resetModules();
6633    }
6634
6635};
6636
6637Y.Loader.prototype = {
6638    /**
6639    * Gets the module info from the local moduleInfo hash, or from the
6640    * default metadata and populate the local moduleInfo hash.
6641    * @method getModuleInfo
6642    * @param {string} name of the module
6643    * @public
6644    */
6645    getModuleInfo: function(name) {
6646
6647        var m = this.moduleInfo[name],
6648            rawMetaModules, globalRenderedMods, internal, v;
6649
6650        if (m) {
6651            return m;
6652        }
6653
6654        rawMetaModules = META.modules;
6655        globalRenderedMods = GLOBAL_ENV._renderedMods;
6656        internal = this._internal;
6657
6658        /*
6659        The logic here is:
6660
6661        - if the `moduleInfo[name]` is avilable,
6662          then short circuit
6663        - otherwise, if the module is in the globalCache (cross Y instance),
6664          then port it from the global registry into `moduleInfo[name]`
6665        - otherwise, if the module has raw metadata (from meta modules)
6666          then add it to the global registry and to `moduleInfo[name]`
6667
6668        */
6669        if (globalRenderedMods && globalRenderedMods.hasOwnProperty(name) && !this.ignoreRegistered) {
6670            this.moduleInfo[name] = Y.merge(globalRenderedMods[name]);
6671        } else {
6672            if (rawMetaModules.hasOwnProperty(name)) {
6673                this._internal = true; // making sure that modules from raw data are marked as internal
6674                v = this.addModule(rawMetaModules[name], name);
6675                // Inspect the page for the CSS module and mark it as loaded.
6676                if (v && v.type === CSS) {
6677                    if (this.isCSSLoaded(v.name, true)) {
6678                        this.loaded[v.name] = true;
6679                    }
6680                }
6681                this._internal = internal;
6682            }
6683        }
6684        return this.moduleInfo[name];
6685    },
6686    /**
6687    * Expand the names that are aliases to other modules.
6688    * @method _expandAliases
6689    * @param {string[]} list a module name or a list of names to be expanded
6690    * @private
6691    * @return {array}
6692    */
6693    _expandAliases: function(list) {
6694        var expanded = [],
6695            aliases = YUI.Env.aliases,
6696            i, name;
6697        list = Y.Array(list);
6698        for (i = 0; i < list.length; i += 1) {
6699            name = list[i];
6700            expanded.push.apply(expanded, aliases[name] ? aliases[name] : [name]);
6701        }
6702        return expanded;
6703    },
6704    /**
6705    * Populate the conditions cache from raw modules, this is necessary
6706    * because no other module will require a conditional module, instead
6707    * the condition has to be executed and then the module is analyzed
6708    * to be included in the final requirement list. Without this cache
6709    * conditional modules will be simply ignored.
6710    * @method _populateConditionsCache
6711    * @private
6712    */
6713    _populateConditionsCache: function() {
6714        var rawMetaModules = META.modules,
6715            cache = GLOBAL_ENV._conditions,
6716            i, j, t, trigger;
6717
6718        // if we have conditions in cache and cache is enabled
6719        // we should port them to this loader instance
6720        if (cache && !this.ignoreRegistered) {
6721            for (i in cache) {
6722                if (cache.hasOwnProperty(i)) {
6723                    this.conditions[i] = Y.merge(cache[i]);
6724                }
6725            }
6726        } else {
6727            for (i in rawMetaModules) {
6728                if (rawMetaModules.hasOwnProperty(i) && rawMetaModules[i].condition) {
6729                    t = this._expandAliases(rawMetaModules[i].condition.trigger);
6730                    for (j = 0; j < t.length; j += 1) {
6731                        trigger = t[j];
6732                        this.conditions[trigger] = this.conditions[trigger] || {};
6733                        this.conditions[trigger][rawMetaModules[i].name || i] = rawMetaModules[i].condition;
6734                    }
6735                }
6736            }
6737            GLOBAL_ENV._conditions = this.conditions;
6738        }
6739    },
6740    /**
6741    * Reset modules in the module cache to a pre-processed state so additional
6742    * computations with a different skin or language will work as expected.
6743    * @method _resetModules
6744    * @private
6745    */
6746    _resetModules: function() {
6747        var self = this, i, o,
6748            mod, name, details;
6749        for (i in self.moduleInfo) {
6750            if (self.moduleInfo.hasOwnProperty(i) && self.moduleInfo[i]) {
6751                mod = self.moduleInfo[i];
6752                name = mod.name;
6753                details  = (YUI.Env.mods[name] ? YUI.Env.mods[name].details : null);
6754
6755                if (details) {
6756                    self.moduleInfo[name]._reset = true;
6757                    self.moduleInfo[name].requires = details.requires || [];
6758                    self.moduleInfo[name].optional = details.optional || [];
6759                    self.moduleInfo[name].supersedes = details.supercedes || [];
6760                }
6761
6762                if (mod.defaults) {
6763                    for (o in mod.defaults) {
6764                        if (mod.defaults.hasOwnProperty(o)) {
6765                            if (mod[o]) {
6766                                mod[o] = mod.defaults[o];
6767                            }
6768                        }
6769                    }
6770                }
6771                mod.langCache = undefined;
6772                mod.skinCache = undefined;
6773                if (mod.skinnable) {
6774                    self._addSkin(self.skin.defaultSkin, mod.name);
6775                }
6776            }
6777        }
6778    },
6779    /**
6780    Regex that matches a CSS URL. Used to guess the file type when it's not
6781    specified.
6782
6783    @property REGEX_CSS
6784    @type RegExp
6785    @final
6786    @protected
6787    @since 3.5.0
6788    **/
6789    REGEX_CSS: /\.css(?:[?;].*)?$/i,
6790
6791    /**
6792    * Default filters for raw and debug
6793    * @property FILTER_DEFS
6794    * @type Object
6795    * @final
6796    * @protected
6797    */
6798    FILTER_DEFS: {
6799        RAW: {
6800            'searchExp': '-min\\.js',
6801            'replaceStr': '.js'
6802        },
6803        DEBUG: {
6804            'searchExp': '-min\\.js',
6805            'replaceStr': '-debug.js'
6806        },
6807        COVERAGE: {
6808            'searchExp': '-min\\.js',
6809            'replaceStr': '-coverage.js'
6810        }
6811    },
6812    /*
6813    * Check the pages meta-data and cache the result.
6814    * @method _inspectPage
6815    * @private
6816    */
6817    _inspectPage: function() {
6818        var self = this, v, m, req, mr, i;
6819
6820        for (i in ON_PAGE) {
6821            if (ON_PAGE.hasOwnProperty(i)) {
6822                v = ON_PAGE[i];
6823                if (v.details) {
6824                    m = self.getModuleInfo(v.name);
6825                    req = v.details.requires;
6826                    mr = m && m.requires;
6827
6828                   if (m) {
6829                       if (!m._inspected && req && mr.length !== req.length) {
6830                           // console.log('deleting ' + m.name);
6831                           delete m.expanded;
6832                       }
6833                   } else {
6834                       m = self.addModule(v.details, i);
6835                   }
6836                   m._inspected = true;
6837               }
6838            }
6839        }
6840    },
6841    /*
6842    * returns true if b is not loaded, and is required directly or by means of modules it supersedes.
6843    * @private
6844    * @method _requires
6845    * @param {String} mod1 The first module to compare
6846    * @param {String} mod2 The second module to compare
6847    */
6848   _requires: function(mod1, mod2) {
6849
6850        var i, rm, after_map, s,
6851            m = this.getModuleInfo(mod1),
6852            other = this.getModuleInfo(mod2);
6853
6854        if (!m || !other) {
6855            return false;
6856        }
6857
6858        rm = m.expanded_map;
6859        after_map = m.after_map;
6860
6861        // check if this module should be sorted after the other
6862        // do this first to short circut circular deps
6863        if (after_map && (mod2 in after_map)) {
6864            return true;
6865        }
6866
6867        after_map = other.after_map;
6868
6869        // and vis-versa
6870        if (after_map && (mod1 in after_map)) {
6871            return false;
6872        }
6873
6874        // check if this module requires one the other supersedes
6875        s = other.supersedes;
6876        if (s) {
6877            for (i = 0; i < s.length; i++) {
6878                if (this._requires(mod1, s[i])) {
6879                    return true;
6880                }
6881            }
6882        }
6883
6884        s = m.supersedes;
6885        if (s) {
6886            for (i = 0; i < s.length; i++) {
6887                if (this._requires(mod2, s[i])) {
6888                    return false;
6889                }
6890            }
6891        }
6892
6893        // check if this module requires the other directly
6894        // if (r && yArray.indexOf(r, mod2) > -1) {
6895        if (rm && (mod2 in rm)) {
6896            return true;
6897        }
6898
6899        // external css files should be sorted below yui css
6900        if (m.ext && m.type === CSS && !other.ext && other.type === CSS) {
6901            return true;
6902        }
6903
6904        return false;
6905    },
6906    /**
6907    * Apply a new config to the Loader instance
6908    * @method _config
6909    * @private
6910    * @param {Object} o The new configuration
6911    */
6912    _config: function(o) {
6913        var i, j, val, a, f, group, groupName, self = this,
6914            mods = [], mod, modInfo;
6915        // apply config values
6916        if (o) {
6917            for (i in o) {
6918                if (o.hasOwnProperty(i)) {
6919                    val = o[i];
6920                    //TODO This should be a case
6921                    if (i === 'require') {
6922                        self.require(val);
6923                    } else if (i === 'skin') {
6924                        //If the config.skin is a string, format to the expected object
6925                        if (typeof val === 'string') {
6926                            self.skin.defaultSkin = o.skin;
6927                            val = {
6928                                defaultSkin: val
6929                            };
6930                        }
6931
6932                        Y.mix(self.skin, val, true);
6933                    } else if (i === 'groups') {
6934                        for (j in val) {
6935                            if (val.hasOwnProperty(j)) {
6936                                groupName = j;
6937                                group = val[j];
6938                                self.addGroup(group, groupName);
6939                                if (group.aliases) {
6940                                    for (a in group.aliases) {
6941                                        if (group.aliases.hasOwnProperty(a)) {
6942                                            self.addAlias(group.aliases[a], a);
6943                                        }
6944                                    }
6945                                }
6946                            }
6947                        }
6948
6949                    } else if (i === 'modules') {
6950                        // add a hash of module definitions
6951                        for (j in val) {
6952                            if (val.hasOwnProperty(j)) {
6953                                self.addModule(val[j], j);
6954                            }
6955                        }
6956                    } else if (i === 'aliases') {
6957                        for (j in val) {
6958                            if (val.hasOwnProperty(j)) {
6959                                self.addAlias(val[j], j);
6960                            }
6961                        }
6962                    } else if (i === 'gallery') {
6963                        if (this.groups.gallery.update) {
6964                            this.groups.gallery.update(val, o);
6965                        }
6966                    } else if (i === 'yui2' || i === '2in3') {
6967                        if (this.groups.yui2.update) {
6968                            this.groups.yui2.update(o['2in3'], o.yui2, o);
6969                        }
6970                    } else {
6971                        self[i] = val;
6972                    }
6973                }
6974            }
6975        }
6976
6977        // fix filter
6978        f = self.filter;
6979
6980        if (L.isString(f)) {
6981            f = f.toUpperCase();
6982            self.filterName = f;
6983            self.filter = self.FILTER_DEFS[f];
6984            if (f === 'DEBUG') {
6985                self.require('yui-log', 'dump');
6986            }
6987        }
6988
6989        if (self.filterName && self.coverage) {
6990            if (self.filterName === 'COVERAGE' && L.isArray(self.coverage) && self.coverage.length) {
6991                for (i = 0; i < self.coverage.length; i++) {
6992                    mod = self.coverage[i];
6993                    modInfo = self.getModuleInfo(mod);
6994                    if (modInfo && modInfo.use) {
6995                        mods = mods.concat(modInfo.use);
6996                    } else {
6997                        mods.push(mod);
6998                    }
6999                }
7000                self.filters = self.filters || {};
7001                Y.Array.each(mods, function(mod) {
7002                    self.filters[mod] = self.FILTER_DEFS.COVERAGE;
7003                });
7004                self.filterName = 'RAW';
7005                self.filter = self.FILTER_DEFS[self.filterName];
7006            }
7007        }
7008
7009    },
7010
7011    /**
7012     * Returns the skin module name for the specified skin name.  If a
7013     * module name is supplied, the returned skin module name is
7014     * specific to the module passed in.
7015     * @method formatSkin
7016     * @param {string} skin the name of the skin.
7017     * @param {string} mod optional: the name of a module to skin.
7018     * @return {string} the full skin module name.
7019     */
7020    formatSkin: function(skin, mod) {
7021        var s = SKIN_PREFIX + skin;
7022        if (mod) {
7023            s = s + '-' + mod;
7024        }
7025
7026        return s;
7027    },
7028
7029    /**
7030     * Adds the skin def to the module info
7031     * @method _addSkin
7032     * @param {string} skin the name of the skin.
7033     * @param {string} mod the name of the module.
7034     * @param {string} parent parent module if this is a skin of a
7035     * submodule or plugin.
7036     * @return {string} the module name for the skin.
7037     * @private
7038     */
7039    _addSkin: function(skin, mod, parent) {
7040        var pkg, name, nmod,
7041            sinf = this.skin,
7042            mdef = mod && this.getModuleInfo(mod),
7043            ext = mdef && mdef.ext;
7044
7045        // Add a module definition for the module-specific skin css
7046        if (mod) {
7047            name = this.formatSkin(skin, mod);
7048            if (!this.getModuleInfo(name)) {
7049                pkg = mdef.pkg || mod;
7050                nmod = {
7051                    skin: true,
7052                    name: name,
7053                    group: mdef.group,
7054                    type: 'css',
7055                    after: sinf.after,
7056                    path: (parent || pkg) + '/' + sinf.base + skin +
7057                          '/' + mod + '.css',
7058                    ext: ext
7059                };
7060                if (mdef.base) {
7061                    nmod.base = mdef.base;
7062                }
7063                if (mdef.configFn) {
7064                    nmod.configFn = mdef.configFn;
7065                }
7066                this.addModule(nmod, name);
7067
7068            }
7069        }
7070
7071        return name;
7072    },
7073    /**
7074    * Adds an alias module to the system
7075    * @method addAlias
7076    * @param {Array} use An array of modules that makes up this alias
7077    * @param {String} name The name of the alias
7078    * @example
7079    *       var loader = new Y.Loader({});
7080    *       loader.addAlias([ 'node', 'yql' ], 'davglass');
7081    *       loader.require(['davglass']);
7082    *       var out = loader.resolve(true);
7083    *
7084    *       //out.js will contain Node and YQL modules
7085    */
7086    addAlias: function(use, name) {
7087        YUI.Env.aliases[name] = use;
7088        this.addModule({
7089            name: name,
7090            use: use
7091        });
7092    },
7093    /**
7094     * Add a new module group
7095     * @method addGroup
7096     * @param {Object} config An object containing the group configuration data
7097     * @param {String} config.name required, the group name
7098     * @param {String} config.base The base directory for this module group
7099     * @param {String} config.root The root path to add to each combo resource path
7100     * @param {Boolean} config.combine Should the request be combined
7101     * @param {String} config.comboBase Combo service base path
7102     * @param {Object} config.modules The group of modules
7103     * @param {String} name the group name.
7104     * @example
7105     *      var loader = new Y.Loader({});
7106     *      loader.addGroup({
7107     *          name: 'davglass',
7108     *          combine: true,
7109     *          comboBase: '/combo?',
7110     *          root: '',
7111     *          modules: {
7112     *              //Module List here
7113     *          }
7114     *      }, 'davglass');
7115     */
7116    addGroup: function(o, name) {
7117        var mods = o.modules,
7118            self = this,
7119            defaultBase = o.defaultBase || Y.config.defaultBase,
7120            i, v;
7121
7122        name = name || o.name;
7123        o.name = name;
7124        self.groups[name] = o;
7125
7126        if (!o.base && defaultBase && o.root) {
7127            o.base = defaultBase + o.root;
7128        }
7129
7130        if (o.patterns) {
7131            for (i in o.patterns) {
7132                if (o.patterns.hasOwnProperty(i)) {
7133                    o.patterns[i].group = name;
7134                    self.patterns[i] = o.patterns[i];
7135                }
7136            }
7137        }
7138
7139        if (mods) {
7140            for (i in mods) {
7141                if (mods.hasOwnProperty(i)) {
7142                    v = mods[i];
7143                    if (typeof v === 'string') {
7144                        v = { name: i, fullpath: v };
7145                    }
7146                    v.group = name;
7147                    self.addModule(v, i);
7148                }
7149            }
7150        }
7151    },
7152
7153    /**
7154     * Add a new module to the component metadata.
7155     * @method addModule
7156     * @param {Object}
7156 config An object containing the module data.
7157     * @param {String} config.name Required, the component name
7158     * @param {String} config.type Required, the component type (js or css)
7159     * @param {String} config.path Required, the path to the script from `base`
7160     * @param {Array} config.requires Array of modules required by this component
7161     * @param {Array} [config.optional] Array of optional modules for this component
7162     * @param {Array} [config.supersedes] Array of the modules this component replaces
7163     * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one
7164     * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array
7165     * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup
7166     * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path`
7167     * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in
7168     * @param {Object} [config.submodules] Hash of submodules
7169     * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration.
7170     * @param {Array} [config.lang] Array of BCP 47 language tags of languages for which this module has localized resource bundles, e.g., `["en-GB", "zh-Hans-CN"]`
7171     * @param {Object} [config.condition] Specifies that the module should be loaded automatically if a condition is met. This is an object with up to four fields:
7172     * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load
7173     * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded.
7174     * @param {String} [config.condition.ua] The UA name of <a href="UA.html">Y.UA</a> object that returns true when the module is to be loaded. e.g., `"ie"`, `"nodejs"`.
7175     * @param {String} [config.condition.when] Specifies the load order of the conditional module
7176     *  with regard to the position of the trigger module.
7177     *  This should be one of three values: `before`, `after`, or `instead`.  The default is `after`.
7178     * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()`
7179     * @param {Function} [config.configFn] A function to exectute when configuring this module
7180     * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config.
7181     * @param {String[]} [config.optionalRequires] List of dependencies that
7182        may optionally be loaded by this loader. This is targeted mostly at
7183        polyfills, since they should not be in the list of requires because
7184        polyfills are assumed to be available in the global scope.
7185     * @param {Function} [config.test] Test to be called when this module is
7186        added as an optional dependency of another module. If the test function
7187        returns `false`, the module will be ignored and will not be attached to
7188        this YUI instance.
7189     * @param {String} [name] The module name, required if not in the module data.
7190     * @return {Object} the module definition or null if the object passed in did not provide all required attributes.
7191     */
7192    addModule: function(o, name) {
7193        name = name || o.name;
7194
7195        if (typeof o === 'string') {
7196            o = { name: name, fullpath: o };
7197        }
7198
7199
7200        var subs, i, l, t, sup, s, smod, plugins, plug,
7201            j, langs, packName, supName, flatSup, flatLang, lang, ret,
7202            overrides, skinname, when, g, p,
7203            modInfo = this.moduleInfo[name],
7204            conditions = this.conditions, trigger;
7205
7206        //Only merge this data if the temp flag is set
7207        //from an earlier pass from a pattern or else
7208        //an override module (YUI_config) can not be used to
7209        //replace a default module.
7210        if (modInfo && modInfo.temp) {
7211            //This catches temp modules loaded via a pattern
7212            // The module will be added twice, once from the pattern and
7213            // Once from the actual add call, this ensures that properties
7214            // that were added to the module the first time around (group: gallery)
7215            // are also added the second time around too.
7216            o = Y.merge(modInfo, o);
7217        }
7218
7219        o.name = name;
7220
7221        if (!o || !o.name) {
7222            return null;
7223        }
7224
7225        if (!o.type) {
7226            //Always assume it's javascript unless the CSS pattern is matched.
7227            o.type = JS;
7228            p = o.path || o.fullpath;
7229            if (p && this.REGEX_CSS.test(p)) {
7230                o.type = CSS;
7231            }
7232        }
7233
7234        if (!o.path && !o.fullpath) {
7235            o.path = _path(name, name, o.type);
7236        }
7237        o.supersedes = o.supersedes || o.use;
7238
7239        o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
7240
7241        // Handle submodule logic
7242        subs = o.submodules;
7243
7244        this.moduleInfo[name] = o;
7245
7246        o.requires = o.requires || [];
7247
7248        /*
7249        Only allowing the cascade of requires information, since
7250        optional and supersedes are far more fine grained than
7251        a blanket requires is.
7252        */
7253        if (this.requires) {
7254            for (i = 0; i < this.requires.length; i++) {
7255                o.requires.push(this.requires[i]);
7256            }
7257        }
7258        if (o.group && this.groups && this.groups[o.group]) {
7259            g = this.groups[o.group];
7260            if (g.requires) {
7261                for (i = 0; i < g.requires.length; i++) {
7262                    o.requires.push(g.requires[i]);
7263                }
7264            }
7265        }
7266
7267
7268        if (!o.defaults) {
7269            o.defaults = {
7270                requires: o.requires ? [].concat(o.requires) : null,
7271                supersedes: o.supersedes ? [].concat(o.supersedes) : null,
7272                optional: o.optional ? [].concat(o.optional) : null
7273            };
7274        }
7275
7276        if (o.skinnable && o.ext && o.temp) {
7277            skinname = this._addSkin(this.skin.defaultSkin, name);
7278            o.requires.unshift(skinname);
7279        }
7280
7281        if (o.requires.length) {
7282            o.requires = this.filterRequires(o.requires) || [];
7283        }
7284
7285        if (!o.langPack && o.lang) {
7286            langs = yArray(o.lang);
7287            for (j = 0; j < langs.length; j++) {
7288                lang = langs[j];
7289                packName = this.getLangPackName(lang, name);
7290                smod = this.getModuleInfo(packName);
7291                if (!smod) {
7292                    smod = this._addLangPack(lang, o, packName);
7293                }
7294            }
7295        }
7296
7297
7298        if (subs) {
7299            sup = o.supersedes || [];
7300            l = 0;
7301
7302            for (i in subs) {
7303                if (subs.hasOwnProperty(i)) {
7304                    s = subs[i];
7305
7306                    s.path = s.path || _path(name, i, o.type);
7307                    s.pkg = name;
7308                    s.group = o.group;
7309
7310                    if (s.supersedes) {
7311                        sup = sup.concat(s.supersedes);
7312                    }
7313
7314                    smod = this.addModule(s, i);
7315                    sup.push(i);
7316
7317                    if (smod.skinnable) {
7318                        o.skinnable = true;
7319                        overrides = this.skin.overrides;
7320                        if (overrides && overrides[i]) {
7321                            for (j = 0; j < overrides[i].length; j++) {
7322                                skinname = this._addSkin(overrides[i][j],
7323                                         i, name);
7324                                sup.push(skinname);
7325                            }
7326                        }
7327                        skinname = this._addSkin(this.skin.defaultSkin,
7328                                        i, name);
7329                        sup.push(skinname);
7330                    }
7331
7332                    // looks like we are expected to work out the metadata
7333                    // for the parent module language packs from what is
7334                    // specified in the child modules.
7335                    if (s.lang && s.lang.length) {
7336
7337                        langs = yArray(s.lang);
7338                        for (j = 0; j < langs.length; j++) {
7339                            lang = langs[j];
7340                            packName = this.getLangPackName(lang, name);
7341                            supName = this.getLangPackName(lang, i);
7342                            smod = this.getModuleInfo(packName);
7343
7344                            if (!smod) {
7345                                smod = this._addLangPack(lang, o, packName);
7346                            }
7347
7348                            flatSup = flatSup || yArray.hash(smod.supersedes);
7349
7350                            if (!(supName in flatSup)) {
7351                                smod.supersedes.push(supName);
7352                            }
7353
7354                            o.lang = o.lang || [];
7355
7356                            flatLang = flatLang || yArray.hash(o.lang);
7357
7358                            if (!(lang in flatLang)) {
7359                                o.lang.push(lang);
7360                            }
7361
7362// Add rollup file, need to add to supersedes list too
7363
7364                            // default packages
7365                            packName = this.getLangPackName(ROOT_LANG, name);
7366                            supName = this.getLangPackName(ROOT_LANG, i);
7367
7368                            smod = this.getModuleInfo(packName);
7369
7370                            if (!smod) {
7371                                smod = this._addLangPack(lang, o, packName);
7372                            }
7373
7374                            if (!(supName in flatSup)) {
7375                                smod.supersedes.push(supName);
7376                            }
7377
7378// Add rollup file, need to add to supersedes list too
7379
7380                        }
7381                    }
7382
7383                    l++;
7384                }
7385            }
7386            //o.supersedes = YObject.keys(yArray.hash(sup));
7387            o.supersedes = yArray.dedupe(sup);
7388            if (this.allowRollup) {
7389                o.rollup = (l < 4) ? l : Math.min(l - 1, 4);
7390            }
7391        }
7392
7393        plugins = o.plugins;
7394        if (plugins) {
7395            for (i in plugins) {
7396                if (plugins.hasOwnProperty(i)) {
7397                    plug = plugins[i];
7398                    plug.pkg = name;
7399                    plug.path = plug.path || _path(name, i, o.type);
7400                    plug.requires = plug.requires || [];
7401                    plug.group = o.group;
7402                    this.addModule(plug, i);
7403                    if (o.skinnable) {
7404                        this._addSkin(this.skin.defaultSkin, i, name);
7405                    }
7406
7407                }
7408            }
7409        }
7410
7411        if (o.condition) {
7412            t = this._expandAliases(o.condition.trigger);
7413            for (i = 0; i < t.length; i++) {
7414                trigger = t[i];
7415                when = o.condition.when;
7416                conditions[trigger] = conditions[trigger] || {};
7417                conditions[trigger][name] = o.condition;
7418                // the 'when' attribute can be 'before', 'after', or 'instead'
7419                // the default is after.
7420                if (when && when !== 'after') {
7421                    if (when === 'instead') { // replace the trigger
7422                        o.supersedes = o.supersedes || [];
7423                        o.supersedes.push(trigger);
7424                    }
7425                    // before the trigger
7426                        // the trigger requires the conditional mod,
7427                        // so it should appear before the conditional
7428                        // mod if we do not intersede.
7429                } else { // after the trigger
7430                    o.after = o.after || [];
7431                    o.after.push(trigger);
7432                }
7433            }
7434        }
7435
7436        if (o.supersedes) {
7437            o.supersedes = this.filterRequires(o.supersedes);
7438        }
7439
7440        if (o.after) {
7441            o.after = this.filterRequires(o.after);
7442            o.after_map = yArray.hash(o.after);
7443        }
7444
7445        // this.dirty = true;
7446
7447        if (o.configFn) {
7448            ret = o.configFn(o);
7449            if (ret === false) {
7450                delete this.moduleInfo[name];
7451                delete GLOBAL_ENV._renderedMods[name];
7452                o = null;
7453            }
7454        }
7455        //Add to global cache
7456        if (o) {
7457            if (!GLOBAL_ENV._renderedMods) {
7458                GLOBAL_ENV._renderedMods = {};
7459            }
7460            GLOBAL_ENV._renderedMods[name] = Y.mix(GLOBAL_ENV._renderedMods[name] || {}, o);
7461            GLOBAL_ENV._conditions = conditions;
7462        }
7463
7464        return o;
7465    },
7466
7467    /**
7468     * Add a requirement for one or more module
7469     * @method require
7470     * @param {string[] | string*} what the modules to load.
7471     */
7472    require: function(what) {
7473        var a = (typeof what === 'string') ? yArray(arguments) : what;
7474        this.dirty = true;
7475        this.required = Y.merge(this.required, yArray.hash(this.filterRequires(a)));
7476
7477        this._explodeRollups();
7478    },
7479    /**
7480    * Grab all the items that were asked for, check to see if the Loader
7481    * meta-data contains a "use" array. If it doesm remove the asked item and replace it with
7482    * the content of the "use".
7483    * This will make asking for: "dd"
7484    * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
7485    * @private
7486    * @method _explodeRollups
7487    */
7488    _explodeRollups: function() {
7489        var self = this, m, m2, i, a, v, len, len2,
7490        r = self.required;
7491
7492        if (!self.allowRollup) {
7493            for (i in r) {
7494                if (r.hasOwnProperty(i)) {
7495                    m = self.getModule(i);
7496                    if (m && m.use) {
7497                        len = m.use.length;
7498                        for (a = 0; a < len; a++) {
7499                            m2 = self.getModule(m.use[a]);
7500                            if (m2 && m2.use) {
7501                                len2 = m2.use.length;
7502                                for (v = 0; v < len2; v++) {
7503                                    r[m2.use[v]] = true;
7504                                }
7505                            } else {
7506                                r[m.use[a]] = true;
7507                            }
7508                        }
7509                    }
7510                }
7511            }
7512            self.required = r;
7513        }
7514
7515    },
7516    /**
7517    * Explodes the required array to remove aliases and replace them with real modules
7518    * @method filterRequires
7519    * @param {Array} r The original requires array
7520    * @return {Array} The new array of exploded requirements
7521    */
7522    filterRequires: function(r) {
7523        if (r) {
7524            if (!Y.Lang.isArray(r)) {
7525                r = [r];
7526            }
7527            r = Y.Array(r);
7528            var c = [], i, mod, o, m;
7529
7530            for (i = 0; i < r.length; i++) {
7531                mod = this.getModule(r[i]);
7532                if (mod && mod.use) {
7533                    for (o = 0; o < mod.use.length; o++) {
7534                        //Must walk the other modules in case a module is a rollup of rollups (datatype)
7535                        m = this.getModule(mod.use[o]);
7536                        if (m && m.use && (m.name !== mod.name)) {
7537                            c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use)));
7538                        } else {
7539                            c.push(mod.use[o]);
7540                        }
7541                    }
7542                } else {
7543                    c.push(r[i]);
7544                }
7545            }
7546            r = c;
7547        }
7548        return r;
7549    },
7550
7551    /**
7552    Returns `true` if the module can be attached to the YUI instance. Runs
7553    the module's test if there is one and caches its result.
7554
7555    @method _canBeAttached
7556    @param {String} module Name of the module to check.
7557    @return {Boolean} Result of the module's test if it has one, or `true`.
7558    **/
7559    _canBeAttached: function (m) {
7560        m = this.getModule(m);
7561        if (m && m.test) {
7562            if (!m.hasOwnProperty('_testResult')) {
7563                m._testResult = m.test(Y);
7564            }
7565            return m._testResult;
7566        }
7567        // return `true` for modules not registered as Loader will know what
7568        // to do with them later on
7569        return true;
7570    },
7571
7572    /**
7573     * Returns an object containing properties for all modules required
7574     * in order to load the requested module
7575     * @method getRequires
7576     * @param {object}  mod The module definition from moduleInfo.
7577     * @return {array} the expanded requirement list.
7578     */
7579    getRequires: function(mod) {
7580
7581        if (!mod) {
7582            //console.log('returning no reqs for ' + mod.name);
7583            return NO_REQUIREMENTS;
7584        }
7585
7586        if (mod._parsed) {
7587            //console.log('returning requires for ' + mod.name, mod.requires);
7588            return mod.expanded || NO_REQUIREMENTS;
7589        }
7590
7591        //TODO add modue cache here out of scope..
7592
7593        var i, m, j, length, add, packName, lang, testresults = this.testresults,
7594            name = mod.name, cond,
7595            adddef = ON_PAGE[name] && ON_PAGE[name].details,
7596            optReqs = mod.optionalRequires,
7597            d, go, def,
7598            r, old_mod,
7599            o, skinmod, skindef, skinpar, skinname,
7600            intl = mod.lang || mod.intl,
7601            ftests = Y.Features && Y.Features.tests.load,
7602            hash, reparse;
7603
7604        // console.log(name);
7605
7606        // pattern match leaves module stub that needs to be filled out
7607        if (mod.temp && adddef) {
7608            old_mod = mod;
7609            mod = this.addModule(adddef, name);
7610            mod.group = old_mod.group;
7611            mod.pkg = old_mod.pkg;
7612            delete mod.expanded;
7613        }
7614
7615        // console.log('cache: ' + mod.langCache + ' == ' + this.lang);
7616
7617        //If a skin or a lang is different, reparse..
7618        reparse = !((!this.lang || mod.langCache === this.lang) && (mod.skinCache === this.skin.defaultSkin));
7619
7620        if (mod.expanded && !reparse) {
7621            return mod.expanded;
7622        }
7623
7624        // Optional dependencies are dependencies that may or may not be
7625        // available.
7626        // This feature was designed specifically to be used when transpiling
7627        // ES6 modules, in order to use polyfills and regular scripts that define
7628        // global variables without having to import them since they should be
7629        // available in the global scope.
7630        if (optReqs) {
7631            for (i = 0, length = optReqs.length; i < length; i++) {
7632                if (this._canBeAttached(optReqs[i])) {
7633                    mod.requires.push(optReqs[i]);
7634                }
7635            }
7636        }
7637
7638        d = [];
7639        hash = {};
7640        r = this.filterRequires(mod.requires);
7641        if (mod.lang) {
7642            //If a module has a lang attribute, auto add the intl requirement.
7643            d.unshift('intl');
7644            r.unshift('intl');
7645            intl = true;
7646        }
7647        o = this.filterRequires(mod.optional);
7648
7649
7650        mod._parsed = true;
7651        mod.langCache = this.lang;
7652        mod.skinCache = this.skin.defaultSkin;
7653
7654        for (i = 0; i < r.length; i++) {
7655            if (!hash[r[i]]) {
7656                d.push(r[i]);
7657                hash[r[i]] = true;
7658                m = this.getModule(r[i]);
7659                if (m) {
7660                    add = this.getRequires(m);
7661                    intl = intl || (m.expanded_map &&
7662                        (INTL in m.expanded_map));
7663                    for (j = 0; j < add.length; j++) {
7664                        d.push(add[j]);
7665                    }
7666                }
7667            }
7668        }
7669
7670        // get the requirements from superseded modules, if any
7671        r = this.filterRequires(mod.supersedes);
7672        if (r) {
7673            for (i = 0; i < r.length; i++) {
7674                if (!hash[r[i]]) {
7675                    // if this module has submodules, the requirements list is
7676                    // expanded to include the submodules.  This is so we can
7677                    // prevent dups when a submodule is already loaded and the
7678                    // parent is requested.
7679                    if (mod.submodules) {
7680                        d.push(r[i]);
7681                    }
7682
7683                    hash[r[i]] = true;
7684                    m = this.getModule(r[i]);
7685
7686                    if (m) {
7687                        add = this.getRequires(m);
7688                        intl = intl || (m.expanded_map &&
7689                            (INTL in m.expanded_map));
7690                        for (j = 0; j < add.length; j++) {
7691                            d.push(add[j]);
7692                        }
7693                    }
7694                }
7695            }
7696        }
7697
7698        if (o && this.loadOptional) {
7699            for (i = 0; i < o.length; i++) {
7700                if (!hash[o[i]]) {
7701                    d.push(o[i]);
7702                    hash[o[i]] = true;
7703                    m = this.getModuleInfo(o[i]);
7704                    if (m) {
7705                        add = this.getRequires(m);
7706                        intl = intl || (m.expanded_map &&
7707                            (INTL in m.expanded_map));
7708                        for (j = 0; j < add.length; j++) {
7709                            d.push(add[j]);
7710                        }
7711                    }
7712                }
7713            }
7714        }
7715
7716        cond = this.conditions[name];
7717
7718        if (cond) {
7719            //Set the module to not parsed since we have conditionals and this could change the dependency tree.
7720            mod._parsed = false;
7721            if (testresults && ftests) {
7722                oeach(testresults, function(result, id) {
7723                    var condmod = ftests[id].name;
7724                    if (!hash[condmod] && ftests[id].trigger === name) {
7725                        if (result && ftests[id]) {
7726                            hash[condmod] = true;
7727                            d.push(condmod);
7728                        }
7729                    }
7730                });
7731            } else {
7732                for (i in cond) {
7733                    if (cond.hasOwnProperty(i)) {
7734                        if (!hash[i]) {
7735                            def = cond[i];
7736                            //first see if they've specfied a ua check
7737                            //then see if they've got a test fn & if it returns true
7738                            //otherwise just having a condition block is enough
7739                            go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) ||
7740                                        (def.test && def.test(Y, r)));
7741
7742                            if (go) {
7743                                hash[i] = true;
7744                                d.push(i);
7745                                m = this.getModule(i);
7746                                if (m) {
7747                                    add = this.getRequires(m);
7748                                    for (j = 0; j < add.length; j++) {
7749                                        d.push(add[j]);
7750                                    }
7751
7752                                }
7753                            }
7754                        }
7755                    }
7756                }
7757            }
7758        }
7759
7760        // Create skin modules
7761        if (mod.skinnable) {
7762            skindef = this.skin.overrides;
7763            for (i in YUI.Env.aliases) {
7764                if (YUI.Env.aliases.hasOwnProperty(i)) {
7765                    if (Y.Array.indexOf(YUI.Env.aliases[i], name) > -1) {
7766                        skinpar = i;
7767                    }
7768                }
7769            }
7770            if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) {
7771                skinname = name;
7772                if (skindef[skinpar]) {
7773                    skinname = skinpar;
7774                }
7775                for (i = 0; i < skindef[skinname].length; i++) {
7776                    skinmod = this._addSkin(skindef[skinname][i], name);
7777                    if (!this.isCSSLoaded(skinmod, this._boot)) {
7778                        d.push(skinmod);
7779                    }
7780                }
7781            } else {
7782                skinmod = this._addSkin(this.skin.defaultSkin, name);
7783                if (!this.isCSSLoaded(skinmod, this._boot)) {
7784                    d.push(skinmod);
7785                }
7786            }
7787        }
7788
7789        mod._parsed = false;
7790
7791        if (intl) {
7792
7793            if (mod.lang && !mod.langPack && Y.Intl) {
7794                lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
7795                packName = this.getLangPackName(lang, name);
7796                if (packName) {
7797                    d.unshift(packName);
7798                }
7799            }
7800            d.unshift(INTL);
7801        }
7802
7803        mod.expanded_map = yArray.hash(d);
7804
7805        mod.expanded = YObject.keys(mod.expanded_map);
7806
7807        return mod.expanded;
7808    },
7809    /**
7810    * Check to see if named css module is already loaded on the page
7811    * @method isCSSLoaded
7812    * @param {String} name The name of the css file
7813    * @param {Boolean} skip To skip the short-circuit for ignoreRegister
7814    * @return Boolean
7815    */
7816    isCSSLoaded: function(name, skip) {
7817        //TODO - Make this call a batching call with name being an array
7818        if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) {
7819            return false;
7820        }
7821        var el = YUI.Env.cssStampEl,
7822            ret = false,
7823            mod = YUI.Env._cssLoaded[name],
7824            style = el.currentStyle; //IE
7825
7826
7827        if (mod !== undefined) {
7828            return mod;
7829        }
7830
7831        //Add the classname to the element
7832        el.className = name;
7833
7834        if (!style) {
7835            style = Y.config.doc.defaultView.getComputedStyle(el, null);
7836        }
7837
7838        if (style && style.display === 'none') {
7839            ret = true;
7840        }
7841
7842
7843        el.className = ''; //Reset the classname to ''
7844
7845        YUI.Env._cssLoaded[name] = ret;
7846
7847        return ret;
7848    },
7849
7850    /**
7851     * Returns a hash of module names the supplied module satisfies.
7852     * @method getProvides
7853     * @param {string} name The name of the module.
7854     * @return {object} what this module provides.
7855     */
7856    getProvides: function(name) {
7857        var m = this.getModule(name), o, s;
7858            // supmap = this.provides;
7859
7860        if (!m) {
7861            return NOT_FOUND;
7862        }
7863
7864        if (m && !m.provides) {
7865            o = {};
7866            s = m.supersedes;
7867
7868            if (s) {
7869                yArray.each(s, function(v) {
7870                    Y.mix(o, this.getProvides(v));
7871                }, this);
7872            }
7873
7874            o[name] = true;
7875            m.provides = o;
7876
7877        }
7878
7879        return m.provides;
7880    },
7881
7882    /**
7883     * Calculates the dependency tree, the result is stored in the sorted
7884     * property.
7885     * @method calculate
7886     * @param {object} o optional options object.
7887     * @param {string} type optional argument to prune modules.
7888     */
7889    calculate: function(o, type) {
7890        if (o || type || this.dirty) {
7891
7892            if (o) {
7893                this._config(o);
7894            }
7895
7896            if (!this._init) {
7897                this._setup();
7898            }
7899
7900            this._explode();
7901
7902            if (this.allowRollup) {
7903                this._rollup();
7904            } else {
7905                this._explodeRollups();
7906            }
7907            this._reduce();
7908            this._sort();
7909        }
7910    },
7911    /**
7912    * Creates a "psuedo" package for languages provided in the lang array
7913    * @method _addLangPack
7914    * @private
7915    * @param {String} lang The language to create
7916    * @param {Object} m The module definition to create the language pack around
7917    * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US)
7918    * @return {Object} The module definition
7919    */
7920    _addLangPack: function(lang, m, packName) {
7921        var name = m.name,
7922            packPath, conf,
7923            existing = this.getModuleInfo(packName);
7924
7925        if (!existing) {
7926
7927            packPath = _path((m.pkg || name), packName, JS, true);
7928
7929            conf = {
7930                path: packPath,
7931                intl: true,
7932                langPack: true,
7933                ext: m.ext,
7934                group: m.group,
7935                supersedes: []
7936            };
7937            if (m.root) {
7938                conf.root = m.root;
7939            }
7940            if (m.base) {
7941                conf.base = m.base;
7942            }
7943
7944            if (m.configFn) {
7945                conf.configFn = m.configFn;
7946            }
7947
7948            this.addModule(conf, packName);
7949
7950            if (lang) {
7951                Y.Env.lang = Y.Env.lang || {};
7952                Y.Env.lang[lang] = Y.Env.lang[lang] || {};
7953                Y.Env.lang[lang][name] = true;
7954            }
7955        }
7956
7957        return this.getModuleInfo(packName);
7958    },
7959
7960    /**
7961     * Investigates the current YUI configuration on the page.  By default,
7962     * modules already detected will not be loaded again unless a force
7963     * option is encountered.  Called by calculate()
7964     * @method _setup
7965     * @private
7966     */
7967    _setup: function() {
7968        var info = this.moduleInfo, name, i, j, m, l,
7969            packName;
7970
7971        for (name in info) {
7972            if (info.hasOwnProperty(name)) {
7973                m = info[name];
7974                if (m) {
7975
7976                    // remove dups
7977                    //m.requires = YObject.keys(yArray.hash(m.requires));
7978                    m.requires = yArray.dedupe(m.requires);
7979
7980                    // Create lang pack modules
7981                    //if (m.lang && m.lang.length) {
7982                    if (m.lang) {
7983                        // Setup root package if the module has lang defined,
7984                        // it needs to provide a root language pack
7985                        packName = this.getLangPackName(ROOT_LANG, name);
7986                        this._addLangPack(null, m, packName);
7987                    }
7988
7989                }
7990            }
7991        }
7992
7993
7994        //l = Y.merge(this.inserted);
7995        l = {};
7996
7997        // available modules
7998        if (!this.ignoreRegistered) {
7999            Y.mix(l, GLOBAL_ENV.mods);
8000        }
8001
8002        // add the ignore list to the list of loaded packages
8003        if (this.ignore) {
8004            Y.mix(l, yArray.hash(this.ignore));
8005        }
8006
8007        // expand the list to include superseded modules
8008        for (j in l) {
8009            if (l.hasOwnProperty(j)) {
8010                Y.mix(l, this.getProvides(j));
8011            }
8012        }
8013
8014        // remove modules on the force list from the loaded list
8015        if (this.force) {
8016            for (i = 0; i < this.force.length; i++) {
8017                if (this.force[i] in l) {
8018                    delete l[this.force[i]];
8019                }
8020            }
8021        }
8022
8023        Y.mix(this.loaded, l);
8024
8025        this._init = true;
8026    },
8027
8028    /**
8029     * Builds a module name for a language pack
8030     * @method getLangPackName
8031     * @param {string} lang the language code.
8032     * @param {string} mname the module to build it for.
8033     * @return {string} the language pack module name.
8034     */
8035    getLangPackName: function(lang, mname) {
8036        return ('lang/' + mname + ((lang) ? '_' + lang : ''));
8037    },
8038    /**
8039     * Inspects the required modules list looking for additional
8040     * dependencies.  Expands the required list to include all
8041     * required modules.  Called by calculate()
8042     * @method _explode
8043     * @private
8044     */
8045    _explode: function() {
8046        //TODO Move done out of scope
8047        var r = this.required, m, reqs, done = {},
8048            self = this, name, expound;
8049
8050        // the setup phase is over, all modules have been created
8051        self.dirty = false;
8052
8053        self._explodeRollups();
8054        r = self.required;
8055
8056        for (name in r) {
8057            if (r.hasOwnProperty(name)) {
8058                if (!done[name]) {
8059                    done[name] = true;
8060                    m = self.getModule(name);
8061                    if (m) {
8062                        expound = m.expound;
8063
8064                        if (expound) {
8065                            r[expound] = self.getModule(expound);
8066                            reqs = self.getRequires(r[expound]);
8067                            Y.mix(r, yArray.hash(reqs));
8068                        }
8069
8070                        reqs = self.getRequires(m);
8071                        Y.mix(r, yArray.hash(reqs));
8072                    }
8073                }
8074            }
8075        }
8076
8077    },
8078    /**
8079    * The default method used to test a module against a pattern
8080    * @method _patternTest
8081    * @private
8082    * @param {String} mname The module being tested
8083    * @param {String} pname The pattern to match
8084    */
8085    _patternTest: function(mname, pname) {
8086        return (mname.indexOf(pname) > -1);
8087    },
8088    /**
8089    * Get's the loader meta data for the requested module
8090    * @method getModule
8091    * @param {String} mname The module name to get
8092    * @return {Object} The module metadata
8093    */
8094    getModule: function(mname) {
8095        //TODO: Remove name check - it's a quick hack to fix pattern WIP
8096        if (!mname) {
8097            return null;
8098        }
8099
8100        var p, found, pname,
8101            m = this.getModuleInfo(mname),
8102            patterns = this.patterns;
8103
8104        // check the patterns library to see if we should automatically add
8105        // the module with defaults
8106        if (!m || (m && m.ext)) {
8107            for (pname in patterns) {
8108                if (patterns.hasOwnProperty(pname)) {
8109                    p = patterns[pname];
8110
8111                    //There is no test method, create a default one that tests
8112                    // the pattern against the mod name
8113                    if (!p.test) {
8114                        p.test = this._patternTest;
8115                    }
8116
8117                    if (p.test(mname, pname)) {
8118                        // use the metadata supplied for the pattern
8119                        // as the module definition.
8120                        found = p;
8121                        break;
8122                    }
8123                }
8124            }
8125        }
8126
8127        if (!m) {
8128            if (found) {
8129                if (p.action) {
8130                    p.action.call(this, mname, pname);
8131                } else {
8132                    // ext true or false?
8133                    m = this.addModule(Y.merge(found, {
8134                        test: void 0,
8135                        temp: true
8136                    }), mname);
8137                    if (m && found.configFn) {
8138                        m.configFn = found.configFn;
8139                    }
8140                }
8141            }
8142        } else {
8143            if (found && m && found.configFn && !m.configFn) {
8144                m.configFn = found.configFn;
8145                m.configFn(m);
8146            }
8147        }
8148
8149        return m;
8150    },
8151
8152    // impl in rollup submodule
8153    _rollup: function() { },
8154
8155    /**
8156     * Remove superceded modules and loaded modules.  Called by
8157     * calculate() after we have the mega list of all dependencies
8158     * @method _reduce
8159     * @return {object} the reduced dependency hash.
8160     * @private
8161     */
8162    _reduce: function(r) {
8163
8164        r = r || this.required;
8165
8166        var i, j, s, m, type = this.loadType,
8167        ignore = this.ignore ? yArray.hash(this.ignore) : false;
8168
8169        for (i in r) {
8170            if (r.hasOwnProperty(i)) {
8171                m = this.getModule(i);
8172                // remove if already loaded
8173                if (((this.loaded[i] || ON_PAGE[i]) &&
8174                        !this.forceMap[i] && !this.ignoreRegistered) ||
8175                        (type && m && m.type !== type)) {
8176                    delete r[i];
8177                }
8178                if (ignore && ignore[i]) {
8179                    delete r[i];
8180                }
8181                // remove anything this module supersedes
8182                s = m && m.supersedes;
8183                if (s) {
8184                    for (j = 0; j < s.length; j++) {
8185                        if (s[j] in r) {
8186                            delete r[s[j]];
8187                        }
8188                    }
8189                }
8190            }
8191        }
8192
8193        return r;
8194    },
8195    /**
8196    * Handles the queue when a module has been loaded for all cases
8197    * @method _finish
8198    * @private
8199    * @param {String} msg The message from Loader
8200    * @param {Boolean} success A boolean denoting success or failure
8201    */
8202    _finish: function(msg, success) {
8203
8204        _queue.running = false;
8205
8206        var onEnd = this.onEnd;
8207        if (onEnd) {
8208            onEnd.call(this.context, {
8209                msg: msg,
8210                data: this.data,
8211                success: success
8212            });
8213        }
8214        this._continue();
8215    },
8216    /**
8217    * The default Loader onSuccess handler, calls this.onSuccess with a payload
8218    * @method _onSuccess
8219    * @private
8220    */
8221    _onSuccess: function() {
8222        var self = this, skipped = Y.merge(self.skipped), fn,
8223            failed = [], rreg = self.requireRegistration,
8224            success, msg, i, mod;
8225
8226        for (i in skipped) {
8227            if (skipped.hasOwnProperty(i)) {
8228                delete self.inserted[i];
8229            }
8230        }
8231
8232        self.skipped = {};
8233
8234        for (i in self.inserted) {
8235            if (self.inserted.hasOwnProperty(i)) {
8236                mod = self.getModule(i);
8237                if (mod && rreg && mod.type === JS && !(i in YUI.Env.mods)) {
8238                    failed.push(i);
8239                } else {
8240                    Y.mix(self.loaded, self.getProvides(i));
8241                }
8242            }
8243        }
8244
8245        fn = self.onSuccess;
8246        msg = (failed.length) ? 'notregistered' : 'success';
8247        success = !(failed.length);
8248        if (fn) {
8249            fn.call(self.context, {
8250                msg: msg,
8251                data: self.data,
8252                success: success,
8253                failed: failed,
8254                skipped: skipped
8255            });
8256        }
8257        self._finish(msg, success);
8258    },
8259    /**
8260    * The default Loader onProgress handler, calls this.onProgress with a payload
8261    * @method _onProgress
8262    * @private
8263    */
8264    _onProgress: function(e) {
8265        var self = this, i;
8266        //set the internal cache to what just came in.
8267        if (e.data && e.data.length) {
8268            for (i = 0; i < e.data.length; i++) {
8269                e.data[i] = self.getModule(e.data[i].name);
8270            }
8271        }
8272        if (self.onProgress) {
8273            self.onProgress.call(self.context, {
8274                name: e.url,
8275                data: e.data
8276            });
8277        }
8278    },
8279    /**
8280    * The default Loader onFailure handler, calls this.onFailure with a payload
8281    * @method _onFailure
8282    * @private
8283    */
8284    _onFailure: function(o) {
8285        var f = this.onFailure, msg = [], i = 0, len = o.errors.length;
8286
8287        for (i; i < len; i++) {
8288            msg.push(o.errors[i].error);
8289        }
8290
8291        msg = msg.join(',');
8292
8293
8294        if (f) {
8295            f.call(this.context, {
8296                msg: msg,
8297                data: this.data,
8298                success: false
8299            });
8300        }
8301
8302        this._finish(msg, false);
8303
8304    },
8305
8306    /**
8307    * The default Loader onTimeout handler, calls this.onTimeout with a payload
8308    * @method _onTimeout
8309    * @param {Get.Transaction} transaction The Transaction object from `Y.Get`
8310    * @private
8311    */
8312    _onTimeout: function(transaction) {
8313        var f = this.onTimeout;
8314        if (f) {
8315            f.call(this.context, {
8316                msg: 'timeout',
8317                data: this.data,
8318                success: false,
8319                transaction: transaction
8320            });
8321        }
8322    },
8323
8324    /**
8325     * Sorts the dependency tree.  The last step of calculate()
8326     * @method _sort
8327     * @private
8328     */
8329    _sort: function() {
8330        var name,
8331
8332            // Object containing module names.
8333            required = this.required,
8334
8335            // Keep track of whether we've visited a module.
8336            visited = {};
8337
8338        // Will contain modules names, in the correct order,
8339        // according to dependencies.
8340        this.sorted = [];
8341
8342        for (name in required) {
8343            if (!visited[name] && required.hasOwnProperty(name)) {
8344                this._visit(name, visited);
8345            }
8346        }
8347    },
8348
8349    /**
8350     * Recursively visits the dependencies of the module name
8351     * passed in, and appends each module name to the `sorted` property.
8352     * @param {String} name The name of a module.
8353     * @param {Object} visited Keeps track of whether a module was visited.
8354     * @method _visit
8355     * @private
8356     */
8357    _visit: function (name, visited) {
8358        var required, condition, moduleInfo, dependency, dependencies,
8359            trigger, isAfter, i, l;
8360
8361        visited[name] = true;
8362        required = this.required;
8363        moduleInfo = this.moduleInfo[name];
8364        condition = this.conditions[name] || {};
8365
8366        if (moduleInfo) {
8367            // Recurse on each dependency of this module,
8368            // figuring out its dependencies, and so on.
8369            dependencies = moduleInfo.expanded || moduleInfo.requires;
8370
8371            for (i = 0, l = dependencies.length; i < l; ++i) {
8372                dependency = dependencies[i];
8373                trigger = condition[dependency];
8374
8375                // We cannot process this dependency yet if it must
8376                // appear after our current module.
8377                isAfter = trigger && (!trigger.when || trigger.when === "after");
8378
8379                // Is this module name in the required list of modules,
8380                // and have we not already visited it?
8381                if (required[dependency] && !visited[dependency] && !isAfter) {
8382                    this._visit(dependency, visited);
8383                }
8384            }
8385        }
8386
8387        this.sorted.push(name);
8388    },
8389
8390    /**
8391    * Handles the actual insertion of script/link tags
8392    * @method _insert
8393    * @private
8394    * @param {Object} source The YUI instance the request came from
8395    * @param {Object} o The metadata to include
8396    * @param {String} type JS or CSS
8397    * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta
8398    */
8399    _insert: function(source, o, type, skipcalc) {
8400
8401
8402        // restore the state at the time of the request
8403        if (source) {
8404            this._config(source);
8405        }
8406
8407        // build the dependency list
8408        // don't include type so we can process CSS and script in
8409        // one pass when the type is not specified.
8410
8411        var modules = this.resolve(!skipcalc),
8412            self = this, comp = 0, actions = 0,
8413            mods = {}, deps, complete;
8414
8415        self._refetch = [];
8416
8417        if (type) {
8418            //Filter out the opposite type and reset the array so the checks later work
8419            modules[((type === JS) ? CSS : JS)] = [];
8420        }
8421        if (!self.fetchCSS) {
8422            modules.css = [];
8423        }
8424        if (modules.js.length) {
8425            comp++;
8426        }
8427        if (modules.css.length) {
8428            comp++;
8429        }
8430
8431        //console.log('Resolved Modules: ', modules);
8432
8433        complete = function(d) {
8434            actions++;
8435            var errs = {}, i = 0, o = 0, u = '', fn,
8436                modName, resMods;
8437
8438            if (d && d.errors) {
8439                for (i = 0; i < d.errors.length; i++) {
8440                    if (d.errors[i].request) {
8441                        u = d.errors[i].request.url;
8442                    } else {
8443                        u = d.errors[i];
8444                    }
8445                    errs[u] = u;
8446                }
8447            }
8448
8449            if (d && d.data && d.data.length && (d.type === 'success')) {
8450                for (i = 0; i < d.data.length; i++) {
8451                    self.inserted[d.data[i].name] = true;
8452                    //If the external module has a skin or a lang, reprocess it
8453                    if (d.data[i].lang || d.data[i].skinnable) {
8454                        delete self.inserted[d.data[i].name];
8455                        self._refetch.push(d.data[i].name);
8456                    }
8457                }
8458            }
8459
8460            if (actions === comp) {
8461                self._loading = null;
8462                if (self._refetch.length) {
8463                    //Get the deps for the new meta-data and reprocess
8464                    for (i = 0; i < self._refetch.length; i++) {
8465                        deps = self.getRequires(self.getModule(self._refetch[i]));
8466                        for (o = 0; o < deps.length; o++) {
8467                            if (!self.inserted[deps[o]]) {
8468                                //We wouldn't be to this point without the module being here
8469                                mods[deps[o]] = deps[o];
8470                            }
8471                        }
8472                    }
8473                    mods = Y.Object.keys(mods);
8474                    if (mods.length) {
8475                        self.require(mods);
8476                        resMods = self.resolve(true);
8477                        if (resMods.cssMods.length) {
8478                            for (i=0; i <  resMods.cssMods.length; i++) {
8479                                modName = resMods.cssMods[i].name;
8480                                delete YUI.Env._cssLoaded[modName];
8481                                if (self.isCSSLoaded(modName)) {
8482                                    self.inserted[modName] = true;
8483                                    delete self.required[modName];
8484                                }
8485                            }
8486                            self.sorted = [];
8487                            self._sort();
8488                        }
8489                        d = null; //bail
8490                        self._insert(); //insert the new deps
8491                    }
8492                }
8493                if (d && d.fn) {
8494                    fn = d.fn;
8495                    delete d.fn;
8496                    fn.call(self, d);
8497                }
8498            }
8499        };
8500
8501        this._loading = true;
8502
8503        if (!modules.js.length && !modules.css.length) {
8504            actions = -1;
8505            complete({
8506                fn: self._onSuccess
8507            });
8508            return;
8509        }
8510
8511
8512        if (modules.css.length) { //Load CSS first
8513            Y.Get.css(modules.css, {
8514                data: modules.cssMods,
8515                attributes: self.cssAttributes,
8516                insertBefore: self.insertBefore,
8517                charset: self.charset,
8518                timeout: self.timeout,
8519                context: self,
8520                onProgress: function(e) {
8521                    self._onProgress.call(self, e);
8522                },
8523                onTimeout: function(d) {
8524                    self._onTimeout.call(self, d);
8525                },
8526                onSuccess: function(d) {
8527                    d.type = 'success';
8528                    d.fn = self._onSuccess;
8529                    complete.call(self, d);
8530                },
8531                onFailure: function(d) {
8532                    d.type = 'failure';
8533                    d.fn = self._onFailure;
8534                    complete.call(self, d);
8535                }
8536            });
8537        }
8538
8539        if (modules.js.length) {
8540            Y.Get.js(modules.js, {
8541                data: modules.jsMods,
8542                insertBefore: self.insertBefore,
8543                attributes: self.jsAttributes,
8544                charset: self.charset,
8545                timeout: self.timeout,
8546                autopurge: false,
8547                context: self,
8548                async: self.async,
8549                onProgress: function(e) {
8550                    self._onProgress.call(self, e);
8551                },
8552                onTimeout: function(d) {
8553                    self._onTimeout.call(self, d);
8554                },
8555                onSuccess: function(d) {
8556                    d.type = 'success';
8557                    d.fn = self._onSuccess;
8558                    complete.call(self, d);
8559                },
8560                onFailure: function(d) {
8561                    d.type = 'failure';
8562                    d.fn = self._onFailure;
8563                    complete.call(self, d);
8564                }
8565            });
8566        }
8567    },
8568    /**
8569    * Once a loader operation is completely finished, process any additional queued items.
8570    * @method _continue
8571    * @private
8572    */
8573    _continue: function() {
8574        if (!(_queue.running) && _queue.size() > 0) {
8575            _queue.running = true;
8576            _queue.next()();
8577        }
8578    },
8579
8580    /**
8581     * inserts the requested modules and their dependencies.
8582     * <code>type</code> can be "js" or "css".  Both script and
8583     * css are inserted if type is not provided.
8584     * @method insert
8585     * @param {object} o optional options object.
8586     * @param {string} type the type of dependency to insert.
8587     */
8588    insert: function(o, type, skipsort) {
8589        var self = this, copy = Y.merge(this);
8590        delete copy.require;
8591        delete copy.dirty;
8592        _queue.add(function() {
8593            self._insert(copy, o, type, skipsort);
8594        });
8595        this._continue();
8596    },
8597
8598    /**
8599     * Executed every time a module is loaded, and if we are in a load
8600     * cycle, we attempt to load the next script.  Public so that it
8601     * is possible to call this if using a method other than
8602     * Y.register to determine when scripts are fully loaded
8603     * @method loadNext
8604     * @deprecated
8605     * @param {string} mname optional the name of the module that has
8606     * been loaded (which is usually why it is time to load the next
8607     * one).
8608     */
8609    loadNext: function() {
8610        return;
8611    },
8612
8613    /**
8614     * Apply filter defined for this instance to a url/path
8615     * @method _filter
8616     * @param {string} u the string to filter.
8617     * @param {string} name the name of the module, if we are processing
8618     * a single module as opposed to a combined url.
8619     * @return {string} the filtered string.
8620     * @private
8621     */
8622    _filter: function(u, name, group) {
8623        var f = this.filter,
8624            hasFilter = name && (name in this.filters),
8625            modFilter = hasFilter && this.filters[name],
8626            groupName = group || (this.getModuleInfo(name) || {}).group || null;
8627
8628        if (groupName && this.groups[groupName] && this.groups[groupName].filter) {
8629            modFilter = this.groups[groupName].filter;
8630            hasFilter = true;
8631        }
8632
8633        if (u) {
8634            if (hasFilter) {
8635                f = (L.isString(modFilter)) ? this.FILTER_DEFS[modFilter.toUpperCase()] || null : modFilter;
8636            }
8637            if (f) {
8638                u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
8639            }
8640        }
8641        return u;
8642    },
8643
8644    /**
8645     * Generates the full url for a module
8646     * @method _url
8647     * @param {string} path the path fragment.
8648     * @param {String} name The name of the module
8649     * @param {String} [base] The base url to use. Defaults to self.base
8650     * @return {string} the full url.
8651     * @private
8652     */
8653    _url: function(path, name, base) {
8654        return this._filter((base || this.base || '') + path, name);
8655    },
8656    /**
8657    * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules.
8658    * @method resolve
8659    * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else
8660    * @param {Array} [sorted=loader.sorted] An override for the loader.sorted array
8661    * @return {Object} Object hash (js and css) of two arrays of file lists
8662    * @example This method can be used as an off-line dep calculator
8663    *
8664    *        var Y = YUI();
8665    *        var loader = new Y.Loader({
8666    *            filter: 'debug',
8667    *            base: '../../',
8668    *            root: 'build/',
8669    *            combine: true,
8670    *            require: ['node', 'dd', 'console']
8671    *        });
8672    *        var out = loader.resolve(true);
8673    *
8674    */
8675    resolve: function(calc, sorted) {
8676        var self     = this,
8677            resolved = { js: [], jsMods: [], css: [], cssMods: [] },
8678            addSingle,
8679            usePathogen = Y.config.comboLoader && Y.config.customComboBase;
8680
8681        if (self.skin.overrides || self.skin.defaultSkin !== DEFAULT_SKIN || self.ignoreRegistered) {
8682            self._resetModules();
8683        }
8684
8685        if (calc) {
8686            self.calculate();
8687        }
8688        sorted = sorted || self.sorted;
8689
8690        addSingle = function(mod) {
8691            if (mod) {
8692                var group = (mod.group && self.groups[mod.group]) || NOT_FOUND,
8693                    url;
8694
8695                //Always assume it's async
8696                if (group.async === false) {
8697                    mod.async = group.async;
8698                }
8699
8700                url = (mod.fullpath) ? self._filter(mod.fullpath, mod.name) :
8701                      self._url(mod.path, mod.name, group.base || mod.base);
8702
8703                if (mod.attributes || mod.async === false) {
8704                    url = {
8705                        url: url,
8706                        async: mod.async
8707                    };
8708                    if (mod.attributes) {
8709                        url.attributes = mod.attributes;
8710                    }
8711                }
8712                resolved[mod.type].push(url);
8713                resolved[mod.type + 'Mods'].push(mod);
8714            } else {
8715            }
8716
8717        };
8718
8719        /*jslint vars: true */
8720        var inserted     = (self.ignoreRegistered) ? {}
8720 : self.inserted,
8721            comboSources,
8722            maxURLLength,
8723            comboMeta,
8724            comboBase,
8725            comboSep,
8726            group,
8727            mod,
8728            len,
8729            i,
8730            hasComboModule = false;
8731
8732        /*jslint vars: false */
8733
8734        for (i = 0, len = sorted.length; i < len; i++) {
8735            mod = self.getModule(sorted[i]);
8736            if (!mod || inserted[mod.name]) {
8737                continue;
8738            }
8739
8740            group = self.groups[mod.group];
8741
8742            comboBase = self.comboBase;
8743
8744            if (group) {
8745                if (!group.combine || mod.fullpath) {
8746                    //This is not a combo module, skip it and load it singly later.
8747                    addSingle(mod);
8748                    continue;
8749                }
8750                mod.combine = true;
8751
8752                if (typeof group.root === 'string') {
8753                    mod.root = group.root;
8754                }
8755
8756                comboBase    = group.comboBase || comboBase;
8757                comboSep     = group.comboSep;
8758                maxURLLength = group.maxURLLength;
8759            } else {
8760                if (!self.combine) {
8761                    //This is not a combo module, skip it and load it singly later.
8762                    addSingle(mod);
8763                    continue;
8764                }
8765            }
8766
8767            if (!mod.combine && mod.ext) {
8768                addSingle(mod);
8769                continue;
8770            }
8771            hasComboModule = true;
8772            comboSources = comboSources || {};
8773            comboSources[comboBase] = comboSources[comboBase] ||
8774                { js: [], jsMods: [], css: [], cssMods: [] };
8775
8776            comboMeta               = comboSources[comboBase];
8777            comboMeta.group         = mod.group;
8778            comboMeta.comboSep      = comboSep || self.comboSep;
8779            comboMeta.maxURLLength  = maxURLLength || self.maxURLLength;
8780
8781            comboMeta[mod.type + 'Mods'].push(mod);
8782            if (mod.type === JS || mod.type === CSS) {
8783                resolved[mod.type + 'Mods'].push(mod);
8784            }
8785        }
8786        //only encode if we have something to encode
8787        if (hasComboModule) {
8788            if (usePathogen) {
8789                resolved = this._pathogenEncodeComboSources(resolved);
8790            } else {
8791                resolved = this._encodeComboSources(resolved, comboSources);
8792            }
8793        }
8794        return resolved;
8795    },
8796
8797    /**
8798     * Encodes combo sources and appends them to an object hash of arrays from `loader.resolve`.
8799     *
8800     * @method _encodeComboSources
8801     * @param {Object} resolved The object hash of arrays in which to attach the encoded combo sources.
8802     * @param {Object} comboSources An object containing relevant data about modules.
8803     * @return Object
8804     * @private
8805     */
8806    _encodeComboSources: function(resolved, comboSources) {
8807        var fragSubset,
8808            modules,
8809            tmpBase,
8810            baseLen,
8811            frags,
8812            frag,
8813            type,
8814            mod,
8815            maxURLLength,
8816            comboBase,
8817            comboMeta,
8818            comboSep,
8819            i,
8820            len,
8821            self = this;
8822
8823        for (comboBase in comboSources) {
8824            if (comboSources.hasOwnProperty(comboBase)) {
8825                comboMeta    = comboSources[comboBase];
8826                comboSep     = comboMeta.comboSep;
8827                maxURLLength = comboMeta.maxURLLength;
8828                for (type in comboMeta) {
8829                    if (type === JS || type === CSS) {
8830                        modules = comboMeta[type + 'Mods'];
8831                        frags = [];
8832                        for (i = 0, len = modules.length; i < len; i += 1) {
8833                            mod = modules[i];
8834                            frag = ((typeof mod.root === 'string') ? mod.root : self.root) + (mod.path || mod.fullpath);
8835                            frags.push(
8836                                self._filter(frag, mod.name)
8837                            );
8838                        }
8839                        tmpBase = comboBase + frags.join(comboSep);
8840                        baseLen = tmpBase.length;
8841                        if (maxURLLength <= comboBase.length) {
8842                            maxURLLength = MAX_URL_LENGTH;
8843                        }
8844
8845                        if (frags.length) {
8846                            if (baseLen > maxURLLength) {
8847                                fragSubset = [];
8848                                for (i = 0, len = frags.length; i < len; i++) {
8849                                    fragSubset.push(frags[i]);
8850                                    tmpBase = comboBase + fragSubset.join(comboSep);
8851
8852                                    if (tmpBase.length > maxURLLength) {
8853                                        frag = fragSubset.pop();
8854                                        tmpBase = comboBase + fragSubset.join(comboSep);
8855                                        resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
8856                                        fragSubset = [];
8857                                        if (frag) {
8858                                            fragSubset.push(frag);
8859                                        }
8860                                    }
8861                                }
8862                                if (fragSubset.length) {
8863                                    tmpBase = comboBase + fragSubset.join(comboSep);
8864                                    resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
8865                                }
8866                            } else {
8867                                resolved[type].push(self._filter(tmpBase, null, comboMeta.group));
8868                            }
8869                        }
8870                    }
8871                }
8872            }
8873        }
8874        return resolved;
8875    },
8876
8877    /**
8878    Shortcut to calculate, resolve and load all modules.
8879
8880        var loader = new Y.Loader({
8881            ignoreRegistered: true,
8882            modules: {
8883                mod: {
8884                    path: 'mod.js'
8885                }
8886            },
8887            requires: [ 'mod' ]
8888        });
8889        loader.load(function() {
8890            console.log('All modules have loaded..');
8891        });
8892
8893
8894    @method load
8895    @param {Function} cb Executed after all load operations are complete
8896    */
8897    load: function(cb) {
8898        if (!cb) {
8899            return;
8900        }
8901        var self = this,
8902            out = self.resolve(true);
8903
8904        self.data = out;
8905
8906        self.onEnd = function() {
8907            cb.apply(self.context || self, arguments);
8908        };
8909
8910        self.insert();
8911    }
8912};
8913
8914
8915}, '3.18.1', {"requires": ["get", "features"]});
8916YUI.add('loader-rollup', function (Y, NAME) {
8917
8918/**
8919 * Optional automatic rollup logic for reducing http connections
8920 * when not using a combo service.
8921 * @module loader
8922 * @submodule rollup
8923 */
8924
8925/**
8926 * Look for rollup packages to determine if all of the modules a
8927 * rollup supersedes are required.  If so, include the rollup to
8928 * help reduce the total number of connections required.  Called
8929 * by calculate().  This is an optional feature, and requires the
8930 * appropriate submodule to function.
8931 * @method _rollup
8932 * @for Loader
8933 * @private
8934 */
8935Y.Loader.prototype._rollup = function() {
8936    var i, j, m, s, r = this.required, roll,
8937        info = this.moduleInfo, rolled, c, smod;
8938
8939    // find and cache rollup modules
8940    if (this.dirty || !this.rollups) {
8941        this.rollups = {};
8942        for (i in info) {
8943            if (info.hasOwnProperty(i)) {
8944                m = this.getModule(i);
8945                // if (m && m.rollup && m.supersedes) {
8946                if (m && m.rollup) {
8947                    this.rollups[i] = m;
8948                }
8949            }
8950        }
8951    }
8952
8953    // make as many passes as needed to pick up rollup rollups
8954    for (;;) {
8955        rolled = false;
8956
8957        // go through the rollup candidates
8958        for (i in this.rollups) {
8959            if (this.rollups.hasOwnProperty(i)) {
8960                // there can be only one, unless forced
8961                if (!r[i] && ((!this.loaded[i]) || this.forceMap[i])) {
8962                    m = this.getModule(i);
8963                    s = m.supersedes || [];
8964                    roll = false;
8965
8966                    // @TODO remove continue
8967                    if (!m.rollup) {
8968                        continue;
8969                    }
8970
8971                    c = 0;
8972
8973                    // check the threshold
8974                    for (j = 0; j < s.length; j++) {
8975                        smod = info[s[j]];
8976
8977                        // if the superseded module is loaded, we can't
8978                        // load the rollup unless it has been forced.
8979                        if (this.loaded[s[j]] && !this.forceMap[s[j]]) {
8980                            roll = false;
8981                            break;
8982                        // increment the counter if this module is required.
8983                        // if we are beyond the rollup threshold, we will
8984                        // use the rollup module
8985                        } else if (r[s[j]] && m.type === smod.type) {
8986                            c++;
8987                            roll = (c >= m.rollup);
8988                            if (roll) {
8989                                break;
8990                            }
8991                        }
8992                    }
8993
8994                    if (roll) {
8995                        // add the rollup
8996                        r[i] = true;
8997                        rolled = true;
8998
8999                        // expand the rollup's dependencies
9000                        this.getRequires(m);
9001                    }
9002                }
9003            }
9004        }
9005
9006        // if we made it here w/o rolling up something, we are done
9007        if (!rolled) {
9008            break;
9009        }
9010    }
9011};
9012
9013
9014}, '3.18.1', {"requires": ["loader-base"]});
9015YUI.add('loader-yui3', function (Y, NAME) {
9016
9017/* This file is auto-generated by (yogi loader --yes --mix --start ../) */
9018
9019/*jshint maxlen:900, eqeqeq: false */
9020
9021/**
9022 * YUI 3 module metadata
9023 * @module loader
9024 * @submodule loader-yui3
9025 */
9026YUI.Env[Y.version].modules = YUI.Env[Y.version].modules || {};
9027Y.mix(YUI.Env[Y.version].modules, {
9028    "align-plugin": {
9029        "requires": [
9030            "node-screen",
9031            "node-pluginhost"
9032        ]
9033    },
9034    "anim": {
9035        "use": [
9036            "anim-base",
9037            "anim-color",
9038            "anim-curve",
9039            "anim-easing",
9040            "anim-node-plugin",
9041            "anim-scroll",
9042            "anim-xy"
9043        ]
9044    },
9045    "anim-base": {
9046        "requires": [
9047            "base-base",
9048            "node-style",
9049            "color-base"
9050        ]
9051    },
9052    "anim-color": {
9053        "requires": [
9054            "anim-base"
9055        ]
9056    },
9057    "anim-curve": {
9058        "requires": [
9059            "anim-xy"
9060        ]
9061    },
9062    "anim-easing": {
9063        "requires": [
9064            "anim-base"
9065        ]
9066    },
9067    "anim-node-plugin": {
9068        "requires": [
9069            "node-pluginhost",
9070            "anim-base"
9071        ]
9072    },
9073    "anim-scroll": {
9074        "requires": [
9075            "anim-base"
9076        ]
9077    },
9078    "anim-shape": {
9079        "requires": [
9080            "anim-base",
9081            "anim-easing",
9082            "anim-color",
9083            "matrix"
9084        ]
9085    },
9086    "anim-shape-transform": {
9087        "use": [
9088            "anim-shape"
9089        ]
9090    },
9091    "anim-xy": {
9092        "requires": [
9093            "anim-base",
9094            "node-screen"
9095        ]
9096    },
9097    "app": {
9098        "use": [
9099            "app-base",
9100            "app-content",
9101            "app-transitions",
9102            "lazy-model-list",
9103            "model",
9104            "model-list",
9105            "model-sync-rest",
9106            "model-sync-local",
9107            "router",
9108            "view",
9109            "view-node-map"
9110        ]
9111    },
9112    "app-base": {
9113        "requires": [
9114            "classnamemanager",
9115            "pjax-base",
9116            "router",
9117            "view"
9118        ]
9119    },
9120    "app-content": {
9121        "requires": [
9122            "app-base",
9123            "pjax-content"
9124        ]
9125    },
9126    "app-transitions": {
9127        "requires": [
9128            "app-base"
9129        ]
9130    },
9131    "app-transitions-css": {
9132        "type": "css"
9133    },
9134    "app-transitions-native": {
9135        "condition": {
9136            "name": "app-transitions-native",
9137            "test": function (Y) {
9138    var doc  = Y.config.doc,
9139        node = doc ? doc.documentElement : null;
9140
9141    if (node && node.style) {
9142        return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
9143    }
9144
9145    return false;
9146},
9147            "trigger": "app-transitions"
9148        },
9149        "requires": [
9150            "app-transitions",
9151            "app-transitions-css",
9152            "parallel",
9153            "transition"
9154        ]
9155    },
9156    "array-extras": {
9157        "requires": [
9158            "yui-base"
9159        ]
9160    },
9161    "array-invoke": {
9162        "requires": [
9163            "yui-base"
9164        ]
9165    },
9166    "arraylist": {
9167        "requires": [
9168            "yui-base"
9169        ]
9170    },
9171    "arraylist-add": {
9172        "requires": [
9173            "arraylist"
9174        ]
9175    },
9176    "arraylist-filter": {
9177        "requires": [
9178            "arraylist"
9179        ]
9180    },
9181    "arraysort": {
9182        "requires": [
9183            "yui-base"
9184        ]
9185    },
9186    "async-queue": {
9187        "requires": [
9188            "event-custom"
9189        ]
9190    },
9191    "attribute": {
9192        "use": [
9193            "attribute-base",
9194            "attribute-complex"
9195        ]
9196    },
9197    "attribute-base": {
9198        "requires": [
9199            "attribute-core",
9200            "attribute-observable",
9201            "attribute-extras"
9202        ]
9203    },
9204    "attribute-complex": {
9205        "requires": [
9206            "attribute-base"
9207        ]
9208    },
9209    "attribute-core": {
9210        "requires": [
9211            "oop"
9212        ]
9213    },
9214    "attribute-events": {
9215        "use": [
9216            "attribute-observable"
9217        ]
9218    },
9219    "attribute-extras": {
9220        "requires": [
9221            "oop"
9222        ]
9223    },
9224    "attribute-observable": {
9225        "requires": [
9226            "event-custom"
9227        ]
9228    },
9229    "autocomplete": {
9230        "use": [
9231            "autocomplete-base",
9232            "autocomplete-sources",
9233            "autocomplete-list",
9234            "autocomplete-plugin"
9235        ]
9236    },
9237    "autocomplete-base": {
9238        "optional": [
9239            "autocomplete-sources"
9240        ],
9241        "requires": [
9242            "array-extras",
9243            "base-build",
9244            "escape",
9245            "event-valuechange",
9246            "node-base"
9247        ]
9248    },
9249    "autocomplete-filters": {
9250        "requires": [
9251            "array-extras",
9252            "text-wordbreak"
9253        ]
9254    },
9255    "autocomplete-filters-accentfold": {
9256        "requires": [
9257            "array-extras",
9258            "text-accentfold",
9259            "text-wordbreak"
9260        ]
9261    },
9262    "autocomplete-highlighters": {
9263        "requires": [
9264            "array-extras",
9265            "highlight-base"
9266        ]
9267    },
9268    "autocomplete-highlighters-accentfold": {
9269        "requires": [
9270            "array-extras",
9271            "highlight-accentfold"
9272        ]
9273    },
9274    "autocomplete-list": {
9275        "after": [
9276            "autocomplete-sources"
9277        ],
9278        "lang": [
9279            "en",
9280            "es",
9281            "hu",
9282            "it"
9283        ],
9284        "requires": [
9285            "autocomplete-base",
9286            "event-resize",
9287            "node-screen",
9288            "selector-css3",
9289            "shim-plugin",
9290            "widget",
9291            "widget-position",
9292            "widget-position-align"
9293        ],
9294        "skinnable": true
9295    },
9296    "autocomplete-list-keys": {
9297        "condition": {
9298            "name": "autocomplete-list-keys",
9299            "test": function (Y) {
9300    // Only add keyboard support to autocomplete-list if this doesn't appear to
9301    // be an iOS or Android-based mobile device.
9302    //
9303    // There's currently no feasible way to actually detect whether a device has
9304    // a hardware keyboard, so this sniff will have to do. It can easily be
9305    // overridden by manually loading the autocomplete-list-keys module.
9306    //
9307    // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
9308    // doesn't fire the keyboard events used by AutoCompleteList, so there's
9309    // no point loading the -keys module even when a bluetooth keyboard may be
9310    // available.
9311    return !(Y.UA.ios || Y.UA.android);
9312},
9313            "trigger": "autocomplete-list"
9314        },
9315        "requires": [
9316            "autocomplete-list",
9317            "base-build"
9318        ]
9319    },
9320    "autocomplete-plugin": {
9321        "requires": [
9322            "autocomplete-list",
9323            "node-pluginhost"
9324        ]
9325    },
9326    "autocomplete-sources": {
9327        "optional": [
9328            "io-base",
9329            "json-parse",
9330            "jsonp",
9331            "yql"
9332        ],
9333        "requires": [
9334            "autocomplete-base"
9335        ]
9336    },
9337    "axes": {
9338        "use": [
9339            "axis-numeric",
9340            "axis-category",
9341            "axis-time",
9342            "axis-stacked"
9343        ]
9344    },
9345    "axes-base": {
9346        "use": [
9347            "axis-numeric-base",
9348            "axis-category-base",
9349            "axis-time-base",
9350            "axis-stacked-base"
9351        ]
9352    },
9353    "axis": {
9354        "requires": [
9355            "dom",
9356            "widget",
9357            "widget-position",
9358            "widget-stack",
9359            "graphics",
9360            "axis-base"
9361        ]
9362    },
9363    "axis-base": {
9364        "requires": [
9365            "classnamemanager",
9366            "datatype-number",
9367            "datatype-date",
9368            "base",
9369            "event-custom"
9370        ]
9371    },
9372    "axis-category": {
9373        "requires": [
9374            "axis",
9375            "axis-category-base"
9376        ]
9377    },
9378    "axis-category-base": {
9379        "requires": [
9380            "axis-base"
9381        ]
9382    },
9383    "axis-numeric": {
9384        "requires": [
9385            "axis",
9386            "axis-numeric-base"
9387        ]
9388    },
9389    "axis-numeric-base": {
9390        "requires": [
9391            "axis-base"
9392        ]
9393    },
9394    "axis-stacked": {
9395        "requires": [
9396            "axis-numeric",
9397            "axis-stacked-base"
9398        ]
9399    },
9400    "axis-stacked-base": {
9401        "requires": [
9402            "axis-numeric-base"
9403        ]
9404    },
9405    "axis-time": {
9406        "requires": [
9407            "axis",
9408            "axis-time-base"
9409        ]
9410    },
9411    "axis-time-base": {
9412        "requires": [
9413            "axis-base"
9414        ]
9415    },
9416    "base": {
9417        "use": [
9418            "base-base",
9419            "base-pluginhost",
9420            "base-build"
9421        ]
9422    },
9423    "base-base": {
9424        "requires": [
9425            "attribute-base",
9426            "base-core",
9427            "base-observable"
9428        ]
9429    },
9430    "base-build": {
9431        "requires": [
9432            "base-base"
9433        ]
9434    },
9435    "base-core": {
9436        "requires": [
9437            "attribute-core"
9438        ]
9439    },
9440    "base-observable": {
9441        "requires": [
9442            "attribute-observable",
9443            "base-core"
9444        ]
9445    },
9446    "base-pluginhost": {
9447        "requires": [
9448            "base-base",
9449            "pluginhost"
9450        ]
9451    },
9452    "button": {
9453        "requires": [
9454            "button-core",
9455            "cssbutton",
9456            "widget"
9457        ]
9458    },
9459    "button-core": {
9460        "requires": [
9461            "attribute-core",
9462            "classnamemanager",
9463            "node-base",
9464            "escape"
9465        ]
9466    },
9467    "button-group": {
9468        "requires": [
9469            "button-plugin",
9470            "cssbutton",
9471            "widget"
9472        ]
9473    },
9474    "button-plugin": {
9475        "requires": [
9476            "button-core",
9477            "cssbutton",
9478            "node-pluginhost"
9479        ]
9480    },
9481    "cache": {
9482        "use": [
9483            "cache-base",
9484            "cache-offline",
9485            "cache-plugin"
9486        ]
9487    },
9488    "cache-base": {
9489        "requires": [
9490            "base"
9491        ]
9492    },
9493    "cache-offline": {
9494        "requires": [
9495            "cache-base",
9496            "json"
9497        ]
9498    },
9499    "cache-plugin": {
9500        "requires": [
9501            "plugin",
9502            "cache-base"
9503        ]
9504    },
9505    "calendar": {
9506        "requires": [
9507            "calendar-base",
9508            "calendarnavigator"
9509        ],
9510        "skinnable": true
9511    },
9512    "calendar-base": {
9513        "lang": [
9514            "de",
9515            "en",
9516            "es",
9517            "es-AR",
9518            "fr",
9519            "hu",
9520            "it",
9521            "ja",
9522            "nb-NO",
9523            "nl",
9524            "pt-BR",
9525            "ru",
9526            "zh-Hans",
9527            "zh-Hans-CN",
9528            "zh-Hant",
9529            "zh-Hant-HK",
9530            "zh-HANT-TW"
9531        ],
9532        "requires": [
9533            "widget",
9534            "datatype-date",
9535            "datatype-date-math",
9536            "cssgrids"
9537        ],
9538        "skinnable": true
9539    },
9540    "calendarnavigator": {
9541        "requires": [
9542            "plugin",
9543            "classnamemanager",
9544            "datatype-date",
9545            "node"
9546        ],
9547        "skinnable": true
9548    },
9549    "charts": {
9550        "use": [
9551            "charts-base"
9552        ]
9553    },
9554    "charts-base": {
9555        "requires": [
9556            "dom",
9557            "event-mouseenter",
9558            "event-touch",
9559            "graphics-group",
9560            "axes",
9561            "series-pie",
9562            "series-line",
9563            "series-marker",
9564            "series-area",
9565            "series-spline",
9566            "series-column",
9567            "series-bar",
9568            "series-areaspline",
9569            "series-combo",
9570            "series-combospline",
9571            "series-line-stacked",
9572            "series-marker-stacked",
9573            "series-area-stacked",
9574            "series-spline-stacked",
9575            "series-column-stacked",
9576            "series-bar-stacked",
9577            "series-areaspline-stacked",
9578            "series-combo-stacked",
9579            "series-combospline-stacked"
9580        ]
9581    },
9582    "charts-legend": {
9583        "requires": [
9584            "charts-base"
9585        ]
9586    },
9587    "classnamemanager": {
9588        "requires": [
9589            "yui-base"
9590        ]
9591    },
9592    "clickable-rail": {
9593        "requires": [
9594            "slider-base"
9595        ]
9596    },
9597    "collection": {
9598        "use": [
9599            "array-extras",
9600            "arraylist",
9601            "arraylist-add",
9602            "arraylist-filter",
9603            "array-invoke"
9604        ]
9605    },
9606    "color": {
9607        "use": [
9608            "color-base",
9609            "color-hsl",
9610            "color-harmony"
9611        ]
9612    },
9613    "color-base": {
9614        "requires": [
9615            "yui-base"
9616        ]
9617    },
9618    "color-harmony": {
9619        "requires": [
9620            "color-hsl"
9621        ]
9622    },
9623    "color-hsl": {
9624        "requires": [
9625            "color-base"
9626        ]
9627    },
9628    "color-hsv": {
9629        "requires": [
9630            "color-base"
9631        ]
9632    },
9633    "console": {
9634        "lang": [
9635            "en",
9636            "es",
9637            "hu",
9638            "it",
9639            "ja"
9640        ],
9641        "requires": [
9642            "yui-log",
9643            "widget"
9644        ],
9645        "skinnable": true
9646    },
9647    "console-filters": {
9648        "requires": [
9649            "plugin",
9650            "console"
9651        ],
9652        "skinnable": true
9653    },
9654    "content-editable": {
9655        "requires": [
9656            "node-base",
9657            "editor-selection",
9658            "stylesheet",
9659            "plugin"
9660        ]
9661    },
9662    "controller": {
9663        "use": [
9664            "router"
9665        ]
9666    },
9667    "cookie": {
9668        "requires": [
9669            "yui-base"
9670        ]
9671    },
9672    "createlink-base": {
9673        "requires": [
9674            "editor-base"
9675        ]
9676    },
9677    "cssbase": {
9678        "after": [
9679            "cssreset",
9680            "cssfonts",
9681            "cssgrids",
9682            "cssreset-context",
9683            "cssfonts-context",
9684            "cssgrids-context"
9685        ],
9686        "type": "css"
9687    },
9688    "cssbase-context": {
9689        "after": [
9690            "cssreset",
9691            "cssfonts",
9692            "cssgrids",
9693            "cssreset-context",
9694            "cssfonts-context",
9695            "cssgrids-context"
9696        ],
9697        "type": "css"
9698    },
9699    "cssbutton": {
9700        "type": "css"
9701    },
9702    "cssfonts": {
9703        "type": "css"
9704    },
9705    "cssfonts-context": {
9706        "type": "css"
9707    },
9708    "cssgrids": {
9709        "optional": [
9710            "cssnormalize"
9711        ],
9712        "type": "css"
9713    },
9714    "cssgrids-base": {
9715        "optional": [
9716            "cssnormalize"
9717        ],
9718        "type": "css"
9719    },
9720    "cssgrids-responsive": {
9721        "optional": [
9722            "cssnormalize"
9723        ],
9724        "requires": [
9725            "cssgrids",
9726            "cssgrids-responsive-base"
9727        ],
9728        "type": "css"
9729    },
9730    "cssgrids-units": {
9731        "optional": [
9732            "cssnormalize"
9733        ],
9734        "requires": [
9735            "cssgrids-base"
9736        ],
9737        "type": "css"
9738    },
9739    "cssnormalize": {
9740        "type": "css"
9741    },
9742    "cssnormalize-context": {
9743        "type": "css"
9744    },
9745    "cssreset": {
9746        "type": "css"
9747    },
9748    "cssreset-context": {
9749        "type": "css"
9750    },
9751    "dataschema": {
9752        "use": [
9753            "dataschema-base",
9754            "dataschema-json",
9755            "dataschema-xml",
9756            "dataschema-array",
9757            "dataschema-text"
9758        ]
9759    },
9760    "dataschema-array": {
9761        "requires": [
9762            "dataschema-base"
9763        ]
9764    },
9765    "dataschema-base": {
9766        "requires": [
9767            "base"
9768        ]
9769    },
9770    "dataschema-json": {
9771        "requires": [
9772            "dataschema-base",
9773            "json"
9774        ]
9775    },
9776    "dataschema-text": {
9777        "requires": [
9778            "dataschema-base"
9779        ]
9780    },
9781    "dataschema-xml": {
9782        "requires": [
9783            "dataschema-base"
9784        ]
9785    },
9786    "datasource": {
9787        "use": [
9788            "datasource-local",
9789            "datasource-io",
9790            "datasource-get",
9791            "datasource-function",
9792            "datasource-cache",
9793            "datasource-jsonschema",
9794            "datasource-xmlschema",
9795            "datasource-arrayschema",
9796            "datasource-textschema",
9797            "datasource-polling"
9798        ]
9799    },
9800    "datasource-arrayschema": {
9801        "requires": [
9802            "datasource-local",
9803            "plugin",
9804            "dataschema-array"
9805        ]
9806    },
9807    "datasource-cache": {
9808        "requires": [
9809            "datasource-local",
9810            "plugin",
9811            "cache-base"
9812        ]
9813    },
9814    "datasource-function": {
9815        "requires": [
9816            "datasource-local"
9817        ]
9818    },
9819    "datasource-get": {
9820        "requires": [
9821            "datasource-local",
9822            "get"
9823        ]
9824    },
9825    "datasource-io": {
9826        "requires": [
9827            "datasource-local",
9828            "io-base"
9829        ]
9830    },
9831    "datasource-jsonschema": {
9832        "requires": [
9833            "datasource-local",
9834            "plugin",
9835            "dataschema-json"
9836        ]
9837    },
9838    "datasource-local": {
9839        "requires": [
9840            "base"
9841        ]
9842    },
9843    "datasource-polling": {
9844        "requires": [
9845            "datasource-local"
9846        ]
9847    },
9848    "datasource-textschema": {
9849        "requires": [
9850            "datasource-local",
9851            "plugin",
9852            "dataschema-text"
9853        ]
9854    },
9855    "datasource-xmlschema": {
9856        "requires": [
9857            "datasource-local",
9858            "plugin",
9859            "datatype-xml",
9860            "dataschema-xml"
9861        ]
9862    },
9863    "datatable": {
9864        "use": [
9865            "datatable-core",
9866            "datatable-table",
9867            "datatable-head",
9868            "datatable-body",
9869            "datatable-base",
9870            "datatable-column-widths",
9871            "datatable-message",
9872            "datatable-mutable",
9873            "datatable-sort",
9874            "datatable-datasource"
9875        ]
9876    },
9877    "datatable-base": {
9878        "requires": [
9879            "datatable-core",
9880            "datatable-table",
9881            "datatable-head",
9882            "datatable-body",
9883            "base-build",
9884            "widget"
9885        ],
9886        "skinnable": true
9887    },
9888    "datatable-body": {
9889        "requires": [
9890            "datatable-core",
9891            "view",
9892            "classnamemanager"
9893        ]
9894    },
9895    "datatable-column-widths": {
9896        "requires": [
9897            "datatable-base"
9898        ]
9899    },
9900    "datatable-core": {
9901        "requires": [
9902            "escape",
9903            "model-list",
9904            "node-event-delegate"
9905        ]
9906    },
9907    "datatable-datasource": {
9908        "requires": [
9909            "datatable-base",
9910            "plugin",
9911            "datasource-local"
9912        ]
9913    },
9914    "datatable-foot": {
9915        "requires": [
9916            "datatable-core",
9917            "view"
9918        ]
9919    },
9920    "datatable-formatters": {
9921        "requires": [
9922            "datatable-body",
9923            "datatype-number-format",
9924            "datatype-dat
9924e-format",
9925            "escape"
9926        ]
9927    },
9928    "datatable-head": {
9929        "requires": [
9930            "datatable-core",
9931            "view",
9932            "classnamemanager"
9933        ]
9934    },
9935    "datatable-highlight": {
9936        "requires": [
9937            "datatable-base",
9938            "event-hover"
9939        ],
9940        "skinnable": true
9941    },
9942    "datatable-keynav": {
9943        "requires": [
9944            "datatable-base"
9945        ]
9946    },
9947    "datatable-message": {
9948        "lang": [
9949            "en",
9950            "fr",
9951            "es",
9952            "hu",
9953            "it"
9954        ],
9955        "requires": [
9956            "datatable-base"
9957        ],
9958        "skinnable": true
9959    },
9960    "datatable-mutable": {
9961        "requires": [
9962            "datatable-base"
9963        ]
9964    },
9965    "datatable-paginator": {
9966        "lang": [
9967            "en",
9968            "fr"
9969        ],
9970        "requires": [
9971            "model",
9972            "view",
9973            "paginator-core",
9974            "datatable-foot",
9975            "datatable-paginator-templates"
9976        ],
9977        "skinnable": true
9978    },
9979    "datatable-paginator-templates": {
9980        "requires": [
9981            "template"
9982        ]
9983    },
9984    "datatable-scroll": {
9985        "requires": [
9986            "datatable-base",
9987            "datatable-column-widths",
9988            "dom-screen"
9989        ],
9990        "skinnable": true
9991    },
9992    "datatable-sort": {
9993        "lang": [
9994            "en",
9995            "fr",
9996            "es",
9997            "hu"
9998        ],
9999        "requires": [
10000            "datatable-base"
10001        ],
10002        "skinnable": true
10003    },
10004    "datatable-table": {
10005        "requires": [
10006            "datatable-core",
10007            "datatable-head",
10008            "datatable-body",
10009            "view",
10010            "classnamemanager"
10011        ]
10012    },
10013    "datatype": {
10014        "use": [
10015            "datatype-date",
10016            "datatype-number",
10017            "datatype-xml"
10018        ]
10019    },
10020    "datatype-date": {
10021        "use": [
10022            "datatype-date-parse",
10023            "datatype-date-format",
10024            "datatype-date-math"
10025        ]
10026    },
10027    "datatype-date-format": {
10028        "lang": [
10029            "ar",
10030            "ar-JO",
10031            "ca",
10032            "ca-ES",
10033            "da",
10034            "da-DK",
10035            "de",
10036            "de-AT",
10037            "de-DE",
10038            "el",
10039            "el-GR",
10040            "en",
10041            "en-AU",
10042            "en-CA",
10043            "en-GB",
10044            "en-IE",
10045            "en-IN",
10046            "en-JO",
10047            "en-MY",
10048            "en-NZ",
10049            "en-PH",
10050            "en-SG",
10051            "en-US",
10052            "es",
10053            "es-AR",
10054            "es-BO",
10055            "es-CL",
10056            "es-CO",
10057            "es-EC",
10058            "es-ES",
10059            "es-MX",
10060            "es-PE",
10061            "es-PY",
10062            "es-US",
10063            "es-UY",
10064            "es-VE",
10065            "fi",
10066            "fi-FI",
10067            "fr",
10068            "fr-BE",
10069            "fr-CA",
10070            "fr-FR",
10071            "hi",
10072            "hi-IN",
10073            "hu",
10074            "id",
10075            "id-ID",
10076            "it",
10077            "it-IT",
10078            "ja",
10079            "ja-JP",
10080            "ko",
10081            "ko-KR",
10082            "ms",
10083            "ms-MY",
10084            "nb",
10085            "nb-NO",
10086            "nl",
10087            "nl-BE",
10088            "nl-NL",
10089            "pl",
10090            "pl-PL",
10091            "pt",
10092            "pt-BR",
10093            "ro",
10094            "ro-RO",
10095            "ru",
10096            "ru-RU",
10097            "sv",
10098            "sv-SE",
10099            "th",
10100            "th-TH",
10101            "tr",
10102            "tr-TR",
10103            "vi",
10104            "vi-VN",
10105            "zh-Hans",
10106            "zh-Hans-CN",
10107            "zh-Hant",
10108            "zh-Hant-HK",
10109            "zh-Hant-TW"
10110        ]
10111    },
10112    "datatype-date-math": {
10113        "requires": [
10114            "yui-base"
10115        ]
10116    },
10117    "datatype-date-parse": {},
10118    "datatype-number": {
10119        "use": [
10120            "datatype-number-parse",
10121            "datatype-number-format"
10122        ]
10123    },
10124    "datatype-number-format": {},
10125    "datatype-number-parse": {
10126        "requires": [
10127            "escape"
10128        ]
10129    },
10130    "datatype-xml": {
10131        "use": [
10132            "datatype-xml-parse",
10133            "datatype-xml-format"
10134        ]
10135    },
10136    "datatype-xml-format": {},
10137    "datatype-xml-parse": {},
10138    "dd": {
10139        "use": [
10140            "dd-ddm-base",
10141            "dd-ddm",
10142            "dd-ddm-drop",
10143            "dd-drag",
10144            "dd-proxy",
10145            "dd-constrain",
10146            "dd-drop",
10147            "dd-scroll",
10148            "dd-delegate"
10149        ]
10150    },
10151    "dd-constrain": {
10152        "requires": [
10153            "dd-drag"
10154        ]
10155    },
10156    "dd-ddm": {
10157        "requires": [
10158            "dd-ddm-base",
10159            "event-resize"
10160        ]
10161    },
10162    "dd-ddm-base": {
10163        "requires": [
10164            "node",
10165            "base",
10166            "yui-throttle",
10167            "classnamemanager"
10168        ]
10169    },
10170    "dd-ddm-drop": {
10171        "requires": [
10172            "dd-ddm"
10173        ]
10174    },
10175    "dd-delegate": {
10176        "requires": [
10177            "dd-drag",
10178            "dd-drop-plugin",
10179            "event-mouseenter"
10180        ]
10181    },
10182    "dd-drag": {
10183        "requires": [
10184            "dd-ddm-base",
10185            "selector-css2"
10186        ]
10187    },
10188    "dd-drop": {
10189        "requires": [
10190            "dd-drag",
10191            "dd-ddm-drop"
10192        ]
10193    },
10194    "dd-drop-plugin": {
10195        "requires": [
10196            "dd-drop"
10197        ]
10198    },
10199    "dd-gestures": {
10200        "condition": {
10201            "name": "dd-gestures",
10202            "trigger": "dd-drag",
10203            "ua": "touchEnabled"
10204        },
10205        "requires": [
10206            "dd-drag",
10207            "event-synthetic",
10208            "event-gestures"
10209        ]
10210    },
10211    "dd-plugin": {
10212        "optional": [
10213            "dd-constrain",
10214            "dd-proxy"
10215        ],
10216        "requires": [
10217            "dd-drag"
10218        ]
10219    },
10220    "dd-proxy": {
10221        "requires": [
10222            "dd-drag"
10223        ]
10224    },
10225    "dd-scroll": {
10226        "requires": [
10227            "dd-drag"
10228        ]
10229    },
10230    "dial": {
10231        "lang": [
10232            "en",
10233            "es",
10234            "hu"
10235        ],
10236        "requires": [
10237            "widget",
10238            "dd-drag",
10239            "event-mouseenter",
10240            "event-move",
10241            "event-key",
10242            "transition",
10243            "intl"
10244        ],
10245        "skinnable": true
10246    },
10247    "dom": {
10248        "use": [
10249            "dom-base",
10250            "dom-screen",
10251            "dom-style",
10252            "selector-native",
10253            "selector"
10254        ]
10255    },
10256    "dom-base": {
10257        "requires": [
10258            "dom-core"
10259        ]
10260    },
10261    "dom-core": {
10262        "requires": [
10263            "oop",
10264            "features"
10265        ]
10266    },
10267    "dom-screen": {
10268        "requires": [
10269            "dom-base",
10270            "dom-style"
10271        ]
10272    },
10273    "dom-style": {
10274        "requires": [
10275            "dom-base"
10276        ]
10277    },
10278    "dom-style-ie": {
10279        "condition": {
10280            "name": "dom-style-ie",
10281            "test": function (Y) {
10282
10283    var testFeature = Y.Features.test,
10284        addFeature = Y.Features.add,
10285        WINDOW = Y.config.win,
10286        DOCUMENT = Y.config.doc,
10287        DOCUMENT_ELEMENT = 'documentElement',
10288        ret = false;
10289
10290    addFeature('style', 'computedStyle', {
10291        test: function() {
10292            return WINDOW && 'getComputedStyle' in WINDOW;
10293        }
10294    });
10295
10296    addFeature('style', 'opacity', {
10297        test: function() {
10298            return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
10299        }
10300    });
10301
10302    ret =  (!testFeature('style', 'opacity') &&
10303            !testFeature('style', 'computedStyle'));
10304
10305    return ret;
10306},
10307            "trigger": "dom-style"
10308        },
10309        "requires": [
10310            "dom-style",
10311            "color-base"
10312        ]
10313    },
10314    "dump": {
10315        "requires": [
10316            "yui-base"
10317        ]
10318    },
10319    "editor": {
10320        "use": [
10321            "frame",
10322            "editor-selection",
10323            "exec-command",
10324            "editor-base",
10325            "editor-para",
10326            "editor-br",
10327            "editor-bidi",
10328            "editor-tab",
10329            "createlink-base"
10330        ]
10331    },
10332    "editor-base": {
10333        "requires": [
10334            "base",
10335            "frame",
10336            "node",
10337            "exec-command",
10338            "editor-selection"
10339        ]
10340    },
10341    "editor-bidi": {
10342        "requires": [
10343            "editor-base"
10344        ]
10345    },
10346    "editor-br": {
10347        "requires": [
10348            "editor-base"
10349        ]
10350    },
10351    "editor-inline": {
10352        "requires": [
10353            "editor-base",
10354            "content-editable"
10355        ]
10356    },
10357    "editor-lists": {
10358        "requires": [
10359            "editor-base"
10360        ]
10361    },
10362    "editor-para": {
10363        "requires": [
10364            "editor-para-base"
10365        ]
10366    },
10367    "editor-para-base": {
10368        "requires": [
10369            "editor-base"
10370        ]
10371    },
10372    "editor-para-ie": {
10373        "condition": {
10374            "name": "editor-para-ie",
10375            "trigger": "editor-para",
10376            "ua": "ie",
10377            "when": "instead"
10378        },
10379        "requires": [
10380            "editor-para-base"
10381        ]
10382    },
10383    "editor-selection": {
10384        "requires": [
10385            "node"
10386        ]
10387    },
10388    "editor-tab": {
10389        "requires": [
10390            "editor-base"
10391        ]
10392    },
10393    "escape": {
10394        "requires": [
10395            "yui-base"
10396        ]
10397    },
10398    "event": {
10399        "after": [
10400            "node-base"
10401        ],
10402        "use": [
10403            "event-base",
10404            "event-delegate",
10405            "event-synthetic",
10406            "event-mousewheel",
10407            "event-mouseenter",
10408            "event-key",
10409            "event-focus",
10410            "event-resize",
10411            "event-hover",
10412            "event-outside",
10413            "event-touch",
10414            "event-move",
10415            "event-flick",
10416            "event-valuechange",
10417            "event-tap"
10418        ]
10419    },
10420    "event-base": {
10421        "after": [
10422            "node-base"
10423        ],
10424        "requires": [
10425            "event-custom-base"
10426        ]
10427    },
10428    "event-base-ie": {
10429        "after": [
10430            "event-base"
10431        ],
10432        "condition": {
10433            "name": "event-base-ie",
10434            "test": function(Y) {
10435    var imp = Y.config.doc && Y.config.doc.implementation;
10436    return (imp && (!imp.hasFeature('Events', '2.0')));
10437},
10438            "trigger": "node-base"
10439        },
10440        "requires": [
10441            "node-base"
10442        ]
10443    },
10444    "event-contextmenu": {
10445        "requires": [
10446            "event-synthetic",
10447            "dom-screen"
10448        ]
10449    },
10450    "event-custom": {
10451        "use": [
10452            "event-custom-base",
10453            "event-custom-complex"
10454        ]
10455    },
10456    "event-custom-base": {
10457        "requires": [
10458            "oop"
10459        ]
10460    },
10461    "event-custom-complex": {
10462        "requires": [
10463            "event-custom-base"
10464        ]
10465    },
10466    "event-delegate": {
10467        "requires": [
10468            "node-base"
10469        ]
10470    },
10471    "event-flick": {
10472        "requires": [
10473            "node-base",
10474            "event-touch",
10475            "event-synthetic"
10476        ]
10477    },
10478    "event-focus": {
10479        "requires": [
10480            "event-synthetic"
10481        ]
10482    },
10483    "event-gestures": {
10484        "use": [
10485            "event-flick",
10486            "event-move"
10487        ]
10488    },
10489    "event-hover": {
10490        "requires": [
10491            "event-mouseenter"
10492        ]
10493    },
10494    "event-key": {
10495        "requires": [
10496            "event-synthetic"
10497        ]
10498    },
10499    "event-mouseenter": {
10500        "requires": [
10501            "event-synthetic"
10502        ]
10503    },
10504    "event-mousewheel": {
10505        "requires": [
10506            "node-base"
10507        ]
10508    },
10509    "event-move": {
10510        "requires": [
10511            "node-base",
10512            "event-touch",
10513            "event-synthetic"
10514        ]
10515    },
10516    "event-outside": {
10517        "requires": [
10518            "event-synthetic"
10519        ]
10520    },
10521    "event-resize": {
10522        "requires": [
10523            "node-base",
10524            "event-synthetic"
10525        ]
10526    },
10527    "event-simulate": {
10528        "requires": [
10529            "event-base"
10530        ]
10531    },
10532    "event-synthetic": {
10533        "requires": [
10534            "node-base",
10535            "event-custom-complex"
10536        ]
10537    },
10538    "event-tap": {
10539        "requires": [
10540            "node-base",
10541            "event-base",
10542            "event-touch",
10543            "event-synthetic"
10544        ]
10545    },
10546    "event-touch": {
10547        "requires": [
10548            "node-base"
10549        ]
10550    },
10551    "event-valuechange": {
10552        "requires": [
10553            "event-focus",
10554            "event-synthetic"
10555        ]
10556    },
10557    "exec-command": {
10558        "requires": [
10559            "frame"
10560        ]
10561    },
10562    "features": {
10563        "requires": [
10564            "yui-base"
10565        ]
10566    },
10567    "file": {
10568        "requires": [
10569            "file-flash",
10570            "file-html5"
10571        ]
10572    },
10573    "file-flash": {
10574        "requires": [
10575            "base"
10576        ]
10577    },
10578    "file-html5": {
10579        "requires": [
10580            "base"
10581        ]
10582    },
10583    "frame": {
10584        "requires": [
10585            "base",
10586            "node",
10587            "plugin",
10588            "selector-css3",
10589            "yui-throttle"
10590        ]
10591    },
10592    "gesture-simulate": {
10593        "requires": [
10594            "async-queue",
10595            "event-simulate",
10596            "node-screen"
10597        ]
10598    },
10599    "get": {
10600        "requires": [
10601            "yui-base"
10602        ]
10603    },
10604    "graphics": {
10605        "requires": [
10606            "node",
10607            "event-custom",
10608            "pluginhost",
10609            "matrix",
10610            "classnamemanager"
10611        ]
10612    },
10613    "graphics-canvas": {
10614        "condition": {
10615            "name": "graphics-canvas",
10616            "test": function(Y) {
10617    var DOCUMENT = Y.config.doc,
10618        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
10619		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
10620        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
10621    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
10622},
10623            "trigger": "graphics"
10624        },
10625        "requires": [
10626            "graphics",
10627            "color-base"
10628        ]
10629    },
10630    "graphics-canvas-default": {
10631        "condition": {
10632            "name": "graphics-canvas-default",
10633            "test": function(Y) {
10634    var DOCUMENT = Y.config.doc,
10635        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
10636		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
10637        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
10638    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
10639},
10640            "trigger": "graphics"
10641        }
10642    },
10643    "graphics-group": {
10644        "requires": [
10645            "graphics"
10646        ]
10647    },
10648    "graphics-svg": {
10649        "condition": {
10650            "name": "graphics-svg",
10651            "test": function(Y) {
10652    var DOCUMENT = Y.config.doc,
10653        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
10654		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
10655        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
10656
10657    return svg && (useSVG || !canvas);
10658},
10659            "trigger": "graphics"
10660        },
10661        "requires": [
10662            "graphics"
10663        ]
10664    },
10665    "graphics-svg-default": {
10666        "condition": {
10667            "name": "graphics-svg-default",
10668            "test": function(Y) {
10669    var DOCUMENT = Y.config.doc,
10670        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
10671		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
10672        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
10673
10674    return svg && (useSVG || !canvas);
10675},
10676            "trigger": "graphics"
10677        }
10678    },
10679    "graphics-vml": {
10680        "condition": {
10681            "name": "graphics-vml",
10682            "test": function(Y) {
10683    var DOCUMENT = Y.config.doc,
10684		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
10685    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
10686},
10687            "trigger": "graphics"
10688        },
10689        "requires": [
10690            "graphics",
10691            "color-base"
10692        ]
10693    },
10694    "graphics-vml-default": {
10695        "condition": {
10696            "name": "graphics-vml-default",
10697            "test": function(Y) {
10698    var DOCUMENT = Y.config.doc,
10699		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
10700    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
10701},
10702            "trigger": "graphics"
10703        }
10704    },
10705    "handlebars": {
10706        "use": [
10707            "handlebars-compiler"
10708        ]
10709    },
10710    "handlebars-base": {
10711        "requires": []
10712    },
10713    "handlebars-compiler": {
10714        "requires": [
10715            "handlebars-base"
10716        ]
10717    },
10718    "highlight": {
10719        "use": [
10720            "highlight-base",
10721            "highlight-accentfold"
10722        ]
10723    },
10724    "highlight-accentfold": {
10725        "requires": [
10726            "highlight-base",
10727            "text-accentfold"
10728        ]
10729    },
10730    "highlight-base": {
10731        "requires": [
10732            "array-extras",
10733            "classnamemanager",
10734            "escape",
10735            "text-wordbreak"
10736        ]
10737    },
10738    "history": {
10739        "use": [
10740            "history-base",
10741            "history-hash",
10742            "history-html5"
10743        ]
10744    },
10745    "history-base": {
10746        "requires": [
10747            "event-custom-complex"
10748        ]
10749    },
10750    "history-hash": {
10751        "after": [
10752            "history-html5"
10753        ],
10754        "requires": [
10755            "event-synthetic",
10756            "history-base",
10757            "yui-later"
10758        ]
10759    },
10760    "history-hash-ie": {
10761        "condition": {
10762            "name": "history-hash-ie",
10763            "test": function (Y) {
10764    var docMode = Y.config.doc && Y.config.doc.documentMode;
10765
10766    return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
10767            !docMode || docMode < 8);
10768},
10769            "trigger": "history-hash"
10770        },
10771        "requires": [
10772            "history-hash",
10773            "node-base"
10774        ]
10775    },
10776    "history-html5": {
10777        "optional": [
10778            "json"
10779        ],
10780        "requires": [
10781            "event-base",
10782            "history-base",
10783            "node-base"
10784        ]
10785    },
10786    "imageloader": {
10787        "requires": [
10788            "base-base",
10789            "node-style",
10790            "node-screen"
10791        ]
10792    },
10793    "intl": {
10794        "requires": [
10795            "intl-base",
10796            "event-custom"
10797        ]
10798    },
10799    "intl-base": {
10800        "requires": [
10801            "yui-base"
10802        ]
10803    },
10804    "io": {
10805        "use": [
10806            "io-base",
10807            "io-xdr",
10808            "io-form",
10809            "io-upload-iframe",
10810            "io-queue"
10811        ]
10812    },
10813    "io-base": {
10814        "requires": [
10815            "event-custom-base",
10816            "querystring-stringify-simple"
10817        ]
10818    },
10819    "io-form": {
10820        "requires": [
10821            "io-base",
10822            "node-base"
10823        ]
10824    },
10825    "io-nodejs": {
10826        "condition": {
10827            "name": "io-nodejs",
10828            "trigger": "io-base",
10829            "ua": "nodejs"
10830        },
10831        "requires": [
10832            "io-base"
10833        ]
10834    },
10835    "io-queue": {
10836        "requires": [
10837            "io-base",
10838            "queue-promote"
10839        ]
10840    },
10841    "io-upload-iframe": {
10842        "requires": [
10843            "io-base",
10844            "node-base"
10845        ]
10846    },
10847    "io-xdr": {
10848        "requires": [
10849            "io-base",
10850            "datatype-xml-parse"
10851        ]
10852    },
10853    "json": {
10854        "use": [
10855            "json-parse",
10856            "json-stringify"
10857        ]
10858    },
10859    "json-parse": {
10860        "requires": [
10861            "yui-base"
10862        ]
10863    },
10864    "json-parse-shim": {
10865        "condition": {
10866            "name": "json-parse-shim",
10867            "test": function (Y) {
10868    var _JSON = Y.config.global.JSON,
10869        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
10870        nativeSupport = Y.config.useNativeJSONParse !== false && !!Native;
10871
10872    function workingNative( k, v ) {
10873        return k === "ok" ? true : v;
10874    }
10875
10876    // Double check basic functionality.  This is mainly to catch early broken
10877    // implementations of the JSON API in Firefox 3.1 beta1 and beta2
10878    if ( nativeSupport ) {
10879        try {
10880            nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
10881        }
10882        catch ( e ) {
10883            nativeSupport = false;
10884        }
10885    }
10886
10887    return !nativeSupport;
10888},
10889            "trigger": "json-parse"
10890        },
10891        "requires": [
10892            "json-parse"
10893        ]
10894    },
10895    "json-stringify": {
10896        "requires": [
10897            "yui-base"
10898        ]
10899    },
10900    "json-stringify-shim": {
10901        "condition": {
10902            "name": "json-stringify-shim",
10903            "test": function (Y) {
10904    var _JSON = Y.config.global.JSON,
10905        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
10906        nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native;
10907
10908    // Double check basic native functionality.  This is primarily to catch broken
10909    // early JSON API implementations in Firefox 3.1 beta1 and beta2.
10910    if ( nativeSupport ) {
10911        try {
10912            nativeSupport = ( '0' === Native.stringify(0) );
10913        } catch ( e ) {
10914            nativeSupport = false;
10915        }
10916    }
10917
10918
10919    return !nativeSupport;
10920},
10921            "trigger": "json-stringify"
10922        },
10923        "requires": [
10924            "json-stringify"
10925        ]
10926    },
10927    "jsonp": {
10928        "requires": [
10929            "get",
10930            "oop"
10931        ]
10932    },
10933    "jsonp-url": {
10934        "requires": [
10935            "jsonp"
10936        ]
10937    },
10938    "lazy-model-list": {
10939        "requires": [
10940            "model-list"
10941        ]
10942    },
10943    "loader": {
10944        "use": [
10945            "loader-base",
10946            "loader-rollup",
10947            "loader-yui3"
10948        ]
10949    },
10950    "loader-base": {
10951        "requires": [
10952            "get",
10953            "features"
10954        ]
10955    },
10956    "loader-pathogen-combohandler": {},
10957    "loader-pathogen-encoder": {
10958        "use": [
10959            "loader-base",
10960            "loader-rollup",
10961            "loader-yui3",
10962            "loader-pathogen-combohandler"
10963        ]
10964    },
10965    "loader-rollup": {
10966        "requires": [
10967            "loader-base"
10968        ]
10969    },
10970    "loader-yui3": {
10971        "requires": [
10972            "loader-base"
10973        ]
10974    },
10975    "matrix": {
10976        "requires": [
10977            "yui-base"
10978        ]
10979    },
10980    "model": {
10981        "requires": [
10982            "base-build",
10983            "escape",
10984            "json-parse"
10985        ]
10986    },
10987    "model-list": {
10988        "requires": [
10989            "array-extras",
10990            "array-invoke",
10991            "arraylist",
10992            "base-build",
10993            "escape",
10994            "json-parse",
10995            "model"
10996        ]
10997    },
10998    "model-sync-local": {
10999        "requires": [
11000            "model",
11001            "json-stringify"
11002        ]
11003    },
11004    "model-sync-rest": {
11005        "requires": [
11006            "model",
11007            "io-base",
11008            "json-stringify"
11009        ]
11010    },
11011    "node": {
11012        "use": [
11013            "node-base",
11014            "node-event-delegate",
11015            "node-pluginhost",
11016            "node-screen",
11017            "node-style"
11018        ]
11019    },
11020    "node-base": {
11021        "requires": [
11022            "event-base",
11023            "node-core",
11024            "dom-base",
11025            "dom-style"
11026        ]
11027    },
11028    "node-core": {
11029        "requires": [
11030            "dom-core",
11031            "selector"
11032        ]
11033    },
11034    "node-event-delegate": {
11035        "requires": [
11036            "node-base",
11037            "event-delegate"
11038        ]
11039    },
11040    "node-event-html5": {
11041        "requires": [
11042            "node-base"
11043        ]
11044    },
11045    "node-event-simulate": {
11046        "requires": [
11047            "node-base",
11048            "event-simulate",
11049            "gesture-simulate"
11050        ]
11051    },
11052    "node-flick": {
11053        "requires": [
11054            "classnamemanager",
11055            "transition",
11056            "event-flick",
11057            "plugin"
11058        ],
11059        "skinnable": true
11060    },
11061    "node-focusmanager": {
11062        "requires": [
11063            "attribute",
11064            "node",
11065            "plugin",
11066            "node-event-simulate",
11067            "event-key",
11068            "event-focus"
11069        ]
11070    },
11071    "node-load": {
11072        "requires": [
11073            "node-base",
11074            "io-base"
11075        ]
11076    },
11077    "node-menunav": {
11078        "requires": [
11079            "node",
11080            "classnamemanager",
11081            "plugin",
11082            "node-focusmanager"
11083        ],
11084        "skinnable": true
11085    },
11086    "node-pluginhost": {
11087        "requires": [
11088            "node-base",
11089            "pluginhost"
11090        ]
11091    },
11092    "node-screen": {
11093        "requires": [
11094            "dom-screen",
11095            "node-base"
11096        ]
11097    },
11098    "node-scroll-info": {
11099        "requires": [
11100            "array-extras",
11101            "base-build",
11102            "event-resize",
11103            "node-pluginhost",
11104            "plugin",
11105            "selector"
11106        ]
11107    },
11108    "node-style": {
11109        "requires": [
11110            "dom-style",
11111            "node-base"
11112        ]
11113    },
11114    "oop": {
11115        "requires": [
11116            "yui-base"
11117        ]
11118    },
11119    "overlay": {
11120        "requires": [
11121            "widget",
11122            "widget-stdmod",
11123            "widget-position",
11124            "widget-position-align",
11125            "widget-stack",
11126            "widget-position-constrain"
11127        ],
11128        "skinnable": true
11129    },
11130    "paginator": {
11131        "requires": [
11132            "paginator-core"
11133        ]
11134    },
11135    "paginator-core": {
11136        "requires": [
11137            "base"
11138        ]
11139    },
11140    "paginator-url": {
11141        "requires": [
11142            "paginator"
11143        ]
11144    },
11145    "panel": {
11146        "requires": [
11147            "widget",
11148            "widget-autohide",
11149            "widget-buttons",
11150            "widget-modality",
11151            "widget-position",
11152            "widget-position-align",
11153            "widget-position-constrain",
11154            "widget-stack",
11155            "widget-stdmod"
11156        ],
11157        "skinnable": true
11158    },
11159    "parallel": {
11160        "requires": [
11161            "yui-base"
11162        ]
11163    },
11164    "pjax": {
11165        "requires": [
11166            "pjax-base",
11167            "pjax-content"
11168        ]
11169    },
11170    "pjax-base": {
11171        "requires": [
11172            "classnamemanager",
11173            "node-event-delegate",
11174            "router"
11175        ]
11176    },
11177    "pjax-content": {
11178        "requires": [
11179            "io-base",
11180            "node-base",
11181            "router"
11182        ]
11183    },
11184    "pjax-plugin": {
11185        "requires": [
11186            "node-pluginhost",
11187            "pjax",
11188            "plugin"
11189        ]
11190    },
11191    "plugin": {
11192        "requires": [
11193            "base-base"
11194        ]
11195    },
11196    "pluginhost": {
11197        "use": [
11198            "pluginhost-base",
11199            "pluginhost-config"
11200        ]
11201    },
11202    "pluginhost-base": {
11203        "requires": [
11204            "yui-base"
11205        ]
11206    },
11207    "pluginhost-config": {
11208        "requires": [
11209            "pluginhost-base"
11210        ]
11211    },
11212    "promise": {
11213        "requires": [
11214            "timers"
11215        ]
11216    },
11217    "querystring": {
11218        "use": [
11219            "querystring-parse",
11220            "querystring-stringify"
11221        ]
11222    },
11223    "querystring-parse": {
11224        "requires": [
11225            "yui-base",
11226            "array-extras"
11227        ]
11228    },
11229    "querystring-parse-simple": {
11230        "requires": [
11231            "yui-base"
11232        ]
11233    },
11234    "querystring-stringify": {
11235        "requires": [
11236            "yui-base"
11237        ]
11238    },
11239    "querystring-stringify-simple": {
11240        "requires": [
11241            "yui-base"
11242        ]
11243    },
11244    "queue-promote": {
11245        "requires": [
11246            "yui-base"
11247        ]
11248    },
11249    "range-slider": {
11250        "requires": [
11251            "slider-base",
11252            "slider-value-range",
11253            "clickable-rail"
11254        ]
11255    },
11256    "recordset": {
11257        "use": [
11258            "recordset-base",
11259            "recordset-sort",
11260            "recordset-filter",
11261            "recordset-indexer"
11262        ]
11263    },
11264    "recordset-base": {
11265        "requires": [
11266            "base",
11267            "arraylist"
11268        ]
11269    },
11270    "recordset-filter": {
11271        "requires": [
11272            "recordset-base",
11273            "array-extras",
11274            "plugin"
11275        ]
11276    },
11277    "recordset-indexer": {
11278        "requires": [
11279            "recordset-base",
11280            "plugin"
11281        ]
11282    },
11283    "recordset-sort": {
11284        "requires": [
11285            "arraysort",
11286            "recordset-base",
11287            "plugin"
11288        ]
11289    },
11290    "resize": {
11291        "use": [
11292            "resize-base",
11293            "resize-proxy",
11294            "resize-constrain"
11295        ]
11296    },
11297    "resize-base": {
11298        "requires": [
11299            "base",
11300            "widget",
11301            "event",
11302            "oop",
11303            "dd-drag",
11304            "dd-delegate",
11305            "dd-drop"
11306        ],
11307        "skinnable": true
11308    },
11309    "resize-constrain": {
11310        "requires": [
11311            "plugin",
11312            "resize-base"
11313        ]
11314    },
11315    "resize-plugin": {
11316        "optional": [
11317            "resize-constrain"
11318        ],
11319        "requires": [
11320            "resize-base",
11321            "plugin"
11322        ]
11323    },
11324    "resize-proxy": {
11325        "requires": [
11326            "plugin",
11327            "resize-base"
11328        ]
11329    },
11330    "router": {
11331        "optional": [
11332            "querystring-parse"
11333        ],
11334        "requires": [
11335            "array-extras",
11336            "base-build",
11337            "history"
11338        ]
11339    },
11340    "scrollview": {
11341        "requires": [
11342            "scrollview-base",
11343            "scrollview-scrollbars"
11344        ]
11345    },
11346    "scrollview-base": {
11347        "requires": [
11348            "widget",
11349            "event-gestures",
11350            "event-mousewheel",
11351            "transition"
11352        ],
11353        "skinnable": true
11354    },
11355    "scrollview-base-ie": {
11356        "condition": {
11357            "name": "scrollview-base-ie",
11358            "trigger": "scrollview-base",
11359            "ua": "ie"
11360        },
11361        "requires": [
11362            "scrollview-base"
11363        ]
11364    },
11365    "scrollview-list": {
11366        "requires": [
11367            "plugin",
11368            "classnamemanager"
11369        ],
11370        "skinnable": true
11371    },
11372    "scrollview-paginator": {
11373        "requires": [
11374            "plugin",
11375            "classnamemanager"
11376        ]
11377    },
11378    "scrollview-scrollbars": {
11379        "requires": [
11380            "classnamemanager",
11381            "transition",
11382            "plugin"
11383        ],
11384        "skinnable": true
11385    },
11386    "selector": {
11387        "requires": [
11388            "selector-native"
11389        ]
11390    },
11391    "selector-css2": {
11392        "condition": {
11393            "name": "selector-css2",
11394            "test": function (Y) {
11395    var DOCUMENT = Y.config.doc,
11396        ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
11397
11398    return ret;
11399},
11400            "trigger": "selector"
11401        },
11402        "requires": [
11403            "selector-native"
11404        ]
11405    },
11406    "selector-css3": {
11407        "requires": [
11408            "selector-native",
11409            "selector-css2"
11410        ]
11411    },
11412    "selector-native": {
11413        "requires": [
11414            "dom-base"
11415        ]
11416    },
11417    "series-area": {
11418        "requires": [
11419            "series-cartesian",
11420            "series-fill-util"
11421        ]
11422    },
11423    "series-area-stacked": {
11424        "requires": [
11425            "series-stacked",
11426            "series-area"
11427        ]
11428    },
11429    "series-areaspline": {
11430        "requires": [
11431            "series-area",
11432            "series-curve-util"
11433        ]
11434    },
11435    "series-areaspline-stacked": {
11436        "requires": [
11437            "series-stacked",
11438            "series-areaspline"
11439        ]
11440    },
11441    "series-bar": {
11442        "requires": [
11443            "series-marker",
11444            "series-histogram-base"
11445        ]
11446    },
11447    "series-bar-stacked": {
11448        "requires": [
11449            "series-stacked",
11450            "series-bar"
11451        ]
11452    },
11453    "series-base": {
11454        "requires": [
11455            "graphics",
11456            "axis-base"
11457        ]
11458    },
11459    "series-candlestick": {
11460        "requires": [
11461            "series-range"
11462        ]
11463    },
11464    "series-cartesian": {
11465        "requires": [
11466            "series-base"
11467        ]
11468    },
11469    "series-column": {
11470        "requires": [
11471            "series-marker",
11472            "series-histogram-base"
11473        ]
11474    },
11475    "series-column-stacked": {
11476        "requires": [
11477            "series-stacked",
11478            "series-column"
11479        ]
11480    },
11481    "series-combo": {
11482        "requires": [
11483            "series-cartesian",
11484            "series-line-util",
11485            "series-plot-util",
11486            "series-fill-util"
11487        ]
11488    },
11489    "series-combo-stacked": {
11490        "requires": [
11491            "series-stacked",
11492            "series-combo"
11493        ]
11494    },
11495    "series-combospline": {
11496        "requires": [
11497            "series-combo",
11498            "series-curve-util"
11499        ]
11500    },
11501    "series-combospline-stacked": {
11502        "requires": [
11503            "series-combo-stacked",
11504            "series-curve-util"
11505        ]
11506    },
11507    "series-curve-util": {},
11508    "series-fill-util": {},
11509    "series-histogram-base": {
11510        "requires": [
11511            "series-cartesian",
11512            "series-plot-util"
11513        ]
11514    },
11515    "series-line": {
11516        "requires": [
11517            "series-cartesian",
11518            "series-line-util"
11519        ]
11520    },
11521    "series-line-stacked": {
11522        "requires": [
11523            "series-stacked",
11524            "series-line"
11525        ]
11526    },
11527    "series-line-util": {},
11528    "series-marker": {
11529        "requires": [
11530            "series-cartesian",
11531            "series-plot-util"
11532        ]
11533    },
11534    "series-marker-stacked": {
11535        "requires": [
11536            "series-stacked",
11537            "series-marker"
11538        ]
11539    },
11540    "series-ohlc": {
11541        "requires": [
11542            "series-range"
11543        ]
11544    },
11545    "series-pie": {
11546        "requires": [
11547            "series-base",
11548            "series-plot-util"
11549        ]
11550    },
11551    "series-plot-util": {},
11552    "series-range": {
11553        "requires": [
11554            "series-cartesian"
11555        ]
11556    },
11557    "series-spline": {
11558        "requires": [
11559            "series-line",
11560            "series-curve-util"
11561        ]
11562    },
11563    "series-spline-stacked": {
11564        "requires": [
11565            "series-stacked",
11566            "series-spline"
11567        ]
11568    },
11569    "series-stacked": {
11570        "requires": [
11571            "axis-stacked"
11572        ]
11573    },
11574    "shim-plugin": {
11575        "requires": [
11576            "node-style",
11577            "node-pluginhost"
11578        ]
11579    },
11580    "slider": {
11581        "use": [
11582            "slider-base",
11583            "slider-value-range",
11584            "clickable-rail",
11585            "range-slider"
11586        ]
11587    },
11588    "slider-base": {
11589        "requires": [
11590            "widget",
11591            "dd-constrain",
11592            "event-key"
11593        ],
11594        "skinnable": true
11595    },
11596    "slider-value-range": {
11597        "requires": [
11598            "slider-base"
11599        ]
11600    },
11601    "sortable": {
11602        "requires": [
11603            "dd-delegate",
11604            "dd-drop-plugin",
11605            "dd-proxy"
11606        ]
11607    },
11608    "sortable-scroll": {
11609        "requires": [
11610            "dd-scroll",
11611            "sortable"
11612        ]
11613    },
11614    "stylesheet": {
11615        "requires": [
11616            "yui-base"
11617        ]
11618    },
11619    "substitute": {
11620        "optional": [
11621            "dump"
11622        ],
11623        "requires": [
11624            "yui-base"
11625        ]
11626    },
11627    "swf": {
11628        "requires": [
11629            "event-custom",
11630            "node",
11631            "swfdetect",
11632            "escape"
11633        ]
11634    },
11635    "swfdetect": {
11636        "requires": [
11637            "yui-base"
11638        ]
11639    },
11640    "tabview": {
11641        "requires": [
11642            "widget",
11643            "widget-parent",
11644            "widget-child",
11645            "tabview-base",
11646            "node-pluginhost",
11647            "node-focusmanager"
11648        ],
11649        "skinnable": true
11650    },
11651    "tabview-base": {
11652        "requires": [
11653            "node-event-delegate",
11654            "classnamemanager"
11655        ]
11656    },
11657    "tabview-plugin": {
11658        "requires": [
11659            "tabview-base"
11660        ]
11661    },
11662    "template": {
11663        "use": [
11664            "template-base",
11665            "template-micro"
11666        ]
11667    },
11668    "template-base": {
11669        "requires": [
11670            "yui-base"
11671        ]
11672    },
11673    "template-micro": {
11674        "requires": [
11675            "escape"
11676        ]
11677    },
11678    "test": {
11679        "requires": [
11680            "event-simulate",
11681            "event-custom",
11682            "json-stringify"
11683        ]
11684    },
11685  
11685  "test-console": {
11686        "requires": [
11687            "console-filters",
11688            "test",
11689            "array-extras"
11690        ],
11691        "skinnable": true
11692    },
11693    "text": {
11694        "use": [
11695            "text-accentfold",
11696            "text-wordbreak"
11697        ]
11698    },
11699    "text-accentfold": {
11700        "requires": [
11701            "array-extras",
11702            "text-data-accentfold"
11703        ]
11704    },
11705    "text-data-accentfold": {
11706        "requires": [
11707            "yui-base"
11708        ]
11709    },
11710    "text-data-wordbreak": {
11711        "requires": [
11712            "yui-base"
11713        ]
11714    },
11715    "text-wordbreak": {
11716        "requires": [
11717            "array-extras",
11718            "text-data-wordbreak"
11719        ]
11720    },
11721    "timers": {
11722        "requires": [
11723            "yui-base"
11724        ]
11725    },
11726    "transition": {
11727        "requires": [
11728            "node-style"
11729        ]
11730    },
11731    "transition-timer": {
11732        "condition": {
11733            "name": "transition-timer",
11734            "test": function (Y) {
11735    var DOCUMENT = Y.config.doc,
11736        node = (DOCUMENT) ? DOCUMENT.documentElement: null,
11737        ret = true;
11738
11739    if (node && node.style) {
11740        ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
11741    }
11742
11743    return ret;
11744},
11745            "trigger": "transition"
11746        },
11747        "requires": [
11748            "transition"
11749        ]
11750    },
11751    "tree": {
11752        "requires": [
11753            "base-build",
11754            "tree-node"
11755        ]
11756    },
11757    "tree-labelable": {
11758        "requires": [
11759            "tree"
11760        ]
11761    },
11762    "tree-lazy": {
11763        "requires": [
11764            "base-pluginhost",
11765            "plugin",
11766            "tree"
11767        ]
11768    },
11769    "tree-node": {},
11770    "tree-openable": {
11771        "requires": [
11772            "tree"
11773        ]
11774    },
11775    "tree-selectable": {
11776        "requires": [
11777            "tree"
11778        ]
11779    },
11780    "tree-sortable": {
11781        "requires": [
11782            "tree"
11783        ]
11784    },
11785    "uploader": {
11786        "requires": [
11787            "uploader-html5",
11788            "uploader-flash"
11789        ]
11790    },
11791    "uploader-flash": {
11792        "requires": [
11793            "swfdetect",
11794            "escape",
11795            "widget",
11796            "base",
11797            "cssbutton",
11798            "node",
11799            "event-custom",
11800            "uploader-queue"
11801        ]
11802    },
11803    "uploader-html5": {
11804        "requires": [
11805            "widget",
11806            "node-event-simulate",
11807            "file-html5",
11808            "uploader-queue"
11809        ]
11810    },
11811    "uploader-queue": {
11812        "requires": [
11813            "base"
11814        ]
11815    },
11816    "view": {
11817        "requires": [
11818            "base-build",
11819            "node-event-delegate"
11820        ]
11821    },
11822    "view-node-map": {
11823        "requires": [
11824            "view"
11825        ]
11826    },
11827    "widget": {
11828        "use": [
11829            "widget-base",
11830            "widget-htmlparser",
11831            "widget-skin",
11832            "widget-uievents"
11833        ]
11834    },
11835    "widget-anim": {
11836        "requires": [
11837            "anim-base",
11838            "plugin",
11839            "widget"
11840        ]
11841    },
11842    "widget-autohide": {
11843        "requires": [
11844            "base-build",
11845            "event-key",
11846            "event-outside",
11847            "widget"
11848        ]
11849    },
11850    "widget-base": {
11851        "requires": [
11852            "attribute",
11853            "base-base",
11854            "base-pluginhost",
11855            "classnamemanager",
11856            "event-focus",
11857            "node-base",
11858            "node-style"
11859        ],
11860        "skinnable": true
11861    },
11862    "widget-base-ie": {
11863        "condition": {
11864            "name": "widget-base-ie",
11865            "trigger": "widget-base",
11866            "ua": "ie"
11867        },
11868        "requires": [
11869            "widget-base"
11870        ]
11871    },
11872    "widget-buttons": {
11873        "requires": [
11874            "button-plugin",
11875            "cssbutton",
11876            "widget-stdmod"
11877        ]
11878    },
11879    "widget-child": {
11880        "requires": [
11881            "base-build",
11882            "widget"
11883        ]
11884    },
11885    "widget-htmlparser": {
11886        "requires": [
11887            "widget-base"
11888        ]
11889    },
11890    "widget-modality": {
11891        "requires": [
11892            "base-build",
11893            "event-outside",
11894            "widget"
11895        ],
11896        "skinnable": true
11897    },
11898    "widget-parent": {
11899        "requires": [
11900            "arraylist",
11901            "base-build",
11902            "widget"
11903        ]
11904    },
11905    "widget-position": {
11906        "requires": [
11907            "base-build",
11908            "node-screen",
11909            "widget"
11910        ]
11911    },
11912    "widget-position-align": {
11913        "requires": [
11914            "widget-position"
11915        ]
11916    },
11917    "widget-position-constrain": {
11918        "requires": [
11919            "widget-position"
11920        ]
11921    },
11922    "widget-skin": {
11923        "requires": [
11924            "widget-base"
11925        ]
11926    },
11927    "widget-stack": {
11928        "requires": [
11929            "base-build",
11930            "widget"
11931        ],
11932        "skinnable": true
11933    },
11934    "widget-stdmod": {
11935        "requires": [
11936            "base-build",
11937            "widget"
11938        ]
11939    },
11940    "widget-uievents": {
11941        "requires": [
11942            "node-event-delegate",
11943            "widget-base"
11944        ]
11945    },
11946    "yql": {
11947        "requires": [
11948            "oop"
11949        ]
11950    },
11951    "yql-jsonp": {
11952        "condition": {
11953            "name": "yql-jsonp",
11954            "test": function (Y) {
11955    /* Only load the JSONP module when not in nodejs or winjs
11956    TODO Make the winjs module a CORS module
11957    */
11958    return (!Y.UA.nodejs && !Y.UA.winjs);
11959},
11960            "trigger": "yql"
11961        },
11962        "requires": [
11963            "yql",
11964            "jsonp",
11965            "jsonp-url"
11966        ]
11967    },
11968    "yql-nodejs": {
11969        "condition": {
11970            "name": "yql-nodejs",
11971            "trigger": "yql",
11972            "ua": "nodejs"
11973        },
11974        "requires": [
11975            "yql"
11976        ]
11977    },
11978    "yql-winjs": {
11979        "condition": {
11980            "name": "yql-winjs",
11981            "trigger": "yql",
11982            "ua": "winjs"
11983        },
11984        "requires": [
11985            "yql"
11986        ]
11987    },
11988    "yui": {},
11989    "yui-base": {},
11990    "yui-later": {
11991        "requires": [
11992            "yui-base"
11993        ]
11994    },
11995    "yui-log": {
11996        "requires": [
11997            "yui-base"
11998        ]
11999    },
12000    "yui-throttle": {
12001        "requires": [
12002            "yui-base"
12003        ]
12004    }
12005});
12006YUI.Env[Y.version].md5 = '2fd2be6b12ee9f999b4367499ae61aae';
12007
12008
12009}, '3.18.1', {"requires": ["loader-base"]});
12010YUI.add('yui', function (Y, NAME) {}, '3.18.1', {
12011    "use": [
12012        "yui-base",
12013        "get",
12014        "features",
12015        "intl-base",
12016        "yui-log",
12017        "yui-later",
12018        "loader-base",
12019        "loader-rollup",
12020        "loader-yui3"
12021    ]
12022});
12023YUI.add('oop', function (Y, NAME) {
12024
12025/**
12026Adds object inheritance and manipulation utilities to the YUI instance. This
12027module is required by most YUI components.
12028
12029@module oop
12030**/
12031
12032var L            = Y.Lang,
12033    A            = Y.Array,
12034    OP           = Object.prototype,
12035    CLONE_MARKER = '_~yuim~_',
12036
12037    hasOwn   = OP.hasOwnProperty,
12038    toString = OP.toString;
12039
12040/**
12041Calls the specified _action_ method on _o_ if it exists. Otherwise, if _o_ is an
12042array, calls the _action_ method on `Y.Array`, or if _o_ is an object, calls the
12043_action_ method on `Y.Object`.
12044
12045If _o_ is an array-like object, it will be coerced to an array.
12046
12047This is intended to be used with array/object iteration methods that share
12048signatures, such as `each()`, `some()`, etc.
12049
12050@method dispatch
12051@param {Object} o Array or object to dispatch to.
12052@param {Function} f Iteration callback.
12053    @param {Mixed} f.value Value being iterated.
12054    @param {Mixed} f.key Current object key or array index.
12055    @param {Mixed} f.object Object or array being iterated.
12056@param {Object} c `this` object to bind the iteration callback to.
12057@param {Boolean} proto If `true`, prototype properties of objects will be
12058    iterated.
12059@param {String} action Function name to be dispatched on _o_. For example:
12060    'some', 'each', etc.
12061@private
12062@return {Mixed} Returns the value returned by the chosen iteration action, which
12063    varies.
12064**/
12065function dispatch(o, f, c, proto, action) {
12066    if (o && o[action] && o !== Y) {
12067        return o[action].call(o, f, c);
12068    } else {
12069        switch (A.test(o)) {
12070            case 1:
12071                return A[action](o, f, c);
12072            case 2:
12073                return A[action](Y.Array(o, 0, true), f, c);
12074            default:
12075                return Y.Object[action](o, f, c, proto);
12076        }
12077    }
12078}
12079
12080/**
12081Augments the _receiver_ with prototype properties from the _supplier_. The
12082receiver may be a constructor function or an object. The supplier must be a
12083constructor function.
12084
12085If the _receiver_ is an object, then the _supplier_ constructor will be called
12086immediately after _receiver_ is augmented, with _receiver_ as the `this` object.
12087
12088If the _receiver_ is a constructor function, then all prototype methods of
12089_supplier_ that are copied to _receiver_ will be sequestered, and the
12090_supplier_ constructor will not be called immediately. The first time any
12091sequestered method is called on the _receiver_'s prototype, all sequestered
12092methods will be immediately copied to the _receiver_'s prototype, the
12093_supplier_'s constructor will be executed, and finally the newly unsequestered
12094method that was called will be executed.
12095
12096This sequestering logic sounds like a bunch of complicated voodoo, but it makes
12097it cheap to perform frequent augmentation by ensuring that suppliers'
12098constructors are only called if a supplied method is actually used. If none of
12099the supplied methods is ever used, then there's no need to take the performance
12100hit of calling the _supplier_'s constructor.
12101
12102@method augment
12103@param {Function|Object} receiver Object or function to be augmented.
12104@param {Function} supplier Function that supplies the prototype properties with
12105  which to augment the _receiver_.
12106@param {Boolean} [overwrite=false] If `true`, properties already on the receiver
12107  will be overwritten if found on the supplier's prototype.
12108@param {String[]} [whitelist] An array of property names. If specified,
12109  only the whitelisted prototype properties will be applied to the receiver, and
12110  all others will be ignored.
12111@param {Array|any} [args] Argument or array of arguments to pass to the
12112  supplier's constructor when initializing.
12113@return {Function} Augmented object.
12114@for YUI
12115**/
12116Y.augment = function (receiver, supplier, overwrite, whitelist, args) {
12117    var rProto    = receiver.prototype,
12118        sequester = rProto && supplier,
12119        sProto    = supplier.prototype,
12120        to        = rProto || receiver,
12121
12122        copy,
12123        newPrototype,
12124        replacements,
12125        sequestered,
12126        unsequester;
12127
12128    args = args ? Y.Array(args) : [];
12129
12130    if (sequester) {
12131        newPrototype = {};
12132        replacements = {};
12133        sequestered  = {};
12134
12135        copy = function (value, key) {
12136            if (overwrite || !(key in rProto)) {
12137                if (toString.call(value) === '[object Function]') {
12138                    sequestered[key] = value;
12139
12140                    newPrototype[key] = replacements[key] = function () {
12141                        return unsequester(this, value, arguments);
12142                    };
12143                } else {
12144                    newPrototype[key] = value;
12145                }
12146            }
12147        };
12148
12149        unsequester = function (instance, fn, fnArgs) {
12150            // Unsequester all sequestered functions.
12151            for (var key in sequestered) {
12152                if (hasOwn.call(sequestered, key)
12153                        && instance[key] === replacements[key]) {
12154
12155                    instance[key] = sequestered[key];
12156                }
12157            }
12158
12159            // Execute the supplier constructor.
12160            supplier.apply(instance, args);
12161
12162            // Finally, execute the original sequestered function.
12163            return fn.apply(instance, fnArgs);
12164        };
12165
12166        if (whitelist) {
12167            Y.Array.each(whitelist, function (name) {
12168                if (name in sProto) {
12169                    copy(sProto[name], name);
12170                }
12171            });
12172        } else {
12173            Y.Object.each(sProto, copy, null, true);
12174        }
12175    }
12176
12177    Y.mix(to, newPrototype || sProto, overwrite, whitelist);
12178
12179    if (!sequester) {
12180        supplier.apply(to, args);
12181    }
12182
12183    return receiver;
12184};
12185
12186/**
12187 * Copies object properties from the supplier to the receiver. If the target has
12188 * the property, and the property is an object, the target object will be
12189 * augmented with the supplier's value.
12190 *
12191 * @method aggregate
12192 * @param {Object} receiver Object to receive the augmentation.
12193 * @param {Object} supplier Object that supplies the properties with which to
12194 *     augment the receiver.
12195 * @param {Boolean} [overwrite=false] If `true`, properties already on the receiver
12196 *     will be overwritten if found on the supplier.
12197 * @param {String[]} [whitelist] Whitelist. If supplied, only properties in this
12198 *     list will be applied to the receiver.
12199 * @return {Object} Augmented object.
12200 */
12201Y.aggregate = function(r, s, ov, wl) {
12202    return Y.mix(r, s, ov, wl, 0, true);
12203};
12204
12205/**
12206 * Utility to set up the prototype, constructor and superclass properties to
12207 * support an inheritance strategy that can chain constructors and methods.
12208 * Static members will not be inherited.
12209 *
12210 * @method extend
12211 * @param {function} r   the object to modify.
12212 * @param {function} s the object to inherit.
12213 * @param {object} px prototype properties to add/override.
12214 * @param {object} sx static properties to add/override.
12215 * @return {object} the extended object.
12216 */
12217Y.extend = function(r, s, px, sx) {
12218    if (!s || !r) {
12219        Y.error('extend failed, verify dependencies');
12220    }
12221
12222    var sp = s.prototype, rp = Y.Object(sp);
12223    r.prototype = rp;
12224
12225    rp.constructor = r;
12226    r.superclass = sp;
12227
12228    // assign constructor property
12229    if (s != Object && sp.constructor == OP.constructor) {
12230        sp.constructor = s;
12231    }
12232
12233    // add prototype overrides
12234    if (px) {
12235        Y.mix(rp, px, true);
12236    }
12237
12238    // add object overrides
12239    if (sx) {
12240        Y.mix(r, sx, true);
12241    }
12242
12243    return r;
12244};
12245
12246/**
12247 * Executes the supplied function for each item in
12248 * a collection.  Supports arrays, objects, and
12249 * NodeLists
12250 * @method each
12251 * @param {object} o the object to iterate.
12252 * @param {function} f the function to execute.  This function
12253 * receives the value, key, and object as parameters.
12254 * @param {object} c the execution context for the function.
12255 * @param {boolean} proto if true, prototype properties are
12256 * iterated on objects.
12257 * @return {YUI} the YUI instance.
12258 */
12259Y.each = function(o, f, c, proto) {
12260    return dispatch(o, f, c, proto, 'each');
12261};
12262
12263/**
12264 * Executes the supplied function for each item in
12265 * a collection.  The operation stops if the function
12266 * returns true. Supports arrays, objects, and
12267 * NodeLists.
12268 * @method some
12269 * @param {object} o the object to iterate.
12270 * @param {function} f the function to execute.  This function
12271 * receives the value, key, and object as parameters.
12272 * @param {object} c the execution context for the function.
12273 * @param {boolean} proto if true, prototype properties are
12274 * iterated on objects.
12275 * @return {boolean} true if the function ever returns true,
12276 * false otherwise.
12277 */
12278Y.some = function(o, f, c, proto) {
12279    return dispatch(o, f, c, proto, 'some');
12280};
12281
12282/**
12283Deep object/array copy. Function clones are actually wrappers around the
12284original function. Array-like objects are treated as arrays. Primitives are
12285returned untouched. Optionally, a function can be provided to handle other data
12286types, filter keys, validate values, etc.
12287
12288**Note:** Cloning a non-trivial object is a reasonably heavy operation, due to
12289the need to recursively iterate down non-primitive properties. Clone should be
12290used only when a deep clone down to leaf level properties is explicitly
12291required. This method will also
12292
12293In many cases (for example, when trying to isolate objects used as hashes for
12294configuration properties), a shallow copy, using `Y.merge()` is normally
12295sufficient. If more than one level of isolation is required, `Y.merge()` can be
12296used selectively at each level which needs to be isolated from the original
12297without going all the way to leaf properties.
12298
12299@method clone
12300@param {object} o what to clone.
12301@param {boolean} safe if true, objects will not have prototype items from the
12302    source. If false, they will. In this case, the original is initially
12303    protected, but the clone is not completely immune from changes to the source
12304    object prototype. Also, cloned prototype items that are deleted from the
12305    clone will result in the value of the source prototype being exposed. If
12306    operating on a non-safe clone, items should be nulled out rather than
12307    deleted.
12308@param {function} f optional function to apply to each item in a collection; it
12309    will be executed prior to applying the value to the new object.
12310    Return false to prevent the copy.
12311@param {object} c optional execution context for f.
12312@param {object} owner Owner object passed when clone is iterating an object.
12313    Used to set up context for cloned functions.
12314@param {object} cloned hash of previously cloned objects to avoid multiple
12315    clones.
12316@return {Array|Object} the cloned object.
12317**/
12318Y.clone = function(o, safe, f, c, owner, cloned) {
12319    var o2, marked, stamp;
12320
12321    // Does not attempt to clone:
12322    //
12323    // * Non-typeof-object values, "primitive" values don't need cloning.
12324    //
12325    // * YUI instances, cloning complex object like YUI instances is not
12326    //   advised, this is like cloning the world.
12327    //
12328    // * DOM nodes (#2528250), common host objects like DOM nodes cannot be
12329    //   "subclassed" in Firefox and old versions of IE. Trying to use
12330    //   `Object.create()` or `Y.extend()` on a DOM node will throw an error in
12331    //   these browsers.
12332    //
12333    // Instad, the passed-in `o` will be return as-is when it matches one of the
12334    // above criteria.
12335    if (!L.isObject(o) ||
12336            Y.instanceOf(o, YUI) ||
12337            (o.addEventListener || o.attachEvent)) {
12338
12339        return o;
12340    }
12341
12342    marked = cloned || {};
12343
12344    switch (L.type(o)) {
12345        case 'date':
12346            return new Date(o);
12347        case 'regexp':
12348            // if we do this we need to set the flags too
12349            // return new RegExp(o.source);
12350            return o;
12351        case 'function':
12352            // o2 = Y.bind(o, owner);
12353            // break;
12354            return o;
12355        case 'array':
12356            o2 = [];
12357            break;
12358        default:
12359
12360            // #2528250 only one clone of a given object should be created.
12361            if (o[CLONE_MARKER]) {
12362                return marked[o[CLONE_MARKER]];
12363            }
12364
12365            stamp = Y.guid();
12366
12367            o2 = (safe) ? {} : Y.Object(o);
12368
12369            o[CLONE_MARKER] = stamp;
12370            marked[stamp] = o;
12371    }
12372
12373    Y.each(o, function(v, k) {
12374        if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
12375            if (k !== CLONE_MARKER) {
12376                if (k == 'prototype') {
12377                    // skip the prototype
12378                // } else if (o[k] === o) {
12379                //     this[k] = this;
12380                } else {
12381                    this[k] =
12382                        Y.clone(v, safe, f, c, owner || o, marked);
12383                }
12384            }
12385        }
12386    }, o2);
12387
12388    if (!cloned) {
12389        Y.Object.each(marked, function(v, k) {
12390            if (v[CLONE_MARKER]) {
12391                try {
12392                    delete v[CLONE_MARKER];
12393                } catch (e) {
12394                    v[CLONE_MARKER] = null;
12395                }
12396            }
12397        }, this);
12398        marked = null;
12399    }
12400
12401    return o2;
12402};
12403
12404/**
12405 * Returns a function that will execute the supplied function in the
12406 * supplied object's context, optionally adding any additional
12407 * supplied parameters to the beginning of the arguments collection the
12408 * supplied to the function.
12409 *
12410 * @method bind
12411 * @param {Function|String} f the function to bind, or a function name
12412 * to execute on the context object.
12413 * @param {object} c the execution context.
12414 * @param {any} args* 0..n arguments to include before the arguments the
12415 * function is executed with.
12416 * @return {function} the wrapped function.
12417 */
12418Y.bind = function(f, c) {
12419    var xargs = arguments.length > 2 ?
12420            Y.Array(arguments, 2, true) : null;
12421    return function() {
12422        var fn = L.isString(f) ? c[f] : f,
12423            args = (xargs) ?
12424                xargs.concat(Y.Array(arguments, 0, true)) : arguments;
12425        return fn.apply(c || fn, args);
12426    };
12427};
12428
12429/**
12430 * Returns a function that will execute the supplied function in the
12431 * supplied object's context, optionally adding any additional
12432 * supplied parameters to the end of the arguments the function
12433 * is executed with.
12434 *
12435 * @method rbind
12436 * @param {Function|String} f the function to bind, or a function name
12437 * to execute on the context object.
12438 * @param {object} c the execution context.
12439 * @param {any} args* 0..n arguments to append to the end of
12440 * arguments collection supplied to the function.
12441 * @return {function} the wrapped function.
12442 */
12443Y.rbind = function(f, c) {
12444    var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
12445    return function() {
12446        var fn = L.isString(f) ? c[f] : f,
12447            args = (xargs) ?
12448                Y.Array(arguments, 0, true).concat(xargs) : arguments;
12449        return fn.apply(c || fn, args);
12450    };
12451};
12452
12453
12454}, '3.18.1', {"requires": ["yui-base"]});
12455YUI.add('event-custom-base', function (Y, NAME) {
12456
12457/**
12458 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
12459 * events.
12460 * @module event-custom
12461 */
12462
12463Y.Env.evt = {
12464    handles: {},
12465    plugins: {}
12466};
12467
12468/**
12469 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
12470 * events.
12471 * @module event-custom
12472 * @submodule event-custom-base
12473 */
12474
12475/**
12476 * Allows for the insertion of methods that are executed before or after
12477 * a specified method
12478 * @class Do
12479 * @static
12480 */
12481
12482var DO_BEFORE = 0,
12483    DO_AFTER = 1,
12484
12485DO = {
12486
12487    /**
12488     * Cache of objects touched by the utility
12489     * @property objs
12490     * @static
12491     * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object
12492     * replaces the role of this property, but is considered to be private, and
12493     * is only mentioned to provide a migration path.
12494     *
12495     * If you have a use case which warrants migration to the _yuiaop property,
12496     * please file a ticket to let us know what it's used for and we can see if
12497     * we need to expose hooks for that functionality more formally.
12498     */
12499    objs: null,
12500
12501    /**
12502     * <p>Execute the supplied method before the specified function.  Wrapping
12503     * function may optionally return an instance of the following classes to
12504     * further alter runtime behavior:</p>
12505     * <dl>
12506     *     <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
12507     *         <dd>Immediatly stop execution and return
12508     *         <code>returnValue</code>.  No other wrapping functions will be
12509     *         executed.</dd>
12510     *     <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt>
12511     *         <dd>Replace the arguments that the original function will be
12512     *         called with.</dd>
12513     *     <dt></code>Y.Do.Prevent(message)</code></dt>
12514     *         <dd>Don't execute the wrapped function.  Other before phase
12515     *         wrappers will be executed.</dd>
12516     * </dl>
12517     *
12518     * @method before
12519     * @param fn {Function} the function to execute
12520     * @param obj the object hosting the method to displace
12521     * @param sFn {string} the name of the method to displace
12522     * @param c The execution context for fn
12523     * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
12524     * when the event fires.
12525     * @return {EventHandle} handle for the subscription
12526     * @static
12527     */
12528    before: function(fn, obj, sFn, c) {
12529        var f = fn, a;
12530        if (c) {
12531            a = [fn, c].concat(Y.Array(arguments, 4, true));
12532            f = Y.rbind.apply(Y, a);
12533        }
12534
12535        return this._inject(DO_BEFORE, f, obj, sFn);
12536    },
12537
12538    /**
12539     * <p>Execute the supplied method after the specified function.  Wrapping
12540     * function may optionally return an instance of the following classes to
12541     * further alter runtime behavior:</p>
12542     * <dl>
12543     *     <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
12544     *         <dd>Immediatly stop execution and return
12545     *         <code>returnValue</code>.  No other wrapping functions will be
12546     *         executed.</dd>
12547     *     <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt>
12548     *         <dd>Return <code>returnValue</code> instead of the wrapped
12549     *         method's original return value.  This can be further altered by
12550     *         other after phase wrappers.</dd>
12551     * </dl>
12552     *
12553     * <p>The static properties <code>Y.Do.originalRetVal</code> and
12554     * <code>Y.Do.currentRetVal</code> will be populated for reference.</p>
12555     *
12556     * @method after
12557     * @param fn {Function} the function to execute
12558     * @param obj the object hosting the method to displace
12559     * @param sFn {string} the name of the method to displace
12560     * @param c The execution context for fn
12561     * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
12562     * @return {EventHandle} handle for the subscription
12563     * @static
12564     */
12565    after: function(fn, obj, sFn, c) {
12566        var f = fn, a;
12567        if (c) {
12568            a = [fn, c].concat(Y.Array(arguments, 4, true));
12569            f = Y.rbind.apply(Y, a);
12570        }
12571
12572        return this._inject(DO_AFTER, f, obj, sFn);
12573    },
12574
12575    /**
12576     * Execute the supplied method before or after the specified function.
12577     * Used by <code>before</code> and <code>after</code>.
12578     *
12579     * @method _inject
12580     * @param when {string} before or after
12581     * @param fn {Function} the function to execute
12582     * @param obj the object hosting the method to displace
12583     * @param sFn {string} the name of the method to displace
12584     * @param c The execution context for fn
12585     * @return {EventHandle} handle for the subscription
12586     * @private
12587     * @static
12588     */
12589    _inject: function(when, fn, obj, sFn) {
12590        // object id
12591        var id = Y.stamp(obj), o, sid;
12592
12593        if (!obj._yuiaop) {
12594            // create a map entry for the obj if it doesn't exist, to hold overridden methods
12595            obj._yuiaop = {};
12596        }
12597
12598        o = obj._yuiaop;
12599
12600        if (!o[sFn]) {
12601            // create a map entry for the method if it doesn't exist
12602            o[sFn] = new Y.Do.Method(obj, sFn);
12603
12604            // re-route the method to our wrapper
12605            obj[sFn] = function() {
12606                return o[sFn].exec.apply(o[sFn], arguments);
12607            };
12608        }
12609
12610        // subscriber id
12611        sid = id + Y.stamp(fn) + sFn;
12612
12613        // register the callback
12614        o[sFn].register(sid, fn, when);
12615
12616        return new Y.EventHandle(o[sFn], sid);
12617    },
12618
12619    /**
12620     * Detach a before or after subscription.
12621     *
12622     * @method detach
12623     * @param handle {EventHandle} the subscription handle
12624     * @static
12625     */
12626    detach: function(handle) {
12627        if (handle.detach) {
12628            handle.detach();
12629        }
12630    }
12631};
12632
12633Y.Do = DO;
12634
12635//////////////////////////////////////////////////////////////////////////
12636
12637/**
12638 * Contains the return value from the wrapped method, accessible
12639 * by 'after' event listeners.
12640 *
12641 * @property originalRetVal
12642 * @static
12643 * @since 3.2.0
12644 */
12645
12646/**
12647 * Contains the current state of the return value, consumable by
12648 * 'after' event listeners, and updated if an after subscriber
12649 * changes the return value generated by the wrapped function.
12650 *
12651 * @property currentRetVal
12652 * @static
12653 * @since 3.2.0
12654 */
12655
12656//////////////////////////////////////////////////////////////////////////
12657
12658/**
12659 * Wrapper for a displaced method with aop enabled
12660 * @class Do.Method
12661 * @constructor
12662 * @param obj The object to operate on
12663 * @param sFn The name of the method to displace
12664 */
12665DO.Method = function(obj, sFn) {
12666    this.obj = obj;
12667    this.methodName = sFn;
12668    this.method = obj[sFn];
12669    this.before = {};
12670    this.after = {};
12671};
12672
12673/**
12674 * Register a aop subscriber
12675 * @method register
12676 * @param sid {string} the subscriber id
12677 * @param fn {Function} the function to execute
12678 * @param when {string} when to execute the function
12679 */
12680DO.Method.prototype.register = function (sid, fn, when) {
12681    if (when) {
12682        this.after[sid] = fn;
12683    } else {
12684        this.before[sid] = fn;
12685    }
12686};
12687
12688/**
12689 * Unregister a aop subscriber
12690 * @method delete
12691 * @param sid {string} the subscriber id
12692 * @param fn {Function} the function to execute
12693 * @param when {string} when to execute the function
12694 */
12695DO.Method.prototype._delete = function (sid) {
12696    delete this.before[sid];
12697    delete this.after[sid];
12698};
12699
12700/**
12701 * <p>Execute the wrapped method.  All arguments are passed into the wrapping
12702 * functions.  If any of the before wrappers return an instance of
12703 * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped
12704 * function nor any after phase subscribers will be executed.</p>
12705 *
12706 * <p>The return value will be the return value of the wrapped function or one
12707 * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or
12708 * <code>Y.Do.AlterReturn</code>.
12709 *
12710 * @method exec
12711 * @param arg* {any} Arguments are passed to the wrapping and wrapped functions
12712 * @return {any} Return value of wrapped function unless overwritten (see above)
12713 */
12714DO.Method.prototype.exec = function () {
12715
12716    var args = Y.Array(arguments, 0, true),
12717        i, ret, newRet,
12718        bf = this.before,
12719        af = this.after,
12720        prevented = false;
12721
12722    // execute before
12723    for (i in bf) {
12724        if (bf.hasOwnProperty(i)) {
12725            ret = bf[i].apply(this.obj, args);
12726            if (ret) {
12727                switch (ret.constructor) {
12728                    case DO.Halt:
12729                        return ret.retVal;
12730                    case DO.AlterArgs:
12731                        args = ret.newArgs;
12732                        break;
12733                    case DO.Prevent:
12734                        prevented = true;
12735                        break;
12736                    default:
12737                }
12738            }
12739        }
12740    }
12741
12742    // execute method
12743    if (!prevented) {
12744        ret = this.method.apply(this.obj, args);
12745    }
12746
12747    DO.originalRetVal = ret;
12748    DO.currentRetVal = ret;
12749
12750    // execute after methods.
12751    for (i in af) {
12752        if (af.hasOwnProperty(i)) {
12753            newRet = af[i].apply(this.obj, args);
12754            // Stop processing if a Halt object is returned
12755            if (newRet && newRet.constructor === DO.Halt) {
12756                return newRet.retVal;
12757            // Check for a new return value
12758            } else if (newRet && newRet.constructor === DO.AlterReturn) {
12759                ret = newRet.newRetVal;
12760                // Update the static retval state
12761                DO.currentRetVal = ret;
12762            }
12763        }
12764    }
12765
12766    return ret;
12767};
12768
12769//////////////////////////////////////////////////////////////////////////
12770
12771/**
12772 * Return an AlterArgs object when you want to change the arguments that
12773 * were passed into the function.  Useful for Do.before subscribers.  An
12774 * example would be a service that scrubs out illegal characters prior to
12775 * executing the core business logic.
12776 * @class Do.AlterArgs
12777 * @constructor
12778 * @param msg {String} (optional) Explanation of the altered return value
12779 * @param newArgs {Array} Call parameters to be used for the original method
12780 *                        instead of the arguments originally passed in.
12781 */
12782DO.AlterArgs = function(msg, newArgs) {
12783    this.msg = msg;
12784    this.newArgs = newArgs;
12785};
12786
12787/**
12788 * Return an AlterReturn object when you want to change the result returned
12789 * from the core method to the caller.  Useful for Do.after subscribers.
12790 * @class Do.AlterReturn
12791 * @constructor
12792 * @param msg {String} (optional) Explanation of the altered return value
12793 * @param newRetVal {any} Return value passed to code that invoked the wrapped
12794 *                      function.
12795 */
12796DO.AlterReturn = function(msg, newRetVal) {
12797    this.msg = msg;
12798    this.newRetVal = newRetVal;
12799};
12800
12801/**
12802 * Return a Halt object when you want to terminate the execution
12803 * of all subsequent subscribers as well as the wrapped method
12804 * if it has not exectued yet.  Useful for Do.before subscribers.
12805 * @class Do.Halt
12806 * @constructor
12807 * @param msg {String} (optional) Explanation of why the termination was done
12808 * @param retVal {any} Return value passed to code that invoked the wrapped
12809 *                      function.
12810 */
12811DO.Halt = function(msg, retVal) {
12812    this.msg = msg;
12813    this.retVal = retVal;
12814};
12815
12816/**
12817 * Return a Prevent object when you want to prevent the wrapped function
12818 * from executing, but want the remaining listeners to execute.  Useful
12819 * for Do.before subscribers.
12820 * @class Do.Prevent
12821 * @constructor
12822 * @param msg {String} (optional) Explanation of why the termination was done
12823 */
12824DO.Prevent = function(msg) {
12825    this.msg = msg;
12826};
12827
12828/**
12829 * Return an Error object when you want to terminate the execution
12830 * of all subsequent method calls.
12831 * @class Do.Error
12832 * @constructor
12833 * @param msg {String} (optional) Explanation of the altered return value
12834 * @param retVal {any} Return value passed to code that invoked the wrapped
12835 *                      function.
12836 * @deprecated use Y.Do.Halt or Y.Do.Prevent
12837 */
12838DO.Error = DO.Halt;
12839
12840
12841//////////////////////////////////////////////////////////////////////////
12842
12843/**
12844 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
12845 * events.
12846 * @module event-custom
12847 * @submodule event-custom-base
12848 */
12849
12850
12851// var onsubscribeType = "_event:onsub",
12852var YArray = Y.Array,
12853
12854    AFTER = 'after',
12855    CONFIGS = [
12856        'broadcast',
12857        'monitored',
12858        'bubbles',
12859        'context',
12860        'contextFn',
12861        'currentTarget',
12862        'defaultFn',
12863        'defaultTargetOnly',
12864        'details',
12865        'emitFacade',
12866        'fireOnce',
12867        'async',
12868        'host',
12869        'preventable',
12870        'preventedFn',
12871        'queuable',
12872        'silent',
12873        'stoppedFn',
12874        'target',
12875        'type'
12876    ],
12877
12878    CONFIGS_HASH = YArray.hash(CONFIGS),
12879
12880    nativeSlice = Array.prototype.slice,
12881
12882    YUI3_SIGNATURE = 9,
12883    YUI_LOG = 'yui:log',
12884
12885    mixConfigs = function(r, s, ov) {
12886        var p;
12887
12888        for (p in s) {
12889            if (CONFIGS_HASH[p] && (ov || !(p in r))) {
12890                r[p] = s[p];
12891            }
12892        }
12893
12894        return r;
12895    };
12896
12897/**
12898 * The CustomEvent class lets you define events for your application
12899 * that can be subscribed to by one or more independent component.
12900 *
12901 * @param {String} type The type of event, which is passed to the callback
12902 * when the event fires.
12903 * @param {object} defaults configuration object.
12904 * @class CustomEvent
12905 * @constructor
12906 */
12907
12908 /**
12909 * The type of event, returned to subscribers when the event fires
12910 * @property type
12911 * @type string
12912 */
12913
12914/**
12915 * By default all custom events are logged in the debug build, set silent
12916 * to true to disable debug outpu for this event.
12917 * @property silent
12918 * @type boolean
12919 */
12920
12921Y.CustomEvent = function(type, defaults) {
12922
12923    this._kds = Y.CustomEvent.keepDeprecatedSubs;
12924
12925    this.id = Y.guid();
12926
12927    this.type = type;
12928    this.silent = this.logSystem = (type === YUI_LOG);
12929
12930    if (this._kds) {
12931        /**
12932         * The subscribers to this event
12933         * @property subscribers
12934         * @type Subscriber {}
12935         * @deprecated
12936         */
12937
12938        /**
12939         * 'After' subscribers
12940         * @property afters
12941         * @type Subscriber {}
12942         * @deprecated
12943         */
12944        this.subscribers = {};
12945        this.afters = {};
12946    }
12947
12948    if (defaults) {
12949        mixConfigs(this, defaults, true);
12950    }
12951};
12952
12953/**
12954 * Static flag to enable population of the <a href="#property_subscribers">`subscribers`</a>
12955 * and  <a href="#property_subscribers">`afters`</a> properties held on a `CustomEvent` instance.
12956 *
12957 * These properties were changed to private properties (`_subscribers` and `_afters`), and
12958 * converted from objects to arrays for performance reasons.
12959 *
12960 * Setting this property to true will populate the deprecated `subscribers` and `afters`
12961 * properties for people who may be using them (which is expected to be rare). There will
12962 * be a performance hit, compared to the new array based implementation.
12963 *
12964 * If you are using these deprecated properties for a use case which the public API
12965 * does not support, please file an enhancement request, and we can provide an alternate
12966 * public implementation which doesn't have the performance cost required to maintiain the
12967 * properties as objects.
12968 *
12969 * @property keepDeprecatedSubs
12970 * @static
12971 * @for CustomEvent
12972 * @type boolean
12973 * @default false
12974 * @deprecated
12975 */
12976Y.CustomEvent.keepDeprecatedSubs = false;
12977
12978Y.CustomEvent.mixConfigs = mixConfigs;
12979
12980Y.CustomEvent.prototype = {
12981
12982    constructor: Y.CustomEvent,
12983
12984    /**
12985     * Monitor when an event is attached or detached.
12986     *
12987     * @property monitored
12988     * @type boolean
12989     */
12990
12991    /**
12992     * If 0, this event does not broadcast.  If 1, the YUI instance is notified
12993     * every time this event fires.  If 2, the YUI instance and the YUI global
12994     * (if event is enabled on the global) are notified every time this event
12995     * fires.
12996     * @property broadcast
12997     * @type int
12998     */
12999
13000    /**
13001     * Specifies whether this event should be queued when the host is actively
13002     * processing an event.  This will effect exectution order of the callbacks
13003     * for the various events.
13004     * @property queuable
13005     * @type boolean
13006     * @default false
13007     */
13008
13009    /**
13010     * This event has fired if true
13011     *
13012     * @property fired
13013     * @type boolean
13014     * @default false;
13015     */
13016
13017    /**
13018     * An array containing the arguments the custom event
13019     * was last fired with.
13020     * @property firedWith
13021     * @type Array
13022     */
13023
13024    /**
13025     * This event should only fire one time if true, and if
13026     * it has fired, any new subscribers should be notified
13027     * immediately.
13028     *
13029     * @property fireOnce
13030     * @type boolean
13031     * @default false;
13032     */
13033
13034    /**
13035     * fireOnce listeners will fire syncronously unless async
13036     * is set to true
13037     * @property async
13038     * @type boolean
13039     * @default false
13040     */
13041
13042    /**
13043     * Flag for stopPropagation that is modified during fire()
13044     * 1 means to stop propagation to bubble targets.  2 means
13045     * to also stop additional subscribers on this target.
13046     * @property stopped
13047     * @type int
13048     */
13049
13050    /**
13051     * Flag for preventDefault that is modified during fire().
13052     * if it is not 0, the default behavior for this event
13053     * @property prevented
13054     * @type int
13055     */
13056
13057    /**
13058     * Specifies the host for this custom event.  This is used
13059     * to enable event bubbling
13060     * @property host
13061     * @type EventTarget
13062     */
13063
13064    /**
13065     * The default function to execute after event listeners
13066     * have fire, but only if the default action was not
13067     * prevented.
13068     * @property defaultFn
13069     * @type Function
13070     */
13071
13072    /**
13073     * Flag for the default function to execute only if the
13074     * firing event is the current target. This happens only
13075     * when using custom event delegation and setting the
13076     * flag to `true` mimics the behavior of event delegation
13077     * in the DOM.
13078     *
13079     * @property defaultTargetOnly
13080     * @type Boolean
13081     * @default false
13082     */
13083
13084    /**
13085     * The function to execute if a subscriber calls
13086     * stopPropagation or stopImmediatePropagation
13087     * @property stoppedFn
13088     * @type Function
13089     */
13090
13091    /**
13092     * The function to execute if a subscriber calls
13093     * preventDefault
13094     * @property preventedFn
13095     * @type Function
13096     */
13097
13098    /**
13099     * The subscribers to this event
13100     * @property _subscribers
13101     * @type Subscriber []
13102     * @private
13103     */
13104
13105    /**
13106     * 'After' subscribers
13107     * @property _afters
13108     * @type Subscriber []
13109     * @private
13110     */
13111
13112    /**
13113     * If set to true, the custom event will deliver an EventFacade object
13114     * that is similar to a DOM event object.
13115     * @property emitFacade
13116     * @type boolean
13117     * @default false
13118     */
13119
13120    /**
13121     * Supports multiple options for listener signatures in order to
13122     * port YUI 2 apps.
13123     * @property signature
13124     * @type int
13125     * @default 9
13126     */
13127    signature : YUI3_SIGNATURE,
13128
13129    /**
13130     * The context the the event will fire from by default.  Defaults to the YUI
13131     * instance.
13132     * @property context
13133     * @type object
13134     */
13135    context : Y,
13136
13137    /**
13138     * Specifies whether or not this event's default function
13139     * can be cancelled by a subscriber by executing preventDefault()
13140     * on the event facade
13141     * @property preventable
13142     * @type boolean
13143     * @default true
13144     */
13145    preventable : true,
13146
13147    /**
13148     * Specifies whether or not a subscriber can stop the event propagation
13149     * via stopPropagation(), stopImmediatePropagation(), or halt()
13150     *
13151     * Events can only bubble if emitFacade is true.
13152     *
13153     * @property bubbles
13154     * @type boolean
13155     * @default true
13156     */
13157    bubbles : true,
13158
13159    /**
13160     * Returns the number of subscribers for this event as the sum of the on()
13161     * subscribers and after() subscribers.
13162     *
13163     * @method hasSubs
13164     * @return Number
13165     */
13166    hasSubs: function(when) {
13167        var s = 0,
13168            a = 0,
13169            subs = this._subscribers,
13170            afters = this._afters,
13171            sib = this.sibling;
13172
13173        if (subs) {
13174            s = subs.length;
13175        }
13176
13177        if (afters) {
13178            a = afters.length;
13179        }
13180
13181        if (sib) {
13182            subs = sib._subscribers;
13183            afters = sib._afters;
13184
13185            if (subs) {
13186                s += subs.length;
13187            }
13188
13189            if (afters) {
13190                a += afters.length;
13191            }
13192        }
13193
13194        if (when) {
13195            return (when === 'after') ? a : s;
13196        }
13197
13198        return (s + a);
13199    },
13200
13201    /**
13202     * Monitor the event state for the subscribed event.  The first parameter
13203     * is what should be monitored, the rest are the normal parameters when
13204     * subscribing to an event.
13205     * @method monitor
13206     * @param what {string} what to monitor ('detach', 'attach', 'publish').
13207     * @return {EventHandle} return value from the monitor event subscription.
13208     */
13209    monitor: function(what) {
13210        this.monitored = true;
13211        var type = this.id + '|' + this.type + '_' + what,
13212            args = nativeSlice.call(arguments, 0);
13213        args[0] = type;
13214        return this.host.on.apply(this.host, args);
13215    },
13216
13217    /**
13218     * Get all of the subscribers to this event and any sibling event
13219     * @method getSubs
13220     * @return {Array} first item is the on subscribers, second the after.
13221     */
13222    getSubs: function() {
13223
13224        var sibling = this.sibling,
13225            subs = this._subscribers,
13226            afters = this._afters,
13227            siblingSubs,
13228            siblingAfters;
13229
13230        if (sibling) {
13231            siblingSubs = sibling._subscribers;
13232            siblingAfters = sibling._afters;
13233        }
13234
13235        if (siblingSubs) {
13236            if (subs) {
13237                subs = subs.concat(siblingSubs);
13238            } else {
13239                subs = siblingSubs.concat();
13240            }
13241        } else {
13242            if (subs) {
13243                subs = subs.concat();
13244            } else {
13245                subs = [];
13246            }
13247        }
13248
13249        if (siblingAfters) {
13250            if (afters) {
13251                afters = afters.concat(siblingAfters);
13252            } else {
13253                afters = siblingAfters.concat();
13254            }
13255        } else {
13256            if (afters) {
13257                afters = afters.concat();
13258            } else {
13259                afters = [];
13260            }
13261        }
13262
13263        return [subs, afters];
13264    },
13265
13266    /**
13267     * Apply configuration properties.  Only applies the CONFIG whitelist
13268     * @method applyConfig
13269     * @param o hash of properties to apply.
13270     * @param force {boolean} if true, properties that exist on the event
13271     * will be overwritten.
13272     */
13273    applyConfig: function(o, force) {
13274        mixConfigs(this, o, force);
13275    },
13276
13277    /**
13278     * Create the Subscription for subscribing function, context, and bound
13279     * arguments.  If this is a fireOnce event, the subscriber is immediately
13280     * notified.
13281     *
13282     * @method _on
13283     * @param fn {Function} Subscription callback
13284     * @param [context] {Object} Override `this` in the callback
13285     * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire()
13286     * @param [when] {String} "after" to slot into after subscribers
13287     * @return {EventHandle}
13288     * @protected
13289     */
13290    _on: function(fn, context, args, when) {
13291
13292
13293        var s = new Y.Subscriber(fn, context, args, when),
13294            firedWith;
13295
13296        if (this.fireOnce && this.fired) {
13297
13298            firedWith = this.firedWith;
13299
13300            // It's a little ugly for this to know about facades,
13301            // but given the current breakup, not much choice without
13302            // moving a whole lot of stuff around.
13303            if (this.emitFacade && this._addFacadeToArgs) {
13304                this._addFacadeToArgs(firedWith);
13305            }
13306
13307            if (this.async) {
13308                setTimeout(Y.bind(this._notify, this, s, firedWith), 0);
13309            } else {
13310                this._notify(s, firedWith);
13311            }
13312        }
13313
13314        if (when === AFTER) {
13315            if (!this._afters) {
13316                this._afters = [];
13317            }
13318            this._afters.push(s);
13319        } else {
13320            if (!this._subscribers) {
13321                this._subscribers = [];
13322            }
13323            this._subscribers.push(s);
13324        }
13325
13326        if (this._kds) {
13327            if (when === AFTER) {
13328                this.afters[s.id] = s;
13329            } else {
13330                this.subscribers[s.id] = s;
13331            }
13332        }
13333
13334        return new Y.EventHandle(this, s);
13335    },
13336
13337    /**
13338     * Listen for this event
13339     * @method subscribe
13340     * @param {Function} fn The function to execute.
13341     * @return {EventHandle} Unsubscribe handle.
13342     * @deprecated use on.
13343     */
13344    subscribe: function(fn, context) {
13345        var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
13346        return this._on(fn, context, a, true);
13347    },
13348
13349    /**
13350     * Listen for this event
13351     * @method on
13352     * @param {Function} fn The function to execute.
13353     * @param {object} context optional execution context.
13354     * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
13355     * when the event fires.
13356     * @return {EventHandle} An object with a detach method to detch the handler(s).
13357     */
13358    on: function(fn, context) {
13359        var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
13360
13361        if (this.monitored && this.host) {
13362            this.host._monitor('attach', this, {
13363                args: arguments
13364            });
13365        }
13366        return this._on(fn, context, a, true);
13367    },
13368
13369    /**
13370     * Listen for this event after the normal subscribers have been notified and
13371     * the default behavior has been applied.  If a normal subscriber prevents the
13372     * default behavior, it also prevents after listeners from firing.
13373     * @method after
13374     * @param {Function} fn The function to execute.
13375     * @param {object} context optional execution context.
13376     * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
13377     * when the event fires.
13378     * @return {EventHandle} handle Unsubscribe handle.
13379     */
13380    after: function(fn, context) {
13381        var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
13382        return this._on(fn, context, a, AFTER);
13383    },
13384
13385    /**
13386     * Detach listeners.
13387     * @method detach
13388     * @param {Function} fn  The subscribed function to remove, if not supplied
13389     *                       all will be removed.
13390     * @param {Object}   context The context object passed to subscribe.
13391     * @return {Number} returns the number of subscribers unsubscribed.
13392     */
13393    detach: function(fn, context) {
13394        // unsubscribe handle
13395        if (fn && fn.detach) {
13396            return fn.detach();
13397        }
13398
13399        var i, s,
13400            found = 0,
13401            subs = this._subscribers,
13402            afters = this._afters;
13403
13404        if (subs) {
13405            for (i = subs.length; i >= 0; i--) {
13406                s = subs[i];
13407                if (s && (!fn || fn === s.fn)) {
13408                    this._delete(s, subs, i);
13409                    found++;
13410                }
13411            }
13412        }
13413
13414        if (afters) {
13415            for (i = afters.length; i >= 0; i--) {
13416                s = afters[i];
13417                if (s && (!fn || fn === s.fn)) {
13418                    this._delete(s, afters, i);
13419                    found++;
13420                }
13421            }
13422        }
13423
13424        return found;
13425    },
13426
13427    /**
13428     * Detach listeners.
13429     * @method unsubscribe
13430     * @param {Function} fn  The subscribed function to remove, if not supplied
13431     *                       all will be removed.
13432     * @param {Object}   context The context object passed to subscribe.
13433     * @return {int|undefined} returns the number of subscribers unsubscribed.
13434     * @deprecated use detach.
13435     */
13436    unsubscribe: function() {
13437        return this.detach.apply(this, arguments);
13438    },
13439
13440    /**
13441     * Notify a single subscriber
13442     * @method _notify
13443     * @param {Subscriber} s the subscriber.
13444     * @param {Array} args the arguments array to apply to the listener.
13445     * @protected
13446     */
13447    _notify: function(s, args, ef) {
13448
13449
13450        var ret;
13451
13452        ret = s.notify(args, this);
13453
13454        if (false === ret || this.stopped > 1) {
13455            return false;
13456        }
13457
13458        return true;
13459    },
13460
13461    /**
13462     * Logger abstraction to centralize the application of the silent flag
13463     * @method log
13464     * @param {string} msg message to log.
13465     * @param {string} cat log category.
13466     */
13467    log: function(msg, cat) {
13468    },
13469
13470    /**
13471     * Notifies the subscribers.  The callback functions will be executed
13472     * from the context specified when the event was created, and with the
13473     * following parameters:
13474     *   <ul>
13475     *   <li>The type of event</li>
13476     *   <li>All of the arguments fire() was executed with as an array</li>
13477     *   <li>The custom object (if any) that was passed into the subscribe()
13478     *       method</li>
13479     *   </ul>
13480     * @method fire
13481     * @param {Object*} arguments an arbitrary set of parameters to pass to
13482     *                            the handler.
13483     * @return {boolean} false if one of the subscribers returned false,
13484     *                   true otherwise.
13485     *
13486     */
13487    fire: function() {
13488
13489        // push is the fastest way to go from arguments to arrays
13490        // for most browsers currently
13491        // http://jsperf.com/push-vs-concat-vs-slice/2
13492
13493        var args = [];
13494        args.push.apply(args, arguments);
13495
13496        return this._fire(args);
13497    },
13498
13499    /**
13500     * Private internal implementation for `fire`, which is can be used directly by
13501     * `EventTarget` and other event module classes which have already converted from
13502     * an `arguments` list to an array, to avoid the repeated overhead.
13503     *
13504     * @method _fire
13505     * @private
13506     * @param {Array} args The array of arguments passed to be passed to handlers.
13507     * @return {boolean} false if one of the subscribers returned false, true otherwise.
13508     */
13509    _fire: function(args) {
13510
13511        if (this.fireOnce && this.fired) {
13512            return true;
13513        } else {
13514
13515            // this doesn't happen if the event isn't published
13516            // this.host._monitor('fire', this.type, args);
13517
13518            this.fired = true;
13519
13520            if (this.fireOnce) {
13521                this.firedWith = args;
13522            }
13523
13524            if (this.emitFacade) {
13525                return this.fireComplex(args);
13526            } else {
13527                return this.fireSimple(args);
13528            }
13529        }
13530    },
13531
13532    /**
13533     * Set up for notifying subscribers of non-emitFacade events.
13534     *
13535     * @method fireSimple
13536     * @param args {Array} Arguments passed to fire()
13537     * @return Boolean false if a subscriber returned false
13538     * @protected
13539     */
13540    fireSimple: function(args) {
13541        this.stopped = 0;
13542        this.prevented = 0;
13543        if (this.hasSubs()) {
13544            var subs = this.getSubs();
13545            this._procSubs(subs[0], args);
13546            this._procSubs(subs[1], args);
13547        }
13548        if (this.broadcast) {
13549            this._broadcast(args);
13550        }
13551        return this.stopped ? false : true;
13552    },
13553
13554    // Requires the event-custom-complex module for full funcitonality.
13555    fireComplex: function(args) {
13556        args[0] = args[0] || {};
13557        return this.fireSimple(args);
13558    },
13559
13560    /**
13561     * Notifies a list of subscribers.
13562     *
13563     * @method _procSubs
13564     * @param subs {Array} List of subscribers
13565     * @param args {Array} Arguments passed to fire()
13566     * @param ef {}
13567     * @return Boolean false if a subscriber returns false or stops the event
13568     *              propagation via e.stopPropagation(),
13569     *              e.stopImmediatePropagation(), or e.halt()
13570     * @private
13571     */
13572    _procSubs: function(subs, args, ef) {
13573        var s, i, l;
13574
13575        for (i = 0, l = subs.length; i < l; i++) {
13576            s = subs[i];
13577            if (s && s.fn) {
13578                if (false === this._notify(s, args, ef)) {
13579                    this.stopped = 2;
13580                }
13581                if (this.stopped === 2) {
13582                    return false;
13583                }
13584            }
13585        }
13586
13587        return true;
13588    },
13589
13590    /**
13591     * Notifies the YUI instance if the event is configured with broadcast = 1,
13592     * and both the YUI instance and Y.Global if configured with broadcast = 2.
13593     *
13594     * @method _broadcast
13595     * @param args {Array} Arguments sent to fire()
13596     * @private
13597     */
13598    _broadcast: function(args) {
13599        if (!this.stopped && this.broadcast) {
13600
13601            var a = args.concat();
13602            a.unshift(this.type);
13603
13604            if (this.host !== Y) {
13605                Y.fire.apply(Y, a);
13606            }
13607
13608            if (this.broadcast === 2) {
13609                Y.Global.fire.apply(Y.Global, a);
13610            }
13611        }
13612    },
13613
13614    /**
13615     * Removes all listeners
13616     * @method unsubscribeAll
13617     * @return {Number} The number of listeners unsubscribed.
13618     * @deprecated use detachAll.
13619     */
13620    unsubscribeAll: function() {
13621        return this.detachAll.apply(this, arguments);
13622    },
13623
13624    /**
13625     * Removes all listeners
13626     * @method detachAll
13627     * @return {Number} The number of listeners unsubscribed.
13628     */
13629    detachAll: function() {
13630        return this.detach();
13631    },
13632
13633    /**
13634     * Deletes the subscriber from the internal store of on() and after()
13635     * subscribers.
13636     *
13637     * @method _delete
13638     * @param s subscriber object.
13639     * @param subs (optional) on or after subscriber array
13640     * @param index (optional) The index found.
13641     * @private
13642     */
13643    _delete: function(s, subs, i) {
13644        var when = s._when;
13645
13646        if (!subs) {
13647            subs = (when === AFTER) ? this._afters : this._subscribers;
13648        }
13649
13650        if (subs) {
13651            i = YArray.indexOf(subs, s, 0);
13652
13653            if (s && subs[i] === s) {
13654                subs.splice(i, 1);
13655            }
13656        }
13657
13658        if (this._kds) {
13659            if (when === AFTER) {
13660                delete this.afters[s.id];
13661            } else {
13662                delete this.subscribers[s.id];
13663            }
13664        }
13665
13666        if (this.monitored && this.host) {
13667            this.host._monitor('detach', this, {
13668                ce: this,
13669                sub: s
13670            });
13671        }
13672
13673        if (s) {
13674            s.deleted = true;
13675        }
13676    }
13677};
13678/**
13679 * Stores the subscriber information to be used when the event fires.
13680 * @param {Function} fn       The wrapped function to execute.
13681 * @param {Object}   context  The value of the keyword 'this' in the listener.
13682 * @param {Array} args*       0..n additional arguments to supply the listener.
13683 *
13684 * @class Subscriber
13685 * @constructor
13686 */
13687Y.Subscriber = function(fn, context, args, when) {
13688
13689    /**
13690     * The callback that will be execute when the event fires
13691     * This is wrapped by Y.rbind if obj was supplied.
13692     * @property fn
13693     * @type Function
13694     */
13695    this.fn = fn;
13696
13697    /**
13698     * Optional 'this' keyword for the listener
13699     * @property context
13700     * @type Object
13701     */
13702    this.context = context;
13703
13704    /**
13705     * Unique subscriber id
13706     * @property id
13707     * @type String
13708     */
13709    this.id = Y.guid();
13710
13711    /**
13712     * Additional arguments to propagate to the subscriber
13713     * @property args
13714     * @type Array
13715     */
13716    this.args = args;
13717
13718    this._when = when;
13719
13720    /**
13721     * Custom events for a given fire transaction.
13722     * @property events
13723     * @type {EventTarget}
13724     */
13725    // this.events = null;
13726
13727    /**
13728     * This listener only reacts to the event once
13729     * @property once
13730     */
13731    // this.once = false;
13732
13733};
13734
13735Y.Subscriber.prototype = {
13736    constructor: Y.Subscriber,
13737
13738    _notify: function(c, args, ce) {
13739        if (this.deleted && !this.postponed) {
13740            if (this.postponed) {
13741                delete this.fn;
13742                delete this.context;
13743            } else {
13744                delete this.postponed;
13745                return null;
13746            }
13747        }
13748        var a = this.args, ret;
13749        switch (ce.signature) {
13750            case 0:
13751                ret = this.fn.call(c, ce.type, args, c);
13752                break;
13753            case 1:
13754                ret = this.fn.call(c, args[0] || null, c);
13755                break;
13756            default:
13757                if (a || args) {
13758                    args = args || [];
13759                    a = (a) ? args.concat(a) : args;
13760                    ret = this.fn.apply(c, a);
13761                } else {
13762                    ret = this.fn.call(c);
13763                }
13764        }
13765
13766        if (this.once) {
13767            ce._delete(this);
13768        }
13769
13770        return ret;
13771    },
13772
13773    /**
13774     * Executes the subscriber.
13775     * @method notify
13776     * @param args {Array} Arguments array for the subscriber.
13777     * @param ce {CustomEvent} The custom event that sent the notification.
13778     */
13779    notify: function(args, ce) {
13780        var c = this.context,
13781            ret = true;
13782
13783        if (!c) {
13784            c = (ce.contextFn) ? ce.contextFn() : ce.context;
13785        }
13786
13787        // only catch errors if we will not re-throw them.
13788        if (Y.config && Y.config.throwFail) {
13789            ret = this._notify(c, args, ce);
13790        } else {
13791            try {
13792                ret = this._notify(c, args, ce);
13793            } catch (e) {
13794                Y.error(this + ' failed: ' + e.message, e);
13795            }
13796        }
13797
13798        return ret;
13799    },
13800
13801    /**
13802     * Returns true if the fn and obj match this objects properties.
13803     * Used by the unsubscribe method to match the right subscriber.
13804     *
13805     * @method contains
13806     * @param {Function} fn the function to execute.
13807     * @param {Object} context optional 'this' keyword for the listener.
13808     * @return {boolean} true if the supplied arguments match this
13809     *                   subscriber's signature.
13810     */
13811    contains: function(fn, context) {
13812        if (context) {
13813            return ((this.fn === fn) && this.context === context);
13814        } else {
13815            return (this.fn === fn);
13816        }
13817    },
13818
13819    valueOf : function() {
13820        return this.id;
13821    }
13822
13823};
13824/**
13825 * Return value from all subscribe operations
13826 * @class EventHandle
13827 * @constructor
13828 * @param {CustomEvent} evt the custom event.
13829 * @param {Subscriber} sub the subscriber.
13830 */
13831Y.EventHandle = function(evt, sub) {
13832
13833    /**
13834     * The custom event
13835     *
13836     * @property evt
13837     * @type CustomEvent
13838     */
13839    this.evt = evt;
13840
13841    /**
13842     * The subscriber object
13843     *
13844     * @property sub
13845     * @type Subscriber
13846     */
13847    this.sub = sub;
13848};
13849
13850Y.EventHandle.prototype = {
13851    batch: function(f, c) {
13852        f.call(c || this, this);
13853        if (Y.Lang.isArray(this.evt)) {
13854            Y.Array.each(this.evt, function(h) {
13855                h.batch.call(c || h, f);
13856            });
13857        }
13858    },
13859
13860    /**
13861     * Detaches this subscriber
13862     * @method detach
13863     * @return {Number} the number of detached listeners
13864     */
13865    detach: function() {
13866        var evt = this.evt, detached = 0, i;
13867        if (evt) {
13868            if (Y.Lang.isArray(evt)) {
13869                for (i = 0; i < evt.length; i++) {
13870                    detached += evt[i].detach();
13871                }
13872            } else {
13873                evt._delete(this.sub);
13874                detached = 1;
13875            }
13876
13877        }
13878
13879        return detached;
13880    },
13881
13882    /**
13883     * Monitor the event state for the subscribed event.  The first parameter
13884     * is what should be monitored, the rest are the normal parameters when
13885     * subscribing to an event.
13886     * @method monitor
13887     * @param what {string} what to monitor ('attach', 'detach', 'publish').
13888     * @return {EventHandle} return value from the monitor event subscription.
13889     */
13890    monitor: function(what) {
13891        return this.evt.monitor.apply(this.evt, arguments);
13892    }
13893};
13894
13895/**
13896 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
13897 * events.
13898 * @module event-custom
13899 * @submodule event-custom-base
13900 */
13901
13902/**
13903 * EventTarget provides the implementation for any object to
13904 * publish, subscribe and fire to custom events, and also
13905 * alows other EventTargets to target the object with events
13906 * sourced from the other object.
13907 * EventTarget is designed to be used with Y.augment to wrap
13908 * EventCustom in an interface that allows events to be listened to
13909 * and fired by name.  This makes it possible for implementing code to
13910 * subscribe to an event that either has not been created yet, or will
13911 * not be created at all.
13912 * @class EventTarget
13913 * @param opts a configuration object
13914 * @config emitFacade {boolean} if true, all events will emit event
13915 * facade payloads by default (default false)
13916 * @config prefix {String} the prefix to apply to non-prefixed event names
13917 */
13918
13919var L = Y.Lang,
13920    PREFIX_DELIMITER = ':',
13921    CATEGORY_DELIMITER = '|',
13922    AFTER_PREFIX = '~AFTER~',
13923    WILD_TYPE_RE = /(.*?)(:)(.*?)/,
13924
13925    _wildType = Y.cached(function(type) {
13926        return type.replace(WILD_TYPE_RE, "*$2$3");
13927    }),
13928
13929    /**
13930     * If the instance has a prefix attribute and the
13931     * event type is not prefixed, the instance prefix is
13932     * applied to the supplied type.
13933     * @method _getType
13934     * @private
13935     */
13936    _getType = function(type, pre) {
13937
13938        if (!pre || !type || type.indexOf(PREFIX_DELIMITER) > -1) {
13939            return type;
13940        }
13941
13942        return pre + PREFIX_DELIMITER + type;
13943    },
13944
13945    /**
13946     * Returns an array with the detach key (if provided),
13947     * and the prefixed event name from _getType
13948     * Y.on('detachcategory| menu:click', fn)
13949     * @method _parseType
13950     * @private
13951     */
13952    _parseType = Y.cached(function(type, pre) {
13953
13954        var t = type, detachcategory, after, i;
13955
13956        if (!L.isString(t)) {
13957            return t;
13958        }
13959
13960        i = t.indexOf(AFTER_PREFIX);
13961
13962        if (i > -1) {
13963            after = true;
13964            t = t.substr(AFTER_PREFIX.length);
13965        }
13966
13967        i = t.indexOf(CATEGORY_DELIMITER);
13968
13969        if (i > -1) {
13970            detachcategory = t.substr(0, (i));
13971            t = t.substr(i+1);
13972            if (t === '*') {
13973                t = null;
13974            }
13975        }
13976
13977        // detach category, full type with instance prefix, is this an after listener, short type
13978        return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
13979    }),
13980
13981    ET = function(opts) {
13982
13983        var etState = this._yuievt,
13984            etConfig;
13985
13986        if (!etState) {
13987            etState = this._yuievt = {
13988                events: {},    // PERF: Not much point instantiating lazily. We're bound to have events
13989                targets: null, // PERF: Instantiate lazily, if user actually adds target,
13990                config: {
13991                    host: this,
13992                    context: this
13993                },
13994                chain: Y.config.chain
13995            };
13996        }
13997
13998        etConfig = etState.config;
13999
14000        if (opts) {
14001            mixConfigs(etConfig, opts, true);
14002
14003            if (opts.chain !== undefined) {
14004                etState.chain = opts.chain;
14005            }
14006
14007            if (opts.prefix) {
14008                etConfig.prefix = opts.prefix;
14009            }
14010        }
14011    };
14012
14013ET.prototype = {
14014
14015    constructor: ET,
14016
14017    /**
14018     * Listen to a custom event hosted by this object one time.
14019     * This is the equivalent to <code>on</code> except the
14020     * listener is immediatelly detached when it is executed.
14021     * @method once
14022     * @param {String} type The name of the event
14023     * @param {Function} fn The callback to execute in response to the event
14024     * @param {Object} [context] Override `this` object in callback
14025     * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14026     * @return {EventHandle} A subscription handle capable of detaching the
14027     *                       subscription
14028     */
14029    once: function() {
14030        var handle = this.on.apply(this, arguments);
14031        handle.batch(function(hand) {
14032            if (hand.sub) {
14033                hand.sub.once = true;
14034            }
14035        });
14036        return handle;
14037    },
14038
14039    /**
14040     * Listen to a custom event hosted by this object one time.
14041     * This is the equivalent to <code>after</code> except the
14042     * listener is immediatelly detached when it is executed.
14043     * @method onceAfter
14044     * @param {String} type The name of the event
14045     * @param {Function} fn The callback to execute in response to the event
14046     * @param {Object} [context] Override `this` object in callback
14047     * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14048     * @return {EventHandle} A subscription handle capable of detaching that
14049     *                       subscription
14050     */
14051    onceAfter: function() {
14052        var handle = this.after.apply(this, arguments);
14053        handle.batch(function(hand) {
14054            if (hand.sub) {
14055                hand.sub.once = true;
14056            }
14057        });
14058        return handle;
14059    },
14060
14061    /**
14062     * Takes the type parameter passed to 'on' and parses out the
14063     * various pieces that could be included in the type.  If the
14064     * event type is passed without a prefix, it will be expanded
14065     * to include the prefix one is supplied or the event target
14066     * is configured with a default prefix.
14067     * @method parseType
14068     * @param {String} type the type
14069     * @param {String} [pre] The prefix. Defaults to this._yuievt.config.prefix
14070     * @since 3.3.0
14071     * @return {Array} an array containing:
14072     *  * the detach category, if supplied,
14073     *  * the prefixed event type,
14074     *  * whether or not this is an after listener,
14075     *  * the supplied event type
14076     */
14077    parseType: function(type, pre) {
14078        return _parseType(type, pre || this._yuievt.config.prefix);
14079    },
14080
14081    /**
14082     * Subscribe a callback function to a custom event fired by this object or
14083     * from an object that bubbles its events to this object.
14084     *
14085     *      this.on("change", this._onChange, this);
14086     *
14087     * Callback functions for events published with `emitFacade = true` will
14088     * receive an `EventFacade` as the first argument (typically named "e").
14089     * These callbacks can then call `e.preventDefault()` to disable the
14090     * behavior published to that event's `defaultFn`.  See the `EventFacade`
14091     * API for all available properties and methods. Subscribers to
14092     * non-`emitFacade` events will receive the arguments passed to `fire()`
14093     * after the event name.
14094     *
14095     * To subscribe to multiple events at once, pass an object as the first
14096     * argument, where the key:value pairs correspond to the eventName:callback.
14097     *
14098     *      this.on({
14099     *          "attrChange" : this._onAttrChange,
14100     *          "change"     : this._onChange
14101     *      });
14102     *
14103     * You can also pass an array of event names as the first argument to
14104     * subscribe to all listed events with the same callback.
14105     *
14106     *      this.on([ "change", "attrChange" ], this._onChange);
14107     *
14108     * Returning `false` from a callback is supported as an alternative to
14109     * calling `e.preventDefault(); e.stopPropagation();`.  However, it is
14110     * recommended to use the event methods whenever possible.
14111     *
14112     * @method on
14113     * @param {String} type The name of the event
14114     * @param {Function} fn The callback to execute in response to the event
14115     * @param {Object} [context] Override `this` object in callback
14116     * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14117     * @return {EventHandle} A subscription handle capable of detaching that
14118     *                       subscription
14119     */
14120    on: function(type, fn, context) {
14121
14122        var yuievt = this._yuievt,
14123            parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce,
14124            detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
14125            Node = Y.Node, n, domevent, isArr;
14126
14127        // full name, args, detachcategory, after
14128        this._monitor('attach', parts[1], {
14129            args: arguments,
14130            category: parts[0],
14131            after: parts[2]
14132        });
14133
14134        if (L.isObject(type)) {
14135
14136            if (L.isFunction(type)) {
14137                return Y.Do.before.apply(Y.Do, arguments);
14138            }
14139
14140            f = fn;
14141            c = context;
14142            args = nativeSlice.call(arguments, 0);
14143            ret = [];
14144
14145            if (L.isArray(type)) {
14146                isArr = true;
14147            }
14148
14149            after = type._after;
14150            delete type._after;
14151
14152            Y.each(type, function(v, k) {
14153
14154                if (L.isObject(v)) {
14155                    f = v.fn || ((L.isFunction(v)) ? v : f);
14156                    c = v.context || c;
14157                }
14158
14159                var nv = (after) ? AFTER_PREFIX : '';
14160
14161                args[0] = nv + ((isArr) ? v : k);
14162                args[1] = f;
14163                args[2] = c;
14164
14165                ret.push(this.on.apply(this, args));
14166
14167            }, this);
14168
14169            return (yuievt.chain) ? this : new Y.EventHandle(ret);
14170        }
14171
14172        detachcategory = parts[0];
14173        after = parts[2];
14174        shorttype = parts[3];
14175
14176        // extra redirection so we catch adaptor events too.  take a look at this.
14177        if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
14178            args = nativeSlice.call(arguments, 0);
14179            args.splice(2, 0, Node.getDOMNode(this));
14180            return Y.on.apply(Y, args);
14181        }
14182
14183        type = parts[1];
14184
14185        if (Y.instanceOf(this, YUI)) {
14186
14187            adapt = Y.Env.evt.plugins[type];
14188            args  = nativeSlice.call(arguments, 0);
14189            args[0] = shorttype;
14190
14191            if (Node) {
14192                n = args[2];
14193
14194                if (Y.instanceOf(n, Y.NodeList)) {
14195                    n = Y.NodeList.getDOMNodes(n);
14196                } else if (Y.instanceOf(n, Node)) {
14197                    n = Node.getDOMNode(n);
14198                }
14199
14200                domevent = (shorttype in Node.DOM_EVENTS);
14201
14202                // Captures both DOM events and event plugins.
14203                if (domevent) {
14204                    args[2] = n;
14205                }
14206            }
14207
14208            // check for the existance of an event adaptor
14209            if (adapt) {
14210                handle = adapt.on.apply(Y, args);
14211            } else if ((!type) || domevent) {
14212                handle = Y.Event._attach(args);
14213            }
14214
14215        }
14216
14217        if (!handle) {
14218            ce = yuievt.events[type] || this.publish(type);
14219            handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true);
14220
14221            // TODO: More robust regex, accounting for category
14222            if (type.indexOf("*:") !== -1) {
14223                this._hasSiblings = true;
14224            }
14225        }
14226
14227        if (detachcategory) {
14228            store[detachcategory] = store[detachcategory] || {};
14229            store[detachcategory][type] = store[detachcategory][type] || [];
14230            store[detachcategory][type].push(handle);
14231        }
14232
14233        return (yuievt.chain) ? this : handle;
14234
14235    },
14236
14237    /**
14238     * subscribe to an event
14239     * @method subscribe
14240     * @deprecated use on
14241     */
14242    subscribe: function() {
14243        return this.on.apply(this, arguments);
14244    },
14245
14246    /**
14247     * Detach one or more listeners the from the specified event
14248     * @method detach
14249     * @param type {string|Object}   Either the handle to the subscriber or the
14250     *                        type of event.  If the type
14251     *                        is not specified, it will attempt to remove
14252     *                        the listener from all hosted events.
14253     * @param fn   {Function} The subscribed function to unsubscribe, if not
14254     *                          supplied, all subscribers will be removed.
14255     * @param context  {Object}   The custom object passed to subscribe.  This is
14256     *                        optional, but if supplied will be used to
14257     *                        disambiguate multiple listeners that are the same
14258     *                        (e.g., you subscribe many object using a function
14259     *                        that lives on the prototype)
14260     * @return {EventTarget} the host
14261     */
14262    detach: function(type, fn, context) {
14263
14264        var evts = this._yuievt.events,
14265            i,
14266            Node = Y.Node,
14267            isNode = Node && (Y.instanceOf(this, Node));
14268
14269        // detachAll disabled on the Y instance.
14270        if (!type && (this !== Y)) {
14271            for (i in evts) {
14272                if (evts.hasOwnProperty(i)) {
14273                    evts[i].detach(fn, context);
14274                }
14275            }
14276            if (isNode) {
14277                Y.Event.purgeElement(Node.getDOMNode(this));
14278            }
14279
14280            return this;
14281        }
14282
14283        var parts = _parseType(type, this._yuievt.config.prefix),
14284        detachcategory = L.isArray(parts) ? parts[0] : null,
14285        shorttype = (parts) ? parts[3] : null,
14286        adapt, store = Y.Env.evt.handles, detachhost, cat, args,
14287        ce,
14288
14289        keyDetacher = function(lcat, ltype, host) {
14290            var handles = lcat[ltype], ce, i;
14291            if (handles) {
14292                for (i = handles.length - 1; i >= 0; --i) {
14293                    ce = handles[i].evt;
14294                    if (ce.host === host || ce.el === host) {
14295                        handles[i].detach();
14296                    }
14297                }
14298            }
14299        };
14300
14301        if (detachcategory) {
14302
14303            cat = store[detachcategory];
14304            type = parts[1];
14305            detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
14306
14307            if (cat) {
14308                if (type) {
14309                    keyDetacher(cat, type, detachhost);
14310                } else {
14311                    for (i in cat) {
14312                        if (cat.hasOwnProperty(i)) {
14313                            keyDetacher(cat, i, detachhost);
14314                        }
14315                    }
14316                }
14317
14318                return this;
14319            }
14320
14321        // If this is an event handle, use it to detach
14322        } else if (L.isObject(type) && type.detach) {
14323            type.detach();
14324            return this;
14325        // extra redirection so we catch adaptor events too.  take a look at this.
14326        } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
14327            args = nativeSlice.call(arguments, 0);
14328            args[2] = Node.getDOMNode(this);
14329            Y.detach.apply(Y, args);
14330            return this;
14331        }
14332
14333        adapt = Y.Env.evt.plugins[shorttype];
14334
14335        // The YUI instance handles DOM events and adaptors
14336        if (Y.instanceOf(this, YUI)) {
14337            args = nativeSlice.call(arguments, 0);
14338            // use the adaptor specific detach code if
14339            if (adapt && adapt.detach) {
14340                adapt.detach.apply(Y, args);
14341                return this;
14342            // DOM event fork
14343            } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
14344                args[0] = type;
14345                Y.Event.detach.apply(Y.Event, args);
14346                return this;
14347            }
14348        }
14349
14350        // ce = evts[type];
14351        ce = evts[parts[1]];
14352        if (ce) {
14353            ce.detach(fn, context);
14354        }
14355
14356        return this;
14357    },
14358
14359    /**
14360     * detach a listener
14361     * @method unsubscribe
14362     * @deprecated use detach
14363     */
14364    unsubscribe: function() {
14365        return this.detach.apply(this, arguments);
14366    },
14367
14368    /**
14369     * Removes all listeners from the specified event.  If the event type
14370     * is not specified, all listeners from all hosted custom events will
14371     * be removed.
14372     * @method detachAll
14373     * @param type {String}   The type, or name of the event
14374     */
14375    detachAll: function(type) {
14376        return this.detach(type);
14377    },
14378
14379    /**
14380     * Removes all listeners from the specified event.  If the event type
14381     * is not specified, all listeners from all hosted custom events will
14382     * be removed.
14383     * @method unsubscribeAll
14384     * @param type {String}   The type, or name of the event
14385     * @deprecated use detachAll
14386     */
14387    unsubscribeAll: function() {
14388        return this.detachAll.apply(this, arguments);
14389    },
14390
14391    /**
14392     * Creates a new custom event of the specified type.  If a custom event
14393     * by that name already exists, it will not be re-created.  In either
14394     * case the custom event is returned.
14395     *
14396     * @method publish
14397     *
14398     * @param type {String} the type, or name of the event
14399     * @param opts {object} optional config params.  Valid properties are:
14400     * @param [opts.broadcast=false] {Boolean} whether or not the YUI instance and YUI global
14401     *      are notified when the event is fired.
14402     * @param [opts.bubbles=true] {Boolean} Whether or not this event bubbles. Events can
14403     *      only bubble if `emitFacade` is true.
14404     * @param [opts.context=this] {Object} the default execution context for the listeners.
14405     * @param [opts.defaultFn] {Function} the default function to execute when this event
14406     *      fires if preventDefault was not called.
14407     * @param [opts.emitFacade=false] {Boolean} whether or not this event emits a facade.
14408     * @param [opts.prefix] {String} the prefix for this targets events, e.g., 'menu' in 'menu:click'.
14409     * @param [opts.fireOnce=false] {Boolean} if an event is configured to fire once,
14410     *      new subscribers after the fire will be notified immediately.
14411     * @param [opts.async=false] {Boolean} fireOnce event listeners will fire synchronously
14412     *      if the event has already fired unless `async` is `true`.
14413     * @param [opts.preventable=true] {Boolean} whether or not `preventDefault()` has an effect.
14414     * @param [opts.preventedFn] {Function} a function that is executed when `preventDefault()` is called.
14415     * @param [opts.queuable=false] {Boolean} whether or not this event can be queued during bubbling.
14416     * @param [opts.silent] {Boolean} if silent is true, debug messages are not provided for this event.
14417     * @param [opts.stoppedFn] {Function} a function that is executed when stopPropagation is called.
14418     * @param [opts.monitored] {Boolean} specifies whether or not this event should send notifications about
14419     *      when the event has been attached, detached, or published.
14420     * @param [opts.type] {String} the event type (valid option if not provided as the first parameter to publish).
14421     *
14422     * @return {CustomEvent} the custom event
14423     *
14424     */
14425    publish: function(type, opts) {
14426
14427        var ret,
14428            etState = this._yuievt,
14429            etConfig = etState.config,
14430            pre = etConfig.prefix;
14431
14432        if (typeof type === "string")  {
14433            if (pre) {
14434                type = _getType(type, pre);
14435            }
14436            ret = this._publish(type, etConfig, opts);
14437        } else {
14438            ret = {};
14439
14440            Y.each(type, function(v, k) {
14441                if (pre) {
14442                    k = _getType(k, pre);
14443                }
14444                ret[k] = this._publish(k, etConfig, v || opts);
14445            }, this);
14446
14447        }
14448
14449        return ret;
14450    },
14451
14452    /**
14453     * Returns the fully qualified type, given a short type string.
14454     * That is, returns "foo:bar" when given "bar" if "foo" is the configured prefix.
14455     *
14456     * NOTE: This method, unlike _getType, does no checking of the value passed in, and
14457     * is designed to be used with the low level _publish() method, for critical path
14458     * implementations which need to fast-track publish for performance reasons.
14459     *
14460     * @method _getFullType
14461     * @private
14462     * @param {String} type The short type to prefix
14463     * @return {String} The prefixed type, if a prefix is set, otherwise the type passed in
14464     */
14465    _getFullType : function(type) {
14466
14467        var pre = this._yuievt.config.prefix;
14468
14469        if (pre) {
14470            return pre + PREFIX_DELIMITER + type;
14471        } else {
14472            return type;
14473        }
14474    },
14475
14476    /**
14477     * The low level event publish implementation. It expects all the massaging to have been done
14478     * outside of this method. e.g. the `type` to `fullType` conversion. It's designed to be a fast
14479     * path publish, which can be used by critical code paths to improve performance.
14480     *
14481     * @method _publish
14482     * @private
14483     * @param {String} fullType The prefixed type of the event to publish.
14484     * @param {Object} etOpts The EventTarget specific configuration to mix into the published event.
14485     * @param {Object} ceOpts The publish specific configuration to mix into the published event.
14486     * @return {CustomEvent} The published event. If called without `etOpts` or `ceOpts`, this will
14487     * be the default `CustomEvent` instance, and can be configured independently.
14488     */
14489    _publish : function(fullType, etOpts, ceOpts) {
14490
14491        var ce,
14492            etState = this._yuievt,
14493            etConfig = etState.config,
14494            host = etConfig.host,
14495            context = etConfig.context,
14496            events = etState.events;
14497
14498        ce = events[fullType];
14499
14500        // PERF: Hate to pull the check out of monitor, but trying to keep critical path tight.
14501        if ((etConfig.monitored && !ce) || (ce && ce.monitored)) {
14502            this._monitor('publish', fullType, {
14503                args: arguments
14504            });
14505        }
14506
14507        if (!ce) {
14508            // Publish event
14509            ce = events[fullType] = new Y.CustomEvent(fullType, etOpts);
14510
14511            if (!etOpts) {
14512                ce.host = host;
14513                ce.context = context;
14514            }
14515        }
14516
14517        if (ceOpts) {
14518            mixConfigs(ce, ceOpts, true);
14519        }
14520
14521        return ce;
14522    },
14523
14524    /**
14525     * This is the entry point for the event monitoring system.
14526     * You can monitor 'attach', 'detach', 'fire', and 'publish'.
14527     * When configured, these events generate an event.  click ->
14528     * click_attach, click_detach, click_publish -- these can
14529     * be subscribed to like other events to monitor the event
14530     * system.  Inividual published events can have monitoring
14531     * turned on or off (publish can't be turned off before it
14532     * it published) by setting the events 'monitor' config.
14533     *
14534     * @method _monitor
14535     * @param what {String} 'attach', 'detach', 'fire', or 'publish'
14536     * @param eventType {String|CustomEvent} The prefixed name of the event being monitored, or the CustomEvent object.
14537     * @param o {Object} Information about the event interaction, such as
14538     *                  fire() args, subscription category, publish config
14539     * @private
14540     */
14541    _monitor: function(what, eventType, o) {
14542        var monitorevt, ce, type;
14543
14544        if (eventType) {
14545            if (typeof eventType === "string") {
14546                type = eventType;
14547                ce = this.getEvent(eventType, true);
14548            } else {
14549                ce = eventType;
14550                type = eventType.type;
14551            }
14552
14553            if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
14554                monitorevt = type + '_' + what;
14555                o.monitored = what;
14556                this.fire.call(this, monitorevt, o);
14557            }
14558        }
14559    },
14560
14561    /**
14562     * Fire a custom event by name.  The callback functions will be executed
14563     * from the context specified when the event was created, and with the
14564     * following parameters.
14565     *
14566     * The first argument is the event type, and any additional arguments are
14567     * passed to the listeners as parameters.  If the first of these is an
14568     * object literal, and the event is configured to emit an event facade,
14569     * that object is mixed into the event facade and the facade is provided
14570     * in place of the original object.
14571     *
14572     * If the custom event object hasn't been created, then the event hasn't
14573     * been published and it has no subscribers.  For performance sake, we
14574     * immediate exit in this case.  This means the event won't bubble, so
14575     * if the intention is that a bubble target be notified, the event must
14576     * be published on this object first.
14577     *
14578     * @method fire
14579     * @param type {String|Object} The type of the event, or an object that contains
14580     * a 'type' property.
14581     * @param arguments {Object*} an arbitrary set of parameters to pass to
14582     * the handler.  If the first of these is an object literal and the event is
14583     * configured to emit an event facade, the event facade will replace that
14584     * parameter after the properties the object literal contains are copied to
14585     * the event facade.
14586     * @return {Boolean} True if the whole lifecycle of the event went through,
14587     * false if at any point the event propagation was halted.
14588     */
14589    fire: function(type) {
14590
14591        var typeIncluded = (typeof type === "string"),
14592            argCount = arguments.length,
14593            t = type,
14594            yuievt = this._yuievt,
14595            etConfig = yuievt.config,
14596            pre = etConfig.prefix,
14597            ret,
14598            ce,
14599            ce2,
14600            args;
14601
14602        if (typeIncluded && argCount <= 3) {
14603
14604            // PERF: Try to avoid slice/iteration for the common signatures
14605
14606            // Most common
14607            if (argCount === 2) {
14608                args = [arguments[1]]; // fire("foo", {})
14609            } else if (argCount === 3) {
14610                args = [arguments[1], arguments[2]]; // fire("foo", {}, opts)
14611            } else {
14612                args = []; // fire("foo")
14613            }
14614
14615        } else {
14616            args = nativeSlice.call(arguments, ((typeIncluded) ? 1 : 0));
14617        }
14618
14619        if (!typeIncluded) {
14620            t = (type && type.type);
14621        }
14622
14623        if (pre) {
14624            t = _getType(t, pre);
14625        }
14626
14627        ce = yuievt.events[t];
14628
14629        if (this._hasSiblings) {
14630            ce2 = this.getSibling(t, ce);
14631
14632            if (ce2 && !ce) {
14633                ce = this.publish(t);
14634            }
14635        }
14636
14637        // PERF: trying to avoid function call, since this is a critical path
14638        if ((etConfig.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
14639            this._monitor('fire', (ce || t), {
14640                args: args
14641            });
14642        }
14643
14644        // this event has not been published or subscribed to
14645        if (!ce) {
14646            if (yuievt.hasTargets) {
14647                return this.bubble({ type: t }, args, this);
14648            }
14649
14650            // otherwise there is nothing to be done
14651            ret = true;
14652        } else {
14653
14654            if (ce2) {
14655                ce.sibling = ce2;
14656            }
14657
14658            ret = ce._fire(args);
14659        }
14660
14661        return (yuievt.chain) ? this : ret;
14662    },
14663
14664    getSibling: function(type, ce) {
14665        var ce2;
14666
14667        // delegate to *:type events if there are subscribers
14668        if (type.indexOf(PREFIX_DELIMITER) > -1) {
14669            type = _wildType(type);
14670            ce2 = this.getEvent(type, true);
14671            if (ce2) {
14672                ce2.applyConfig(ce);
14673                ce2.bubbles = false;
14674                ce2.broadcast = 0;
14675            }
14676        }
14677
14678        return ce2;
14679    },
14680
14681    /**
14682     * Returns the custom event of the provided type has been created, a
14683     * falsy value otherwise
14684     * @method getEvent
14685     * @param type {String} the type, or name of the event
14686     * @param prefixed {String} if true, the type is prefixed already
14687     * @return {CustomEvent} the custom event or null
14688     */
14689    getEvent: function(type, prefixed) {
14690        var pre, e;
14691
14692        if (!prefixed) {
14693            pre = this._yuievt.config.prefix;
14694            type = (pre) ? _getType(type, pre) : type;
14695        }
14696        e = this._yuievt.events;
14697        return e[type] || null;
14698    },
14699
14700    /**
14701     * Subscribe to a custom event hosted by this object.  The
14702     * supplied callback will execute after any listeners add
14703     * via the subscribe method, and after the default function,
14704     * if configured for the event, has executed.
14705     *
14706     * @method after
14707     * @param {String} type The name of the event
14708     * @param {Function} fn The callback to execute in response to the event
14709     * @param {Object} [context] Override `this` object in callback
14710     * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14711     * @return {EventHandle} A subscription handle capable of detaching the
14712     *                       subscription
14713     */
14714    after: function(type, fn) {
14715
14716        var a = nativeSlice.call(arguments, 0);
14717
14718        switch (L.type(type)) {
14719            case 'function':
14720                return Y.Do.after.apply(Y.Do, arguments);
14721            case 'array':
14722            //     YArray.each(a[0], function(v) {
14723            //         v = AFTER_PREFIX + v;
14724            //     });
14725            //     break;
14726            case 'object':
14727                a[0]._after = true;
14728                break;
14729            default:
14730                a[0] = AFTER_PREFIX + type;
14731        }
14732
14733        return this.on.apply(this, a);
14734
14735    },
14736
14737    /**
14738     * Executes the callback before a DOM event, custom event
14739     * or method.  If the first argument is a function, it
14740     * is assumed the target is a method.  For DOM and custom
14741     * events, this is an alias for Y.on.
14742     *
14743     * For DOM and custom events:
14744     * type, callback, context, 0-n arguments
14745     *
14746     * For methods:
14747     * callback, object (method host), methodName, context, 0-n arguments
14748     *
14749     * @method before
14750     * @return detach handle
14751     */
14752    before: function() {
14753        return this.on.apply(this, arguments);
14754    }
14755
14756};
14757
14758Y.EventTarget = ET;
14759
14760// make Y an event target
14761Y.mix(Y, ET.prototype);
14762ET.call(Y, { bubbles: false });
14763
14764YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
14765
14766/**
14767 * Hosts YUI page level events.  This is where events bubble to
14768 * when the broadcast config is set to 2.  This property is
14769 * only available if the custom event module is loaded.
14770 * @property Global
14771 * @type EventTarget
14772 * @for YUI
14773 */
14774Y.Global = YUI.Env.globalEvents;
14775
14776// @TODO implement a global namespace function on Y.Global?
14777
14778/**
14779`Y.on()` can do many things:
14780
14781<ul>
14782    <li>Subscribe to custom events `publish`ed and `fire`d from Y</li>
14783    <li>Subscribe to custom events `publish`ed with `broadcast` 1 or 2 and
14784        `fire`d from any object in the YUI instance sandbox</li>
14785    <li>Subscribe to DOM events</li>
14786    <li>Subscribe to the execution of a method on any object, effectively
14787    treating that method as an event</li>
14788</ul>
14789
14790For custom event subscriptions, pass the custom event name as the first argument
14791and callback as the second. The `this` object in the callback will be `Y` unless
14792an override is passed as the third argument.
14793
14794    Y.on('io:complete', function () {
14795        Y.MyApp.updateStatus('Transaction complete');
14796    });
14797
14798To subscribe to DOM events, pass the name of a DOM event as the first argument
14799and a CSS selector string as the third argument after the callback function.
14800Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`,
14801array, or simply omitted (the default is the `window` object).
14802
14803    Y.on('click', function (e) {
14804        e.preventDefault();
14805
14806        // proceed with ajax form submission
14807        var url = this.get('action');
14808        ...
14809    }, '#my-form');
14810
14811The `this` object in DOM event callbacks will be the `Node` targeted by the CSS
14812selector or other identifier.
14813
14814`on()` subscribers for DOM events or custom events `publish`ed with a
14815`defaultFn` can prevent the default behavior with `e.preventDefault()` from the
14816event object passed as the first parameter to the subscription callback.
14817
14818To subscribe to the execution of an object method, pass arguments corresponding to the call signature for
14819<a href="../classes/Do.html#methods_before">`Y.Do.before(...)`</a>.
14820
14821NOTE: The formal parameter list below is for events, not for function
14822injection.  See `Y.Do.before` for that signature.
14823
14824@method on
14825@param {String} type DOM or custom event name
14826@param {Function} fn The callback to execute in response to the event
14827@param {Object} [context] Override `this` object in callback
14828@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14829@return {EventHandle} A subscription handle capable of detaching the
14830                      subscription
14831@see Do.before
14832@for YUI
14833**/
14834
14835/**
14836Listen for an event one time.  Equivalent to `on()`, except that
14837the listener is immediately detached when executed.
14838
14839See the <a href="#methods_on">`on()` method</a> for additional subscription
14840options.
14841
14842@see on
14843@method once
14844@param {String} type DOM or custom event name
14845@param {Function} fn The callback to execute in response to the event
14846@param {Object} [context] Override `this` object in callback
14847@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14848@return {EventHandle} A subscription handle capable of detaching the
14849                      subscription
14850@for YUI
14851**/
14852
14853/**
14854Listen for an event one time.  Equivalent to `once()`, except, like `after()`,
14855the subscription callback executes after all `on()` subscribers and the event's
14856`defaultFn` (if configured) have executed.  Like `after()` if any `on()` phase
14857subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()`
14858subscribers will execute.
14859
14860The listener is immediately detached when executed.
14861
14862See the <a href="#methods_on">`on()` method</a> for additional subscription
14863options.
14864
14865@see once
14866@method onceAfter
14867@param {String} type The custom event name
14868@param {Function} fn The callback to execute in response to the event
14869@param {Object} [context] Override `this` object in callback
14870@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
14871@return {EventHandle} A subscription handle capable of detaching the
14872                      subscription
14873@for YUI
14874**/
14875
14876/**
14877Like `on()`, this method creates a subscription to a custom event or to the
14878execution of a method on an object.
14879
14880For events, `after()` subscribers are executed after the event's
14881`defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber.
14882
14883See the <a href="#methods_on">`on()` method</a> for additional subscription
14884options.
14885
14886NOTE: The subscription signature shown is for events, not for function
14887injection.  See <a href="../classes/Do.html#methods_after">`Y.Do.after`</a>
14888for that signature.
14889
14890@see on
14891@see Do.after
14892@method after
14893@param {String} type The custom event name
14894@param {Function} fn The callback to execute in response to the event
14895@param {Object} [context] Override `this` object in callback
14896@param {Any} [args*] 0..n additional arguments to supply to the subscriber
14897@return {EventHandle} A subscription handle capable of detaching the
14898                      subscription
14899@for YUI
14900**/
14901
14902
14903}, '3.18.1', {"requires": ["oop"]});
14904YUI.add('dom-core', function (Y, NAME) {
14905
14906var NODE_TYPE = 'nodeType',
14907    OWNER_DOCUMENT = 'ownerDocument',
14908    DOCUMENT_ELEMENT = 'documentElement',
14909    DEFAULT_VIEW = 'defaultView',
14910    PARENT_WINDOW = 'parentWindow',
14911    TAG_NAME = 'tagName',
14912    PARENT_NODE = 'parentNode',
14913    PREVIOUS_SIBLING = 'previousSibling',
14914    NEXT_SIBLING = 'nextSibling',
14915    CONTAINS = 'contains',
14916    COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
14917    EMPTY_ARRAY = [],
14918
14919    // IE < 8 throws on node.contains(textNode)
14920    supportsContainsTextNode = (function() {
14921        var node = Y.config.doc.createElement('div'),
14922            textNode = node.appendChild(Y.config.doc.createTextNode('')),
14923            result = false;
14924
14925        try {
14926            result = node.contains(textNode);
14927        } catch(e) {}
14928
14929        return result;
14930    })(),
14931
14932/**
14933 * The DOM utility provides a cross-browser abtraction layer
14934 * normalizing DOM tasks, and adds extra helper functionality
14935 * for other common tasks.
14936 * @module dom
14937 * @main dom
14938 * @submodule dom-base
14939 * @for DOM
14940 *
14941 */
14942
14943/**
14944 * Provides DOM helper methods.
14945 * @class DOM
14946 *
14947 */
14948
14949Y_DOM = {
14950    /**
14951     * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
14952     * @method byId
14953     * @param {String} id the id attribute
14954     * @param {Object} doc optional The document to search. Defaults to current document
14955     * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
14956     */
14957    byId: function(id, doc) {
14958        // handle dupe IDs and IE name collision
14959        return Y_DOM.allById(id, doc)[0] || null;
14960    },
14961
14962    getId: function(node) {
14963        var id;
14964        // HTMLElement returned from FORM when INPUT name === "id"
14965        // IE < 8: HTMLCollection returned when INPUT id === "id"
14966        // via both getAttribute and form.id
14967        if (node.id && !node.id.tagName && !node.id.item) {
14968            id = node.id;
14969        } else if (node.attributes && node.attributes.id) {
14970            id = node.attributes.id.value;
14971        }
14972
14973        return id;
14974    },
14975
14976    setId: function(node, id) {
14977        if (node.setAttribute) {
14978            node.setAttribute('id', id);
14979        } else {
14980            node.id = id;
14981        }
14982    },
14983
14984    /*
14985     * Finds the ancestor of the element.
14986     * @method ancestor
14987     * @param {HTMLElement} element The html element.
14988     * @param {Function} fn optional An optional boolean test to apply.
14989     * The optional function is passed the current DOM node being tested as its only argument.
14990     * If no function is given, the parentNode is returned.
14991     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
14992     * @return {HTMLElement | null} The matching DOM node or null if none found.
14993     */
14994    ancestor: function(element, fn, testSelf, stopFn) {
14995        var ret = null;
14996        if (testSelf) {
14997            ret = (!fn || fn(element)) ? element : null;
14998
14999        }
15000        return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null, stopFn);
15001    },
15002
15003    /*
15004     * Finds the ancestors of the element.
15005     * @method ancestors
15006     * @param {HTMLElement} element The html element.
15007     * @param {Function} fn optional An optional boolean test to apply.
15008     * The optional function is passed the current DOM node being tested as its only argument.
15009     * If no function is given, all ancestors are returned.
15010     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
15011     * @return {Array} An array containing all matching DOM nodes.
15012     */
15013    ancestors: function(element, fn, testSelf, stopFn) {
15014        var ancestor = element,
15015            ret = [];
15016
15017        while ((ancestor = Y_DOM.ancestor(ancestor, fn, testSelf, stopFn))) {
15018            testSelf = false;
15019            if (ancestor) {
15020                ret.unshift(ancestor);
15021
15022                if (stopFn && stopFn(ancestor)) {
15023                    return ret;
15024                }
15025            }
15026        }
15027
15028        return ret;
15029    },
15030
15031    /**
15032     * Searches the element by the given axis for the first matching element.
15033     * @method elementByAxis
15034     * @param {HTMLElement} element The html element.
15035     * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
15036     * @param {Function} [fn] An optional boolean test to apply.
15037     * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or
15038     * just element nodes will be returned(default)
15039     * The optional function is passed the current HTMLElement being tested as its only argument.
15040     * If no function is given, the first element is returned.
15041     * @return {HTMLElement | null} The matching element or null if none found.
15042     */
15043    elementByAxis: function(element, axis, fn, all, stopAt) {
15044        while (element && (element = element[axis])) { // NOTE: assignment
15045                if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
15046                    return element;
15047                }
15048
15049                if (stopAt && stopAt(element)) {
15050                    return null;
15051                }
15052        }
15053        return null;
15054    },
15055
15056    /**
15057     * Determines whether or not one HTMLElement is or contains another HTMLElement.
15058     * @method contains
15059     * @param {HTMLElement} element The containing html element.
15060     * @param {HTMLElement} needle The html element that may be contained.
15061     * @return {Boolean} Whether or not the element is or contains the needle.
15062     */
15063    contains: function(element, needle) {
15064        var ret = false;
15065
15066        if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
15067            ret = false;
15068        } else if (element[CONTAINS] &&
15069                // IE < 8 throws on node.contains(textNode) so fall back to brute.
15070                // Falling back for other nodeTypes as well.
15071                (needle[NODE_TYPE] === 1 || supportsContainsTextNode)) {
15072                ret = element[CONTAINS](needle);
15073        } else if (element[COMPARE_DOCUMENT_POSITION]) {
15074            // Match contains behavior (node.contains(node) === true).
15075            // Needed for Firefox < 4.
15076            if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
15077                ret = true;
15078            }
15079        } else {
15080            ret = Y_DOM._bruteContains(element, needle);
15081        }
15082
15083        return ret;
15084    },
15085
15086    /**
15087     * Determines whether or not the HTMLElement is part of the document.
15088     * @method inDoc
15089     * @param {HTMLElement} element The containing html element.
15090     * @param {HTMLElement} doc optional The document to check.
15091     * @return {Boolean} Whether or not the element is attached to the document.
15092     */
15093    inDoc: function(element, doc) {
15094        var ret = false,
15095            rootNode;
15096
15097        if (element && element.nodeType) {
15098            (doc) || (doc = element[OWNER_DOCUMENT]);
15099
15100            rootNode = doc[DOCUMENT_ELEMENT];
15101
15102            // contains only works with HTML_ELEMENT
15103            if (rootNode && rootNode.contains && element.tagName) {
15104                ret = rootNode.contains(element);
15105            } else {
15106                ret = Y_DOM.contains(rootNode, element);
15107            }
15108        }
15109
15110        return ret;
15111
15112    },
15113
15114   allById: function(id, root) {
15115        root = root || Y.config.doc;
15116        var nodes = [],
15117            ret = [],
15118            i,
15119            node;
15120
15121        if (root.querySelectorAll) {
15122            ret = root.querySelectorAll('[id="' + id + '"]');
15123        } else if (root.all) {
15124            nodes = root.all(id);
15125
15126            if (nodes) {
15127                // root.all may return HTMLElement or HTMLCollection.
15128                // some elements are also HTMLCollection (FORM, SELECT).
15129                if (nodes.nodeName) {
15130                    if (nodes.id === id) { // avoid false positive on name
15131                        ret.push(nodes);
15132                        nodes = EMPTY_ARRAY; // done, no need to filter
15133                    } else { //  prep for filtering
15134                        nodes = [nodes];
15135                    }
15136                }
15137
15138                if (nodes.length) {
15139                    // filter out matches on node.name
15140                    // and element.id as reference to element with id === 'id'
15141                    for (i = 0; node = nodes[i++];) {
15142                        if (node.id === id  ||
15143                                (node.attributes && node.attributes.id &&
15144                                node.attributes.id.value === id)) {
15145                            ret.push(node);
15146                        }
15147                    }
15148                }
15149            }
15150        } else {
15151            ret = [Y_DOM._getDoc(root).getElementById(id)];
15152        }
15153
15154        return ret;
15155   },
15156
15157
15158    isWindow: function(obj) {
15159        return !!(obj && obj.scrollTo && obj.document);
15160    },
15161
15162    _removeChildNodes: function(node) {
15163        while (node.firstChild) {
15164            node.removeChild(node.firstChild);
15165        }
15166    },
15167
15168    siblings: function(node, fn) {
15169        var nodes = [],
15170            sibling = node;
15171
15172        while ((sibling = sibling[PREVIOUS_SIBLING])) {
15173            if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
15174                nodes.unshift(sibling);
15175            }
15176        }
15177
15178        sibling = node;
15179        while ((sibling = sibling[NEXT_SIBLING])) {
15180            if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
15181                nodes.push(sibling);
15182            }
15183        }
15184
15185        return nodes;
15186    },
15187
15188    /**
15189     * Brute force version of contains.
15190     * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
15191     * @method _bruteContains
15192     * @private
15193     * @param {HTMLElement} element The containing html element.
15194     * @param {HTMLElement} needle The html element that may be contained.
15195     * @return {Boolean} Whether or not the element is or contains the needle.
15196     */
15197    _bruteContains: function(element, needle) {
15198        while (needle) {
15199            if (element === needle) {
15200                return true;
15201            }
15202            needle = needle.parentNode;
15203        }
15204        return false;
15205    },
15206
15207// TODO: move to Lang?
15208    /**
15209     * Memoizes dynamic regular expressions to boost runtime performance.
15210     * @method _getRegExp
15211     * @private
15212     * @param {String} str The string to convert to a regular expression.
15213     * @param {String} flags optional An optinal string of flags.
15214     * @return {RegExp} An instance of RegExp
15215     */
15216    _getRegExp: function(str, flags) {
15217        flags = flags || '';
15218        Y_DOM._regexCache = Y_DOM._regexCache || {};
15219        if (!Y_DOM._regexCache[str + flags]) {
15220            Y_DOM._regexCache[str + flags] = new RegExp(str, flags);
15221        }
15222        return Y_DOM._regexCache[str + flags];
15223    },
15224
15225// TODO: make getDoc/Win true privates?
15226    /**
15227     * returns the appropriate document.
15228     * @method _getDoc
15229     * @private
15230     * @param {HTMLElement} element optional Target element.
15231     * @return {Object} The document for the given element or the default document.
15232     */
15233    _getDoc: function(element) {
15234        var doc = Y.config.doc;
15235        if (element) {
15236            doc = (element[NODE_TYPE] === 9) ? element : // element === document
15237                element[OWNER_DOCUMENT] || // element === DOM node
15238                element.document || // element === window
15239                Y.config.doc; // default
15240        }
15241
15242        return doc;
15243    },
15244
15245    /**
15246     * returns the appropriate window.
15247     * @method _getWin
15248     * @private
15249     * @param {HTMLElement} element optional Target element.
15250     * @return {Object} The window for the given element or the default window.
15251     */
15252    _getWin: function(element) {
15253        var doc = Y_DOM._getDoc(element);
15254        return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
15255    },
15256
15257    _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
15258        fn = (typeof fn === 'string') ? Y_DOM[fn] : fn;
15259        var result,
15260            i = 0,
15261            node,
15262            ret;
15263
15264        if (fn && nodes) {
15265            while ((node = nodes[i++])) {
15266                result = result = fn.call(Y_DOM, node, arg1, arg2, arg3, etc);
15267                if (typeof result !== 'undefined') {
15268                    (ret) || (ret = []);
15269                    ret.push(result);
15270                }
15271            }
15272        }
15273
15274        return (typeof ret !== 'undefined') ? ret : nodes;
15275    },
15276
15277    generateID: function(el) {
15278        var id = el.id;
15279
15280        if (!id) {
15281            id = Y.stamp(el);
15282            el.id = id;
15283        }
15284
15285        return id;
15286    }
15287};
15288
15289
15290Y.DOM = Y_DOM;
15291
15292
15293}, '3.18.1', {"requires": ["oop", "features"]});
15294YUI.add('dom-base', function (Y, NAME) {
15295
15296/**
15297* @for DOM
15298* @module dom
15299*/
15300var documentElement = Y.config.doc.documentElement,
15301    Y_DOM = Y.DOM,
15302    TAG_NAME = 'tagName',
15303    OWNER_DOCUMENT = 'ownerDocument',
15304    EMPTY_STRING = '',
15305    addFeature = Y.Features.add,
15306    testFeature = Y.Features.test;
15307
15308Y.mix(Y_DOM, {
15309    /**
15310     * Returns the text content of the HTMLElement.
15311     * @method getText
15312     * @param {HTMLElement} element The html element.
15313     * @return {String} The text content of the element (includes text of any descending elements).
15314     */
15315    getText: (documentElement.textContent !== undefined) ?
15316        function(element) {
15317            var ret = '';
15318            if (element) {
15319                ret = element.textContent;
15320            }
15321            return ret || '';
15322        } : function(element) {
15323            var ret = '';
15324            if (element) {
15325                ret = element.innerText || element.nodeValue; // might be a textNode
15326            }
15327            return ret || '';
15328        },
15329
15330    /**
15331     * Sets the text content of the HTMLElement.
15332     * @method setText
15333     * @param {HTMLElement} element The html element.
15334     * @param {String} content The content to add.
15335     */
15336    setText: (documentElement.textContent !== undefined) ?
15337        function(element, content) {
15338            if (element) {
15339                element.textContent = content;
15340            }
15341        } : function(element, content) {
15342            if ('innerText' in element) {
15343                element.innerText = content;
15344            } else if ('nodeValue' in element) {
15345                element.nodeValue = content;
15346            }
15347    },
15348
15349    CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
15350        'for': 'htmlFor',
15351        'class': 'className'
15352    } : { // w3c
15353        'htmlFor': 'for',
15354        'className': 'class'
15355    },
15356
15357    /**
15358     * Provides a normalized attribute interface.
15359     * @method setAttribute
15360     * @param {HTMLElement} el The target element for the attribute.
15361     * @param {String} attr The attribute to set.
15362     * @param {String} val The value of the attribute.
15363     */
15364    setAttribute: function(el, attr, val, ieAttr) {
15365        if (el && attr && el.setAttribute) {
15366            attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
15367            el.setAttribute(attr, val, ieAttr);
15368        }
15369    },
15370
15371
15372    /**
15373     * Provides a normalized attribute interface.
15374     * @method getAttribute
15375     * @param {HTMLElement} el The target element for the attribute.
15376     * @param {String} attr The attribute to get.
15377     * @return {String} The current value of the attribute.
15378     */
15379    getAttribute: function(el, attr, ieAttr) {
15380        ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
15381        var ret = '';
15382        if (el && attr && el.getAttribute) {
15383            attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
15384            // BUTTON value issue for IE < 8
15385            ret = (el.tagName === "BUTTON" && attr === 'value') ? Y_DOM.getValue(el) : el.getAttribute(attr, ieAttr);
15386
15387            if (ret === null) {
15388                ret = ''; // per DOM spec
15389            }
15390        }
15391        return ret;
15392    },
15393
15394    VALUE_SETTERS: {},
15395
15396    VALUE_GETTERS: {},
15397
15398    getValue: function(node) {
15399        var ret = '', // TODO: return null?
15400            getter;
15401
15402        if (node && node[TAG_NAME]) {
15403            getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
15404
15405            if (getter) {
15406                ret = getter(node);
15407            } else {
15408                ret = node.value;
15409            }
15410        }
15411
15412        // workaround for IE8 JSON stringify bug
15413        // which converts empty string values to null
15414        if (ret === EMPTY_STRING) {
15415            ret = EMPTY_STRING; // for real
15416        }
15417
15418        return (typeof ret === 'string') ? ret : '';
15419    },
15420
15421    setValue: function(node, val) {
15422        var setter;
15423
15424        if (node && node[TAG_NAME]) {
15425            setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
15426            val = (val === null) ? '' : val;
15427            if (setter) {
15428                setter(node, val);
15429            } else {
15430                node.value = val;
15431            }
15432        }
15433    },
15434
15435    creators: {}
15436});
15437
15438addFeature('value-set', 'select', {
15439    test: function() {
15440        var node = Y.config.doc.createElement('select');
15441        node.innerHTML = '<option>1</option><option>2</option>';
15442        node.value = '2';
15443        return (node.value && node.value === '2');
15444    }
15445});
15446
15447if (!testFeature('value-set', 'select')) {
15448    Y_DOM.VALUE_SETTERS.select = function(node, val) {
15449        for (var i = 0, options = node.getElementsByTagName('option'), option;
15450                option = options[i++];) {
15451            if (Y_DOM.getValue(option) === val) {
15452                option.selected = true;
15453                //Y_DOM.setAttribute(option, 'selected', 'selected');
15454                break;
15455            }
15456        }
15457    };
15458}
15459
15460Y.mix(Y_DOM.VALUE_GETTERS, {
15461    button: function(node) {
15462        return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
15463    }
15464});
15465
15466Y.mix(Y_DOM.VALUE_SETTERS, {
15467    // IE: node.value changes the button text, which should be handled via innerHTML
15468    button: function(node, val) {
15469        var attr = node.attributes.value;
15470        if (!attr) {
15471            attr = node[OWNER_DOCUMENT].createAttribute('value');
15472            node.setAttributeNode(attr);
15473        }
15474
15475        attr.value = val;
15476    }
15477});
15478
15479
15480Y.mix(Y_DOM.VALUE_GETTERS, {
15481    option: function(node) {
15482        var attrs = node.attributes;
15483        return (attrs.value && attrs.value.specified) ? node.value : node.text;
15484    },
15485
15486    select: function(node) {
15487        var val = node.value,
15488            options = node.options;
15489
15490        if (options && options.length) {
15491            // TODO: implement multipe select
15492            if (node.multiple) {
15493            } else if (node.selectedIndex > -1) {
15494                val = Y_DOM.getValue(options[node.selectedIndex]);
15495            }
15496        }
15497
15498        return val;
15499    }
15500});
15501var addClass, hasClass, removeClass;
15502
15503Y.mix(Y.DOM, {
15504    /**
15505     * Determines whether a DOM element has the given className.
15506     * @method hasClass
15507     * @for DOM
15508     * @param {HTMLElement} element The DOM element.
15509     * @param {String} className the class name to search for
15510     * @return {Boolean} Whether or not the element has the given class.
15511     */
15512    hasClass: function(node, className) {
15513        var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
15514        return re.test(node.className);
15515    },
15516
15517    /**
15518     * Adds a class name to a given DOM element.
15519     * @method addClass
15520     * @for DOM
15521     * @param {HTMLElement} element The DOM element.
15522     * @param {String} className the class name to add to the class attribute
15523     */
15524    addClass: function(node, className) {
15525        if (!Y.DOM.hasClass(node, className)) { // skip if already present
15526            node.className = Y.Lang.trim([node.className, className].join(' '));
15527        }
15528    },
15529
15530    /**
15531     * Removes a class name from a given element.
15532     * @method removeClass
15533     * @for DOM
15534     * @param {HTMLElement} element The DOM element.
15535     * @param {String} className the class name to remove from the class attribute
15536     */
15537    removeClass: function(node, className) {
15538        if (className && hasClass(node, className)) {
15539            node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
15540                            className + '(?:\\s+|$)'), ' '));
15541
15542            if ( hasClass(node, className) ) { // in case of multiple adjacent
15543                removeClass(node, className);
15544            }
15545        }
15546    },
15547
15548    /**
15549     * Replace a class with another class for a given element.
15550     * If no oldClassName is present, the newClassName is simply added.
15551     * @method replaceClass
15552     * @for DOM
15553     * @param {HTMLElement} element The DOM element
15554     * @param {String} oldClassName the class name to be replaced
15555     * @param {String} newClassName the class name that will be replacing the old class name
15556     */
15557    replaceClass: function(node, oldC, newC) {
15558        removeClass(node, oldC); // remove first in case oldC === newC
15559        addClass(node, newC);
15560    },
15561
15562    /**
15563     * If the className exists on the node it is removed, if it doesn't exist it is added.
15564     * @method toggleClass
15565     * @for DOM
15566     * @param {HTMLElement} element The DOM element
15567     * @param {String} className the class name to be toggled
15568     * @param {Boolean} addClass optional boolean to indicate whether class
15569     * should be added or removed regardless of current state
15570     */
15571    toggleClass: function(node, className, force) {
15572        var add = (force !== undefined) ? force :
15573                !(hasClass(node, className));
15574
15575        if (add) {
15576            addClass(node, className);
15577        } else {
15578            removeClass(node, className);
15579        }
15580    }
15581});
15582
15583hasClass = Y.DOM.hasClass;
15584removeClass = Y.DOM.removeClass;
15585addClass = Y.DOM.addClass;
15586
15587var re_tag = /<([a-z]+)/i,
15588
15589    Y_DOM = Y.DOM,
15590
15591    addFeature = Y.Features.add,
15592    testFeature = Y.Features.test,
15593
15594    creators = {},
15595
15596    createFromDIV = function(html, tag) {
15597        var div = Y.config.doc.createElement('div'),
15598            ret = true;
15599
15600        div.innerHTML = html;
15601        if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) {
15602            ret = false;
15603        }
15604
15605        return ret;
15606    },
15607
15608    re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
15609
15610    TABLE_OPEN = '<table>',
15611    TABLE_CLOSE = '</table>',
15612
15613    selectedIndex;
15614
15615Y.mix(Y.DOM, {
15616    _fragClones: {},
15617
15618    _create: function(html, doc, tag) {
15619        tag = tag || 'div';
15620
15621        var frag = Y_DOM._fragClones[tag];
15622        if (frag) {
15623            frag = frag.cloneNode(false);
15624        } else {
15625            frag = Y_DOM._fragClones[tag] = doc.createElement(tag);
15626        }
15627        frag.innerHTML = html;
15628        return frag;
15629    },
15630
15631    _children: function(node, tag) {
15632            var i = 0,
15633            children = node.children,
15634            childNodes,
15635            hasComments,
15636            child;
15637
15638        if (children && children.tags) { // use tags filter when possible
15639            if (tag) {
15640                children = node.children.tags(tag);
15641            } else { // IE leaks comments into children
15642                hasComments = children.tags('!').length;
15643            }
15644        }
15645
15646        if (!children || (!children.tags && tag) || hasComments) {
15647            childNodes = children || node.childNodes;
15648            children = [];
15649            while ((child = childNodes[i++])) {
15650                if (child.nodeType === 1) {
15651                    if (!tag || tag === child.tagName) {
15652                        children.push(child);
15653                    }
15654                }
15655            }
15656        }
15657
15658        return children || [];
15659    },
15660
15661    /**
15662     * Creates a new dom node using the provided markup string.
15663     * @method create
15664     * @param {String} html The markup used to create the element
15665     * @param {HTMLDocument} doc An optional document context
15666     * @return {HTMLElement|DocumentFragment} returns a single HTMLElement
15667     * when creating one node, and a documentFragment when creating
15668     * multiple nodes.
15669     */
15670    create: function(html, doc) {
15671        if (typeof html === 'string') {
15672            html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
15673
15674        }
15675
15676        doc = doc || Y.config.doc;
15677        var m = re_tag.exec(html),
15678            create = Y_DOM._create,
15679            custom = creators,
15680            ret = null,
15681            creator, tag, node, nodes;
15682
15683        if (html != undefined) { // not undefined or null
15684            if (m && m[1]) {
15685                creator = custom[m[1].toLowerCase()];
15686                if (typeof creator === 'function') {
15687                    create = creator;
15688                } else {
15689                    tag = creator;
15690                }
15691            }
15692
15693            node = create(html, doc, tag);
15694            nodes = node.childNodes;
15695
15696            if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
15697                ret = node.removeChild(nodes[0]);
15698            } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected)
15699                selectedIndex = node.selectedIndex;
15700
15701                if (nodes.length === 2) {
15702                    ret = nodes[0].nextSibling;
15703                } else {
15704                    node.removeChild(nodes[0]);
15705                    ret = Y_DOM._nl2frag(nodes, doc);
15706                }
15707            } else { // return multiple nodes as a fragment
15708                 ret = Y_DOM._nl2frag(nodes, doc);
15709            }
15710
15711        }
15712
15713        return ret;
15714    },
15715
15716    _nl2frag: function(nodes, doc) {
15717        var ret = null,
15718            i, len;
15719
15720        if (nodes && (nodes.push || nodes.item) && nodes[0]) {
15721            doc = doc || nodes[0].ownerDocument;
15722            ret = doc.createDocumentFragment();
15723
15724            if (nodes.item) { // convert live list to static array
15725                nodes = Y.Array(nodes, 0, true);
15726            }
15727
15728            for (i = 0, len = nodes.length; i < len; i++) {
15729                ret.appendChild(nodes[i]);
15730            }
15731        } // else inline with log for minification
15732        return ret;
15733    },
15734
15735    /**
15736     * Inserts content in a node at the given location
15737     * @method addHTML
15738     * @param {HTMLElement} node The node to insert into
15739     * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted
15740     * @param {HTMLElement} where Where to insert the content
15741     * If no "where" is given, content is appended to the node
15742     * Possible values for "where"
15743     * <dl>
15744     * <dt>HTMLElement</dt>
15745     * <dd>The element to insert before</dd>
15746     * <dt>"replace"</dt>
15747     * <dd>Replaces the existing HTML</dd>
15748     * <dt>"before"</dt>
15749     * <dd>Inserts before the existing HTML</dd>
15750     * <dt>"before"</dt>
15751     * <dd>Inserts content before the node</dd>
15752     * <dt>"after"</dt>
15753     * <dd>Inserts content after the node</dd>
15754     * </dl>
15755     */
15756    addHTML: function(node, content, where) {
15757        var nodeParent = node.parentNode,
15758            i = 0,
15759            item,
15760            ret = content,
15761            newNode;
15762
15763
15764        if (content != undefined) { // not null or undefined (maybe 0)
15765            if (content.nodeType) { // DOM node, just add it
15766                newNode = content;
15767            } else if (typeof content == 'string' || typeof content == 'number') {
15768                ret = newNode = Y_DOM.create(content);
15769            } else if (content[0] && content[0].nodeType) { // array or collection
15770                newNode = Y.config.doc.createDocumentFragment();
15771                while ((item = content[i++])) {
15772                    newNode.appendChild(item); // append to fragment for insertion
15773                }
15774            }
15775        }
15776
15777        if (where) {
15778            if (newNode && where.parentNode) { // insert regardless of relationship to node
15779                where.parentNode.insertBefore(newNode, where);
15780            } else {
15781                switch (where) {
15782                    case 'replace':
15783                        while (node.firstChild) {
15784                            node.removeChild(node.firstChild);
15785                        }
15786                        if (newNode) { // allow empty content to clear node
15787                            node.appendChild(newNode);
15788                        }
15789                        break;
15790                    case 'before':
15791                        if (newNode) {
15792                            nodeParent.insertBefore(newNode, node);
15793                        }
15794                        break;
15795                    case 'after':
15796                        if (newNode) {
15797                            if (node.nextSibling) { // IE errors if refNo
15797de is null
15798                                nodeParent.insertBefore(newNode, node.nextSibling);
15799                            } else {
15800                                nodeParent.appendChild(newNode);
15801                            }
15802                        }
15803                        break;
15804                    default:
15805                        if (newNode) {
15806                            node.appendChild(newNode);
15807                        }
15808                }
15809            }
15810        } else if (newNode) {
15811            node.appendChild(newNode);
15812        }
15813
15814        // `select` elements are the only elements with `selectedIndex`.
15815        // Don't grab the dummy `option` element's `selectedIndex`.
15816        if (node.nodeName == "SELECT" && selectedIndex > 0) {
15817            node.selectedIndex = selectedIndex - 1;
15818        }
15819
15820        return ret;
15821    },
15822
15823    wrap: function(node, html) {
15824        var parent = (html && html.nodeType) ? html : Y.DOM.create(html),
15825            nodes = parent.getElementsByTagName('*');
15826
15827        if (nodes.length) {
15828            parent = nodes[nodes.length - 1];
15829        }
15830
15831        if (node.parentNode) {
15832            node.parentNode.replaceChild(parent, node);
15833        }
15834        parent.appendChild(node);
15835    },
15836
15837    unwrap: function(node) {
15838        var parent = node.parentNode,
15839            lastChild = parent.lastChild,
15840            next = node,
15841            grandparent;
15842
15843        if (parent) {
15844            grandparent = parent.parentNode;
15845            if (grandparent) {
15846                node = parent.firstChild;
15847                while (node !== lastChild) {
15848                    next = node.nextSibling;
15849                    grandparent.insertBefore(node, parent);
15850                    node = next;
15851                }
15852                grandparent.replaceChild(lastChild, parent);
15853            } else {
15854                parent.removeChild(node);
15855            }
15856        }
15857    }
15858});
15859
15860addFeature('innerhtml', 'table', {
15861    test: function() {
15862        var node = Y.config.doc.createElement('table');
15863        try {
15864            node.innerHTML = '<tbody></tbody>';
15865        } catch(e) {
15866            return false;
15867        }
15868        return (node.firstChild && node.firstChild.nodeName === 'TBODY');
15869    }
15870});
15871
15872addFeature('innerhtml-div', 'tr', {
15873    test: function() {
15874        return createFromDIV('<tr></tr>', 'tr');
15875    }
15876});
15877
15878addFeature('innerhtml-div', 'script', {
15879    test: function() {
15880        return createFromDIV('<script></script>', 'script');
15881    }
15882});
15883
15884if (!testFeature('innerhtml', 'table')) {
15885    // TODO: thead/tfoot with nested tbody
15886        // IE adds TBODY when creating TABLE elements (which may share this impl)
15887    creators.tbody = function(html, doc) {
15888        var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc),
15889            tb = Y.DOM._children(frag, 'tbody')[0];
15890
15891        if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
15892            tb.parentNode.removeChild(tb); // strip extraneous tbody
15893        }
15894        return frag;
15895    };
15896}
15897
15898if (!testFeature('innerhtml-div', 'script')) {
15899    creators.script = function(html, doc) {
15900        var frag = doc.createElement('div');
15901
15902        frag.innerHTML = '-' + html;
15903        frag.removeChild(frag.firstChild);
15904        return frag;
15905    };
15906
15907    creators.link = creators.style = creators.script;
15908}
15909
15910if (!testFeature('innerhtml-div', 'tr')) {
15911    Y.mix(creators, {
15912        option: function(html, doc) {
15913            return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
15914        },
15915
15916        tr: function(html, doc) {
15917            return Y_DOM.create('<tbody>' + html + '</tbody>', doc);
15918        },
15919
15920        td: function(html, doc) {
15921            return Y_DOM.create('<tr>' + html + '</tr>', doc);
15922        },
15923
15924        col: function(html, doc) {
15925            return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc);
15926        },
15927
15928        tbody: 'table'
15929    });
15930
15931    Y.mix(creators, {
15932        legend: 'fieldset',
15933        th: creators.td,
15934        thead: creators.tbody,
15935        tfoot: creators.tbody,
15936        caption: creators.tbody,
15937        colgroup: creators.tbody,
15938        optgroup: creators.option
15939    });
15940}
15941
15942Y_DOM.creators = creators;
15943Y.mix(Y.DOM, {
15944    /**
15945     * Sets the width of the element to the given size, regardless
15946     * of box model, border, padding, etc.
15947     * @method setWidth
15948     * @param {HTMLElement} element The DOM element.
15949     * @param {String|Number} size The pixel height to size to
15950     */
15951
15952    setWidth: function(node, size) {
15953        Y.DOM._setSize(node, 'width', size);
15954    },
15955
15956    /**
15957     * Sets the height of the element to the given size, regardless
15958     * of box model, border, padding, etc.
15959     * @method setHeight
15960     * @param {HTMLElement} element The DOM element.
15961     * @param {String|Number} size The pixel height to size to
15962     */
15963
15964    setHeight: function(node, size) {
15965        Y.DOM._setSize(node, 'height', size);
15966    },
15967
15968    _setSize: function(node, prop, val) {
15969        val = (val > 0) ? val : 0;
15970        var size = 0;
15971
15972        node.style[prop] = val + 'px';
15973        size = (prop === 'height') ? node.offsetHeight : node.offsetWidth;
15974
15975        if (size > val) {
15976            val = val - (size - val);
15977
15978            if (val < 0) {
15979                val = 0;
15980            }
15981
15982            node.style[prop] = val + 'px';
15983        }
15984    }
15985});
15986
15987
15988}, '3.18.1', {"requires": ["dom-core"]});
15989YUI.add('color-base', function (Y, NAME) {
15990
15991/**
15992Color provides static methods for color conversion.
15993
15994    Y.Color.toRGB('f00'); // rgb(255, 0, 0)
15995
15996    Y.Color.toHex('rgb(255, 255, 0)'); // #ffff00
15997
15998@module color
15999@submodule color-base
16000@class Color
16001@since 3.8.0
16002**/
16003
16004var REGEX_HEX = /^#?([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})(\ufffe)?/,
16005    REGEX_HEX3 = /^#?([\da-fA-F]{1})([\da-fA-F]{1})([\da-fA-F]{1})(\ufffe)?/,
16006    REGEX_RGB = /rgba?\(([\d]{1,3}), ?([\d]{1,3}), ?([\d]{1,3}),? ?([.\d]*)?\)/,
16007    TYPES = { 'HEX': 'hex', 'RGB': 'rgb', 'RGBA': 'rgba' },
16008    CONVERTS = { 'hex': 'toHex', 'rgb': 'toRGB', 'rgba': 'toRGBA' };
16009
16010
16011Y.Color = {
16012    /**
16013    @static
16014    @property KEYWORDS
16015    @type Object
16016    @since 3.8.0
16017    **/
16018    KEYWORDS: {
16019        'black': '000', 'silver': 'c0c0c0', 'gray': '808080', 'white': 'fff',
16020        'maroon': '800000', 'red': 'f00', 'purple': '800080', 'fuchsia': 'f0f',
16021        'green': '008000', 'lime': '0f0', 'olive': '808000', 'yellow': 'ff0',
16022        'navy': '000080', 'blue': '00f', 'teal': '008080', 'aqua': '0ff'
16023    },
16024
16025    /**
16026        NOTE: `(\ufffe)?` is added to the Regular Expression to carve out a
16027        place for the alpha channel that is returned from toArray
16028        without compromising any usage of the Regular Expression
16029
16030    @static
16031    @property REGEX_HEX
16032    @type RegExp
16033    @default /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})(\ufffe)?/
16034    @since 3.8.0
16035    **/
16036    REGEX_HEX: REGEX_HEX,
16037
16038    /**
16039        NOTE: `(\ufffe)?` is added to the Regular Expression to carve out a
16040        place for the alpha channel that is returned from toArray
16041        without compromising any usage of the Regular Expression
16042
16043    @static
16044    @property REGEX_HEX3
16045    @type RegExp
16046    @default /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})(\ufffe)?/
16047    @since 3.8.0
16048    **/
16049    REGEX_HEX3: REGEX_HEX3,
16050
16051    /**
16052    @static
16053    @property REGEX_RGB
16054    @type RegExp
16055    @default /rgba?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3}),? ?([.0-9]{1,3})?\)/
16056    @since 3.8.0
16057    **/
16058    REGEX_RGB: REGEX_RGB,
16059
16060    re_RGB: REGEX_RGB,
16061
16062    re_hex: REGEX_HEX,
16063
16064    re_hex3: REGEX_HEX3,
16065
16066    /**
16067    @static
16068    @property STR_HEX
16069    @type String
16070    @default #{*}{*}{*}
16071    @since 3.8.0
16072    **/
16073    STR_HEX: '#{*}{*}{*}',
16074
16075    /**
16076    @static
16077    @property STR_RGB
16078    @type String
16079    @default rgb({*}, {*}, {*})
16080    @since 3.8.0
16081    **/
16082    STR_RGB: 'rgb({*}, {*}, {*})',
16083
16084    /**
16085    @static
16086    @property STR_RGBA
16087    @type String
16088    @default rgba({*}, {*}, {*}, {*})
16089    @since 3.8.0
16090    **/
16091    STR_RGBA: 'rgba({*}, {*}, {*}, {*})',
16092
16093    /**
16094    @static
16095    @property TYPES
16096    @type Object
16097    @default {'rgb':'rgb', 'rgba':'rgba'}
16098    @since 3.8.0
16099    **/
16100    TYPES: TYPES,
16101
16102    /**
16103    @static
16104    @property CONVERTS
16105    @type Object
16106    @default {}
16107    @since 3.8.0
16108    **/
16109    CONVERTS: CONVERTS,
16110
16111    /**
16112     Converts the provided string to the provided type.
16113     You can use the `Y.Color.TYPES` to get a valid `to` type.
16114     If the color cannot be converted, the original color will be returned.
16115
16116     @public
16117     @method convert
16118     @param {String} str
16119     @param {String} to
16120     @return {String}
16121     @since 3.8.0
16122     **/
16123    convert: function (str, to) {
16124        var convert = Y.Color.CONVERTS[to.toLowerCase()],
16125            clr = str;
16126
16127        if (convert && Y.Color[convert]) {
16128            clr = Y.Color[convert](str);
16129        }
16130
16131        return clr;
16132    },
16133
16134    /**
16135    Converts provided color value to a hex value string
16136
16137    @public
16138    @method toHex
16139    @param {String} str Hex or RGB value string
16140    @return {String} returns array of values or CSS string if options.css is true
16141    @since 3.8.0
16142    **/
16143    toHex: function (str) {
16144        var clr = Y.Color._convertTo(str, 'hex'),
16145            isTransparent = clr.toLowerCase() === 'transparent';
16146
16147        if (clr.charAt(0) !== '#' && !isTransparent) {
16148            clr = '#' + clr;
16149        }
16150
16151        return isTransparent ? clr.toLowerCase() : clr.toUpperCase();
16152    },
16153
16154    /**
16155    Converts provided color value to an RGB value string
16156    @public
16157    @method toRGB
16158    @param {String} str Hex or RGB value string
16159    @return {String}
16160    @since 3.8.0
16161    **/
16162    toRGB: function (str) {
16163        var clr = Y.Color._convertTo(str, 'rgb');
16164        return clr.toLowerCase();
16165    },
16166
16167    /**
16168    Converts provided color value to an RGB value string
16169    @public
16170    @method toRGBA
16171    @param {String} str Hex or RGB value string
16172    @return {String}
16173    @since 3.8.0
16174    **/
16175    toRGBA: function (str) {
16176        var clr = Y.Color._convertTo(str, 'rgba' );
16177        return clr.toLowerCase();
16178    },
16179
16180    /**
16181    Converts the provided color string to an array of values where the
16182        last value is the alpha value. Will return an empty array if
16183        the provided string is not able to be parsed.
16184
16185        NOTE: `(\ufffe)?` is added to `HEX` and `HEX3` Regular Expressions to
16186        carve out a place for the alpha channel that is returned from
16187        toArray without compromising any usage of the Regular Expression
16188
16189        Y.Color.toArray('fff');              // ['ff', 'ff', 'ff', 1]
16190        Y.Color.toArray('rgb(0, 0, 0)');     // ['0', '0', '0', 1]
16191        Y.Color.toArray('rgba(0, 0, 0, 0)'); // ['0', '0', '0', 1]
16192
16193
16194
16195    @public
16196    @method toArray
16197    @param {String} str
16198    @return {Array}
16199    @since 3.8.0
16200    **/
16201    toArray: function(str) {
16202        // parse with regex and return "matches" array
16203        var type = Y.Color.findType(str).toUpperCase(),
16204            regex,
16205            arr,
16206            length,
16207            lastItem;
16208
16209        if (type === 'HEX' && str.length < 5) {
16210            type = 'HEX3';
16211        }
16212
16213        if (type.charAt(type.length - 1) === 'A') {
16214            type = type.slice(0, -1);
16215        }
16216
16217        regex = Y.Color['REGEX_' + type];
16218
16219        if (regex) {
16220            arr = regex.exec(str) || [];
16221            length = arr.length;
16222
16223            if (length) {
16224
16225                arr.shift();
16226                length--;
16227
16228                if (type === 'HEX3') {
16229                    arr[0] += arr[0];
16230                    arr[1] += arr[1];
16231                    arr[2] += arr[2];
16232                }
16233
16234                lastItem = arr[length - 1];
16235                if (!lastItem) {
16236                    arr[length - 1] = 1;
16237                }
16238            }
16239        }
16240
16241        return arr;
16242
16243    },
16244
16245    /**
16246    Converts the array of values to a string based on the provided template.
16247    @public
16248    @method fromArray
16249    @param {Array} arr
16250    @param {String} template
16251    @return {String}
16252    @since 3.8.0
16253    **/
16254    fromArray: function(arr, template) {
16255        arr = arr.concat();
16256
16257        if (typeof template === 'undefined') {
16258            return arr.join(', ');
16259        }
16260
16261        var replace = '{*}';
16262
16263        template = Y.Color['STR_' + template.toUpperCase()];
16264
16265        if (arr.length === 3 && template.match(/\{\*\}/g).length === 4) {
16266            arr.push(1);
16267        }
16268
16269        while ( template.indexOf(replace) >= 0 && arr.length > 0) {
16270            template = template.replace(replace, arr.shift());
16271        }
16272
16273        return template;
16274    },
16275
16276    /**
16277    Finds the value type based on the str value provided.
16278    @public
16279    @method findType
16280    @param {String} str
16281    @return {String}
16282    @since 3.8.0
16283    **/
16284    findType: function (str) {
16285        if (Y.Color.KEYWORDS[str]) {
16286            return 'keyword';
16287        }
16288
16289        var index = str.indexOf('('),
16290            key;
16291
16292        if (index > 0) {
16293            key = str.substr(0, index);
16294        }
16295
16296        if (key && Y.Color.TYPES[key.toUpperCase()]) {
16297            return Y.Color.TYPES[key.toUpperCase()];
16298        }
16299
16300        return 'hex';
16301
16302    }, // return 'keyword', 'hex', 'rgb'
16303
16304    /**
16305    Retrives the alpha channel from the provided string. If no alpha
16306        channel is present, `1` will be returned.
16307    @protected
16308    @method _getAlpha
16309    @param {String} clr
16310    @return {Number}
16311    @since 3.8.0
16312    **/
16313    _getAlpha: function (clr) {
16314        var alpha,
16315            arr = Y.Color.toArray(clr);
16316
16317        if (arr.length > 3) {
16318            alpha = arr.pop();
16319        }
16320
16321        return +alpha || 1;
16322    },
16323
16324    /**
16325    Returns the hex value string if found in the KEYWORDS object
16326    @protected
16327    @method _keywordToHex
16328    @param {String} clr
16329    @return {String}
16330    @since 3.8.0
16331    **/
16332    _keywordToHex: function (clr) {
16333        var keyword = Y.Color.KEYWORDS[clr];
16334
16335        if (keyword) {
16336            return keyword;
16337        }
16338    },
16339
16340    /**
16341    Converts the provided color string to the value type provided as `to`
16342    @protected
16343    @method _convertTo
16344    @param {String} clr
16345    @param {String} to
16346    @return {String}
16347    @since 3.8.0
16348    **/
16349    _convertTo: function(clr, to) {
16350
16351        if (clr === 'transparent') {
16352            return clr;
16353        }
16354
16355        var from = Y.Color.findType(clr),
16356            originalTo = to,
16357            needsAlpha,
16358            alpha,
16359            method,
16360            ucTo;
16361
16362        if (from === 'keyword') {
16363            clr = Y.Color._keywordToHex(clr);
16364            from = 'hex';
16365        }
16366
16367        if (from === 'hex' && clr.length < 5) {
16368            if (clr.charAt(0) === '#') {
16369                clr = clr.substr(1);
16370            }
16371
16372            clr = '#' + clr.charAt(0) + clr.charAt(0) +
16373                        clr.charAt(1) + clr.charAt(1) +
16374                        clr.charAt(2) + clr.charAt(2);
16375        }
16376
16377        if (from === to) {
16378            return clr;
16379        }
16380
16381        if (from.charAt(from.length - 1) === 'a') {
16382            from = from.slice(0, -1);
16383        }
16384
16385        needsAlpha = (to.charAt(to.length - 1) === 'a');
16386        if (needsAlpha) {
16387            to = to.slice(0, -1);
16388            alpha = Y.Color._getAlpha(clr);
16389        }
16390
16391        ucTo = to.charAt(0).toUpperCase() + to.substr(1).toLowerCase();
16392        method = Y.Color['_' + from + 'To' + ucTo ];
16393
16394        // check to see if need conversion to rgb first
16395        // check to see if there is a direct conversion method
16396        // convertions are: hex <-> rgb <-> hsl
16397        if (!method) {
16398            if (from !== 'rgb' && to !== 'rgb') {
16399                clr = Y.Color['_' + from + 'ToRgb'](clr);
16400                from = 'rgb';
16401                method = Y.Color['_' + from + 'To' + ucTo ];
16402            }
16403        }
16404
16405        if (method) {
16406            clr = ((method)(clr, needsAlpha));
16407        }
16408
16409        // process clr from arrays to strings after conversions if alpha is needed
16410        if (needsAlpha) {
16411            if (!Y.Lang.isArray(clr)) {
16412                clr = Y.Color.toArray(clr);
16413            }
16414            clr.push(alpha);
16415            clr = Y.Color.fromArray(clr, originalTo.toUpperCase());
16416        }
16417
16418        return clr;
16419    },
16420
16421    /**
16422    Processes the hex string into r, g, b values. Will return values as
16423        an array, or as an rgb string.
16424    @protected
16425    @method _hexToRgb
16426    @param {String} str
16427    @param {Boolean} [toArray]
16428    @return {String|Array}
16429    @since 3.8.0
16430    **/
16431    _hexToRgb: function (str, toArray) {
16432        var r, g, b;
16433
16434        /*jshint bitwise:false*/
16435        if (str.charAt(0) === '#') {
16436            str = str.substr(1);
16437        }
16438
16439        str = parseInt(str, 16);
16440
16441        r = str >> 16;
16442        g = str >> 8 & 0xFF;
16443        b = str & 0xFF;
16444
16445        if (toArray) {
16446            return [r, g, b];
16447        }
16448
16449        return 'rgb(' + r + ', ' + g + ', ' + b + ')';
16450    },
16451
16452    /**
16453    Processes the rgb string into r, g, b values. Will return values as
16454        an array, or as a hex string.
16455    @protected
16456    @method _rgbToHex
16457    @param {String} str
16458    @param {Boolean} [toArray]
16459    @return {String|Array}
16460    @since 3.8.0
16461    **/
16462    _rgbToHex: function (str) {
16463        /*jshint bitwise:false*/
16464        var rgb = Y.Color.toArray(str),
16465            hex = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16);
16466
16467        hex = (+hex).toString(16);
16468
16469        while (hex.length < 6) {
16470            hex = '0' + hex;
16471        }
16472
16473        return '#' + hex;
16474    }
16475
16476};
16477
16478
16479
16480}, '3.18.1', {"requires": ["yui-base"]});
16481YUI.add('dom-style', function (Y, NAME) {
16482
16483/**
16484 * Add style management functionality to DOM.
16485 * @module dom
16486 * @submodule dom-style
16487 * @for DOM
16488 */
16489
16490var DOCUMENT_ELEMENT = 'documentElement',
16491    DEFAULT_VIEW = 'defaultView',
16492    OWNER_DOCUMENT = 'ownerDocument',
16493    STYLE = 'style',
16494    FLOAT = 'float',
16495    CSS_FLOAT = 'cssFloat',
16496    STYLE_FLOAT = 'styleFloat',
16497    TRANSPARENT = 'transparent',
16498    GET_COMPUTED_STYLE = 'getComputedStyle',
16499    GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
16500
16501    DOCUMENT = Y.config.doc,
16502
16503    Y_DOM = Y.DOM,
16504
16505    TRANSFORM,
16506    TRANSFORMORIGIN,
16507    VENDOR_TRANSFORM = [
16508        'WebkitTransform',
16509        'MozTransform',
16510        'OTransform',
16511        'msTransform',
16512        'transform'
16513    ],
16514
16515    re_unit = /width|height|top|left|right|bottom|margin|padding/i;
16516
16517Y.Array.each(VENDOR_TRANSFORM, function(val) {
16518    if (val in DOCUMENT[DOCUMENT_ELEMENT].style) {
16519        TRANSFORM = val;
16520        TRANSFORMORIGIN = val + "Origin";
16521    }
16522});
16523
16524Y.mix(Y_DOM, {
16525    DEFAULT_UNIT: 'px',
16526
16527    CUSTOM_STYLES: {
16528    },
16529
16530
16531    /**
16532     * Sets a style property for a given element.
16533     * @method setStyle
16534     * @param {HTMLElement} node The HTMLElement to apply the style to.
16535     * @param {String} att The style property to set.
16536     * @param {String|Number} val The value.
16537     * @param {Object} [style] The style node. Defaults to `node.style`.
16538     */
16539    setStyle: function(node, att, val, style) {
16540        style = style || node.style;
16541        var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES;
16542
16543        if (style) {
16544            if (val === null || val === '') { // normalize unsetting
16545                val = '';
16546            } else if (!isNaN(Number(val)) && re_unit.test(att)) { // number values may need a unit
16547                val += Y_DOM.DEFAULT_UNIT;
16548            }
16549
16550            if (att in CUSTOM_STYLES) {
16551                if (CUSTOM_STYLES[att].set) {
16552                    CUSTOM_STYLES[att].set(node, val, style);
16553                    return; // NOTE: return
16554                } else if (typeof CUSTOM_STYLES[att] === 'string') {
16555                    att = CUSTOM_STYLES[att];
16556                }
16557            } else if (att === '') { // unset inline styles
16558                att = 'cssText';
16559                val = '';
16560            }
16561            style[att] = val;
16562        }
16563    },
16564
16565    /**
16566     * Returns the current style value for the given property.
16567     * @method getStyle
16568     * @param {HTMLElement} node The HTMLElement to get the style from.
16569     * @param {String} att The style property to get.
16570     * @param {Object} [style] The style node. Defaults to `node.style`.
16571     */
16572    getStyle: function(node, att, style) {
16573        style = style || node.style;
16574        var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES,
16575            val = '';
16576
16577        if (style) {
16578            if (att in CUSTOM_STYLES) {
16579                if (CUSTOM_STYLES[att].get) {
16580                    return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
16581                } else if (typeof CUSTOM_STYLES[att] === 'string') {
16582                    att = CUSTOM_STYLES[att];
16583                }
16584            }
16585            val = style[att];
16586            if (val === '') { // TODO: is empty string sufficient?
16587                val = Y_DOM[GET_COMPUTED_STYLE](node, att);
16588            }
16589        }
16590
16591        return val;
16592    },
16593
16594    /**
16595     * Sets multiple style properties.
16596     * @method setStyles
16597     * @param {HTMLElement} node The HTMLElement to apply the styles to.
16598     * @param {Object} hash An object literal of property:value pairs.
16599     */
16600    setStyles: function(node, hash) {
16601        var style = node.style;
16602        Y.each(hash, function(v, n) {
16603            Y_DOM.setStyle(node, n, v, style);
16604        }, Y_DOM);
16605    },
16606
16607    /**
16608     * Returns the computed style for the given node.
16609     * @method getComputedStyle
16610     * @param {HTMLElement} node The HTMLElement to get the style from.
16611     * @param {String} att The style property to get.
16612     * @return {String} The computed value of the style property.
16613     */
16614    getComputedStyle: function(node, att) {
16615        var val = '',
16616            doc = node[OWNER_DOCUMENT],
16617            computed;
16618
16619        if (node[STYLE] && doc[DEFAULT_VIEW] && doc[DEFAULT_VIEW][GET_COMPUTED_STYLE]) {
16620            computed = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null);
16621            if (computed) { // FF may be null in some cases (ticket #2530548)
16622                val = computed[att];
16623            }
16624        }
16625        return val;
16626    }
16627});
16628
16629// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
16630if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== undefined) {
16631    Y_DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
16632} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== undefined) {
16633    Y_DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
16634}
16635
16636// safari converts transparent to rgba(), others use "transparent"
16637if (Y.UA.webkit) {
16638    Y_DOM[GET_COMPUTED_STYLE] = function(node, att) {
16639        var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
16640            val = view[GET_COMPUTED_STYLE](node, '')[att];
16641
16642        if (val === 'rgba(0, 0, 0, 0)') {
16643            val = TRANSPARENT;
16644        }
16645
16646        return val;
16647    };
16648
16649}
16650
16651Y.DOM._getAttrOffset = function(node, attr) {
16652    var val = Y.DOM[GET_COMPUTED_STYLE](node, attr),
16653        offsetParent = node.offsetParent,
16654        position,
16655        parentOffset,
16656        offset;
16657
16658    if (val === 'auto') {
16659        position = Y.DOM.getStyle(node, 'position');
16660        if (position === 'static' || position === 'relative') {
16661            val = 0;
16662        } else if (offsetParent && offsetParent[GET_BOUNDING_CLIENT_RECT]) {
16663            parentOffset = offsetParent[GET_BOUNDING_CLIENT_RECT]()[attr];
16664            offset = node[GET_BOUNDING_CLIENT_RECT]()[attr];
16665            if (attr === 'left' || attr === 'top') {
16666                val = offset - parentOffset;
16667            } else {
16668                val = parentOffset - node[GET_BOUNDING_CLIENT_RECT]()[attr];
16669            }
16670        }
16671    }
16672
16673    return val;
16674};
16675
16676Y.DOM._getOffset = function(node) {
16677    var pos,
16678        xy = null;
16679
16680    if (node) {
16681        pos = Y_DOM.getStyle(node, 'position');
16682        xy = [
16683            parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'left'), 10),
16684            parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'top'), 10)
16685        ];
16686
16687        if ( isNaN(xy[0]) ) { // in case of 'auto'
16688            xy[0] = parseInt(Y_DOM.getStyle(node, 'left'), 10); // try inline
16689            if ( isNaN(xy[0]) ) { // default to offset value
16690                xy[0] = (pos === 'relative') ? 0 : node.offsetLeft || 0;
16691            }
16692        }
16693
16694        if ( isNaN(xy[1]) ) { // in case of 'auto'
16695            xy[1] = parseInt(Y_DOM.getStyle(node, 'top'), 10); // try inline
16696            if ( isNaN(xy[1]) ) { // default to offset value
16697                xy[1] = (pos === 'relative') ? 0 : node.offsetTop || 0;
16698            }
16699        }
16700    }
16701
16702    return xy;
16703
16704};
16705
16706if (TRANSFORM) {
16707    Y_DOM.CUSTOM_STYLES.transform = {
16708        set: function(node, val, style) {
16709            style[TRANSFORM] = val;
16710        },
16711
16712        get: function(node) {
16713            return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORM);
16714        }
16715    };
16716
16717    Y_DOM.CUSTOM_STYLES.transformOrigin = {
16718        set: function(node, val, style) {
16719            style[TRANSFORMORIGIN] = val;
16720        },
16721
16722        get: function(node) {
16723            return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORMORIGIN);
16724        }
16725    };
16726}
16727
16728
16729}, '3.18.1', {"requires": ["dom-base"]});
16730YUI.add('selector-native', function (Y, NAME) {
16731
16732(function(Y) {
16733/**
16734 * The selector-native module provides support for native querySelector
16735 * @module dom
16736 * @submodule selector-native
16737 * @for Selector
16738 */
16739
16740/**
16741 * Provides support for using CSS selectors to query the DOM
16742 * @class Selector
16743 * @static
16744 * @for Selector
16745 */
16746
16747Y.namespace('Selector'); // allow native module to standalone
16748
16749var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
16750    OWNER_DOCUMENT = 'ownerDocument';
16751
16752var Selector = {
16753    _types: {
16754        esc: {
16755            token: '\uE000',
16756            re: /\\[:\[\]\(\)#\.\'\>+~"]/gi
16757        },
16758
16759        attr: {
16760            token: '\uE001',
16761            re: /(\[[^\]]*\])/g
16762        },
16763
16764        pseudo: {
16765            token: '\uE002',
16766            re: /(\([^\)]*\))/g
16767        }
16768    },
16769
16770    /**
16771     *  Use the native version of `querySelectorAll`, if it exists.
16772     *
16773     * @property useNative
16774     * @default true
16775     * @static
16776     */
16777    useNative: true,
16778
16779    _escapeId: function(id) {
16780        if (id) {
16781            id = id.replace(/([:\[\]\(\)#\.'<>+~"])/g,'\\$1');
16782        }
16783        return id;
16784    },
16785
16786    _compare: ('sourceIndex' in Y.config.doc.documentElement) ?
16787        function(nodeA, nodeB) {
16788            var a = nodeA.sourceIndex,
16789                b = nodeB.sourceIndex;
16790
16791            if (a === b) {
16792                return 0;
16793            } else if (a > b) {
16794                return 1;
16795            }
16796
16797            return -1;
16798
16799        } : (Y.config.doc.documentElement[COMPARE_DOCUMENT_POSITION] ?
16800        function(nodeA, nodeB) {
16801            if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
16802                return -1;
16803            } else {
16804                return 1;
16805            }
16806        } :
16807        function(nodeA, nodeB) {
16808            var rangeA, rangeB, compare;
16809            if (nodeA && nodeB) {
16810                rangeA = nodeA[OWNER_DOCUMENT].createRange();
16811                rangeA.setStart(nodeA, 0);
16812                rangeB = nodeB[OWNER_DOCUMENT].createRange();
16813                rangeB.setStart(nodeB, 0);
16814                compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
16815            }
16816
16817            return compare;
16818
16819    }),
16820
16821    _sort: function(nodes) {
16822        if (nodes) {
16823            nodes = Y.Array(nodes, 0, true);
16824            if (nodes.sort) {
16825                nodes.sort(Selector._compare);
16826            }
16827        }
16828
16829        return nodes;
16830    },
16831
16832    _deDupe: function(nodes) {
16833        var ret = [],
16834            i, node;
16835
16836        for (i = 0; (node = nodes[i++]);) {
16837            if (!node._found) {
16838                ret[ret.length] = node;
16839                node._found = true;
16840            }
16841        }
16842
16843        for (i = 0; (node = ret[i++]);) {
16844            node._found = null;
16845            node.removeAttribute('_found');
16846        }
16847
16848        return ret;
16849    },
16850
16851    /**
16852     * Retrieves a set of nodes based on a given CSS selector.
16853     * @method query
16854     *
16855     * @param {String} selector A CSS selector.
16856     * @param {HTMLElement} root optional A node to start the query from. Defaults to `Y.config.doc`.
16857     * @param {Boolean} firstOnly optional Whether or not to return only the first match.
16858     * @return {HTMLElement[]} The array of nodes that matched the given selector.
16859     * @static
16860     */
16861    query: function(selector, root, firstOnly, skipNative) {
16862        root = root || Y.config.doc;
16863        var ret = [],
16864            useNative = (Y.Selector.useNative && Y.config.doc.querySelector && !skipNative),
16865            queries = [[selector, root]],
16866            query,
16867            result,
16868            i,
16869            fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
16870
16871        if (selector && fn) {
16872            // split group into seperate queries
16873            if (!skipNative && // already done if skipping
16874                    (!useNative || root.tagName)) { // split native when element scoping is needed
16875                queries = Selector._splitQueries(selector, root);
16876            }
16877
16878            for (i = 0; (query = queries[i++]);) {
16879                result = fn(query[0], query[1], firstOnly);
16880                if (!firstOnly) { // coerce DOM Collection to Array
16881                    result = Y.Array(result, 0, true);
16882                }
16883                if (result) {
16884                    ret = ret.concat(result);
16885                }
16886            }
16887
16888            if (queries.length > 1) { // remove dupes and sort by doc order
16889                ret = Selector._sort(Selector._deDupe(ret));
16890            }
16891        }
16892
16893        return (firstOnly) ? (ret[0] || null) : ret;
16894
16895    },
16896
16897    _replaceSelector: function(selector) {
16898        var esc = Y.Selector._parse('esc', selector), // pull escaped colon, brackets, etc.
16899            attrs,
16900            pseudos;
16901
16902        // first replace escaped chars, which could be present in attrs or pseudos
16903        selector = Y.Selector._replace('esc', selector);
16904
16905        // then replace pseudos before attrs to avoid replacing :not([foo])
16906        pseudos = Y.Selector._parse('pseudo', selector);
16907        selector = Selector._replace('pseudo', selector);
16908
16909        attrs = Y.Selector._parse('attr', selector);
16910        selector = Y.Selector._replace('attr', selector);
16911
16912        return {
16913            esc: esc,
16914            attrs: attrs,
16915            pseudos: pseudos,
16916            selector: selector
16917        };
16918    },
16919
16920    _restoreSelector: function(replaced) {
16921        var selector = replaced.selector;
16922        selector = Y.Selector._restore('attr', selector, replaced.attrs);
16923        selector = Y.Selector._restore('pseudo', selector, replaced.pseudos);
16924        selector = Y.Selector._restore('esc', selector, replaced.esc);
16925        return selector;
16926    },
16927
16928    _replaceCommas: function(selector) {
16929        var replaced = Y.Selector._replaceSelector(selector),
16930            selector = replaced.selector;
16931
16932        if (selector) {
16933            selector = selector.replace(/,/g, '\uE007');
16934            replaced.selector = selector;
16935            selector = Y.Selector._restoreSelector(replaced);
16936        }
16937        return selector;
16938    },
16939
16940    // allows element scoped queries to begin with combinator
16941    // e.g. query('> p', document.body) === query('body > p')
16942    _splitQueries: function(selector, node) {
16943        if (selector.indexOf(',') > -1) {
16944            selector = Y.Selector._replaceCommas(selector);
16945        }
16946
16947        var groups = selector.split('\uE007'), // split on replaced comma token
16948            queries = [],
16949            prefix = '',
16950            id,
16951            i,
16952            len;
16953
16954        if (node) {
16955            // enforce for element scoping
16956            if (node.nodeType === 1) { // Elements only
16957                id = Y.Selector._escapeId(Y.DOM.getId(node));
16958
16959                if (!id) {
16960                    id = Y.guid();
16961                    Y.DOM.setId(node, id);
16962                }
16963
16964                prefix = '[id="' + id + '"] ';
16965            }
16966
16967            for (i = 0, len = groups.length; i < len; ++i) {
16968                selector =  prefix + groups[i];
16969                queries.push([selector, node]);
16970            }
16971        }
16972
16973        return queries;
16974    },
16975
16976    _nativeQuery: function(selector, root, one) {
16977        if (
16978            (Y.UA.webkit || Y.UA.opera) &&          // webkit (chrome, safari) and Opera
16979            selector.indexOf(':checked') > -1 &&    // fail to pick up "selected"  with ":checked"
16980            (Y.Selector.pseudos && Y.Selector.pseudos.checked)
16981        ) {
16982            return Y.Selector.query(selector, root, one, true); // redo with skipNative true to try brute query
16983        }
16984        try {
16985            return root['querySelector' + (one ? '' : 'All')](selector);
16986        } catch(e) { // fallback to brute if available
16987            return Y.Selector.query(selector, root, one, true); // redo with skipNative true
16988        }
16989    },
16990
16991    /**
16992     * Filters out nodes that do not match the given CSS selector.
16993     * @method filter
16994     *
16995     * @param {HTMLElement[]} nodes An array of nodes.
16996     * @param {String} selector A CSS selector to test each node against.
16997     * @return {HTMLElement[]} The nodes that matched the given CSS selector.
16998     * @static
16999     */
17000    filter: function(nodes, selector) {
17001        var ret = [],
17002            i, node;
17003
17004        if (nodes && selector) {
17005            for (i = 0; (node = nodes[i++]);) {
17006                if (Y.Selector.test(node, selector)) {
17007                    ret[ret.length] = node;
17008                }
17009            }
17010        } else {
17011        }
17012
17013        return ret;
17014    },
17015
17016    /**
17017     * Determines whether or not the given node matches the given CSS selector.
17018     * @method test
17019     *
17020     * @param {HTMLElement} node A node to test.
17021     * @param {String} selector A CSS selector to test the node against.
17022     * @param {HTMLElement} root optional A node to start the query from. Defaults to the parent document of the node.
17023     * @return {Boolean} Whether or not the given node matched the given CSS selector.
17024     * @static
17025     */
17026    test: function(node, selector, root) {
17027        var ret = false,
17028            useFrag = false,
17029            groups,
17030            parent,
17031            item,
17032            items,
17033            frag,
17034            id,
17035            i, j, group;
17036
17037        if (node && node.tagName) { // only test HTMLElements
17038
17039            if (typeof selector == 'function') { // test with function
17040                ret = selector.call(node, node);
17041            } else { // test with query
17042                // we need a root if off-doc
17043                groups = selector.split(',');
17044                if (!root && !Y.DOM.inDoc(node)) {
17045                    parent = node.parentNode;
17046                    if (parent) {
17047                        root = parent;
17048                    } else { // only use frag when no parent to query
17049                        frag = node[OWNER_DOCUMENT].createDocumentFragment();
17050                        frag.appendChild(node);
17051                        root = frag;
17052                        useFrag = true;
17053                    }
17054                }
17055                root = root || node[OWNER_DOCUMENT];
17056
17057                id = Y.Selector._escapeId(Y.DOM.getId(node));
17058                if (!id) {
17059                    id = Y.guid();
17060                    Y.DOM.setId(node, id);
17061                }
17062
17063                for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
17064                    group += '[id="' + id + '"]';
17065                    items = Y.Selector.query(group, root);
17066
17067                    for (j = 0; item = items[j++];) {
17068                        if (item === node) {
17069                            ret = true;
17070                            break;
17071                        }
17072                    }
17073                    if (ret) {
17074                        break;
17075                    }
17076                }
17077
17078                if (useFrag) { // cleanup
17079                    frag.removeChild(node);
17080                }
17081            };
17082        }
17083
17084        return ret;
17085    },
17086
17087    /**
17088     * A convenience method to emulate Y.Node's aNode.ancestor(selector).
17089     * @method ancestor
17090     *
17091     * @param {HTMLElement} node A node to start the query from.
17092     * @param {String} selector A CSS selector to test the node against.
17093     * @param {Boolean} testSelf optional Whether or not to include the node in the scan.
17094     * @return {HTMLElement} The ancestor node matching the selector, or null.
17095     * @static
17096     */
17097    ancestor: function (node, selector, testSelf) {
17098        return Y.DOM.ancestor(node, function(n) {
17099            return Y.Selector.test(n, selector);
17100        }, testSelf);
17101    },
17102
17103    _parse: function(name, selector) {
17104        return selector.match(Y.Selector._types[name].re);
17105    },
17106
17107    _replace: function(name, selector) {
17108        var o = Y.Selector._types[name];
17109        return selector.replace(o.re, o.token);
17110    },
17111
17112    _restore: function(name, selector, items) {
17113        if (items) {
17114            var token = Y.Selector._types[name].token,
17115                i, len;
17116            for (i = 0, len = items.length; i < len; ++i) {
17117                selector = selector.replace(token, items[i]);
17118            }
17119        }
17120        return selector;
17121    }
17122};
17123
17124Y.mix(Y.Selector, Selector, true);
17125
17126})(Y);
17127
17128
17129}, '3.18.1', {"requires": ["dom-base"]});
17130YUI.add('selector', function (Y, NAME) {
17131
17132
17133
17134}, '3.18.1', {"requires": ["selector-native"]});
17135YUI.add('node-core', function (Y, NAME) {
17136
17137/**
17138 * The Node Utility provides a DOM-like interface for interacting with DOM nodes.
17139 * @module node
17140 * @main node
17141 * @submodule node-core
17142 */
17143
17144/**
17145 * The Node class provides a wrapper for manipulating DOM Nodes.
17146 * Node properties can be accessed via the set/get methods.
17147 * Use `Y.one()` to retrieve Node instances.
17148 *
17149 * <strong>NOTE:</strong> Node properties are accessed using
17150 * the <code>set</code> and <code>get</code> methods.
17151 *
17152 * @class Node
17153 * @constructor
17154 * @param {HTMLElement} node the DOM node to be mapped to the Node instance.
17155 * @uses EventTarget
17156 */
17157
17158// "globals"
17159var DOT = '.',
17160    NODE_NAME = 'nodeName',
17161    NODE_TYPE = 'nodeType',
17162    OWNER_DOCUMENT = 'ownerDocument',
17163    TAG_NAME = 'tagName',
17164    UID = '_yuid',
17165    EMPTY_OBJ = {},
17166
17167    _slice = Array.prototype.slice,
17168
17169    Y_DOM = Y.DOM,
17170
17171    Y_Node = function(node) {
17172        if (!this.getDOMNode) { // support optional "new"
17173            return new Y_Node(node);
17174        }
17175
17176        if (typeof node == 'string') {
17177            node = Y_Node._fromString(node);
17178            if (!node) {
17179                return null; // NOTE: return
17180            }
17181        }
17182
17183        var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
17184
17185        if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
17186            node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
17187        }
17188
17189        uid = uid || Y.stamp(node);
17190        if (!uid) { // stamp failed; likely IE non-HTMLElement
17191            uid = Y.guid();
17192        }
17193
17194        this[UID] = uid;
17195
17196        /**
17197         * The underlying DOM node bound to the Y.Node instance
17198         * @property _node
17199         * @type HTMLElement
17200         * @private
17201         */
17202        this._node = node;
17203
17204        this._stateProxy = node; // when augmented with Attribute
17205
17206        if (this._initPlugins) { // when augmented with Plugin.Host
17207            this._initPlugins();
17208        }
17209    },
17210
17211    // used with previous/next/ancestor tests
17212    _wrapFn = function(fn) {
17213        var ret = null;
17214        if (fn) {
17215            ret = (typeof fn == 'string') ?
17216            function(n) {
17217                return Y.Selector.test(n, fn);
17218            } :
17219            function(n) {
17220                return fn(Y.one(n));
17221            };
17222        }
17223
17224        return ret;
17225    };
17226// end "globals"
17227
17228Y_Node.ATTRS = {};
17229Y_Node.DOM_EVENTS = {};
17230
17231Y_Node._fromString = function(node) {
17232    if (node) {
17233        if (node.indexOf('doc') === 0) { // doc OR document
17234            node = Y.config.doc;
17235        } else if (node.indexOf('win') === 0) { // win OR window
17236            node = Y.config.win;
17237        } else {
17238            node = Y.Selector.query(node, null, true);
17239        }
17240    }
17241
17242    return node || null;
17243};
17244
17245/**
17246 * The name of the component
17247 * @static
17248 * @type String
17249 * @property NAME
17250 */
17251Y_Node.NAME = 'node';
17252
17253/*
17254 * The pattern used to identify ARIA attributes
17255 */
17256Y_Node.re_aria = /^(?:role$|aria-)/;
17257
17258Y_Node.SHOW_TRANSITION = 'fadeIn';
17259Y_Node.HIDE_TRANSITION = 'fadeOut';
17260
17261/**
17262 * A list of Node instances that have been created
17263 * @private
17264 * @type Object
17265 * @property _instances
17266 * @static
17267 *
17268 */
17269Y_Node._instances = {};
17270
17271/**
17272 * Retrieves the DOM node bound to a Node instance
17273 * @method getDOMNode
17274 * @static
17275 *
17276 * @param {Node|HTMLElement} node The Node instance or an HTMLElement
17277 * @return {HTMLElement} The DOM node bound to the Node instance.  If a DOM node is passed
17278 * as the node argument, it is simply returned.
17279 */
17280Y_Node.getDOMNode = function(node) {
17281    if (node) {
17282        return (node.nodeType) ? node : node._node || null;
17283    }
17284    return null;
17285};
17286
17287/**
17288 * Checks Node return values and wraps DOM Nodes as Y.Node instances
17289 * and DOM Collections / Arrays as Y.NodeList instances.
17290 * Other return values just pass thru.  If undefined is returned (e.g. no return)
17291 * then the Node instance is returned for chainability.
17292 * @method scrubVal
17293 * @static
17294 *
17295 * @param {HTMLElement|HTMLElement[]|Node} node The Node instance or an HTMLElement
17296 * @return {Node | NodeList | Any} Depends on what is returned from the DOM node.
17297 */
17298Y_Node.scrubVal = function(val, node) {
17299    if (val) { // only truthy values are risky
17300         if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
17301            if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
17302                val = Y.one(val);
17303            } else if ((val.item && !val._nodes) || // dom collection or Node instance
17304                    (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
17305                val = Y.all(val);
17306            }
17307        }
17308    } else if (typeof val === 'undefined') {
17309        val = node; // for chaining
17310    } else if (val === null) {
17311        val = null; // IE: DOM null not the same as null
17312    }
17313
17314    return val;
17315};
17316
17317/**
17318 * Adds methods to the Y.Node prototype, routing through scrubVal.
17319 * @method addMethod
17320 * @static
17321 *
17322 * @param {String} name The name of the method to add
17323 * @param {Function} fn The function that becomes the method
17324 * @param {Object} context An optional context to call the method with
17325 * (defaults to the Node instance)
17326 * @return {any} Depends on what is returned from the DOM node.
17327 */
17328Y_Node.addMethod = function(name, fn, context) {
17329    if (name && fn && typeof fn == 'function') {
17330        Y_Node.prototype[name] = function() {
17331            var args = _slice.call(arguments),
17332                node = this,
17333                ret;
17334
17335            if (args[0] && args[0]._node) {
17336                args[0] = args[0]._node;
17337            }
17338
17339            if (args[1] && args[1]._node) {
17340                args[1] = args[1]._node;
17341            }
17342            args.unshift(node._node);
17343
17344            ret = fn.apply(context || node, args);
17345
17346            if (ret) { // scrub truthy
17347                ret = Y_Node.scrubVal(ret, node);
17348            }
17349
17350            (typeof ret != 'undefined') || (ret = node);
17351            return ret;
17352        };
17353    } else {
17354    }
17355};
17356
17357/**
17358 * Imports utility methods to be added as Y.Node methods.
17359 * @method importMethod
17360 * @static
17361 *
17362 * @param {Object} host The object that contains the method to import.
17363 * @param {String} name The name of the method to import
17364 * @param {String} altName An optional name to use in place of the host name
17365 * @param {Object} context An optional context to call the method with
17366 */
17367Y_Node.importMethod = function(host, name, altName) {
17368    if (typeof name == 'string') {
17369        altName = altName || name;
17370        Y_Node.addMethod(altName, host[name], host);
17371    } else {
17372        Y.Array.each(name, function(n) {
17373            Y_Node.importMethod(host, n);
17374        });
17375    }
17376};
17377
17378/**
17379 * Retrieves a NodeList based on the given CSS selector.
17380 * @method all
17381 *
17382 * @param {string} selector The CSS selector to test against.
17383 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
17384 * @for YUI
17385 */
17386
17387/**
17388 * Returns a single Node instance bound to the node or the
17389 * first element matching the given selector. Returns null if no match found.
17390 * <strong>Note:</strong> For chaining purposes you may want to
17391 * use <code>Y.all</code>, which returns a NodeList when no match is found.
17392 * @method one
17393 * @param {String | HTMLElement} node a node or Selector
17394 * @return {Node | null} a Node instance or null if no match found.
17395 * @for YUI
17396 */
17397
17398/**
17399 * Returns a single Node instance bound to the node or the
17400 * first element matching the given selector. Returns null if no match found.
17401 * <strong>Note:</strong> For chaining purposes you may want to
17402 * use <code>Y.all</code>, which returns a NodeList when no match is found.
17403 * @method one
17404 * @static
17405 * @param {String | HTMLElement} node a node or Selector
17406 * @return {Node | null} a Node instance or null if no match found.
17407 * @for Node
17408 */
17409Y_Node.one = function(node) {
17410    var instance = null,
17411        cachedNode,
17412        uid;
17413
17414    if (node) {
17415        if (typeof node == 'string') {
17416            node = Y_Node._fromString(node);
17417            if (!node) {
17418                return null; // NOTE: return
17419            }
17420        } else if (node.getDOMNode) {
17421            return node; // NOTE: return
17422        }
17423
17424        if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
17425            uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
17426            instance = Y_Node._instances[uid]; // reuse exising instances
17427            cachedNode = instance ? instance._node : null;
17428            if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
17429                instance = new Y_Node(node);
17430                if (node.nodeType != 11) { // dont cache document fragment
17431                    Y_Node._instances[instance[UID]] = instance; // cache node
17432                }
17433            }
17434        }
17435    }
17436
17437    return instance;
17438};
17439
17440/**
17441 * The default setter for DOM properties
17442 * Called with instance context (this === the Node instance)
17443 * @method DEFAULT_SETTER
17444 * @static
17445 * @param {String} name The attribute/property being set
17446 * @param {any} val The value to be set
17447 * @return {any} The value
17448 */
17449Y_Node.DEFAULT_SETTER = function(name, val) {
17450    var node = this._stateProxy,
17451        strPath;
17452
17453    if (name.indexOf(DOT) > -1) {
17454        strPath = name;
17455        name = name.split(DOT);
17456        // only allow when defined on node
17457        Y.Object.setValue(node, name, val);
17458    } else if (typeof node[name] != 'undefined') { // pass thru DOM properties
17459        node[name] = val;
17460    }
17461
17462    return val;
17463};
17464
17465/**
17466 * The default getter for DOM properties
17467 * Called with instance context (this === the Node instance)
17468 * @method DEFAULT_GETTER
17469 * @static
17470 * @param {String} name The attribute/property to look up
17471 * @return {any} The current value
17472 */
17473Y_Node.DEFAULT_GETTER = function(name) {
17474    var node = this._stateProxy,
17475        val;
17476
17477    if (name.indexOf && name.indexOf(DOT) > -1) {
17478        val = Y.Object.getValue(node, name.split(DOT));
17479    } else if (typeof node[name] != 'undefined') { // pass thru from DOM
17480        val = node[name];
17481    }
17482
17483    return val;
17484};
17485
17486Y.mix(Y_Node.prototype, {
17487    DATA_PREFIX: 'data-',
17488
17489    /**
17490     * The method called when outputting Node instances as strings
17491     * @method toString
17492     * @return {String} A string representation of the Node instance
17493     */
17494    toString: function() {
17495        var str = this[UID] + ': not bound to a node',
17496            node = this._node,
17497            attrs, id, className;
17498
17499        if (node) {
17500            attrs = node.attributes;
17501            id = (attrs && attrs.id) ? node.getAttribute('id') : null;
17502            className = (attrs && attrs.className) ? node.getAttribute('className') : null;
17503            str = node[NODE_NAME];
17504
17505            if (id) {
17506                str += '#' + id;
17507            }
17508
17509            if (className) {
17510                str += '.' + className.replace(' ', '.');
17511            }
17512
17513            // TODO: add yuid?
17514            str += ' ' + this[UID];
17515        }
17516        return str;
17517    },
17518
17519    /**
17520     * Returns an attribute value on the Node instance.
17521     * Unless pre-configured (via `Node.ATTRS`), get hands
17522     * off to the underlying DOM node.  Only valid
17523     * attributes/properties for the node will be queried.
17524     * @method get
17525     * @param {String} attr The attribute
17526     * @return {any} The current value of the attribute
17527     */
17528    get: function(attr) {
17529        var val;
17530
17531        if (this._getAttr) { // use Attribute imple
17532            val = this._getAttr(attr);
17533        } else {
17534            val = this._get(attr);
17535        }
17536
17537        if (val) {
17538            val = Y_Node.scrubVal(val, this);
17539        } else if (val === null) {
17540            val = null; // IE: DOM null is not true null (even though they ===)
17541        }
17542        return val;
17543    },
17544
17545    /**
17546     * Helper method for get.
17547     * @method _get
17548     * @private
17549     * @param {String} attr The attribute
17550     * @return {any} The current value of the attribute
17551     */
17552    _get: function(attr) {
17553        var attrConfig = Y_Node.ATTRS[attr],
17554            val;
17555
17556        if (attrConfig && attrConfig.getter) {
17557            val = attrConfig.getter.call(this);
17558        } else if (Y_Node.re_aria.test(attr)) {
17559            val = this._node.getAttribute(attr, 2);
17560        } else {
17561            val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
17562        }
17563
17564        return val;
17565    },
17566
17567    /**
17568     * Sets an attribute on the Node instance.
17569     * Unless pre-configured (via Node.ATTRS), set hands
17570     * off to the underlying DOM node.  Only valid
17571     * attributes/properties for the node will be set.
17572     * To set custom attributes use setAttribute.
17573     * @method set
17574     * @param {String} attr The attribute to be set.
17575     * @param {any} val The value to set the attribute to.
17576     * @chainable
17577     */
17578    set: function(attr, val) {
17579        var attrConfig = Y_Node.ATTRS[attr];
17580
17581        if (this._setAttr) { // use Attribute imple
17582            this._setAttr.apply(this, arguments);
17583        } else { // use setters inline
17584            if (attrConfig && attrConfig.setter) {
17585                attrConfig.setter.call(this, val, attr);
17586            } else if (Y_Node.re_aria.test(attr)) { // special case Aria
17587                this._node.setAttribute(attr, val);
17588            } else {
17589                Y_Node.DEFAULT_SETTER.apply(this, arguments);
17590            }
17591        }
17592
17593        return this;
17594    },
17595
17596    /**
17597     * Sets multiple attributes.
17598     * @method setAttrs
17599     * @param {Object} attrMap an object of name/value pairs to set
17600     * @chainable
17601     */
17602    setAttrs: function(attrMap) {
17603        if (this._setAttrs) { // use Attribute imple
17604            this._setAttrs(attrMap);
17605        } else { // use setters inline
17606            Y.Object.each(attrMap, function(v, n) {
17607                this.set(n, v);
17608            }, this);
17609        }
17610
17611        return this;
17612    },
17613
17614    /**
17615     * Returns an object containing the values for the requested attributes.
17616     * @method getAttrs
17617     * @param {Array} attrs an array of attributes to get values
17618     * @return {Object} An object with attribute name/value pairs.
17619     */
17620    getAttrs: function(attrs) {
17621        var ret = {};
17622        if (this._getAttrs) { // use Attribute imple
17623            this._getAttrs(attrs);
17624        } else { // use setters inline
17625            Y.Array.each(attrs, function(v, n) {
17626                ret[v] = this.get(v);
17627            }, this);
17628        }
17629
17630        return ret;
17631    },
17632
17633    /**
17634     * Compares nodes to determine if they match.
17635     * Node instances can be compared to each other and/or HTMLElements.
17636     * @method compareTo
17637     * @param {HTMLElement | Node} refNode The reference node to compare to the node.
17638     * @return {Boolean} True if the nodes match, false if they do not.
17639     */
17640    compareTo: function(refNode) {
17641        var node = this._node;
17642
17643        if (refNode && refNode._node) {
17644            refNode = refNode._node;
17645        }
17646        return node === refNode;
17647    },
17648
17649    /**
17650     * Determines whether the node is appended to the document.
17651     * @method inDoc
17652     * @param {Node|HTMLElement} doc optional An optional document to check against.
17653     * Defaults to current document.
17654     * @return {Boolean} Whether or not this node is appended to the document.
17655     */
17656    inDoc: function(doc) {
17657        var node = this._node;
17658
17659        if (node) {
17660            doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
17661            if (doc.documentElement) {
17662                return Y_DOM.contains(doc.documentElement, node);
17663            }
17664        }
17665
17666        return false;
17667    },
17668
17669    getById: function(id) {
17670        var node = this._node,
17671            ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
17672        if (ret && Y_DOM.contains(node, ret)) {
17673            ret = Y.one(ret);
17674        } else {
17675            ret = null;
17676        }
17677        return ret;
17678    },
17679
17680   /**
17681     * Returns the nearest ancestor that passes the test applied by supplied boolean method.
17682     * @method ancestor
17683     * @param {String | Function} fn A selector string or boolean method for testing elements.
17684     * If a function is used, it receives the current node being tested as the only argument.
17685     * If fn is not passed as an argument, the parent node will be returned.
17686     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
17687     * @param {String | Function} stopFn optional A selector string or boolean
17688     * method to indicate when the search should stop. The search bails when the function
17689     * returns true or the selector matches.
17690     * If a function is used, it receives the current node being tested as the only argument.
17691     * @return {Node} The matching Node instance or null if not found
17692     */
17693    ancestor: function(fn, testSelf, stopFn) {
17694        // testSelf is optional, check for stopFn as 2nd arg
17695        if (arguments.length === 2 &&
17696                (typeof testSelf == 'string' || typeof testSelf == 'function')) {
17697            stopFn = testSelf;
17698        }
17699
17700        return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
17701    },
17702
17703   /**
17704     * Returns the ancestors that pass the test applied by supplied boolean method.
17705     * @method ancestors
17706     * @param {String | Function} fn A selector string or boolean method for testing elements.
17707     * @param {Boolean} testSelf optional Whether or not to include the element in the scan
17708     * If a function is used, it receives the current node being tested as the only argument.
17709     * @return {NodeList} A NodeList instance containing the matching elements
17710     */
17711    ancestors: function(fn, testSelf, stopFn) {
17712        if (arguments.length === 2 &&
17713                (typeof testSelf == 'string' || typeof testSelf == 'function')) {
17714            stopFn = testSelf;
17715        }
17716        return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
17717    },
17718
17719    /**
17720     * Returns the previous matching sibling.
17721     * Returns the nearest element node sibling if no method provided.
17722     * @method previous
17723     * @param {String | Function} fn A selector or boolean method for testing elements.
17724     * If a function is used, it receives the current node being tested as the only argument.
17725     * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or
17726     * just element nodes will be returned(default)
17727     * @return {Node} Node instance or null if not found
17728     */
17729    previous: function(fn, all) {
17730        return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
17731    },
17732
17733    /**
17734     * Returns the next matching sibling.
17735     * Returns the nearest element node sibling if no method provided.
17736     * @method next
17737     * @param {String | Function} fn A selector or boolean method for testing elements.
17738     * If a function is used, it receives the current node being tested as the only argument.
17739     * @param {Boolean} [all] Whether text nodes as well as element nodes should be returned, or
17740     * just element nodes will be returned(default)
17741     * @return {Node} Node instance or null if not found
17742     */
17743    next: function(fn, all) {
17744        return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
17745    },
17746
17747    /**
17748     * Returns all matching siblings.
17749     * Returns all siblings if no method provided.
17750     * @method siblings
17751     * @param {String | Function} fn A selector or boolean method for testing elements.
17752     * If a function is used, it receives the current node being tested as the only argument.
17753     * @return {NodeList} NodeList instance bound to found siblings
17754     */
17755    siblings: function(fn) {
17756        return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
17757    },
17758
17759    /**
17760     * Retrieves a single Node instance, the first element matching the given
17761     * CSS selector.
17762     * Returns null if no match found.
17763     * @method one
17764     *
17765     * @param {string} selector The CSS selector to test against.
17766     * @return {Node | null} A Node instance for the matching HTMLElement or null
17767     * if no match found.
17768     */
17769    one: function(selector) {
17770        return Y.one(Y.Selector.query(selector, this._node, true));
17771    },
17772
17773    /**
17774     * Retrieves a NodeList based on the given CSS selector.
17775     * @method all
17776     *
17777     * @param {string} selector The CSS selector to test against.
17778     * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
17779     */
17780    all: function(selector) {
17781        var nodelist;
17782
17783        if (this._node) {
17784            nodelist = Y.all(Y.Selector.query(selector, this._node));
17785            nodelist._query = selector;
17786            nodelist._queryRoot = this._node;
17787        }
17788
17789        return nodelist || Y.all([]);
17790    },
17791
17792    // TODO: allow fn test
17793    /**
17794     * Test if the supplied node matches the supplied selector.
17795     * @method test
17796     *
17797     * @param {string} selector The CSS selector to test against.
17798     * @return {boolean} Whether or not the node matches the selector.
17799     */
17800    test: function(selector) {
17801        return Y.Selector.test(this._node, selector);
17802    },
17803
17804    /**
17805     * Removes the node from its parent.
17806     * Shortcut for myNode.get('parentNode').removeChild(myNode);
17807     * @method remove
17808     * @param {Boolean} destroy whether or not to call destroy() on the node
17809     * after removal.
17810     * @chainable
17811     *
17812     */
17813    remove: function(destroy) {
17814        var node = this._node;
17815
17816        if (node && node.parentNode) {
17817            node.parentNode.removeChild(node);
17818        }
17819
17820        if (destroy) {
17821            this.destroy();
17822        }
17823
17824        return this;
17825    },
17826
17827    /**
17828     * Replace the node with the other node. This is a DOM update only
17829     * and does not change the node bound to the Node instance.
17830     * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
17831     * @method replace
17832     * @param {Node | HTMLElement} newNode Node to be inserted
17833     * @chainable
17834     *
17835     */
17836    replace: function(newNode) {
17837        var node = this._node;
17838        if (typeof newNode == 'string') {
17839            newNode = Y_Node.create(newNode);
17840        }
17841        node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
17842        return this;
17843    },
17844
17845    /**
17846     * @method replaceChild
17847     * @for Node
17848     * @param {String | HTMLElement | Node} node Node to be inserted
17849     * @param {HTMLElement | Node} refNode Node to be replaced
17850     * @return {Node} The replaced node
17851     */
17852    replaceChild: function(node, refNode) {
17853        if (typeof node == 'string') {
17854            node = Y_DOM.create(node);
17855        }
17856
17857        return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
17858    },
17859
17860    /**
17861     * Nulls internal node references, removes any plugins and event listeners.
17862     * Note that destroy() will not remove the node from its parent or from the DOM. For that
17863     * functionality, call remove(true).
17864     * @method destroy
17865     * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
17866     * node's subtree (default is false)
17867     *
17868     */
17869    destroy: function(recursive) {
17870        var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid',
17871            instance;
17872
17873        this.purge(); // TODO: only remove events add via this Node
17874
17875        if (this.unplug) { // may not be a PluginHost
17876            this.unplug();
17877        }
17878
17879        this.clearData();
17880
17881        if (recursive) {
17882            Y.NodeList.each(this.all('*'), function(node) {
17883                instance = Y_Node._instances[node[UID]];
17884                if (instance) {
17885                   instance.destroy();
17886                } else { // purge in case added by other means
17887                    Y.Event.purgeElement(node);
17888                }
17889            });
17890        }
17891
17892        this._node = null;
17893        this._stateProxy = null;
17894
17895        delete Y_Node._instances[this._yuid];
17896    },
17897
17898    /**
17899     * Invokes a method on the Node instance
17900     * @method invoke
17901     * @param {String} method The name of the method to invoke
17902     * @param {any} [args*] Arguments to invoke the method with.
17903     * @return {any} Whatever the underly method returns.
17904     * DOM Nodes and Collections return values
17905     * are converted to Node/NodeList instances.
17906     *
17907     */
17908    invoke: function(method, a, b, c, d, e) {
17909        var node = this._node,
17910            ret;
17911
17912        if (a && a._node) {
17913            a = a._node;
17914        }
17915
17916        if (b && b._node) {
17917            b = b._node;
17918        }
17919
17920        ret = node[method](a, b, c, d, e);
17921        return Y_Node.scrubVal(ret, this);
17922    },
17923
17924    /**
17925    * @method swap
17926    * @description Swap DOM locations with the given node.
17927    * This does not change which DOM node each Node instance refers to.
17928    * @param {Node} otherNode The node to swap with
17929     * @chainable
17930    */
17931    swap: Y.config.doc.documentElement.swapNode ?
17932        function(otherNode) {
17933            this._node.swapNode(Y_Node.getDOMNode(otherNode));
17934        } :
17935        function(otherNode) {
17936            otherNode = Y_Node.getDOMNode(otherNode);
17937            var node = this._node,
17938                parent = otherNode.parentNode,
17939                nextSibling = otherNode.nextSibling;
17940
17941            if (nextSibling === node) {
17942                parent.insertBefore(node, otherNode);
17943            } else if (otherNode === node.nextSibling) {
17944                parent.insertBefore(otherNode, node);
17945            } else {
17946                node.parentNode.replaceChild(otherNode, node);
17947                Y_DOM.addHTML(parent, node, nextSibling);
17948            }
17949            return this;
17950        },
17951
17952
17953    hasMethod: function(method) {
17954        var node = this._node;
17955        return !!(node && method in node &&
17956                typeof node[method] != 'unknown' &&
17957            (typeof node[method] == 'function' ||
17958                String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
17959    },
17960
17961    isFragment: function() {
17962        return (this.get('nodeType') === 11);
17963    },
17964
17965    /**
17966     * Removes and destroys all of the nodes within the node.
17967     * @method empty
17968     * @chainable
17969     */
17970    empty: function() {
17971        this.get('childNodes').remove().destroy(true);
17972        return this;
17973    },
17974
17975    /**
17976     * Returns the DOM node bound to the Node instance
17977     * @method getDOMNode
17978     * @return {HTMLElement}
17979     */
17980    getDOMNode: function() {
17981        return this._node;
17982    }
17983}, true);
17984
17985Y.Node = Y_Node;
17986Y.one = Y_Node.one;
17987/**
17988 * The NodeList module provides support for managing collections of Nodes.
17989 * @module node
17990 * @submodule node-core
17991 */
17992
17993/**
17994 * The NodeList class provides a wrapper for manipulating DOM NodeLists.
17995 * NodeList properties can be accessed via the set/get methods.
17996 * Use Y.all() to retrieve NodeList instances.
17997 *
17998 * @class NodeList
17999 * @constructor
18000 * @param nodes {String|element|Node|Array} A selector, DOM element, Node, list of DOM elements, or list of Nodes with which to populate this NodeList.
18001 */
18002
18003var NodeList = function(nodes) {
18004    var tmp = [];
18005
18006    if (nodes) {
18007        if (typeof nodes === 'string') { // selector query
18008            this._query = nodes;
18009            nodes = Y.Selector.query(nodes);
18010        } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
18011            nodes = [nodes];
18012        } else if (nodes._node) { // Y.Node
18013            nodes = [nodes._node];
18014        } else if (nodes[0] && nodes[0]._node) { // allow array of Y.Nodes
18015            Y.Array.each(nodes, function(node) {
18016                if (node._node) {
18017                    tmp.push(node._node);
18018                }
18019            });
18020            nodes = tmp;
18021        } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
18022            nodes = Y.Array(nodes, 0, true);
18023        }
18024    }
18025
18026    /**
18027     * The underlying array of DOM nodes bound to the Y.NodeList instance
18028     * @property _nodes
18029     * @private
18030     */
18031    this._nodes = nodes || [];
18032};
18033
18034NodeList.NAME = 'NodeList';
18035
18036/**
18037 * Retrieves the DOM nodes bound to a NodeList instance
18038 * @method getDOMNodes
18039 * @static
18040 *
18041 * @param {NodeList} nodelist The NodeList instance
18042 * @return {Array} The array of DOM nodes bound to the NodeList
18043 */
18044NodeList.getDOMNodes = function(nodelist) {
18045    return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
18046};
18047
18048NodeList.each = function(instance, fn, context) {
18049    var nodes = instance._nodes;
18050    if (nodes && nodes.length) {
18051        Y.Array.each(nodes, fn, context || instance);
18052    } else {
18053    }
18054};
18055
18056NodeList.addMethod = function(name, fn, context) {
18057    if (name && fn) {
18058        NodeList.prototype[name] = function() {
18059            var ret = [],
18060                args = arguments;
18061
18062            Y.Array.each(this._nodes, function(node) {
18063                var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
18064                    instance = Y.Node._instances[node[UID]],
18065                    ctx,
18066                    result;
18067
18068                if (!instance) {
18069                    instance = NodeList._getTempNode(node);
18070                }
18071                ctx = context || instance;
18072                result = fn.apply(ctx, args);
18073                if (result !== undefined && result !== instance) {
18074                    ret[ret.length] = result;
18075                }
18076            });
18077
18078            // TODO: remove tmp pointer
18079            return ret.length ? ret : this;
18080        };
18081    } else {
18082    }
18083};
18084
18085/**
18086 * Import the named method, or methods from the host onto NodeList.
18087 *
18088 * @method importMethod
18089 * @static
18090 * @param {Object}
18090 host The object containing the methods to copy. Typically a prototype.
18091 * @param {String|String[]} name The name, or an Array of names of the methods to import onto NodeList.
18092 * @param {String} [altName] An alternative name to use for the method added to NodeList, which may differ from the name
18093 * of the original host object. Has no effect if <em>name</em> is an array of method names.
18094 */
18095NodeList.importMethod = function(host, name, altName) {
18096    if (typeof name === 'string') {
18097        altName = altName || name;
18098        NodeList.addMethod(altName, host[name]);
18099    } else {
18100        Y.Array.each(name, function(n) {
18101            NodeList.importMethod(host, n);
18102        });
18103    }
18104};
18105
18106NodeList._getTempNode = function(node) {
18107    var tmp = NodeList._tempNode;
18108    if (!tmp) {
18109        tmp = Y.Node.create('<div></div>');
18110        NodeList._tempNode = tmp;
18111    }
18112
18113    tmp._node = node;
18114    tmp._stateProxy = node;
18115    return tmp;
18116};
18117
18118Y.mix(NodeList.prototype, {
18119    _invoke: function(method, args, getter) {
18120        var ret = (getter) ? [] : this;
18121
18122        this.each(function(node) {
18123            var val = node[method].apply(node, args);
18124            if (getter) {
18125                ret.push(val);
18126            }
18127        });
18128
18129        return ret;
18130    },
18131
18132    /**
18133     * Retrieves the Node instance at the given index.
18134     * @method item
18135     *
18136     * @param {Number} index The index of the target Node.
18137     * @return {Node} The Node instance at the given index.
18138     */
18139    item: function(index) {
18140        return Y.one((this._nodes || [])[index]);
18141    },
18142
18143    /**
18144     * Applies the given function to each Node in the NodeList.
18145     * @method each
18146     * @param {Function} fn The function to apply. It receives 3 arguments:
18147     * the current node instance, the node's index, and the NodeList instance
18148     * @param {Object} context optional An optional context to apply the function with
18149     * Default context is the current Node instance
18150     * @chainable
18151     */
18152    each: function(fn, context) {
18153        var instance = this;
18154        Y.Array.each(this._nodes, function(node, index) {
18155            node = Y.one(node);
18156            return fn.call(context || node, node, index, instance);
18157        });
18158        return instance;
18159    },
18160
18161    batch: function(fn, context) {
18162        var nodelist = this;
18163
18164        Y.Array.each(this._nodes, function(node, index) {
18165            var instance = Y.Node._instances[node[UID]];
18166            if (!instance) {
18167                instance = NodeList._getTempNode(node);
18168            }
18169
18170            return fn.call(context || instance, instance, index, nodelist);
18171        });
18172        return nodelist;
18173    },
18174
18175    /**
18176     * Executes the function once for each node until a true value is returned.
18177     * @method some
18178     * @param {Function} fn The function to apply. It receives 3 arguments:
18179     * the current node instance, the node's index, and the NodeList instance
18180     * @param {Object} context optional An optional context to execute the function from.
18181     * Default context is the current Node instance
18182     * @return {Boolean} Whether or not the function returned true for any node.
18183     */
18184    some: function(fn, context) {
18185        var instance = this;
18186        return Y.Array.some(this._nodes, function(node, index) {
18187            node = Y.one(node);
18188            context = context || node;
18189            return fn.call(context, node, index, instance);
18190        });
18191    },
18192
18193    /**
18194     * Creates a documenFragment from the nodes bound to the NodeList instance
18195     * @method toFrag
18196     * @return {Node} a Node instance bound to the documentFragment
18197     */
18198    toFrag: function() {
18199        return Y.one(Y.DOM._nl2frag(this._nodes));
18200    },
18201
18202    /**
18203     * Returns the index of the node in the NodeList instance
18204     * or -1 if the node isn't found.
18205     * @method indexOf
18206     * @param {Node | HTMLElement} node the node to search for
18207     * @return {Number} the index of the node value or -1 if not found
18208     */
18209    indexOf: function(node) {
18210        return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
18211    },
18212
18213    /**
18214     * Filters the NodeList instance down to only nodes matching the given selector.
18215     * @method filter
18216     * @param {String} selector The selector to filter against
18217     * @return {NodeList} NodeList containing the updated collection
18218     * @see Selector
18219     */
18220    filter: function(selector) {
18221        return Y.all(Y.Selector.filter(this._nodes, selector));
18222    },
18223
18224
18225    /**
18226     * Creates a new NodeList containing all nodes at every n indices, where
18227     * remainder n % index equals r.
18228     * (zero-based index).
18229     * @method modulus
18230     * @param {Number} n The offset to use (return every nth node)
18231     * @param {Number} r An optional remainder to use with the modulus operation (defaults to zero)
18232     * @return {NodeList} NodeList containing the updated collection
18233     */
18234    modulus: function(n, r) {
18235        r = r || 0;
18236        var nodes = [];
18237        NodeList.each(this, function(node, i) {
18238            if (i % n === r) {
18239                nodes.push(node);
18240            }
18241        });
18242
18243        return Y.all(nodes);
18244    },
18245
18246    /**
18247     * Creates a new NodeList containing all nodes at odd indices
18248     * (zero-based index).
18249     * @method odd
18250     * @return {NodeList} NodeList containing the updated collection
18251     */
18252    odd: function() {
18253        return this.modulus(2, 1);
18254    },
18255
18256    /**
18257     * Creates a new NodeList containing all nodes at even indices
18258     * (zero-based index), including zero.
18259     * @method even
18260     * @return {NodeList} NodeList containing the updated collection
18261     */
18262    even: function() {
18263        return this.modulus(2);
18264    },
18265
18266    destructor: function() {
18267    },
18268
18269    /**
18270     * Reruns the initial query, when created using a selector query
18271     * @method refresh
18272     * @chainable
18273     */
18274    refresh: function() {
18275        var doc,
18276            nodes = this._nodes,
18277            query = this._query,
18278            root = this._queryRoot;
18279
18280        if (query) {
18281            if (!root) {
18282                if (nodes && nodes[0] && nodes[0].ownerDocument) {
18283                    root = nodes[0].ownerDocument;
18284                }
18285            }
18286
18287            this._nodes = Y.Selector.query(query, root);
18288        }
18289
18290        return this;
18291    },
18292
18293    /**
18294     * Returns the current number of items in the NodeList.
18295     * @method size
18296     * @return {Number} The number of items in the NodeList.
18297     */
18298    size: function() {
18299        return this._nodes.length;
18300    },
18301
18302    /**
18303     * Determines if the instance is bound to any nodes
18304     * @method isEmpty
18305     * @return {Boolean} Whether or not the NodeList is bound to any nodes
18306     */
18307    isEmpty: function() {
18308        return this._nodes.length < 1;
18309    },
18310
18311    toString: function() {
18312        var str = '',
18313            errorMsg = this[UID] + ': not bound to any nodes',
18314            nodes = this._nodes,
18315            node;
18316
18317        if (nodes && nodes[0]) {
18318            node = nodes[0];
18319            str += node[NODE_NAME];
18320            if (node.id) {
18321                str += '#' + node.id;
18322            }
18323
18324            if (node.className) {
18325                str += '.' + node.className.replace(' ', '.');
18326            }
18327
18328            if (nodes.length > 1) {
18329                str += '...[' + nodes.length + ' items]';
18330            }
18331        }
18332        return str || errorMsg;
18333    },
18334
18335    /**
18336     * Returns the DOM node bound to the Node instance
18337     * @method getDOMNodes
18338     * @return {Array}
18339     */
18340    getDOMNodes: function() {
18341        return this._nodes;
18342    }
18343}, true);
18344
18345NodeList.importMethod(Y.Node.prototype, [
18346     /**
18347      * Called on each Node instance. Nulls internal node references,
18348      * removes any plugins and event listeners
18349      * @method destroy
18350      * @param {Boolean} recursivePurge (optional) Whether or not to
18351      * remove listeners from the node's subtree (default is false)
18352      * @see Node.destroy
18353      */
18354    'destroy',
18355
18356     /**
18357      * Called on each Node instance. Removes and destroys all of the nodes
18358      * within the node
18359      * @method empty
18360      * @chainable
18361      * @see Node.empty
18362      */
18363    'empty',
18364
18365     /**
18366      * Called on each Node instance. Removes the node from its parent.
18367      * Shortcut for myNode.get('parentNode').removeChild(myNode);
18368      * @method remove
18369      * @param {Boolean} destroy whether or not to call destroy() on the node
18370      * after removal.
18371      * @chainable
18372      * @see Node.remove
18373      */
18374    'remove',
18375
18376     /**
18377      * Called on each Node instance. Sets an attribute on the Node instance.
18378      * Unless pre-configured (via Node.ATTRS), set hands
18379      * off to the underlying DOM node.  Only valid
18380      * attributes/properties for the node will be set.
18381      * To set custom attributes use setAttribute.
18382      * @method set
18383      * @param {String} attr The attribute to be set.
18384      * @param {any} val The value to set the attribute to.
18385      * @chainable
18386      * @see Node.set
18387      */
18388    'set'
18389]);
18390
18391// one-off implementation to convert array of Nodes to NodeList
18392// e.g. Y.all('input').get('parentNode');
18393
18394/** Called on each Node instance
18395  * @method get
18396  * @see Node
18397  */
18398NodeList.prototype.get = function(attr) {
18399    var ret = [],
18400        nodes = this._nodes,
18401        isNodeList = false,
18402        getTemp = NodeList._getTempNode,
18403        instance,
18404        val;
18405
18406    if (nodes[0]) {
18407        instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
18408        val = instance._get(attr);
18409        if (val && val.nodeType) {
18410            isNodeList = true;
18411        }
18412    }
18413
18414    Y.Array.each(nodes, function(node) {
18415        instance = Y.Node._instances[node._yuid];
18416
18417        if (!instance) {
18418            instance = getTemp(node);
18419        }
18420
18421        val = instance._get(attr);
18422        if (!isNodeList) { // convert array of Nodes to NodeList
18423            val = Y.Node.scrubVal(val, instance);
18424        }
18425
18426        ret.push(val);
18427    });
18428
18429    return (isNodeList) ? Y.all(ret) : ret;
18430};
18431
18432Y.NodeList = NodeList;
18433
18434Y.all = function(nodes) {
18435    return new NodeList(nodes);
18436};
18437
18438Y.Node.all = Y.all;
18439/**
18440 * @module node
18441 * @submodule node-core
18442 */
18443
18444var Y_NodeList = Y.NodeList,
18445    ArrayProto = Array.prototype,
18446    ArrayMethods = {
18447        /** Returns a new NodeList combining the given NodeList(s)
18448          * @for NodeList
18449          * @method concat
18450          * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
18451          * concatenate to the resulting NodeList
18452          * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
18453          */
18454        'concat': 1,
18455        /** Removes the last from the NodeList and returns it.
18456          * @for NodeList
18457          * @method pop
18458          * @return {Node | null} The last item in the NodeList, or null if the list is empty.
18459          */
18460        'pop': 0,
18461        /** Adds the given Node(s) to the end of the NodeList.
18462          * @for NodeList
18463          * @method push
18464          * @param {Node | HTMLElement} nodes One or more nodes to add to the end of the NodeList.
18465          */
18466        'push': 0,
18467        /** Removes the first item from the NodeList and returns it.
18468          * @for NodeList
18469          * @method shift
18470          * @return {Node | null} The first item in the NodeList, or null if the NodeList is empty.
18471          */
18472        'shift': 0,
18473        /** Returns a new NodeList comprising the Nodes in the given range.
18474          * @for NodeList
18475          * @method slice
18476          * @param {Number} begin Zero-based index at which to begin extraction.
18477          As a negative index, start indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence.
18478          * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
18479          slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
18480          As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
18481          If end is omitted, slice extracts to the end of the sequence.
18482          * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
18483          */
18484        'slice': 1,
18485        /** Changes the content of the NodeList, adding new elements while removing old elements.
18486          * @for NodeList
18487          * @method splice
18488          * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
18489          * @param {Number} howMany An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed. In this case, you should specify at least one new element. If no howMany parameter is specified (second syntax above, which is a SpiderMonkey extension), all elements after index are removed.
18490          * {Node | HTMLElement| element1, ..., elementN
18491          The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
18492          * @return {NodeList}
18492 The element(s) removed.
18493          */
18494        'splice': 1,
18495        /** Adds the given Node(s) to the beginning of the NodeList.
18496          * @for NodeList
18497          * @method unshift
18498          * @param {Node | HTMLElement} nodes One or more nodes to add to the NodeList.
18499          */
18500        'unshift': 0
18501    };
18502
18503
18504Y.Object.each(ArrayMethods, function(returnNodeList, name) {
18505    Y_NodeList.prototype[name] = function() {
18506        var args = [],
18507            i = 0,
18508            arg,
18509            ret;
18510
18511        while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists
18512            args.push(arg._node || arg._nodes || arg);
18513        }
18514
18515        ret = ArrayProto[name].apply(this._nodes, args);
18516
18517        if (returnNodeList) {
18518            ret = Y.all(ret);
18519        } else {
18520            ret = Y.Node.scrubVal(ret);
18521        }
18522
18523        return ret;
18524    };
18525});
18526/**
18527 * @module node
18528 * @submodule node-core
18529 */
18530
18531Y.Array.each([
18532    /**
18533     * Passes through to DOM method.
18534     * @for Node
18535     * @method removeChild
18536     * @param {HTMLElement | Node} node Node to be removed
18537     * @return {Node} The removed node
18538     */
18539    'removeChild',
18540
18541    /**
18542     * Passes through to DOM method.
18543     * @method hasChildNodes
18544     * @return {Boolean} Whether or not the node has any childNodes
18545     */
18546    'hasChildNodes',
18547
18548    /**
18549     * Passes through to DOM method.
18550     * @method cloneNode
18551     * @param {Boolean} deep Whether or not to perform a deep clone, which includes
18552     * subtree and attributes
18553     * @return {Node} The clone
18554     */
18555    'cloneNode',
18556
18557    /**
18558     * Passes through to DOM method.
18559     * @method hasAttribute
18560     * @param {String} attribute The attribute to test for
18561     * @return {Boolean} Whether or not the attribute is present
18562     */
18563    'hasAttribute',
18564
18565    /**
18566     * Passes through to DOM method.
18567     * @method scrollIntoView
18568     * @chainable
18569     */
18570    'scrollIntoView',
18571
18572    /**
18573     * Passes through to DOM method.
18574     * @method getElementsByTagName
18575     * @param {String} tagName The tagName to collect
18576     * @return {NodeList} A NodeList representing the HTMLCollection
18577     */
18578    'getElementsByTagName',
18579
18580    /**
18581     * Passes through to DOM method.
18582     * @method focus
18583     * @chainable
18584     */
18585    'focus',
18586
18587    /**
18588     * Passes through to DOM method.
18589     * @method blur
18590     * @chainable
18591     */
18592    'blur',
18593
18594    /**
18595     * Passes through to DOM method.
18596     * Only valid on FORM elements
18597     * @method submit
18598     * @chainable
18599     */
18600    'submit',
18601
18602    /**
18603     * Passes through to DOM method.
18604     * Only valid on FORM elements
18605     * @method reset
18606     * @chainable
18607     */
18608    'reset',
18609
18610    /**
18611     * Passes through to DOM method.
18612     * @method select
18613     * @chainable
18614     */
18615     'select',
18616
18617    /**
18618     * Passes through to DOM method.
18619     * Only valid on TABLE elements
18620     * @method createCaption
18621     * @chainable
18622     */
18623    'createCaption'
18624
18625], function(method) {
18626    Y.Node.prototype[method] = function(arg1, arg2, arg3) {
18627        var ret = this.invoke(method, arg1, arg2, arg3);
18628        return ret;
18629    };
18630});
18631
18632/**
18633 * Passes through to DOM method.
18634 * @method removeAttribute
18635 * @param {String} attribute The attribute to be removed
18636 * @chainable
18637 */
18638 // one-off implementation due to IE returning boolean, breaking chaining
18639Y.Node.prototype.removeAttribute = function(attr) {
18640    var node = this._node;
18641    if (node) {
18642        node.removeAttribute(attr, 0); // comma zero for IE < 8 to force case-insensitive
18643    }
18644
18645    return this;
18646};
18647
18648Y.Node.importMethod(Y.DOM, [
18649    /**
18650     * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
18651     * @method contains
18652     * @param {Node | HTMLElement} needle The possible node or descendent
18653     * @return {Boolean} Whether or not this node is the needle its ancestor
18654     */
18655    'contains',
18656    /**
18657     * Allows setting attributes on DOM nodes, normalizing in some cases.
18658     * This passes through to the DOM node, allowing for custom attributes.
18659     * @method setAttribute
18660     * @for Node
18661     * @chainable
18662     * @param {string} name The attribute name
18663     * @param {string} value The value to set
18664     */
18665    'setAttribute',
18666    /**
18667     * Allows getting attributes on DOM nodes, normalizing in some cases.
18668     * This passes through to the DOM node, allowing for custom attributes.
18669     * @method getAttribute
18670     * @for Node
18671     * @param {string} name The attribute name
18672     * @return {string} The attribute value
18673     */
18674    'getAttribute',
18675
18676    /**
18677     * Wraps the given HTML around the node.
18678     * @method wrap
18679     * @param {String} html The markup to wrap around the node.
18680     * @chainable
18681     * @for Node
18682     */
18683    'wrap',
18684
18685    /**
18686     * Removes the node's parent node.
18687     * @method unwrap
18688     * @chainable
18689     */
18690    'unwrap',
18691
18692    /**
18693     * Applies a unique ID to the node if none exists
18694     * @method generateID
18695     * @return {String} The existing or generated ID
18696     */
18697    'generateID'
18698]);
18699
18700Y.NodeList.importMethod(Y.Node.prototype, [
18701/**
18702 * Allows getting attributes on DOM nodes, normalizing in some cases.
18703 * This passes through to the DOM node, allowing for custom attributes.
18704 * @method getAttribute
18705 * @see Node
18706 * @for NodeList
18707 * @param {string} name The attribute name
18708 * @return {string} The attribute value
18709 */
18710
18711    'getAttribute',
18712/**
18713 * Allows setting attributes on DOM nodes, normalizing in some cases.
18714 * This passes through to the DOM node, allowing for custom attributes.
18715 * @method setAttribute
18716 * @see Node
18717 * @for NodeList
18718 * @chainable
18719 * @param {string} name The attribute name
18720 * @param {string} value The value to set
18721 */
18722    'setAttribute',
18723
18724/**
18725 * Allows for removing attributes on DOM nodes.
18726 * This passes through to the DOM node, allowing for custom attributes.
18727 * @method removeAttribute
18728 * @see Node
18729 * @for NodeList
18730 * @param {string} name The attribute to remove
18731 */
18732    'removeAttribute',
18733/**
18734 * Removes the parent node from node in the list.
18735 * @method unwrap
18736 * @chainable
18737 */
18738    'unwrap',
18739/**
18740 * Wraps the given HTML around each node.
18741 * @method wrap
18742 * @param {String} html The markup to wrap around the node.
18743 * @chainable
18744 */
18745    'wrap',
18746
18747/**
18748 * Applies a unique ID to each node if none exists
18749 * @method generateID
18750 * @return {String} The existing or generated ID
18751 */
18752    'generateID'
18753]);
18754
18755
18756}, '3.18.1', {"requires": ["dom-core", "selector"]});
18757YUI.add('node-base', function (Y, NAME) {
18758
18759/**
18760 * @module node
18761 * @submodule node-base
18762 */
18763
18764var methods = [
18765/**
18766 * Determines whether the node has the given className.
18767 * @method hasClass
18768 * @for Node
18769 * @param {String} className the class name to search for
18770 * @return {Boolean} Whether or not the node has the specified class
18771 */
18772 'hasClass',
18773
18774/**
18775 * Adds a class name to the node.
18776 * @method addClass
18777 * @param {String} className the class name to add to the node's class attribute
18778 * @chainable
18779 */
18780 'addClass',
18781
18782/**
18783 * Removes a class name from the node.
18784 * @method removeClass
18785 * @param {String} className the class name to remove from the node's class attribute
18786 * @chainable
18787 */
18788 'removeClass',
18789
18790/**
18791 * Replace a class with another class on the node.
18792 * If no oldClassName is present, the newClassName is simply added.
18793 * @method replaceClass
18794 * @param {String} oldClassName the class name to be replaced
18795 * @param {String} newClassName the class name that will be replacing the old class name
18796 * @chainable
18797 */
18798 'replaceClass',
18799
18800/**
18801 * If the className exists on the node it is removed, if it doesn't exist it is added.
18802 * @method toggleClass
18803 * @param {String} className the class name to be toggled
18804 * @param {Boolean} force Option to force adding or removing the class.
18805 * @chainable
18806 */
18807 'toggleClass'
18808];
18809
18810Y.Node.importMethod(Y.DOM, methods);
18811/**
18812 * Determines whether each node has the given className.
18813 * @method hasClass
18814 * @see Node.hasClass
18815 * @for NodeList
18816 * @param {String} className the class name to search for
18817 * @return {Array} An array of booleans for each node bound to the NodeList.
18818 */
18819
18820/**
18821 * Adds a class name to each node.
18822 * @method addClass
18823 * @see Node.addClass
18824 * @param {String} className the class name to add to each node's class attribute
18825 * @chainable
18826 */
18827
18828/**
18829 * Removes a class name from each node.
18830 * @method removeClass
18831 * @see Node.removeClass
18832 * @param {String} className the class name to remove from each node's class attribute
18833 * @chainable
18834 */
18835
18836/**
18837 * Replace a class with another class for each node.
18838 * If no oldClassName is present, the newClassName is simply added.
18839 * @method replaceClass
18840 * @see Node.replaceClass
18841 * @param {String} oldClassName the class name to be replaced
18842 * @param {String} newClassName the class name that will be replacing the old class name
18843 * @chainable
18844 */
18845
18846/**
18847 * For each node, if the className exists on the node it is removed, if it doesn't exist it is added.
18848 * @method toggleClass
18849 * @see Node.toggleClass
18850 * @param {String} className the class name to be toggled
18851 * @chainable
18852 */
18853Y.NodeList.importMethod(Y.Node.prototype, methods);
18854/**
18855 * @module node
18856 * @submodule node-base
18857 */
18858
18859var Y_Node = Y.Node,
18860    Y_DOM = Y.DOM;
18861
18862/**
18863 * Returns a new dom node using the provided markup string.
18864 * @method create
18865 * @static
18866 * @param {String} html The markup used to create the element.
18867 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18868 * to escape html content.
18869 * @param {HTMLDocument} doc An optional document context
18870 * @return {Node} A Node instance bound to a DOM node or fragment
18871 * @for Node
18872 */
18873Y_Node.create = function(html, doc) {
18874    if (doc && doc._node) {
18875        doc = doc._node;
18876    }
18877    return Y.one(Y_DOM.create(html, doc));
18878};
18879
18880Y.mix(Y_Node.prototype, {
18881    /**
18882     * Creates a new Node using the provided markup string.
18883     * @method create
18884     * @param {String} html The markup used to create the element.
18885     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18886     * to escape html content.
18887     * @param {HTMLDocument} doc An optional document context
18888     * @return {Node} A Node instance bound to a DOM node or fragment
18889     */
18890    create: Y_Node.create,
18891
18892    /**
18893     * Inserts the content before the reference node.
18894     * @method insert
18895     * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert.
18896     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18897     * to escape html content.
18898     * @param {Int | Node | HTMLElement | String} where The position to insert at.
18899     * Possible "where" arguments
18900     * <dl>
18901     * <dt>Y.Node</dt>
18902     * <dd>The Node to insert before</dd>
18903     * <dt>HTMLElement</dt>
18904     * <dd>The element to insert before</dd>
18905     * <dt>Int</dt>
18906     * <dd>The index of the child element to insert before</dd>
18907     * <dt>"replace"</dt>
18908     * <dd>Replaces the existing HTML</dd>
18909     * <dt>"before"</dt>
18910     * <dd>Inserts before the existing HTML</dd>
18911     * <dt>"before"</dt>
18912     * <dd>Inserts content before the node</dd>
18913     * <dt>"after"</dt>
18914     * <dd>Inserts content after the node</dd>
18915     * </dl>
18916     * @chainable
18917     */
18918    insert: function(content, where) {
18919        this._insert(content, where);
18920        return this;
18921    },
18922
18923    _insert: function(content, where) {
18924        var node = this._node,
18925            ret = null;
18926
18927        if (typeof where == 'number') { // allow index
18928            where = this._node.childNodes[where];
18929        } else if (where && where._node) { // Node
18930            where = where._node;
18931        }
18932
18933        if (content && typeof content != 'string') { // allow Node or NodeList/Array instances
18934            content = content._node || content._nodes || content;
18935        }
18936        ret = Y_DOM.addHTML(node, content, where);
18937
18938        return ret;
18939    },
18940
18941    /**
18942     * Inserts the content as the firstChild of the node.
18943     * @method prepend
18944     * @param {String | Node | HTMLElement} content The content to insert.
18945     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18946     * to escape html content.
18947     * @chainable
18948     */
18949    prepend: function(content) {
18950        return this.insert(content, 0);
18951    },
18952
18953    /**
18954     * Inserts the content as the lastChild of the node.
18955     * @method append
18956     * @param {String | Node | HTMLElement} content The content to insert.
18957     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18958     * to escape html content.
18959     * @chainable
18960     */
18961    append: function(content) {
18962        return this.insert(content, null);
18963    },
18964
18965    /**
18966     * @method appendChild
18967     * @param {String | HTMLElement | Node} node Node to be appended.
18968     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18969     * to escape html content.
18970     * @return {Node} The appended node
18971     */
18972    appendChild: function(node) {
18973        return Y_Node.scrubVal(this._insert(node));
18974    },
18975
18976    /**
18977     * @method insertBefore
18978     * @param {String | HTMLElement | Node} newNode Node to be appended
18979     * @param {HTMLElement | Node} refNode Node to be inserted before.
18980     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
18981     * to escape html content.
18982     * @return {Node} The inserted node
18983     */
18984    insertBefore: function(newNode, refNode) {
18985        return Y.Node.scrubVal(this._insert(newNode, refNode));
18986    },
18987
18988    /**
18989     * Appends the node to the given node.
18990     * @example
18991     *      // appendTo returns the node that has been created beforehand
18992     *      Y.Node.create('<p></p>').appendTo('body').set('text', 'hello world!');
18993     * @method appendTo
18994     * @param {Node | HTMLElement | String}
18994 node The node to append to.
18995     *  If `node` is a string it will be considered as a css selector and only the first matching node will be used.
18996     * @chainable
18997     */
18998    appendTo: function(node) {
18999        Y.one(node).append(this);
19000        return this;
19001    },
19002
19003    // This method is deprecated, and is intentionally left undocumented.
19004    // Use `setHTML` instead.
19005    setContent: function(content) {
19006        this._insert(content, 'replace');
19007        return this;
19008    },
19009
19010    // This method is deprecated, and is intentionally left undocumented.
19011    // Use `getHTML` instead.
19012    getContent: function() {
19013        var node = this;
19014
19015        if (node._node.nodeType === 11) { // 11 === Node.DOCUMENT_FRAGMENT_NODE
19016            // "this", when it is a document fragment, must be cloned because
19017            // the nodes contained in the fragment actually disappear once
19018            // the fragment is appended anywhere
19019            node = node.create("<div/>").append(node.cloneNode(true));
19020        }
19021
19022        return node.get("innerHTML");
19023    }
19024});
19025
19026/**
19027 * Replaces the node's current html content with the content provided.
19028 * Note that this passes to innerHTML and is not escaped.
19029 * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
19030 * to escape html content or `set('text')` to add as text.
19031 * @method setHTML
19032 * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert
19033 * @chainable
19034 */
19035Y.Node.prototype.setHTML = Y.Node.prototype.setContent;
19036
19037/**
19038 * Returns the node's current html content (e.g. innerHTML)
19039 * @method getHTML
19040 * @return {String} The html content
19041 */
19042Y.Node.prototype.getHTML = Y.Node.prototype.getContent;
19043
19044Y.NodeList.importMethod(Y.Node.prototype, [
19045    /**
19046     * Called on each Node instance
19047     * @for NodeList
19048     * @method append
19049     * @see Node.append
19050     */
19051    'append',
19052
19053    /**
19054     * Called on each Node instance
19055     * @for NodeList
19056     * @method insert
19057     * @see Node.insert
19058     */
19059    'insert',
19060
19061    /**
19062     * Called on each Node instance
19063     * @for NodeList
19064     * @method appendChild
19065     * @see Node.appendChild
19066     */
19067    'appendChild',
19068
19069    /**
19070     * Called on each Node instance
19071     * @for NodeList
19072     * @method insertBefore
19073     * @see Node.insertBefore
19074     */
19075    'insertBefore',
19076
19077    /**
19078     * Called on each Node instance
19079     * @for NodeList
19080     * @method prepend
19081     * @see Node.prepend
19082     */
19083    'prepend',
19084
19085    'setContent',
19086
19087    'getContent',
19088
19089    /**
19090     * Called on each Node instance
19091     * Note that this passes to innerHTML and is not escaped.
19092     * Use <a href="../classes/Escape.html#method_html">`Y.Escape.html()`</a>
19093     * to escape html content or `set('text')` to add as text.
19094     * @for NodeList
19095     * @method setHTML
19096     * @see Node.setHTML
19097     */
19098    'setHTML',
19099
19100    /**
19101     * Called on each Node instance
19102     * @for NodeList
19103     * @method getHTML
19104     * @see Node.getHTML
19105     */
19106    'getHTML'
19107]);
19108/**
19109 * @module node
19110 * @submodule node-base
19111 */
19112
19113var Y_Node = Y.Node,
19114    Y_DOM = Y.DOM;
19115
19116/**
19117 * Static collection of configuration attributes for special handling
19118 * @property ATTRS
19119 * @static
19120 * @type object
19121 */
19122Y_Node.ATTRS = {
19123    /**
19124     * Allows for getting and setting the text of an element.
19125     * Formatting is preserved and special characters are treated literally.
19126     * @config text
19127     * @type String
19128     */
19129    text: {
19130        getter: function() {
19131            return Y_DOM.getText(this._node);
19132        },
19133
19134        setter: function(content) {
19135            Y_DOM.setText(this._node, content);
19136            return content;
19137        }
19138    },
19139
19140    /**
19141     * Allows for getting and setting the text of an element.
19142     * Formatting is preserved and special characters are treated literally.
19143     * @config for
19144     * @type String
19145     */
19146    'for': {
19147        getter: function() {
19148            return Y_DOM.getAttribute(this._node, 'for');
19149        },
19150
19151        setter: function(val) {
19152            Y_DOM.setAttribute(this._node, 'for', val);
19153            return val;
19154        }
19155    },
19156
19157    'options': {
19158        getter: function() {
19159            return this._node.getElementsByTagName('option');
19160        }
19161    },
19162
19163    /**
19164     * Returns a NodeList instance of all HTMLElement children.
19165     * @readOnly
19166     * @config children
19167     * @type NodeList
19168     */
19169    'children': {
19170        getter: function() {
19171            var node = this._node,
19172                children = node.children,
19173                childNodes, i, len;
19174
19175            if (!children) {
19176                childNodes = node.childNodes;
19177                children = [];
19178
19179                for (i = 0, len = childNodes.length; i < len; ++i) {
19180                    if (childNodes[i].tagName) {
19181                        children[children.length] = childNodes[i];
19182                    }
19183                }
19184            }
19185            return Y.all(children);
19186        }
19187    },
19188
19189    value: {
19190        getter: function() {
19191            return Y_DOM.getValue(this._node);
19192        },
19193
19194        setter: function(val) {
19195            Y_DOM.setValue(this._node, val);
19196            return val;
19197        }
19198    }
19199};
19200
19201Y.Node.importMethod(Y.DOM, [
19202    /**
19203     * Allows setting attributes on DOM nodes, normalizing in some cases.
19204     * This passes through to the DOM node, allowing for custom attributes.
19205     * @method setAttribute
19206     * @for Node
19207     * @for NodeList
19208     * @chainable
19209     * @param {string} name The attribute name
19210     * @param {string} value The value to set
19211     */
19212    'setAttribute',
19213    /**
19214     * Allows getting attributes on DOM nodes, normalizing in some cases.
19215     * This passes through to the DOM node, allowing for custom attributes.
19216     * @method getAttribute
19217     * @for Node
19218     * @for NodeList
19219     * @param {string} name The attribute name
19220     * @return {string} The attribute value
19221     */
19222    'getAttribute'
19223
19224]);
19225/**
19226 * @module node
19227 * @submodule node-base
19228 */
19229
19230var Y_Node = Y.Node;
19231var Y_NodeList = Y.NodeList;
19232/**
19233 * List of events that route to DOM events
19234 * @static
19235 * @property DOM_EVENTS
19236 * @for Node
19237 */
19238
19239Y_Node.DOM_EVENTS = {
19240    abort: 1,
19241    beforeunload: 1,
19242    blur: 1,
19243    change: 1,
19244    click: 1,
19245    close: 1,
19246    command: 1,
19247    contextmenu: 1,
19248    copy: 1,
19249    cut: 1,
19250    dblclick: 1,
19251    DOMMouseScroll: 1,
19252    drag: 1,
19253    dragstart: 1,
19254    dragenter: 1,
19255    dragover: 1,
19256    dragleave: 1,
19257    dragend: 1,
19258    drop: 1,
19259    error: 1,
19260    focus: 1,
19261    key: 1,
19262    keydown: 1,
19263    keypress: 1,
19264    keyup: 1,
19265    load: 1,
19266    message: 1,
19267    mousedown: 1,
19268    mouseenter: 1,
19269    mouseleave: 1,
19270    mousemove: 1,
19271    mousemultiwheel: 1,
19272    mouseout: 1,
19273    mouseover: 1,
19274    mouseup: 1,
19275    mousewheel: 1,
19276    orientationchange: 1,
19277    paste: 1,
19278    reset: 1,
19279    resize: 1,
19280    select: 1,
19281    selectstart: 1,
19282    submit: 1,
19283    scroll: 1,
19284    textInput: 1,
19285    unload: 1,
19286    invalid: 1
19287};
19288
19289// Add custom event adaptors to this list.  This will make it so
19290// that delegate, key, available, contentready, etc all will
19291// be available through Node.on
19292Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
19293
19294Y.augment(Y_Node, Y.EventTarget);
19295
19296Y.mix(Y_Node.prototype, {
19297    /**
19298     * Removes event listeners from the node and (optionally) its subtree
19299     * @method purge
19300     * @param {Boolean} recurse (optional) Whether or not to remove listeners from the
19301     * node's subtree
19302     * @param {String} type (optional) Only remove listeners of the specified type
19303     * @chainable
19304     *
19305     */
19306    purge: function(recurse, type) {
19307        Y.Event.purgeElement(this._node, recurse, type);
19308        return this;
19309    }
19310
19311});
19312
19313Y.mix(Y.NodeList.prototype, {
19314    _prepEvtArgs: function(type, fn, context) {
19315        // map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
19316        var args = Y.Array(arguments, 0, true);
19317
19318        if (args.length < 2) { // type only (event hash) just add nodes
19319            args[2] = this._nodes;
19320        } else {
19321            args.splice(2, 0, this._nodes);
19322        }
19323
19324        args[3] = context || this;
19324 // default to NodeList instance as context
19325
19326        return args;
19327    },
19328
19329    /**
19330    Subscribe a callback function for each `Node` in the collection to execute
19331    in response to a DOM event.
19332
19333    NOTE: Generally, the `on()` method should be avoided on `NodeLists`, in
19334    favor of using event delegation from a parent Node.  See the Event user
19335    guide for details.
19336
19337    Most DOM events are associated with a preventable default behavior, such as
19338    link clicks navigating to a new page.  Callbacks are passed a
19339    `DOMEventFacade` object as their first argument (usually called `e`) that
19340    can be used to prevent this default behavior with `e.preventDefault()`. See
19341    the `DOMEventFacade` API for all available properties and methods on the
19342    object.
19343
19344    By default, the `this` object will be the `NodeList` that the subscription
19345    came from, <em>not the `Node` that received the event</em>.  Use
19346    `e.currentTarget` to refer to the `Node`.
19347
19348    Returning `false` from a callback is supported as an alternative to calling
19349    `e.preventDefault(); e.stopPropagation();`.  However, it is recommended to
19350    use the event methods.
19351
19352    @example
19353
19354        Y.all(".sku").on("keydown", function (e) {
19355            if (e.keyCode === 13) {
19356                e.preventDefault();
19357
19358                // Use e.currentTarget to refer to the individual Node
19359                var item = Y.MyApp.searchInventory( e.currentTarget.get('value') );
19360                // etc ...
19361            }
19362        });
19363
19364    @method on
19365    @param {String} type The name of the event
19366    @param {Function} fn The callback to execute in response to the event
19367    @param {Object} [context] Override `this` object in callback
19368    @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
19369    @return {EventHandle} A subscription handle capable of detaching that
19370                          subscription
19371    @for NodeList
19372    **/
19373    on: function(type, fn, context) {
19374        return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
19375    },
19376
19377    /**
19378     * Applies an one-time event listener to each Node bound to the NodeList.
19379     * @method once
19380     * @param {String} type The event being listened for
19381     * @param {Function} fn The handler to call when the event fires
19382     * @param {Object} context The context to call the handler with.
19383     * Default is the NodeList instance.
19384     * @return {EventHandle} A subscription handle capable of detaching that
19385     *                    subscription
19386     * @for NodeList
19387     */
19388    once: function(type, fn, context) {
19389        return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
19390    },
19391
19392    /**
19393     * Applies an event listener to each Node bound to the NodeList.
19394     * The handler is called only after all on() handlers are called
19395     * and the event is not prevented.
19396     * @method after
19397     * @param {String} type The event being listened for
19398     * @param {Function} fn The handler to call when the event fires
19399     * @param {Object} context The context to call the handler with.
19400     * Default is the NodeList instance.
19401     * @return {EventHandle} A subscription handle capable of detaching that
19402     *                    subscription
19403     * @for NodeList
19404     */
19405    after: function(type, fn, context) {
19406        return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
19407    },
19408
19409    /**
19410     * Applies an one-time event listener to each Node bound to the NodeList
19411     * that will be called only after all on() handlers are called and the
19412     * event is not prevented.
19413     *
19414     * @method onceAfter
19415     * @param {String} type The event being listened for
19416     * @param {Function} fn The handler to call when the event fires
19417     * @param {Object} context The context to call the handler with.
19418     * Default is the NodeList instance.
19419     * @return {EventHandle} A subscription handle capable of detaching that
19420     *                    subscription
19421     * @for NodeList
19422     */
19423    onceAfter: function(type, fn, context) {
19424        return Y.onceAfter.apply(Y, this._prepEvtArgs.apply(this, arguments));
19425    }
19426});
19427
19428Y_NodeList.importMethod(Y.Node.prototype, [
19429    /**
19430      * Called on each Node instance
19431      * @method detach
19432      * @see Node.detach
19433      * @for NodeList
19434      */
19435    'detach',
19436
19437    /** Called on each Node instance
19438      * @method detachAll
19439      * @see Node.detachAll
19440      * @for NodeList
19441      */
19442    'detachAll'
19443]);
19444
19445/**
19446Subscribe a callback function to execute in response to a DOM event or custom
19447event.
19448
19449Most DOM events are associated with a preventable default behavior such as
19450link clicks navigating to a new page.  Callbacks are passed a `DOMEventFacade`
19451object as their first argument (usually called `e`) that can be used to
19452prevent this default behavior with `e.preventDefault()`. See the
19453`DOMEventFacade` API for all available properties and methods on the object.
19454
19455If the event name passed as the first parameter is not a whitelisted DOM event,
19456it will be treated as a custom event subscriptions, allowing
19457`node.fire('customEventName')` later in the code.  Refer to the Event user guide
19458for the full DOM event whitelist.
19459
19460By default, the `this` object in the callback will refer to the subscribed
19461`Node`.
19462
19463Returning `false` from a callback is supported as an alternative to calling
19464`e.preventDefault(); e.stopPropagation();`.  However, it is recommended to use
19465the event methods.
19466
19467@example
19468
19469    Y.one("#my-form").on("submit", function (e) {
19470        e.preventDefault();
19471
19472        // proceed with ajax form submission instead...
19473    });
19474
19475@method on
19476@param {String} type The name of the event
19477@param {Function} fn The callback to execute in response to the event
19478@param {Object} [context] Override `this` object in callback
19479@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
19480@return {EventHandle} A subscription handle capable of detaching that
19481                      subscription
19482@for Node
19483**/
19484
19485Y.mix(Y.Node.ATTRS, {
19486    offsetHeight: {
19487        setter: function(h) {
19488            Y.DOM.setHeight(this._node, h);
19489            return h;
19490        },
19491
19492        getter: function() {
19493            return this._node.offsetHeight;
19494        }
19495    },
19496
19497    offsetWidth: {
19498        setter: function(w) {
19499            Y.DOM.setWidth(this._node, w);
19500            return w;
19501        },
19502
19503        getter: function() {
19504            return this._node.offsetWidth;
19505        }
19506    }
19507});
19508
19509Y.mix(Y.Node.prototype, {
19510    sizeTo: function(w, h) {
19511        var node;
19512        if (arguments.length < 2) {
19513            node = Y.one(w);
19514            w = node.get('offsetWidth');
19515            h = node.get('offsetHeight');
19516        }
19517
19518        this.setAttrs({
19519            offsetWidth: w,
19520            offsetHeight: h
19521        });
19522    }
19523});
19524
19525if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8
19526    Y.Node.prototype.hasAttribute = function(attr) {
19527        if (attr === 'value') {
19528            if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML
19529                return true;
19530            }
19531        }
19532        return !!(this._node.attributes[attr] &&
19533                this._node.attributes[attr].specified);
19534    };
19535}
19536
19537// IE throws an error when calling focus() on an element that's invisible, not
19538// displayed, or disabled.
19539Y.Node.prototype.focus = function () {
19540    try {
19541        this._node.focus();
19542    } catch (e) {
19543    }
19544
19545    return this;
19546};
19547
19548// IE throws error when setting input.type = 'hidden',
19549// input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
19550Y.Node.ATTRS.type = {
19551    setter: function(val) {
19552        if (val === 'hidden') {
19553            try {
19554                this._node.type = 'hidden';
19555            } catch(e) {
19556                this._node.style.display = 'none';
19557                this._inputType = 'hidden';
19558            }
19559        } else {
19560            try { // IE errors when changing the type from "hidden'
19561                this._node.type = val;
19562            } catch (e) {
19563            }
19564        }
19565        return val;
19566    },
19567
19568    getter: function() {
19569        return this._inputType || this._node.type;
19570    },
19571
19572    _bypassProxy: true // don't update DOM when using with Attribute
19573};
19574
19575if (Y.config.doc.createElement('form').elements.nodeType) {
19576    // IE: elements collection is also FORM node which trips up scrubVal.
19577    Y.Node.ATTRS.elements = {
19578            getter: function() {
19579                return this.all('input, textarea, button, select');
19580            }
19581    };
19582}
19583/**
19584 * Provides methods for managing custom Node data.
19585 *
19586 * @module node
19587 * @main node
19588 * @submodule node-data
19589 */
19590
19591Y.mix(Y.Node.prototype, {
19592    _initData: function() {
19593        if (! ('_data' in this)) {
19594            this._data = {};
19595        }
19596    },
19597
19598    /**
19599    * @method getData
19600    * @for Node
19601    * @description Retrieves arbitrary data stored on a Node instance.
19602    * If no data is associated with the Node, it will attempt to retrieve
19603    * a value from the corresponding HTML data attribute. (e.g. node.getData('foo')
19604    * will check node.getAttribute('data-foo')).
19605    * @param {string} name Optional name of the data field to retrieve.
19606    * If no name is given, all data is returned.
19607    * @return {any | Object} Whatever is stored at the given field,
19608    * or an object hash of all fields.
19609    */
19610    getData: function(name) {
19611        this._initData();
19612        var data = this._data,
19613            ret = data;
19614
19615        if (arguments.length) { // single field
19616            if (name in data) {
19617                ret = data[name];
19618            } else { // initialize from HTML attribute
19619                ret = this._getDataAttribute(name);
19620            }
19621        } else if (typeof data == 'object' && data !== null) { // all fields
19622            ret = {};
19623            Y.Object.each(data, function(v, n) {
19624                ret[n] = v;
19625            });
19626
19627            ret = this._getDataAttributes(ret);
19628        }
19629
19630        return ret;
19631
19632    },
19633
19634    _getDataAttributes: function(ret) {
19635        ret = ret || {};
19636        var i = 0,
19637            attrs = this._node.attributes,
19638            len = attrs.length,
19639            prefix = this.DATA_PREFIX,
19640            prefixLength = prefix.length,
19641            name;
19642
19643        while (i < len) {
19644            name = attrs[i].name;
19645            if (name.indexOf(prefix) === 0) {
19646                name = name.substr(prefixLength);
19647                if (!(name in ret)) { // only merge if not already stored
19648                    ret[name] = this._getDataAttribute(name);
19649                }
19650            }
19651
19652            i += 1;
19653        }
19654
19655        return ret;
19656    },
19657
19658    _getDataAttribute: function(name) {
19659        name = this.DATA_PREFIX + name;
19660
19661        var node = this._node,
19662            attrs = node.attributes,
19663            data = attrs && attrs[name] && attrs[name].value;
19664
19665        return data;
19666    },
19667
19668    /**
19669    * @method setData
19670    * @for Node
19671    * @description Stores arbitrary data on a Node instance.
19672    * This is not stored with the DOM node.
19673    * @param {string} name The name of the field to set. If no val
19674    * is given, name is treated as the data and overrides any existing data.
19675    * @param {any} val The value to be assigned to the field.
19676    * @chainable
19677    */
19678    setData: function(name, val) {
19679        this._initData();
19680        if (arguments.length > 1) {
19681            this._data[name] = val;
19682        } else {
19683            this._data = name;
19684        }
19685
19686       return this;
19687    },
19688
19689    /**
19690    * @method clearData
19691    * @for Node
19692    * @description Clears internally stored data.
19693    * @param {string} name The name of the field to clear. If no name
19694    * is given, all data is cleared.
19695    * @chainable
19696    */
19697    clearData: function(name) {
19698        if ('_data' in this) {
19699            if (typeof name != 'undefined') {
19700                delete this._data[name];
19701            } else {
19702                delete this._data;
19703            }
19704        }
19705
19706        return this;
19707    }
19708});
19709
19710Y.mix(Y.NodeList.prototype, {
19711    /**
19712    * @method getData
19713    * @for NodeList
19714    * @description Retrieves arbitrary data stored on each Node instance
19715    * bound to the NodeList.
19716    * @see Node
19717    * @param {string} name Optional name of the data field to retrieve.
19718    * If no name is given, all data is returned.
19719    * @return {Array} An array containing all of the data for each Node instance.
19720    * or an object hash of all fields.
19721    */
19722    getData: function(name) {
19723        var args = (arguments.length) ? [name] : [];
19724        return this._invoke('getData', args, true);
19725    },
19726
19727    /**
19728    * @method setData
19729    * @for NodeList
19730    * @description Stores arbitrary data on each Node instance bound to the
19731    *  NodeList. This is not stored with the DOM node.
19732    * @param {string} name The name of the field to set. If no name
19733    * is given, name is treated as the data and overrides any existing data.
19734    * @param {any} val The value to be assigned to the field.
19735    * @chainable
19736    */
19737    setData: function(name, val) {
19738        var args = (arguments.length > 1) ? [name, val] : [name];
19739        return this._invoke('setData', args);
19740    },
19741
19742    /**
19743    * @method clearData
19744    * @for NodeList
19745    * @description Clears data on all Node instances bound to the NodeList.
19746    * @param {string} name The name of the field to clear. If no name
19747    * is given, all data is cleared.
19748    * @chainable
19749    */
19750    clearData: function(name) {
19751        var args = (arguments.length) ? [name] : [];
19752        return this._invoke('clearData', [name]);
19753    }
19754});
19755
19756
19757}, '3.18.1', {"requires": ["event-base", "node-core", "dom-base", "dom-style"]});
19758YUI.add('event-base', function (Y, NAME) {
19759
19760/*
19761 * DOM event listener abstraction layer
19762 * @module event
19763 * @submodule event-base
19764 */
19765
19766/**
19767 * The domready event fires at the moment the browser's DOM is
19768 * usable. In most cases, this is before images are fully
19769 * downloaded, allowing you to provide a more responsive user
19770 * interface.
19771 *
19772 * In YUI 3, domready subscribers will be notified immediately if
19773 * that moment has already passed when the subscription is created.
19774 *
19775 * One exception is if the yui.js file is dynamically injected into
19776 * the page.  If this is done, you must tell the YUI instance that
19777 * you did this in order for DOMReady (and window load events) to
19778 * fire normally.  That configuration option is 'injected' -- set
19779 * it to true if the yui.js script is not included inline.
19780 *
19781 * This method is part of the 'event-ready' module, which is a
19782 * submodule of 'event'.
19783 *
19784 * @event domready
19785 * @for YUI
19786 */
19787Y.publish('domready', {
19788    fireOnce: true,
19789    async: true
19790});
19791
19792if (YUI.Env.DOMReady) {
19793    Y.fire('domready');
19794} else {
19795    Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
19796}
19797
19798/**
19799 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
19800 * events.
19801 * @module event
19802 * @submodule event-base
19803 */
19804
19805/**
19806 * Wraps a DOM event, properties requiring browser abstraction are
19807 * fixed here.  Provids a security layer when required.
19808 * @class DOMEventFacade
19809 * @param ev {Event} the DOM event
19810 * @param currentTarget {HTMLElement} the element the listener was attached to
19811 * @param wrapper {CustomEvent} the custom event wrapper for this DOM event
19812 */
19813
19814    var ua = Y.UA,
19815
19816    EMPTY = {},
19817
19818    /**
19819     * webkit key remapping required for Safari < 3.1
19820     * @property webkitKeymap
19821     * @private
19822     */
19823    webkitKeymap = {
19824        63232: 38, // up
19825        63233: 40, // down
19826        63234: 37, // left
19827        63235: 39, // right
19828        63276: 33, // page up
19829        63277: 34, // page down
19830        25:     9, // SHIFT-TAB (Safari provides a different key code in
19831                   // this case, even though the shiftKey modifier is set)
19832        63272: 46, // delete
19833        63273: 36, // home
19834        63275: 35  // end
19835    },
19836
19837    /**
19838     * Returns a wrapped node.  Intended to be used on event targets,
19839     * so it will return the node's parent if the target is a text
19840     * node.
19841     *
19842     * If accessing a property of the node throws an error, this is
19843     * probably the anonymous div wrapper Gecko adds inside text
19844     * nodes.  This likely will only occur when attempting to access
19845     * the relatedTarget.  In this case, we now return null because
19846     * the anonymous div is completely useless and we do not know
19847     * what the related target was because we can't even get to
19848     * the element's parent node.
19849     *
19850     * @method resolve
19851     * @private
19852     */
19853    resolve = function(n) {
19854        if (!n) {
19855            return n;
19856        }
19857        try {
19858            if (n && 3 == n.nodeType) {
19859                n = n.parentNode;
19860            }
19861        } catch(e) {
19862            return null;
19863        }
19864
19865        return Y.one(n);
19866    },
19867
19868    DOMEventFacade = function(ev, currentTarget, wrapper) {
19869        this._event = ev;
19870        this._currentTarget = currentTarget;
19871        this._wrapper = wrapper || EMPTY;
19872
19873        // if not lazy init
19874        this.init();
19875    };
19876
19877Y.extend(DOMEventFacade, Object, {
19878
19879    init: function() {
19880
19881        var e = this._event,
19882            overrides = this._wrapper.overrides,
19883            x = e.pageX,
19884            y = e.pageY,
19885            c,
19886            currentTarget = this._currentTarget;
19887
19888        this.altKey   = e.altKey;
19889        this.ctrlKey  = e.ctrlKey;
19890        this.metaKey  = e.metaKey;
19891        this.shiftKey = e.shiftKey;
19892        this.type     = (overrides && overrides.type) || e.type;
19893        this.clientX  = e.clientX;
19894        this.clientY  = e.clientY;
19895
19896        this.pageX = x;
19897        this.pageY = y;
19898
19899        // charCode is unknown in keyup, keydown. keyCode is unknown in keypress.
19900        // FF 3.6 - 8+? pass 0 for keyCode in keypress events.
19901        // Webkit, FF 3.6-8+?, and IE9+? pass 0 for charCode in keydown, keyup.
19902        // Webkit and IE9+? duplicate charCode in keyCode.
19903        // Opera never sets charCode, always keyCode (though with the charCode).
19904        // IE6-8 don't set charCode or which.
19905        // All browsers other than IE6-8 set which=keyCode in keydown, keyup, and
19906        // which=charCode in keypress.
19907        //
19908        // Moral of the story: (e.which || e.keyCode) will always return the
19909        // known code for that key event phase. e.keyCode is often different in
19910        // keypress from keydown and keyup.
19911        c = e.keyCode || e.charCode;
19912
19913        if (ua.webkit && (c in webkitKeymap)) {
19914            c = webkitKeymap[c];
19915        }
19916
19917        this.keyCode = c;
19918        this.charCode = c;
19919        // Fill in e.which for IE - implementers should always use this over
19920        // e.keyCode or e.charCode.
19921        this.which = e.which || e.charCode || c;
19922        // this.button = e.button;
19923        this.button = this.which;
19924
19925        this.target = resolve(e.target);
19926        this.currentTarget = resolve(currentTarget);
19927        this.relatedTarget = resolve(e.relatedTarget);
19928
19929        if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
19930            this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
19931        }
19932
19933        if (this._touch) {
19934            this._touch(e, currentTarget, this._wrapper);
19935        }
19936    },
19937
19938    stopPropagation: function() {
19939        this._event.stopPropagation();
19940        this._wrapper.stopped = 1;
19941        this.stopped = 1;
19942    },
19943
19944    stopImmediatePropagation: function() {
19945        var e = this._event;
19946        if (e.stopImmediatePropagation) {
19947            e.stopImmediatePropagation();
19948        } else {
19949            this.stopPropagation();
19950        }
19951        this._wrapper.stopped = 2;
19952        this.stopped = 2;
19953    },
19954
19955    preventDefault: function(returnValue) {
19956        var e = this._event;
19957        e.preventDefault();
19958        if (returnValue) {
19959            e.returnValue = returnValue;
19960        }
19961        this._wrapper.prevented = 1;
19962        this.prevented = 1;
19963    },
19964
19965    halt: function(immediate) {
19966        if (immediate) {
19967            this.stopImmediatePropagation();
19968        } else {
19969            this.stopPropagation();
19970        }
19971
19972        this.preventDefault();
19973    }
19974
19975});
19976
19977DOMEventFacade.resolve = resolve;
19978Y.DOM2EventFacade = DOMEventFacade;
19979Y.DOMEventFacade = DOMEventFacade;
19980
19981    /**
19982     * The native event
19983     * @property _event
19984     * @type {DOMEvent}
19985     * @private
19986     */
19987
19988    /**
19989    The name of the event (e.g. "click")
19990
19991    @property type
19992    @type {String}
19993    **/
19994
19995    /**
19996    `true` if the "alt" or "option" key is pressed.
19997
19998    @property altKey
19999    @type {Boolean}
20000    **/
20001
20002    /**
20003    `true` if the shift key is pressed.
20004
20005    @property shiftKey
20006    @type {Boolean}
20007    **/
20008
20009    /**
20010    `true` if the "Windows" key on a Windows keyboard, "command" key on an
20011    Apple keyboard, or "meta" key on other keyboards is pressed.
20012
20013    @property metaKey
20014    @type {Boolean}
20015    **/
20016
20017    /**
20018    `true` if the "Ctrl" or "control" key is pressed.
20019
20020    @property ctrlKey
20021    @type {Boolean}
20022    **/
20023
20024    /**
20025     * The X location of the event on the page (including scroll)
20026     * @property pageX
20027     * @type {Number}
20028     */
20029
20030    /**
20031     * The Y location of the event on the page (including scroll)
20032     * @property pageY
20033     * @type {Number}
20034     */
20035
20036    /**
20037     * The X location of the event in the viewport
20038     * @property clientX
20039     * @type {Number}
20040     */
20041
20042    /**
20043     * The Y location of the event in the viewport
20044     * @property clientY
20045     * @type {Number}
20046     */
20047
20048    /**
20049     * The keyCode for key events.  Uses charCode if keyCode is not available
20050     * @property keyCode
20051     * @type {Number}
20052     */
20053
20054    /**
20055     * The charCode for key events.  Same as keyCode
20056     * @property charCode
20057     * @type {Number}
20058     */
20059
20060    /**
20061     * The button that was pushed. 1 for left click, 2 for middle click, 3 for
20062     * right click.  This is only reliably populated on `mouseup` events.
20063     * @property button
20064     * @type {Number}
20065     */
20066
20067    /**
20068     * The button that was pushed.  Same as button.
20069     * @property which
20070     * @type {Number}
20071     */
20072
20073    /**
20074     * Node reference for the targeted element
20075     * @property target
20076     * @type {Node}
20077     */
20078
20079    /**
20080     * Node reference for the element that the listener was attached to.
20081     * @property currentTarget
20082     * @type {Node}
20083     */
20084
20085    /**
20086     * Node reference to the relatedTarget
20087     * @property relatedTarget
20088     * @type {Node}
20089     */
20090
20091    /**
20092     * Number representing the direction and velocity of the movement of the mousewheel.
20093     * Negative is down, the higher the number, the faster.  Applies to the mousewheel event.
20094     * @property wheelDelta
20095     * @type {Number}
20096     */
20097
20098    /**
20099     * Stops the propagation to the next bubble target
20100     * @method stopPropagation
20101     */
20102
20103    /**
20104     * Stops the propagation to the next bubble target and
20105     * prevents any additional listeners from being exectued
20106     * on the current target.
20107     * @method stopImmediatePropagation
20108     */
20109
20110    /**
20111     * Prevents the event's default behavior
20112     * @method preventDefault
20113     * @param returnValue {string} sets the returnValue of the event to this value
20114     * (rather than the default false value).  This can be used to add a customized
20115     * confirmation query to the beforeunload event).
20116     */
20117
20118    /**
20119     * Stops the event propagation and prevents the default
20120     * event behavior.
20121     * @method halt
20122     * @param immediate {boolean} if true additional listeners
20123     * on the current target will not be executed
20124     */
20125(function() {
20126
20127/**
20128 * The event utility provides functions to add and remove event listeners,
20129 * event cleansing.  It also tries to automatically remove listeners it
20130 * registers during the unload event.
20131 * @module event
20132 * @main event
20133 * @submodule event-base
20134 */
20135
20136/**
20137 * The event utility provides functions to add and remove event listeners,
20138 * event cleansing.  It also tries to automatically remove listeners it
20139 * registers during the unload event.
20140 *
20141 * @class Event
20142 * @static
20143 */
20144
20145Y.Env.evt.dom_wrappers = {};
20146Y.Env.evt.dom_map = {};
20147
20148var _eventenv = Y.Env.evt,
20149    config = Y.config,
20150    win = config.win,
20151    add = YUI.Env.add,
20152    remove = YUI.Env.remove,
20153
20154    onLoad = function() {
20155        YUI.Env.windowLoaded = true;
20156        Y.Event._load();
20157        remove(win, "load", onLoad);
20158    },
20159
20160    onUnload = function() {
20161        Y.Event._unload();
20162    },
20163
20164    EVENT_READY = 'domready',
20165
20166    COMPAT_ARG = '~yui|2|compat~',
20167
20168    shouldIterate = function(o) {
20169        try {
20170            // TODO: See if there's a more performant way to return true early on this, for the common case
20171            return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !Y.DOM.isWindow(o));
20172        } catch(ex) {
20173            return false;
20174        }
20175    },
20176
20177    // aliases to support DOM event subscription clean up when the last
20178    // subscriber is detached. deleteAndClean overrides the DOM event's wrapper
20179    // CustomEvent _delete method.
20180    _ceProtoDelete = Y.CustomEvent.prototype._delete,
20181    _deleteAndClean = function(s) {
20182        var ret = _ceProtoDelete.apply(this, arguments);
20183
20184        if (!this.hasSubs()) {
20185            Y.Event._clean(this);
20186        }
20187
20188        return ret;
20189    },
20190
20191Event = function() {
20192
20193    /**
20194     * True after the onload event has fired
20195     * @property _loadComplete
20196     * @type boolean
20197     * @static
20198     * @private
20199     */
20200    var _loadComplete =  false,
20201
20202    /**
20203     * The number of times to poll after window.onload.  This number is
20204     * increased if additional late-bound handlers are requested after
20205     * the page load.
20206     * @property _retryCount
20207     * @static
20208     * @private
20209     */
20210    _retryCount = 0,
20211
20212    /**
20213     * onAvailable listeners
20214     * @property _avail
20215     * @static
20216     * @private
20217     */
20218    _avail = [],
20219
20220    /**
20221     * Custom event wrappers for DOM events.  Key is
20222     * 'event:' + Element uid stamp + event type
20223     * @property _wrappers
20224     * @type CustomEvent
20225     * @static
20226     * @private
20227     */
20228    _wrappers = _eventenv.dom_wrappers,
20229
20230    _windowLoadKey = null,
20231
20232    /**
20233     * Custom event wrapper map DOM events.  Key is
20234     * Element uid stamp.  Each item is a hash of custom event
20235     * wrappers as provided in the _wrappers collection.  This
20236     * provides the infrastructure for getListeners.
20237     * @property _el_events
20238     * @static
20239     * @private
20240     */
20241    _el_events = _eventenv.dom_map;
20242
20243    return {
20244
20245        /**
20246         * The number of times we should look for elements that are not
20247         * in the DOM at the time the event is requested after the document
20248         * has been loaded.  The default is 1000@amp;40 ms, so it will poll
20249         * for 40 seconds or until all outstanding handlers are bound
20250         * (whichever comes first).
20251         * @property POLL_RETRYS
20252         * @type int
20253         * @static
20254         * @final
20255         */
20256        POLL_RETRYS: 1000,
20257
20258        /**
20259         * The poll interval in milliseconds
20260         * @property POLL_INTERVAL
20261         * @type int
20262         * @static
20263         * @final
20264         */
20265        POLL_INTERVAL: 40,
20266
20267        /**
20268         * addListener/removeListener can throw errors in unexpected scenarios.
20269         * These errors are suppressed, the method returns false, and this property
20270         * is set
20271         * @property lastError
20272         * @static
20273         * @type Error
20274         */
20275        lastError: null,
20276
20277
20278        /**
20279         * poll handle
20280         * @property _interval
20281         * @static
20282         * @private
20283         */
20284        _interval: null,
20285
20286        /**
20287         * document readystate poll handle
20288         * @property _dri
20289         * @static
20290         * @private
20291         */
20292         _dri: null,
20293
20294        /**
20295         * True when the document is initially usable
20296         * @property DOMReady
20297         * @type boolean
20298         * @static
20299         */
20300        DOMReady: false,
20301
20302        /**
20303         * @method startInterval
20304         * @static
20305         * @private
20306         */
20307        startInterval: function() {
20308            if (!Event._interval) {
20309Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
20310            }
20311        },
20312
20313        /**
20314         * Executes the supplied callback when the item with the supplied
20315         * id is found.  This is meant to be used to execute behavior as
20316         * soon as possible as the page loads.  If you use this after the
20317         * initial page load it will poll for a fixed time for the element.
20318         * The number of times it will poll and the frequency are
20319         * configurable.  By default it will poll for 10 seconds.
20320         *
20321         * <p>The callback is executed with a single parameter:
20322         * the custom object parameter, if provided.</p>
20323         *
20324         * @method onAvailable
20325         *
20326         * @param {string||string[]}   id the id of the element, or an array
20327         * of ids to look for.
20328         * @param {function} fn what to execute when the element is found.
20329         * @param {object}   p_obj an optional object to be passed back as
20330         *                   a parameter to fn.
20331         * @param {boolean|object}  p_override If set to true, fn will execute
20332         *                   in the context of p_obj, if set to an object it
20333         *                   will execute in the context of that object
20334         * @param checkContent {boolean} check child node readiness (onContentReady)
20335         * @static
20336         * @deprecated Use Y.on("available")
20337         */
20338        // @TODO fix arguments
20339        onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
20340
20341            var a = Y.Array(id), i, availHandle;
20342
20343            for (i=0; i<a.length; i=i+1) {
20344                _avail.push({
20345                    id:         a[i],
20346                    fn:         fn,
20347                    obj:        p_obj,
20348                    override:   p_override,
20349                    checkReady: checkContent,
20350                    compat:     compat
20351                });
20352            }
20353            _retryCount = this.POLL_RETRYS;
20354
20355            // We want the first test to be immediate, but async
20356            setTimeout(Event._poll, 0);
20357
20358            availHandle = new Y.EventHandle({
20359
20360                _delete: function() {
20361                    // set by the event system for lazy DOM listeners
20362                    if (availHandle.handle) {
20363                        availHandle.handle.detach();
20364                        return;
20365                    }
20366
20367                    var i, j;
20368
20369                    // otherwise try to remove the onAvailable listener(s)
20370                    for (i = 0; i < a.length; i++) {
20371                        for (j = 0; j < _avail.length; j++) {
20372                            if (a[i] === _avail[j].id) {
20373                                _avail.splice(j, 1);
20374                            }
20375                        }
20376                    }
20377                }
20378
20379            });
20380
20381            return availHandle;
20382        },
20383
20384        /**
20385         * Works the same way as onAvailable, but additionally checks the
20386         * state of sibling elements to determine if the content of the
20387         * available element is safe to modify.
20388         *
20389         * <p>The callback is executed with a single parameter:
20390         * the custom object parameter, if provided.</p>
20391         *
20392         * @method onContentReady
20393         *
20394         * @param {string}   id the id of the element to look for.
20395         * @param {function} fn what to execute when the element is ready.
20396         * @param {object}   obj an optional object to be passed back as
20397         *                   a parameter to fn.
20398         * @param {boolean|object}  override If set to true, fn will execute
20399         *                   in the context of p_obj.  If an object, fn will
20400         *                   exectute in the context of that object
20401         *
20402         * @static
20403         * @deprecated Use Y.on("contentready")
20404         */
20405        // @TODO fix arguments
20406        onContentReady: function(id, fn, obj, override, compat) {
20407            return Event.onAvailable(id, fn, obj, override, true, compat);
20408        },
20409
20410        /**
20411         * Adds an event listener
20412         *
20413         * @method attach
20414         *
20415         * @param {String}   type     The type of event to append
20416         * @param {Function} fn        The method the event invokes
20417         * @param {String|HTMLElement|Array|NodeList} el An id, an element
20418         *  reference, or a collection of ids and/or elements to assign the
20419         *  listener to.
20420         * @param {Object}   context optional context object
20421         * @param {Boolean|object}  args 0..n arguments to pass to the callback
20422         * @return {EventHandle} an object to that can be used to detach the listener
20423         *
20424         * @static
20425         */
20426
20427        attach: function(type, fn, el, context) {
20428            return Event._attach(Y.Array(arguments, 0, true));
20429        },
20430
20431        _createWrapper: function (el, type, capture, compat, facade) {
20432
20433            var cewrapper,
20434                ek  = Y.stamp(el),
20435                key = 'event:' + ek + type;
20436
20437            if (false === facade) {
20438                key += 'native';
20439            }
20440            if (capture) {
20441                key += 'capture';
20442            }
20443
20444
20445            cewrapper = _wrappers[key];
20446
20447
20448            if (!cewrapper) {
20449                // create CE wrapper
20450                cewrapper = Y.publish(key, {
20451                    silent: true,
20452                    bubbles: false,
20453                    emitFacade:false,
20454                    contextFn: function() {
20455                        if (compat) {
20456                            return cewrapper.el;
20457                        } else {
20458                            cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
20459                            return cewrapper.nodeRef;
20460                        }
20461                    }
20462                });
20463
20464                cewrapper.overrides = {};
20465
20466                // for later removeListener calls
20467                cewrapper.el = el;
20468                cewrapper.key = key;
20469                cewrapper.domkey = ek;
20470                cewrapper.type = type;
20471                cewrapper.fn = function(e) {
20472                    cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
20473                };
20474                cewrapper.capture = capture;
20475
20476                if (el == win && type == "load") {
20477                    // window load happens once
20478                    cewrapper.fireOnce = true;
20479                    _windowLoadKey = key;
20480                }
20481                cewrapper._delete = _deleteAndClean;
20482
20483                _wrappers[key] = cewrapper;
20484                _el_events[ek] = _el_events[ek] || {};
20485                _el_events[ek][key] = cewrapper;
20486
20487                add(el, type, cewrapper.fn, capture);
20488            }
20489
20490            return cewrapper;
20491
20492        },
20493
20494        _attach: function(args, conf) {
20495
20496            var compat,
20497                handles, oEl, cewrapper, context,
20498                fireNow = false, ret,
20499                type = args[0],
20500                fn = args[1],
20501                el = args[2] || win,
20502                facade = conf && conf.facade,
20503                capture = conf && conf.capture,
20504                overrides = conf && conf.overrides;
20505
20506            if (args[args.length-1] === COMPAT_ARG) {
20507                compat = true;
20508            }
20509
20510            if (!fn || !fn.call) {
20511                return false;
20512            }
20513
20514            // The el argument can be an array of elements or element ids.
20515            if (shouldIterate(el)) {
20516
20517                handles=[];
20518
20519                Y.each(el, function(v, k) {
20520                    args[2] = v;
20521                    handles.push(Event._attach(args.slice(), conf));
20522                });
20523
20524                // return (handles.length === 1) ? handles[0] : handles;
20525                return new Y.EventHandle(handles);
20526
20527            // If the el argument is a string, we assume it is
20528            // actually the id of the element.  If the page is loaded
20529            // we convert el to the actual element, otherwise we
20530            // defer attaching the event until the element is
20531            // ready
20532            } else if (Y.Lang.isString(el)) {
20533
20534                // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
20535
20536                if (compat) {
20537                    oEl = Y.DOM.byId(el);
20538                } else {
20539
20540                    oEl = Y.Selector.query(el);
20541
20542                    switch (oEl.length) {
20543                        case 0:
20544                            oEl = null;
20545                            break;
20546                        case 1:
20547                            oEl = oEl[0];
20548                            break;
20549                        default:
20550                            args[2] = oEl;
20551                            return Event._attach(args, conf);
20552                    }
20553                }
20554
20555                if (oEl) {
20556
20557                    el = oEl;
20558
20559                // Not found = defer adding the event until the element is available
20560                } else {
20561
20562                    ret = Event.onAvailable(el, function() {
20563
20564                        ret.handle = Event._attach(args, conf);
20565
20566                    }, Event, true, false, compat);
20567
20568                    return ret;
20569
20570                }
20571            }
20572
20573            // Element should be an html element or node
20574            if (!el) {
20575                return false;
20576            }
20577
20578            if (Y.Node && Y.instanceOf(el, Y.Node)) {
20579                el = Y.Node.getDOMNode(el);
20580            }
20581
20582            cewrapper = Event._createWrapper(el, type, capture, compat, facade);
20583            if (overrides) {
20584                Y.mix(cewrapper.overrides, overrides);
20585            }
20586
20587            if (el == win && type == "load") {
20588
20589                // if the load is complete, fire immediately.
20590                // all subscribers, including the current one
20591                // will be notified.
20592                if (YUI.Env.windowLoaded) {
20593                    fireNow = true;
20594                }
20595            }
20596
20597            if (compat) {
20598                args.pop();
20599            }
20600
20601            context = args[3];
20602
20603            // set context to the Node if not specified
20604            // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
20605            ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
20606
20607            if (fireNow) {
20608                cewrapper.fire();
20609            }
20610
20611            return ret;
20612
20613        },
20614
20615        /**
20616         * Removes an event listener.  Supports the signature the event was bound
20617         * with, but the preferred way to remove listeners is using the handle
20618         * that is returned when using Y.on
20619         *
20620         * @method detach
20621         *
20622         * @param {String} type the type of event to remove.
20623         * @param {Function} fn the method the event invokes.  If fn is
20624         * undefined, then all event handlers for the type of event are
20625         * removed.
20626         * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
20627         * event handle, an id, an element reference, or a collection
20628         * of ids and/or elements to remove the listener from.
20629         * @return {boolean} true if the unbind was successful, false otherwise.
20630         * @static
20631         */
20632        detach: function(type, fn, el, obj) {
20633
20634            var args=Y.Array(arguments, 0, true), compat, l, ok, i,
20635                id, ce;
20636
20637            if (args[args.length-1] === COMPAT_ARG) {
20638                compat = true;
20639                // args.pop();
20640            }
20641
20642            if (type && type.detach) {
20643                return type.detach();
20644            }
20645
20646            // The el argument can be a string
20647            if (typeof el == "string") {
20648
20649                // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
20650                if (compat) {
20651                    el = Y.DOM.byId(el);
20652                } else {
20653                    el = Y.Selector.query(el);
20654                    l = el.length;
20655                    if (l < 1) {
20656                        el = null;
20657                    } else if (l == 1) {
20658                        el = el[0];
20659                    }
20660                }
20661                // return Event.detach.apply(Event, args);
20662            }
20663
20664            if (!el) {
20665                return false;
20666            }
20667
20668            if (el.detach) {
20669                args.splice(2, 1);
20670                return el.detach.apply(el, args);
20671            // The el argument can be an array of elements or element ids.
20672            } else if (shouldIterate(el)) {
20673                ok = true;
20674                for (i=0, l=el.length; i<l; ++i) {
20675                    args[2] = el[i];
20676                    ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
20677                }
20678
20679                return ok;
20680            }
20681
20682            if (!type || !fn || !fn.call) {
20683                return Event.purgeElement(el, false, type);
20684            }
20685
20686            id = 'event:' + Y.stamp(el) + type;
20687            ce = _wrappers[id];
20688
20689            if (ce) {
20690                return ce.detach(fn);
20691            } else {
20692                return false;
20693            }
20694
20695        },
20696
20697        /**
20698         * Finds the event in the window object, the caller's arguments, or
20699         * in the arguments of another method in the callstack.  This is
20700         * executed automatically for events registered through the event
20701         * manager, so the implementer should not normally need to execute
20702         * this function at all.
20703         * @method getEvent
20704         * @param {Event} e the event parameter from the handler
20705         * @param {HTMLElement} el the element the listener was attached to
20706         * @return {Event} the event
20707         * @static
20708         */
20709        getEvent: function(e, el, noFacade) {
20710            var ev = e || win.event;
20711
20712            return (noFacade) ? ev :
20713                new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
20714        },
20715
20716        /**
20717         * Generates an unique ID for the element if it does not already
20718         * have one.
20719         * @method generateId
20720         * @param el the element to create the id for
20721         * @return {string} the resulting id of the element
20722         * @static
20723         */
20724        generateId: function(el) {
20725            return Y.DOM.generateID(el);
20726        },
20727
20728        /**
20729         * We want to be able to use getElementsByTagName as a collection
20730         * to attach a group of events to.  Unfortunately, different
20731         * browsers return different types of collections.  This function
20732         * tests to determine if the object is array-like.  It will also
20733         * fail if the object is an array, but is empty.
20734         * @method _isValidCollection
20735         * @param o the object to test
20736         * @return {boolean} true if the object is array-like and populated
20737         * @deprecated was not meant to be used directly
20738         * @static
20739         * @private
20740         */
20741        _isValidCollection: shouldIterate,
20742
20743        /**
20744         * hook up any deferred listeners
20745         * @method _load
20746         * @static
20747         * @private
20748         */
20749        _load: function(e) {
20750            if (!_loadComplete) {
20751                _loadComplete = true;
20752
20753                // Just in case DOMReady did not go off for some reason
20754                // E._ready();
20755                if (Y.fire) {
20756                    Y.fire(EVENT_READY);
20757                }
20758
20759                // Available elements may not have been detected before the
20760                // window load event fires. Try to find them now so that the
20761                // the user is more likely to get the onAvailable notifications
20762                // before the window load notification
20763                Event._poll();
20764            }
20765        },
20766
20767        /**
20768         * Polling function that runs before the onload event fires,
20769         * attempting to attach to DOM Nodes as soon as they are
20770         * available
20771         * @method _poll
20772         * @static
20773         * @private
20774         */
20775        _poll: function() {
20776            if (Event.locked) {
20777                return;
20778            }
20779
20780            if (Y.UA.ie && !YUI.Env.DOMReady) {
20781                // Hold off if DOMReady has not fired and check current
20782                // readyState to protect against the IE operation aborted
20783                // issue.
20784                Event.startInterval();
20785                return;
20786            }
20787
20788            Event.locked = true;
20789
20790            // keep trying until after the page is loaded.  We need to
20791            // check the page load state prior to trying to bind the
20792            // elements so that we can be certain all elements have been
20793            // tested appropriately
20794            var i, len, item, el, notAvail, executeItem,
20795                tryAgain = !_loadComplete;
20796
20797            if (!tryAgain) {
20798                tryAgain = (_retryCount > 0);
20799            }
20800
20801            // onAvailable
20802            notAvail = [];
20803
20804            executeItem = function (el, item) {
20805                var context, ov = item.override;
20806                try {
20807                    if (item.compat) {
20808                        if (item.override) {
20809                            if (ov === true) {
20810                                context = item.obj;
20811                            } else {
20812                                context = ov;
20813                            }
20814                        } else {
20815                            context = el;
20816                        }
20817                        item.fn.call(context, item.obj);
20818                    } else {
20819                        context = item.obj || Y.one(el);
20820                        item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
20821                    }
20822                } catch (e) {
20823                }
20824            };
20825
20826            // onAvailable
20827            for (i=0,len=_avail.length; i<len; ++i) {
20828                item = _avail[i];
20829                if (item && !item.checkReady) {
20830
20831                    // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
20832                    el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
20833
20834                    if (el) {
20835                        executeItem(el, item);
20836                        _avail[i] = null;
20837                    } else {
20838                        notAvail.push(item);
20839                    }
20840                }
20841            }
20842
20843            // onContentReady
20844            for (i=0,len=_avail.length; i<len; ++i) {
20845                item = _avail[i];
20846                if (item && item.checkReady) {
20847
20848                    // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
20849                    el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
20850
20851                    if (el) {
20852                        // The element is available, but not necessarily ready
20853                        // @todo should we test parentNode.nextSibling?
20854                        if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
20855                            executeItem(el, item);
20856                            _avail[i] = null;
20857                        }
20858                    } else {
20859                        notAvail.push(item);
20860                    }
20861                }
20862            }
20863
20864            _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
20865
20866            if (tryAgain) {
20867                // we may need to strip the nulled out items here
20868                Event.startInterval();
20869            } else {
20870                clearInterval(Event._interval);
20871                Event._interval = null;
20872            }
20873
20874            Event.locked = false;
20875
20876            return;
20877
20878        },
20879
20880        /**
20881         * Removes all listeners attached to the given element via addListener.
20882         * Optionally, the node's children can also be purged.
20883         * Optionally, you can specify a specific type of event to remove.
20884         * @method purgeElement
20885         * @param {HTMLElement} el the element to purge
20886         * @param {boolean} recurse recursively purge this element's children
20887         * as well.  Use with caution.
20888         * @param {string} type optional type of listener to purge. If
20889         * left out, all listeners will be removed
20890         * @static
20891         */
20892        purgeElement: function(el, recurse, type) {
20893            // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
20894            var oEl = (Y.Lang.isString(el)) ?  Y.Selector.query(el, null, true) : el,
20895                lis = Event.getListeners(oEl, type), i, len, children, child;
20896
20897            if (recurse && oEl) {
20898                lis = lis || [];
20899                children = Y.Selector.query('*', oEl);
20900                len = children.length;
20901                for (i = 0; i < len; ++i) {
20902                    child = Event.getListeners(children[i], type);
20903                    if (child) {
20904                        lis = lis.concat(child);
20905                    }
20906                }
20907            }
20908
20909            if (lis) {
20910                for (i = 0, len = lis.length; i < len; ++i) {
20911                    lis[i].detachAll();
20912                }
20913            }
20914
20915        },
20916
20917        /**
20918         * Removes all object references and the DOM proxy subscription for
20919         * a given event for a DOM node.
20920         *
20921         * @method _clean
20922         * @param wrapper {CustomEvent} Custom event proxy for the DOM
20923         *                  subscription
20924         * @private
20925         * @static
20926         * @since 3.4.0
20927         */
20928        _clean: function (wrapper) {
20929            var key    = wrapper.key,
20930                domkey = wrapper.domkey;
20931
20932            remove(wrapper.el, wrapper.type, wrapper.fn, wrapper.capture);
20933            delete _wrappers[key];
20934            delete Y._yuievt.events[key];
20935            if (_el_events[domkey]) {
20936                delete _el_events[domkey][key];
20937                if (!Y.Object.size(_el_events[domkey])) {
20938                    delete _el_events[domkey];
20939                }
20940            }
20941        },
20942
20943        /**
20944         * Returns all listeners attached to the given element via addListener.
20945         * Optionally, you can specify a specific type of event to return.
20946         * @method getListeners
20947         * @param el {HTMLElement|string} the element or element id to inspect
20948         * @param type {string} optional type of listener to return. If
20949         * left out, all listeners will be returned
20950         * @return {CustomEvent} the custom event wrapper for the DOM event(s)
20951         * @static
20952         */
20953        getListeners: function(el, type) {
20954            var ek = Y.stamp(el, true), evts = _el_events[ek],
20955                results=[] , key = (type) ? 'event:' + ek + type : null,
20956                adapters = _eventenv.plugins;
20957
20958            if (!evts) {
20959                return null;
20960            }
20961
20962            if (key) {
20963                // look for synthetic events
20964                if (adapters[type] && adapters[type].eventDef) {
20965                    key += '_synth';
20966                }
20967
20968                if (evts[key]) {
20969                    results.push(evts[key]);
20970                }
20971
20972                // get native events as well
20973                key += 'native';
20974                if (evts[key]) {
20975                    results.push(evts[key]);
20976                }
20977
20978            } else {
20979                Y.each(evts, function(v, k) {
20980                    results.push(v);
20981                });
20982            }
20983
20984            return (results.length) ? results : null;
20985        },
20986
20987        /**
20988         * Removes all listeners registered by pe.event.  Called
20989         * automatically during the unload event.
20990         * @method _unload
20991         * @static
20992         * @private
20993         */
20994        _unload: function(e) {
20995            Y.each(_wrappers, function(v, k) {
20996                if (v.type == 'unload') {
20997                    v.fire(e);
20998                }
20999                v.detachAll();
21000            });
21001            remove(win, "unload", onUnload);
21002        },
21003
21004        /**
21005         * Adds a DOM event directly without the caching, cleanup, context adj, etc
21006         *
21007         * @method nativeAdd
21008         * @param {HTMLElement} el      the element to bind the handler to
21009         * @param {string}      type   the type of event handler
21010         * @param {function}    fn      the callback to invoke
21011         * @param {Boolean}      capture capture or bubble phase
21012         * @static
21013         * @private
21014         */
21015        nativeAdd: add,
21016
21017        /**
21018         * Basic remove listener
21019         *
21020         * @method nativeRemove
21021         * @param {HTMLElement} el      the element to bind the handler to
21022         * @param {string}      type   the type of event handler
21023         * @param {function}    fn      the callback to invoke
21024         * @param {Boolean}      capture capture or bubble phase
21025         * @static
21026         * @private
21027         */
21028        nativeRemove: remove
21029    };
21030
21031}();
21032
21033Y.Event = Event;
21034
21035if (config.injected || YUI.Env.windowLoaded) {
21036    onLoad();
21037} else {
21038    add(win, "load", onLoad);
21039}
21040
21041// Process onAvailable/onContentReady items when when the DOM is ready in IE
21042if (Y.UA.ie) {
21043    Y.on(EVENT_READY, Event._poll);
21044
21045    // In IE6 and below, detach event handlers when the page is unloaded in
21046    // order to try and prevent cross-page memory leaks. This isn't done in
21047    // other browsers because a) it's not necessary, and b) it breaks the
21048    // back/forward cache.
21049    if (Y.UA.ie < 7) {
21050        try {
21051            add(win, "unload", onUnload);
21052        } catch(e) {
21053        }
21054    }
21055}
21056
21057Event.Custom = Y.CustomEvent;
21058Event.Subscriber = Y.Subscriber;
21059Event.Target = Y.EventTarget;
21060Event.Handle = Y.EventHandle;
21061Event.Facade = Y.EventFacade;
21062
21063Event._poll();
21064
21065}());
21066
21067/**
21068 * DOM event listener abstraction layer
21069 * @module event
21070 * @submodule event-base
21071 */
21072
21073/**
21074 * Executes the callback as soon as the specified element
21075 * is detected in the DOM.  This function expects a selector
21076 * string for the element(s) to detect.  If you already have
21077 * an element reference, you don't need this event.
21078 * @event available
21079 * @param type {string} 'available'
21080 * @param fn {function} the callback function to execute.
21081 * @param el {string} an selector for the element(s) to attach
21082 * @param context optional argument that specifies what 'this' refers to.
21083 * @param args* 0..n additional arguments to pass on to the callback function.
21084 * These arguments will be added after the event object.
21085 * @return {EventHandle} the detach handle
21086 * @for YUI
21087 */
21088Y.Env.evt.plugins.available = {
21089    on: function(type, fn, id, o) {
21090        var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : null;
21091        return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
21092    }
21093};
21094
21095/**
21096 * Executes the callback as soon as the specified element
21097 * is detected in the DOM with a nextSibling property
21098 * (indicating that the element's children are available).
21099 * This function expects a selector
21100 * string for the element(s) to detect.  If you already have
21101 * an element reference, you don't need this event.
21102 * @event contentready
21103 * @param type {string} 'contentready'
21104 * @param fn {function} the callback function to execute.
21105 * @param el {string} an selector for the element(s) to attach.
21106 * @param context optional argument that specifies what 'this' refers to.
21107 * @param args* 0..n additional arguments to pass on to the callback function.
21108 * These arguments will be added after the event object.
21109 * @return {EventHandle} the detach handle
21110 * @for YUI
21111 */
21112Y.Env.evt.plugins.contentready = {
21113    on: function(type, fn, id, o) {
21114        var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
21115        return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
21116    }
21117};
21118
21119
21120}, '3.18.1', {"requires": ["event-custom-base"]});
21121(function() {
21122
21123var stateChangeListener,
21124    GLOBAL_ENV   = YUI.Env,
21125    config       = YUI.config,
21126    doc          = config.doc,
21127    docElement   = doc && doc.documentElement,
21128    EVENT_NAME   = 'onreadystatechange',
21129    pollInterval = config.pollInterval || 40;
21130
21131if (docElement.doScroll && !GLOBAL_ENV._ieready) {
21132    GLOBAL_ENV._ieready = function() {
21133        GLOBAL_ENV._ready();
21134    };
21135
21136/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
21137// Internet Explorer: use the doScroll() method on the root element.
21138// This isolates what appears to be a safe moment to manipulate the
21139// DOM prior to when the document's readyState suggests it is safe to do so.
21140    if (self !== self.top) {
21141        stateChangeListener = function() {
21142            if (doc.readyState == 'complete') {
21143                GLOBAL_ENV.remove(doc, EVENT_NAME, stateChangeListener);
21144                GLOBAL_ENV.ieready();
21145            }
21146        };
21147        GLOBAL_ENV.add(doc, EVENT_NAME, stateChangeListener);
21148    } else {
21149        GLOBAL_ENV._dri = setInterval(function() {
21150            try {
21151                docElement.doScroll('left');
21152                clearInterval(GLOBAL_ENV._dri);
21153                GLOBAL_ENV._dri = null;
21154                GLOBAL_ENV._ieready();
21155            } catch (domNotReady) { }
21156        }, pollInterval);
21157    }
21158}
21159
21160})();
21161YUI.add('event-base-ie', function (Y, NAME) {
21162
21163/*
21164 * Custom event engine, DOM event listener abstraction layer, synthetic DOM
21165 * events.
21166 * @module event
21167 * @submodule event-base
21168 */
21169
21170function IEEventFacade() {
21171    // IEEventFacade.superclass.constructor.apply(this, arguments);
21172    Y.DOM2EventFacade.apply(this, arguments);
21173}
21174
21175/*
21176 * (intentially left out of API docs)
21177 * Alternate Facade implementation that is based on Object.defineProperty, which
21178 * is partially supported in IE8.  Properties that involve setup work are
21179 * deferred to temporary getters using the static _define method.
21180 */
21181function IELazyFacade(e) {
21182    var proxy = Y.config.doc.createEventObject(e),
21183        proto = IELazyFacade.prototype;
21184
21185    // TODO: necessary?
21186    proxy.hasOwnProperty = function () { return true; };
21187
21188    proxy.init = proto.init;
21189    proxy.halt = proto.halt;
21190    proxy.preventDefault           = proto.preventDefault;
21191    proxy.stopPropagation          = proto.stopPropagation;
21192    proxy.stopImmediatePropagation = proto.stopImmediatePropagation;
21193
21194    Y.DOM2EventFacade.apply(proxy, arguments);
21195
21196    return proxy;
21197}
21198
21199
21200var imp = Y.config.doc && Y.config.doc.implementation,
21201    useLazyFacade = Y.config.lazyEventFacade,
21202
21203    buttonMap = {
21204        0: 1, // left click
21205        4: 2, // middle click
21206        2: 3  // right click
21207    },
21208    relatedTargetMap = {
21209        mouseout: 'toElement',
21210        mouseover: 'fromElement'
21211    },
21212
21213    resolve = Y.DOM2EventFacade.resolve,
21214
21215    proto = {
21216        init: function() {
21217
21218            IEEventFacade.superclass.init.apply(this, arguments);
21219
21220            var e = this._event,
21221                x, y, d, b, de, t;
21222
21223            this.target = resolve(e.srcElement);
21224
21225            if (('clientX' in e) && (!x) && (0 !== x)) {
21226                x = e.clientX;
21227                y = e.clientY;
21228
21229                d = Y.config.doc;
21230                b = d.body;
21231                de = d.documentElement;
21232
21233                x += (de.scrollLeft || (b && b.scrollLeft) || 0);
21234                y += (de.scrollTop  || (b && b.scrollTop)  || 0);
21235
21236                this.pageX = x;
21237                this.pageY = y;
21238            }
21239
21240            if (e.type == "mouseout") {
21241                t = e.toElement;
21242            } else if (e.type == "mouseover") {
21243                t = e.fromElement;
21244            }
21245
21246            // fallback to t.relatedTarget to support simulated events.
21247            // IE doesn't support setting toElement or fromElement on generic
21248            // events, so Y.Event.simulate sets relatedTarget instead.
21249            this.relatedTarget = resolve(t || e.relatedTarget);
21250
21251            // which should contain the unicode key code if this is a key event.
21252            // For click events, which is normalized for which mouse button was
21253            // clicked.
21254            this.which = // chained assignment
21255            this.button = e.keyCode || buttonMap[e.button] || e.button;
21256        },
21257
21258        stopPropagation: function() {
21259            this._event.cancelBubble = true;
21260            this._wrapper.stopped = 1;
21261            this.stopped = 1;
21262        },
21263
21264        stopImmediatePropagation: function() {
21265            this.stopPropagation();
21266            this._wrapper.stopped = 2;
21267            this.stopped = 2;
21268        },
21269
21270        preventDefault: function(returnValue) {
21271            this._event.returnValue = returnValue || false;
21272            this._wrapper.prevented = 1;
21273            this.prevented = 1;
21274        }
21275    };
21276
21277Y.extend(IEEventFacade, Y.DOM2EventFacade, proto);
21278
21279Y.extend(IELazyFacade, Y.DOM2EventFacade, proto);
21280IELazyFacade.prototype.init = function () {
21281    var e         = this._event,
21282        overrides = this._wrapper.overrides,
21283        define    = IELazyFacade._define,
21284        lazyProperties = IELazyFacade._lazyProperties,
21285        prop;
21286
21287    this.altKey   = e.altKey;
21288    this.ctrlKey  = e.ctrlKey;
21289    this.metaKey  = e.metaKey;
21290    this.shiftKey = e.shiftKey;
21291    this.type     = (overrides && overrides.type) || e.type;
21292    this.clientX  = e.clientX;
21293    this.clientY  = e.clientY;
21294    this.keyCode  = // chained assignment
21295    this.charCode = e.keyCode;
21296    this.which    = // chained assignment
21297    this.button   = e.keyCode || buttonMap[e.button] || e.button;
21298
21299    for (prop in lazyProperties) {
21300        if (lazyProperties.hasOwnProperty(prop)) {
21301            define(this, prop, lazyProperties[prop]);
21302        }
21303    }
21304
21305    if (this._touch) {
21306        this._touch(e, this._currentTarget, this._wrapper);
21307    }
21308};
21309
21310IELazyFacade._lazyProperties = {
21311    target: function () {
21312        return resolve(this._event.srcElement);
21313    },
21314    relatedTarget: function () {
21315        var e = this._event,
21316            targetProp = relatedTargetMap[e.type] || 'relatedTarget';
21317
21318        // fallback to t.relatedTarget to support simulated events.
21319        // IE doesn't support setting toElement or fromElement on generic
21320        // events, so Y.Event.simulate sets relatedTarget instead.
21321        return resolve(e[targetProp] || e.relatedTarget);
21322    },
21323    currentTarget: function () {
21324        return resolve(this._currentTarget);
21325    },
21326
21327    wheelDelta: function () {
21328        var e = this._event;
21329
21330        if (e.type === "mousewheel" || e.type === "DOMMouseScroll") {
21331            return (e.detail) ?
21332                (e.detail * -1) :
21333                // wheelDelta between -80 and 80 result in -1 or 1
21334                Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
21335        }
21336    },
21337
21338    pageX: function () {
21339        var e = this._event,
21340            val = e.pageX,
21341            doc, bodyScroll, docScroll;
21342
21343        if (val === undefined) {
21344            doc = Y.config.doc;
21345            bodyScroll = doc.body && doc.body.scrollLeft;
21346            docScroll = doc.documentElement.scrollLeft;
21347
21348            val = e.clientX + (docScroll || bodyScroll || 0);
21349        }
21350
21351        return val;
21352    },
21353    pageY: function () {
21354        var e = this._event,
21355            val = e.pageY,
21356            doc, bodyScroll, docScroll;
21357
21358        if (val === undefined) {
21359            doc = Y.config.doc;
21360            bodyScroll = doc.body && doc.body.scrollTop;
21361            docScroll = doc.documentElement.scrollTop;
21362
21363            val = e.clientY + (docScroll || bodyScroll || 0);
21364        }
21365
21366        return val;
21367    }
21368};
21369
21370
21371/**
21372 * Wrapper function for Object.defineProperty that creates a property whose
21373 * value will be calulated only when asked for.  After calculating the value,
21374 * the getter wll be removed, so it will behave as a normal property beyond that
21375 * point.  A setter is also assigned so assigning to the property will clear
21376 * the getter, so foo.prop = 'a'; foo.prop; won't trigger the getter,
21377 * overwriting value 'a'.
21378 *
21379 * Used only by the DOMEventFacades used by IE8 when the YUI configuration
21380 * <code>lazyEventFacade</code> is set to true.
21381 *
21382 * @method _define
21383 * @param o {DOMObject} A DOM object to add the property to
21384 * @param prop {String} The name of the new property
21385 * @param valueFn {Function} The function that will return the initial, default
21386 *                  value for the property.
21387 * @static
21388 * @private
21389 */
21390IELazyFacade._define = function (o, prop, valueFn) {
21391    function val(v) {
21392        var ret = (arguments.length) ? v : valueFn.call(this);
21393
21394        delete o[prop];
21395        Object.defineProperty(o, prop, {
21396            value: ret,
21397            configurable: true,
21398            writable: true
21399        });
21400        return ret;
21401    }
21402    Object.defineProperty(o, prop, {
21403        get: val,
21404        set: val,
21405        configurable: true
21406    });
21407};
21408
21409if (imp && (!imp.hasFeature('Events', '2.0'))) {
21410    if (useLazyFacade) {
21411        // Make sure we can use the lazy facade logic
21412        try {
21413            Object.defineProperty(Y.config.doc.createEventObject(), 'z', {});
21414        } catch (e) {
21415            useLazyFacade = false;
21416        }
21417    }
21418
21419    Y.DOMEventFacade = (useLazyFacade) ? IELazyFacade : IEEventFacade;
21420}
21421
21422
21423}, '3.18.1', {"requires": ["node-base"]});
21424YUI.add('pluginhost-base', function (Y, NAME) {
21425
21426    /**
21427     * Provides the augmentable PluginHost interface, which can be added to any class.
21428     * @module pluginhost
21429     */
21430
21431    /**
21432     * Provides the augmentable PluginHost interface, which can be added to any class.
21433     * @module pluginhost-base
21434     */
21435
21436    /**
21437     * <p>
21438     * An augmentable class, which provides the augmented class with the ability to host plugins.
21439     * It adds <a href="#method_plug">plug</a> and <a href="#method_unplug">unplug</a> methods to the augmented class, which can
21440     * be used to add or remove plugins from instances of the class.
21441     * </p>
21442     *
21443     * <p>Plugins can also be added through the constructor configuration object passed to the host class' constructor using
21444     * the "plugins" property. Supported values for the "plugins" property are those defined by the <a href="#method_plug">plug</a> method.
21445     *
21446     * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host):
21447     * <xmp>
21448     * var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]});
21449     * </xmp>
21450     * </p>
21451     * <p>
21452     * Plug.Host's protected <a href="#method_initPlugins">_initPlugins</a> and <a href="#method_destroyPlugins">_destroyPlugins</a>
21453     * methods should be invoked by the host class at the appropriate point in the host's lifecyle.
21454     * </p>
21455     *
21456     * @class Plugin.Host
21457     */
21458
21459    var L = Y.Lang;
21460
21461    function PluginHost() {
21462        this._plugins = {};
21463    }
21464
21465    PluginHost.prototype = {
21466
21467        /**
21468         * Adds a plugin to the host object. This will instantiate the
21469         * plugin and attach it to the configured namespace on the host object.
21470         *
21471         * @method plug
21472         * @chainable
21473         * @param P {Function | Object |Array} Accepts the plugin class, or an
21474         * object with a "fn" property specifying the plugin class and
21475         * a "cfg" property specifying the configuration for the Plugin.
21476         * <p>
21477         * Additionally an Array can also be passed in, with the above function or
21478         * object values, allowing the user to add multiple plugins in a single call.
21479         * </p>
21480         * @param config (Optional) If the first argument is the plugin class, the second argument
21481         * can be the configuration for the plugin.
21482         * @return {Base} A reference to the host object
21483         */
21484        plug: function(Plugin, config) {
21485            var i, ln, ns;
21486
21487            if (L.isArray(Plugin)) {
21488                for (i = 0, ln = Plugin.length; i < ln; i++) {
21489                    this.plug(Plugin[i]);
21490                }
21491            } else {
21492                if (Plugin && !L.isFunction(Plugin)) {
21493                    config = Plugin.cfg;
21494                    Plugin = Plugin.fn;
21495                }
21496
21497                // Plugin should be fn by now
21498                if (Plugin && Plugin.NS) {
21499                    ns = Plugin.NS;
21500
21501                    config = config || {};
21502                    config.host = this;
21503
21504                    if (this.hasPlugin(ns)) {
21505                        // Update config
21506                        if (this[ns].setAttrs) {
21507                            this[ns].setAttrs(config);
21508                        }
21509                        else {
21510                        }
21511                    } else {
21512                        // Create new instance
21513                        this[ns] = new Plugin(config);
21514                        this._plugins[ns] = Plugin;
21515                    }
21516                }
21517                else {
21518                }
21519            }
21520            return this;
21521        },
21522
21523        /**
21524         * Removes a plugin from the host object. This will destroy the
21525         * plugin instance and delete the namespace from the host object.
21526         *
21527         * @method unplug
21528         * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided,
21529         * all registered plugins are unplugged.
21530         * @return {Base} A reference to the host object
21531         * @chainable
21532         */
21533        unplug: function(plugin) {
21534            var ns = plugin,
21535                plugins = this._plugins;
21536
21537            if (plugin) {
21538                if (L.isFunction(plugin)) {
21539                    ns = plugin.NS;
21540                    if (ns && (!plugins[ns] || plugins[ns] !== plugin)) {
21541                        ns = null;
21542                    }
21543                }
21544
21545                if (ns) {
21546                    if (this[ns]) {
21547                        if (this[ns].destroy) {
21548                            this[ns].destroy();
21549                        }
21550                        delete this[ns];
21551                    }
21552                    if (plugins[ns]) {
21553                        delete plugins[ns];
21554                    }
21555                }
21556            } else {
21557                for (ns in this._plugins) {
21558                    if (this._plugins.hasOwnProperty(ns)) {
21559                        this.unplug(ns);
21560                    }
21561                }
21562            }
21563            return this;
21564        },
21565
21566        /**
21567         * Determines if a plugin has plugged into this host.
21568         *
21569         * @method hasPlugin
21570         * @param {String} ns The plugin's namespace
21571         * @return {Plugin} Returns a truthy value (the plugin instance) if present, or undefined if not.
21572         */
21573        hasPlugin : function(ns) {
21574            return (this._plugins[ns] && this[ns]);
21575        },
21576
21577        /**
21578         * Initializes static plugins registered on the host (using the
21579         * Base.plug static method) and any plugins passed to the
21580         * instance through the "plugins" configuration property.
21581         *
21582         * @method _initPlugins
21583         * @param {Object} config The configuration object with property name/value pairs.
21584         * @private
21585         */
21586
21587        _initPlugins: function(config) {
21588            this._plugins = this._plugins || {};
21589
21590            if (this._initConfigPlugins) {
21591                this._initConfigPlugins(config);
21592            }
21593        },
21594
21595        /**
21596         * Unplugs and destroys all plugins on the host
21597         * @method _destroyPlugins
21598         * @private
21599         */
21600        _destroyPlugins: function() {
21601            this.unplug();
21602        }
21603    };
21604
21605    Y.namespace("Plugin").Host = PluginHost;
21606
21607
21608}, '3.18.1', {"requires": ["yui-base"]});
21609YUI.add('pluginhost-config', function (Y, NAME) {
21610
21611    /**
21612     * Adds pluginhost constructor configuration and static configuration support
21613     * @submodule pluginhost-config
21614     */
21615
21616    var PluginHost = Y.Plugin.Host,
21617        L = Y.Lang;
21618
21619    /**
21620     * A protected initialization method, used by the host class to initialize
21621     * plugin configurations passed the constructor, through the config object.
21622     *
21623     * Host objects should invoke this method at the appropriate time in their
21624     * construction lifecycle.
21625     *
21626     * @method _initConfigPlugins
21627     * @param {Object} config The configuration object passed to the constructor
21628     * @protected
21629     * @for Plugin.Host
21630     */
21631    PluginHost.prototype._initConfigPlugins = function(config) {
21632
21633        // Class Configuration
21634        var classes = (this._getClasses) ? this._getClasses() : [this.constructor],
21635            plug = [],
21636            unplug = {},
21637            constructor, i, classPlug, classUnplug, pluginClassName;
21638
21639        // TODO: Room for optimization. Can we apply statically/unplug in same pass?
21640        for (i = classes.length - 1; i >= 0; i--) {
21641            constructor = classes[i];
21642
21643            classUnplug = constructor._UNPLUG;
21644            if (classUnplug) {
21645                // subclasses over-write
21646                Y.mix(unplug, classUnplug, true);
21647            }
21648
21649            classPlug = constructor._PLUG;
21650            if (classPlug) {
21651                // subclasses over-write
21652                Y.mix(plug, classPlug, true);
21653            }
21654        }
21655
21656        for (pluginClassName in plug) {
21657            if (plug.hasOwnProperty(pluginClassName)) {
21658                if (!unplug[pluginClassName]) {
21659                    this.plug(plug[pluginClassName]);
21660                }
21661            }
21662        }
21663
21664        // User Configuration
21665        if (config && config.plugins) {
21666            this.plug(config.plugins);
21667        }
21668    };
21669
21670    /**
21671     * Registers plugins to be instantiated at the class level (plugins
21672     * which should be plugged into every instance of the class by default).
21673     *
21674     * @method plug
21675     * @static
21676     *
21677     * @param {Function} hostClass The host class on which to register the plugins
21678     * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with f
21678n and cfg properties defined)
21679     * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
21680     * @for Plugin.Host
21681     */
21682    PluginHost.plug = function(hostClass, plugin, config) {
21683        // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ]
21684        var p, i, l, name;
21685
21686        if (hostClass !== Y.Base) {
21687            hostClass._PLUG = hostClass._PLUG || {};
21688
21689            if (!L.isArray(plugin)) {
21690                if (config) {
21691                    plugin = {fn:plugin, cfg:config};
21692                }
21693                plugin = [plugin];
21694            }
21695
21696            for (i = 0, l = plugin.length; i < l;i++) {
21697                p = plugin[i];
21698                name = p.NAME || p.fn.NAME;
21699                hostClass._PLUG[name] = p;
21700            }
21701        }
21702    };
21703
21704    /**
21705     * Unregisters any class level plugins which have been registered by the host class, or any
21706     * other class in the hierarchy.
21707     *
21708     * @method unplug
21709     * @static
21710     *
21711     * @param {Function} hostClass The host class from which to unregister the plugins
21712     * @param {Function | Array} plugin The plugin class, or an array of plugin classes
21713     * @for Plugin.Host
21714     */
21715    PluginHost.unplug = function(hostClass, plugin) {
21716        var p, i, l, name;
21717
21718        if (hostClass !== Y.Base) {
21719            hostClass._UNPLUG = hostClass._UNPLUG || {};
21720
21721            if (!L.isArray(plugin)) {
21722                plugin = [plugin];
21723            }
21724
21725            for (i = 0, l = plugin.length; i < l; i++) {
21726                p = plugin[i];
21727                name = p.NAME;
21728                if (!hostClass._PLUG[name]) {
21729                    hostClass._UNPLUG[name] = p;
21730                } else {
21731                    delete hostClass._PLUG[name];
21732                }
21733            }
21734        }
21735    };
21736
21737
21738}, '3.18.1', {"requires": ["pluginhost-base"]});
21739YUI.add('event-delegate', function (Y, NAME) {
21740
21741/**
21742 * Adds event delegation support to the library.
21743 *
21744 * @module event
21745 * @submodule event-delegate
21746 */
21747
21748var toArray          = Y.Array,
21749    YLang            = Y.Lang,
21750    isString         = YLang.isString,
21751    isObject         = YLang.isObject,
21752    isArray          = YLang.isArray,
21753    selectorTest     = Y.Selector.test,
21754    detachCategories = Y.Env.evt.handles;
21755
21756/**
21757 * <p>Sets up event delegation on a container element.  The delegated event
21758 * will use a supplied selector or filtering function to test if the event
21759 * references at least one node that should trigger the subscription
21760 * callback.</p>
21761 *
21762 * <p>Selector string filters will trigger the callback if the event originated
21763 * from a node that matches it or is contained in a node that matches it.
21764 * Function filters are called for each Node up the parent axis to the
21765 * subscribing container node, and receive at each level the Node and the event
21766 * object.  The function should return true (or a truthy value) if that Node
21767 * should trigger the subscription callback.  Note, it is possible for filters
21768 * to match multiple Nodes for a single event.  In this case, the delegate
21769 * callback will be executed for each matching Node.</p>
21770 *
21771 * <p>For each matching Node, the callback will be executed with its 'this'
21772 * object set to the Node matched by the filter (unless a specific context was
21773 * provided during subscription), and the provided event's
21774 * <code>currentTarget</code> will also be set to the matching Node.  The
21775 * containing Node from which the subscription was originally made can be
21776 * referenced as <code>e.container</code>.
21777 *
21778 * @method delegate
21779 * @param type {String} the event type to delegate
21780 * @param fn {Function} the callback function to execute.  This function
21781 *              will be provided the event object for the delegated event.
21782 * @param el {String|node} the element that is the delegation container
21783 * @param filter {string|Function} a selector that must match the target of the
21784 *              event or a function to test target and its parents for a match
21785 * @param context optional argument that specifies what 'this' refers to.
21786 * @param args* 0..n additional arguments to pass on to the callback function.
21787 *              These arguments will be added after the event object.
21788 * @return {EventHandle} the detach handle
21789 * @static
21790 * @for Event
21791 */
21792function delegate(type, fn, el, filter) {
21793    var args     = toArray(arguments, 0, true),
21794        query    = isString(el) ? el : null,
21795        typeBits, synth, container, categories, cat, i, len, handles, handle;
21796
21797    // Support Y.delegate({ click: fnA, key: fnB }, el, filter, ...);
21798    // and Y.delegate(['click', 'key'], fn, el, filter, ...);
21799    if (isObject(type)) {
21800        handles = [];
21801
21802        if (isArray(type)) {
21803            for (i = 0, len = type.length; i < len; ++i) {
21804                args[0] = type[i];
21805                handles.push(Y.delegate.apply(Y, args));
21806            }
21807        } else {
21808            // Y.delegate({'click', fn}, el, filter) =>
21809            // Y.delegate('click', fn, el, filter)
21810            args.unshift(null); // one arg becomes two; need to make space
21811
21812            for (i in type) {
21813                if (type.hasOwnProperty(i)) {
21814                    args[0] = i;
21815                    args[1] = type[i];
21816                    handles.push(Y.delegate.apply(Y, args));
21817                }
21818            }
21819        }
21820
21821        return new Y.EventHandle(handles);
21822    }
21823
21824    typeBits = type.split(/\|/);
21825
21826    if (typeBits.length > 1) {
21827        cat  = typeBits.shift();
21828        args[0] = type = typeBits.shift();
21829    }
21830
21831    synth = Y.Node.DOM_EVENTS[type];
21832
21833    if (isObject(synth) && synth.delegate) {
21834        handle = synth.delegate.apply(synth, arguments);
21835    }
21836
21837    if (!handle) {
21838        if (!type || !fn || !el || !filter) {
21839            return;
21840        }
21841
21842        container = (query) ? Y.Selector.query(query, null, true) : el;
21843
21844        if (!container && isString(el)) {
21845            handle = Y.on('available', function () {
21846                Y.mix(handle, Y.delegate.apply(Y, args), true);
21847            }, el);
21848        }
21849
21850        if (!handle && container) {
21851            args.splice(2, 2, container); // remove the filter
21852
21853            handle = Y.Event._attach(args, { facade: false });
21854            handle.sub.filter  = filter;
21855            handle.sub._notify = delegate.notifySub;
21856        }
21857    }
21858
21859    if (handle && cat) {
21860        categories = detachCategories[cat]  || (detachCategories[cat] = {});
21861        categories = categories[type] || (categories[type] = []);
21862        categories.push(handle);
21863    }
21864
21865    return handle;
21866}
21867
21868/**
21869Overrides the <code>_notify</code> method on the normal DOM subscription to
21870inject the filtering logic and only proceed in the case of a match.
21871
21872This method is hosted as a private property of the `delegate` method
21873(e.g. `Y.delegate.notifySub`)
21874
21875@method notifySub
21876@param thisObj {Object} default 'this' object for the callback
21877@param args {Array} arguments passed to the event's <code>fire()</code>
21878@param ce {CustomEvent} the custom event managing the DOM subscriptions for
21879             the subscribed event on the subscribing node.
21880@return {Boolean} false if the event was stopped
21881@private
21882@static
21883@since 3.2.0
21884**/
21885delegate.notifySub = function (thisObj, args, ce) {
21886    // Preserve args for other subscribers
21887    args = args.slice();
21888    if (this.args) {
21889        args.push.apply(args, this.args);
21890    }
21891
21892    // Only notify subs if the event occurred on a targeted element
21893    var currentTarget = delegate._applyFilter(this.filter, args, ce),
21894        //container     = e.currentTarget,
21895        e, i, len, ret;
21896
21897    if (currentTarget) {
21898        // Support multiple matches up the the container subtree
21899        currentTarget = toArray(currentTarget);
21900
21901        // The second arg is the currentTarget, but we'll be reusing this
21902        // facade, replacing the currentTarget for each use, so it doesn't
21903        // matter what element we seed it with.
21904        e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce);
21905
21906        e.container = Y.one(ce.el);
21907
21908        for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) {
21909            e.currentTarget = Y.one(currentTarget[i]);
21910
21911            ret = this.fn.apply(this.context || e.currentTarget, args);
21912
21913            if (ret === false) { // stop further notifications
21914                break;
21915            }
21916        }
21917
21918        return ret;
21919    }
21920};
21921
21922/**
21923Compiles a selector string into a filter function to identify whether
21924Nodes along the parent axis of an event's target should trigger event
21925notification.
21926
21927This function is memoized, so previously compiled filter functions are
21928returned if the same selector string is provided.
21929
21930This function may be useful when defining synthetic events for delegate
21931handling.
21932
21933Hosted as a property of the `delegate` method (e.g. `Y.delegate.compileFilter`).
21934
21935@method compileFilter
21936@param selector {String} the selector string to base the filtration on
21937@return {Function}
21938@since 3.2.0
21939@static
21940**/
21941delegate.compileFilter = Y.cached(function (selector) {
21942    return function (target, e) {
21943        return selectorTest(target._node, selector,
21944            (e.currentTarget === e.target) ? null : e.currentTarget._node);
21945    };
21946});
21947
21948/**
21949Regex to test for disabled elements during filtering. This is only relevant to
21950IE to normalize behavior with other browsers, which swallow events that occur
21951to disabled elements. IE fires the event from the parent element instead of the
21952original target, though it does preserve `event.srcElement` as the disabled
21953element. IE also supports disabled on `<a>`, but the event still bubbles, so it
21954acts more like `e.preventDefault()` plus styling. That issue is not handled here
21955because other browsers fire the event on the `<a>`, so delegate is supported in
21956both cases.
21957
21958@property _disabledRE
21959@type {RegExp}
21960@protected
21961@since 3.8.1
21962**/
21963delegate._disabledRE = /^(?:button|input|select|textarea)$/i;
21964
21965/**
21966Walks up the parent axis of an event's target, and tests each element
21967against a supplied filter function.  If any Nodes, including the container,
21968satisfy the filter, the delegated callback will be triggered for each.
21969
21970Hosted as a protected property of the `delegate` method (e.g.
21971`Y.delegate._applyFilter`).
21972
21973@method _applyFilter
21974@param filter {Function} boolean function to test for inclusion in event
21975                 notification
21976@param args {Array} the arguments that would be passed to subscribers
21977@param ce   {CustomEvent} the DOM event wrapper
21978@return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter
21979@protected
21980**/
21981delegate._applyFilter = function (filter, args, ce) {
21982    var e         = args[0],
21983        container = ce.el, // facadeless events in IE, have no e.currentTarget
21984        target    = e.target || e.srcElement,
21985        match     = [],
21986        isContainer = false;
21987
21988    // Resolve text nodes to their containing element
21989    if (target.nodeType === 3) {
21990        target = target.parentNode;
21991    }
21992
21993    // For IE. IE propagates events from the parent element of disabled
21994    // elements, where other browsers swallow the event entirely. To normalize
21995    // this in IE, filtering for matching elements should abort if the target
21996    // is a disabled form control.
21997    if (target.disabled && delegate._disabledRE.test(target.nodeName)) {
21998        return match;
21999    }
22000
22001    // passing target as the first arg rather than leaving well enough alone
22002    // making 'this' in the filter function refer to the target.  This is to
22003    // support bound filter functions.
22004    args.unshift(target);
22005
22006    if (isString(filter)) {
22007        while (target) {
22008            isContainer = (target === container);
22009            if (selectorTest(target, filter, (isContainer ? null: container))) {
22010                match.push(target);
22011            }
22012
22013            if (isContainer) {
22014                break;
22015            }
22016
22017            target = target.parentNode;
22018        }
22019    } else {
22020        // filter functions are implementer code and should receive wrappers
22021        args[0] = Y.one(target);
22022        args[1] = new Y.DOMEventFacade(e, container, ce);
22023
22024        while (target) {
22025            // filter(target, e, extra args...) - this === target
22026            if (filter.apply(args[0], args)) {
22027                match.push(target);
22028            }
22029
22030            if (target === container) {
22031                break;
22032            }
22033
22034            target = target.parentNode;
22035            args[0] = Y.one(target);
22036        }
22037        args[1] = e; // restore the raw DOM event
22038    }
22039
22040    if (match.length <= 1) {
22041        match = match[0]; // single match or undefined
22042    }
22043
22044    // remove the target
22045    args.shift();
22046
22047    return match;
22048};
22049
22050/**
22051 * Sets up event delegation on a container element.  The delegated event
22052 * will use a supplied filter to test if the callback should be executed.
22053 * This filter can be either a selector string or a function that returns
22054 * a Node to use as the currentTarget for the event.
22055 *
22056 * The event object for the delegated event is supplied to the callback
22057 * function.  It is modified slightly in order to support all properties
22058 * that may be needed for event delegation.  'currentTarget' is set to
22059 * the element that matched the selector string filter or the Node returned
22060 * from the filter function.  'container' is set to the element that the
22061 * listener is delegated from (this normally would be the 'currentTarget').
22062 *
22063 * Filter functions will be called with the arguments that would be passed to
22064 * the callback function, including the event object as the first parameter.
22065 * The function should return false (or a falsey value) if the success criteria
22066 * aren't met, and the Node to use as the event's currentTarget and 'this'
22067 * object if they are.
22068 *
22069 * @method delegate
22070 * @param type {string} the event type to delegate
22071 * @param fn {function} the callback function to execute.  This function
22072 * will be provided the event object for the delegated event.
22073 * @param el {string|node} the element that is the delegation container
22074 * @param filter {string|function} a selector that must match the target of the
22075 * event or a function that returns a Node or false.
22076 * @param context optional argument that specifies what 'this' refers to.
22077 * @param args* 0..n additional arguments to pass on to the callback function.
22078 * These arguments will be added after the event object.
22079 * @return {EventHandle} the detach handle
22080 * @for YUI
22081 */
22082Y.delegate = Y.Event.delegate = delegate;
22083
22084
22085}, '3.18.1', {"requires": ["node-base"]});
22086YUI.add('node-event-delegate', function (Y, NAME) {
22087
22088/**
22089 * Functionality to make the node a delegated event container
22090 * @module node
22091 * @submodule node-event-delegate
22092 */
22093
22094/**
22095 * <p>Sets up a delegation listener for an event occurring inside the Node.
22096 * The delegated event will be verified against a supplied selector or
22097 * filtering function to test if the event references at least one node that
22098 * should trigger the subscription callback.</p>
22099 *
22100 * <p>Selector string filters will trigger the callback if the event originated
22101 * from a node that matches it or is contained in a node that matches it.
22102 * Function filters are called for each Node up the parent axis to the
22103 * subscribing container node, and receive at each level the Node and the event
22104 * object.  The function should return true (or a truthy value) if that Node
22105 * should trigger the subscription callback.  Note, it is possible for filters
22106 * to match multiple Nodes for a single event.  In this case, the delegate
22107 * callback will be executed for each matching Node.</p>
22108 *
22109 * <p>For each matching Node, the callback will be executed with its 'this'
22110 * object set to the Node matched by the filter (unless a specific context was
22111 * provided during subscription), and the provided event's
22112 * <code>currentTarget</code> will also be set to the matching Node.  The
22113 * containing Node from which the subscription was originally made can be
22114 * referenced as <code>e.container</code>.
22115 *
22116 * @method delegate
22117 * @param type {String} the event type to delegate
22118 * @param fn {Function} the callback function to execute.  This function
22119 *              will be provided the event object for the delegated event.
22120 * @param spec {String|Function} a selector that must match the target of the
22121 *              event or a function to test target and its parents for a match
22122 * @param context {Object} optional argument that specifies what 'this' refers to.
22123 * @param args* {any} 0..n additional arguments to pass on to the callback function.
22124 *              These arguments will be added after the event object.
22125 * @return {EventHandle} the detach handle
22126 * @for Node
22127 */
22128Y.Node.prototype.delegate = function(type) {
22129
22130    var args = Y.Array(arguments, 0, true),
22131        index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2;
22132
22133    args.splice(index, 0, this._node);
22134
22135    return Y.delegate.apply(Y, args);
22136};
22137
22138
22139}, '3.18.1', {"requires": ["node-base", "event-delegate"]});
22140YUI.add('node-pluginhost', function (Y, NAME) {
22141
22142/**
22143 * @module node
22144 * @submodule node-pluginhost
22145 */
22146
22147/**
22148 * Registers plugins to be instantiated at the class level (plugins
22149 * which should be plugged into every instance of Node by default).
22150 *
22151 * @method plug
22152 * @static
22153 * @for Node
22154 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with f
22154n and cfg properties defined)
22155 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
22156 */
22157Y.Node.plug = function() {
22158    var args = Y.Array(arguments);
22159    args.unshift(Y.Node);
22160    Y.Plugin.Host.plug.apply(Y.Base, args);
22161    return Y.Node;
22162};
22163
22164/**
22165 * Unregisters any class level plugins which have been registered by the Node
22166 *
22167 * @method unplug
22168 * @static
22169 *
22170 * @param {Function | Array} plugin The plugin class, or an array of plugin classes
22171 */
22172Y.Node.unplug = function() {
22173    var args = Y.Array(arguments);
22174    args.unshift(Y.Node);
22175    Y.Plugin.Host.unplug.apply(Y.Base, args);
22176    return Y.Node;
22177};
22178
22179Y.mix(Y.Node, Y.Plugin.Host, false, null, 1);
22180
22181// run PluginHost constructor on cached Node instances
22182Y.Object.each(Y.Node._instances, function (node) {
22183    Y.Plugin.Host.apply(node);
22184});
22185
22186// allow batching of plug/unplug via NodeList
22187// doesn't use NodeList.importMethod because we need real Nodes (not tmpNode)
22188/**
22189 * Adds a plugin to each node in the NodeList.
22190 * This will instantiate the plugin and attach it to the configured namespace on each node
22191 * @method plug
22192 * @for NodeList
22193 * @param P {Function | Object |Array} Accepts the plugin class, or an
22194 * object with a "fn" property specifying the plugin class and
22195 * a "cfg" property specifying the configuration for the Plugin.
22196 * <p>
22197 * Additionally an Array can also be passed in, with the above function or
22198 * object values, allowing the user to add multiple plugins in a single call.
22199 * </p>
22200 * @param config (Optional) If the first argument is the plugin class, the second argument
22201 * can be the configuration for the plugin.
22202 * @chainable
22203 */
22204Y.NodeList.prototype.plug = function() {
22205    var args = arguments;
22206    Y.NodeList.each(this, function(node) {
22207        Y.Node.prototype.plug.apply(Y.one(node), args);
22208    });
22209    return this;
22210};
22211
22212/**
22213 * Removes a plugin from all nodes in the NodeList. This will destroy the
22214 * plugin instance and delete the namespace each node.
22215 * @method unplug
22216 * @for NodeList
22217 * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided,
22218 * all registered plugins are unplugged.
22219 * @chainable
22220 */
22221Y.NodeList.prototype.unplug = function() {
22222    var args = arguments;
22223    Y.NodeList.each(this, function(node) {
22224        Y.Node.prototype.unplug.apply(Y.one(node), args);
22225    });
22226    return this;
22227};
22228
22229
22230}, '3.18.1', {"requires": ["node-base", "pluginhost"]});
22231YUI.add('dom-screen', function (Y, NAME) {
22232
22233(function(Y) {
22234
22235/**
22236 * Adds position and region management functionality to DOM.
22237 * @module dom
22238 * @submodule dom-screen
22239 * @for DOM
22240 */
22241
22242var DOCUMENT_ELEMENT = 'documentElement',
22243    COMPAT_MODE = 'compatMode',
22244    POSITION = 'position',
22245    FIXED = 'fixed',
22246    RELATIVE = 'relative',
22247    LEFT = 'left',
22248    TOP = 'top',
22249    _BACK_COMPAT = 'BackCompat',
22250    MEDIUM = 'medium',
22251    BORDER_LEFT_WIDTH = 'borderLeftWidth',
22252    BORDER_TOP_WIDTH = 'borderTopWidth',
22253    GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
22254    GET_COMPUTED_STYLE = 'getComputedStyle',
22255
22256    Y_DOM = Y.DOM,
22257
22258    // TODO: how about thead/tbody/tfoot/tr?
22259    // TODO: does caption matter?
22260    RE_TABLE = /^t(?:able|d|h)$/i,
22261
22262    SCROLL_NODE;
22263
22264if (Y.UA.ie) {
22265    if (Y.config.doc[COMPAT_MODE] !== 'BackCompat') {
22266        SCROLL_NODE = DOCUMENT_ELEMENT;
22267    } else {
22268        SCROLL_NODE = 'body';
22269    }
22270}
22271
22272Y.mix(Y_DOM, {
22273    /**
22274     * Returns the inner height of the viewport (exludes scrollbar).
22275     * @method winHeight
22276     * @return {Number} The current height of the viewport.
22277     */
22278    winHeight: function(node) {
22279        var h = Y_DOM._getWinSize(node).height;
22280        return h;
22281    },
22282
22283    /**
22284     * Returns the inner width of the viewport (exludes scrollbar).
22285     * @method winWidth
22286     * @return {Number} The current width of the viewport.
22287     */
22288    winWidth: function(node) {
22289        var w = Y_DOM._getWinSize(node).width;
22290        return w;
22291    },
22292
22293    /**
22294     * Document height
22295     * @method docHeight
22296     * @return {Number} The current height of the document.
22297     */
22298    docHeight:  function(node) {
22299        var h = Y_DOM._getDocSize(node).height;
22300        return Math.max(h, Y_DOM._getWinSize(node).height);
22301    },
22302
22303    /**
22304     * Document width
22305     * @method docWidth
22306     * @return {Number} The current width of the document.
22307     */
22308    docWidth:  function(node) {
22309        var w = Y_DOM._getDocSize(node).width;
22310        return Math.max(w, Y_DOM._getWinSize(node).width);
22311    },
22312
22313    /**
22314     * Amount page has been scroll horizontally
22315     * @method docScrollX
22316     * @return {Number} The current amount the screen is scrolled horizontally.
22317     */
22318    docScrollX: function(node, doc) {
22319        doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
22320        var dv = doc.defaultView,
22321            pageOffset = (dv) ? dv.pageXOffset : 0;
22322        return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft, pageOffset);
22323    },
22324
22325    /**
22326     * Amount page has been scroll vertically
22327     * @method docScrollY
22328     * @return {Number} The current amount the screen is scrolled vertically.
22329     */
22330    docScrollY:  function(node, doc) {
22331        doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
22332        var dv = doc.defaultView,
22333            pageOffset = (dv) ? dv.pageYOffset : 0;
22334        return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop, pageOffset);
22335    },
22336
22337    /**
22338     * Gets the current position of an element based on page coordinates.
22339     * Element must be part of the DOM tree to have page coordinates
22340     * (display:none or elements not appended return false).
22341     * @method getXY
22342     * @param element The target element
22343     * @return {Array} The XY position of the element
22344
22345     TODO: test inDocument/display?
22346     */
22347    getXY: function() {
22348        if (Y.config.doc[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
22349            return function(node) {
22350                var xy = null,
22351                    scrollLeft,
22352                    scrollTop,
22353                    mode,
22354                    box,
22355                    offX,
22356                    offY,
22357                    doc,
22358                    win,
22359                    inDoc,
22360                    rootNode;
22361
22362                if (node && node.tagName) {
22363                    doc = node.ownerDocument;
22364                    mode = doc[COMPAT_MODE];
22365
22366                    if (mode !== _BACK_COMPAT) {
22367                        rootNode = doc[DOCUMENT_ELEMENT];
22368                    } else {
22369                        rootNode = doc.body;
22370                    }
22371
22372                    // inline inDoc check for perf
22373                    if (rootNode.contains) {
22374                        inDoc = rootNode.contains(node);
22375                    } else {
22376                        inDoc = Y.DOM.contains(rootNode, node);
22377                    }
22378
22379                    if (inDoc) {
22380                        win = doc.defaultView;
22381
22382                        // inline scroll calc for perf
22383                        if (win && 'pageXOffset' in win) {
22384                            scrollLeft = win.pageXOffset;
22385                            scrollTop = win.pageYOffset;
22386                        } else {
22387                            scrollLeft = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollLeft : Y_DOM.docScrollX(node, doc);
22388                            scrollTop = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollTop : Y_DOM.docScrollY(node, doc);
22389                        }
22390
22391                        if (Y.UA.ie) { // IE < 8, quirks, or compatMode
22392                            if (!doc.documentMode || doc.documentMode < 8 || mode === _BACK_COMPAT) {
22393                                offX = rootNode.clientLeft;
22394                                offY = rootNode.clientTop;
22395                            }
22396                        }
22397                        box = node[GET_BOUNDING_CLIENT_RECT]();
22398                        xy = [box.left, box.top];
22399
22400                        if (offX || offY) {
22401                                xy[0] -= offX;
22402                                xy[1] -= offY;
22403
22404                        }
22405                        if ((scrollTop || scrollLeft)) {
22406                            if (!Y.UA.ios || (Y.UA.ios >= 4.2)) {
22407                                xy[0] += scrollLeft;
22408                                xy[1] += scrollTop;
22409                            }
22410
22411                        }
22412                    } else {
22413                        xy = Y_DOM._getOffset(node);
22414                    }
22415                }
22416                return xy;
22417            };
22418        } else {
22419            return function(node) { // manually calculate by crawling up offsetParents
22420                //Calculate the Top and Left border sizes (assumes pixels)
22421                var xy = null,
22422                    doc,
22423                    parentNode,
22424                    bCheck,
22425                    scrollTop,
22426                    scrollLeft;
22427
22428                if (node) {
22429                    if (Y_DOM.inDoc(node)) {
22430                        xy = [node.offsetLeft, node.offsetTop];
22431                        doc = node.ownerDocument;
22432                        parentNode = node;
22433                        // TODO: refactor with !! or just falsey
22434                        bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
22435
22436                        // TODO: worth refactoring for TOP/LEFT only?
22437                        while ((parentNode = parentNode.offsetParent)) {
22438                            xy[0] += parentNode.offsetLeft;
22439                            xy[1] += parentNode.offsetTop;
22440                            if (bCheck) {
22441                                xy = Y_DOM._calcBorders(parentNode, xy);
22442                            }
22443                        }
22444
22445                        // account for any scrolled ancestors
22446                        if (Y_DOM.getStyle(node, POSITION) != FIXED) {
22447                            parentNode = node;
22448
22449                            while ((parentNode = parentNode.parentNode)) {
22450                                scrollTop = parentNode.scrollTop;
22451                                scrollLeft = parentNode.scrollLeft;
22452
22453                                //Firefox does something funky with borders when overflow is not visible.
22454                                if (Y.UA.gecko && (Y_DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
22455                                        xy = Y_DOM._calcBorders(parentNode, xy);
22456                                }
22457
22458
22459                                if (scrollTop || scrollLeft) {
22460                                    xy[0] -= scrollLeft;
22461                                    xy[1] -= scrollTop;
22462                                }
22463                            }
22464                            xy[0] += Y_DOM.docScrollX(node, doc);
22465                            xy[1] += Y_DOM.docScrollY(node, doc);
22466
22467                        } else {
22468                            //Fix FIXED position -- add scrollbars
22469                            xy[0] += Y_DOM.docScrollX(node, doc);
22470                            xy[1] += Y_DOM.docScrollY(node, doc);
22471                        }
22472                    } else {
22473                        xy = Y_DOM._getOffset(node);
22474                    }
22475                }
22476
22477                return xy;
22478            };
22479        }
22480    }(),// NOTE: Executing for loadtime branching
22481
22482    /**
22483    Gets the width of vertical scrollbars on overflowed containers in the body
22484    content.
22485
22486    @method getScrollbarWidth
22487    @return {Number} Pixel width of a scrollbar in the current browser
22488    **/
22489    getScrollbarWidth: Y.cached(function () {
22490        var doc      = Y.config.doc,
22491            testNode = doc.createElement('div'),
22492            body     = doc.getElementsByTagName('body')[0],
22493            // 0.1 because cached doesn't support falsy refetch values
22494            width    = 0.1;
22495
22496        if (body) {
22497            testNode.style.cssText = "position:absolute;visibility:hidden;overflow:scroll;width:20px;";
22498            testNode.appendChild(doc.createElement('p')).style.height = '1px';
22499            body.insertBefore(testNode, body.firstChild);
22500            width = testNode.offsetWidth - testNode.clientWidth;
22501
22502            body.removeChild(testNode);
22503        }
22504
22505        return width;
22506    }, null, 0.1),
22507
22508    /**
22509     * Gets the current X position of an element based on page coordinates.
22510     * Element must be part of the DOM tree to have page coordinates
22511     * (display:none or elements not appended return false).
22512     * @method getX
22513     * @param element The target element
22514     * @return {Number} The X position of the element
22515     */
22516
22517    getX: function(node) {
22518        return Y_DOM.getXY(node)[0];
22519    },
22520
22521    /**
22522     * Gets the current Y position of an element based on page coordinates.
22523     * Element must be part of the DOM tree to have page coordinates
22524     * (display:none or elements not appended return false).
22525     * @method getY
22526     * @param element The target element
22527     * @return {Number} The Y position of the element
22528     */
22529
22530    getY: function(node) {
22531        return Y_DOM.getXY(node)[1];
22532    },
22533
22534    /**
22535     * Set the position of an html element in page coordinates.
22536     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
22537     * @method setXY
22538     * @param element The target element
22539     * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
22540     * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
22541     */
22542    setXY: function(node, xy, noRetry) {
22543        var setStyle = Y_DOM.setStyle,
22544            pos,
22545            delta,
22546            newXY,
22547            currentXY;
22548
22549        if (node && xy) {
22550            pos = Y_DOM.getStyle(node, POSITION);
22551
22552            delta = Y_DOM._getOffset(node);
22553            if (pos == 'static') { // default to relative
22554                pos = RELATIVE;
22555                setStyle(node, POSITION, pos);
22556            }
22557            currentXY = Y_DOM.getXY(node);
22558
22559            if (xy[0] !== null) {
22560                setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
22561            }
22562
22563            if (xy[1] !== null) {
22564                setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
22565            }
22566
22567            if (!noRetry) {
22568                newXY = Y_DOM.getXY(node);
22569                if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
22570                    Y_DOM.setXY(node, xy, true);
22571                }
22572            }
22573
22574        } else {
22575        }
22576    },
22577
22578    /**
22579     * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
22580     * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
22581     * @method setX
22582     * @param element The target element
22583     * @param {Number} x The X values for new position (coordinates are page-based)
22584     */
22585    setX: function(node, x) {
22586        return Y_DOM.setXY(node, [x, null]);
22587    },
22588
22589    /**
22590     * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
22591     * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
22592     * @method setY
22593     * @param element The target element
22594     * @param {Number} y The Y values for new position (coordinates are page-based)
22595     */
22596    setY: function(node, y) {
22597        return Y_DOM.setXY(node, [null, y]);
22598    },
22599
22600    /**
22601     * @method swapXY
22602     * @description Swap the xy position with another node
22603     * @param {Node} node The node to swap with
22604     * @param {Node} otherNode The other node to swap with
22605     * @return {Node}
22606     */
22607    swapXY: function(node, otherNode) {
22608        var xy = Y_DOM.getXY(node);
22609        Y_DOM.setXY(node, Y_DOM.getXY(otherNode));
22610        Y_DOM.setXY(otherNode, xy);
22611    },
22612
22613    _calcBorders: function(node, xy2) {
22614        var t = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
22615            l = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
22616        if (Y.UA.gecko) {
22617            if (RE_TABLE.test(node.tagName)) {
22618                t = 0;
22619                l = 0;
22620            }
22621        }
22622        xy2[0] += l;
22623        xy2[1] += t;
22624        return xy2;
22625    },
22626
22627    _getWinSize: function(node, doc) {
22628        doc  = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc;
22629        var win = doc.defaultView || doc.parentWindow,
22630            mode = doc[COMPAT_MODE],
22631            h = win.innerHeight,
22632            w = win.innerWidth,
22633            root = doc[DOCUMENT_ELEMENT];
22634
22635        if ( mode && !Y.UA.opera ) { // IE, Gecko
22636            if (mode != 'CSS1Compat') { // Quirks
22637                root = doc.body;
22638            }
22639            h = root.clientHeight;
22640            w = root.clientWidth;
22641        }
22642        return { height: h, width: w };
22643    },
22644
22645    _getDocSize: function(node) {
22646        var doc = (node) ? Y_DOM._getDoc(node) : Y.config.doc,
22647            root = doc[DOCUMENT_ELEMENT];
22648
22649        if (doc[COMPAT_MODE] != 'CSS1Compat') {
22650            root = doc.body;
22651        }
22652
22653        return { height: root.scrollHeight, width: root.scrollWidth };
22654    }
22655});
22656
22657})(Y);
22658(function(Y) {
22659var TOP = 'top',
22660    RIGHT = 'right',
22661    BOTTOM = 'bottom',
22662    LEFT = 'left',
22663
22664    getOffsets = function(r1, r2) {
22665        var t = Math.max(r1[TOP], r2[TOP]),
22666            r = Math.min(r1[RIGHT], r2[RIGHT]),
22667            b = Math.min(r1[BOTTOM], r2[BOTTOM]),
22668            l = Math.max(r1[LEFT], r2[LEFT]),
22669            ret = {};
22670
22671        ret[TOP] = t;
22672        ret[RIGHT] = r;
22673        ret[BOTTOM] = b;
22674        ret[LEFT] = l;
22675        return ret;
22676    },
22677
22678    DOM = Y.DOM;
22679
22680Y.mix(DOM, {
22681    /**
22682     * Returns an Object literal containing the following about this element: (top, right, bottom, left)
22683     * @for DOM
22684     * @method region
22685     * @param {HTMLElement} element The DOM element.
22686     * @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
22687     */
22688    region: function(node) {
22689        var xy = DOM.getXY(node),
22690            ret = false;
22691
22692        if (node && xy) {
22693            ret = DOM._getRegion(
22694                xy[1], // top
22695                xy[0] + node.offsetWidth, // right
22696                xy[1] + node.offsetHeight, // bottom
22697                xy[0] // left
22698            );
22699        }
22700
22701        return ret;
22702    },
22703
22704    /**
22705     * Find the intersect information for the passed nodes.
22706     * @method intersect
22707     * @for DOM
22708     * @param {HTMLElement} element The first element
22709     * @param {HTMLElement | Object} element2 The element or region to check the interect with
22710     * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance e.g. DragDrop)
22711     * @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
22712     */
22713    intersect: function(node, node2, altRegion) {
22714        var r = altRegion || DOM.region(node), region = {},
22715            n = node2,
22716            off;
22717
22718        if (n.tagName) {
22719            region = DOM.region(n);
22720        } else if (Y.Lang.isObject(node2)) {
22721            region = node2;
22722        } else {
22723            return false;
22724        }
22725
22726        off = getOffsets(region, r);
22727        return {
22728            top: off[TOP],
22729            right: off[RIGHT],
22730            bottom: off[BOTTOM],
22731            left: off[LEFT],
22732            area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
22733            yoff: ((off[BOTTOM] - off[TOP])),
22734            xoff: (off[RIGHT] - off[LEFT]),
22735            inRegion: DOM.inRegion(node, node2, false, altRegion)
22736        };
22737
22738    },
22739    /**
22740     * Check if any part of this node is in the passed region
22741     * @method inRegion
22742     * @for DOM
22743     * @param {Object} node The node to get the region from
22744     * @param {Object} node2 The second node to get the region from or an Object literal of the region
22745     * @param {Boolean} all Should all of the node be inside the region
22746     * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance e.g. DragDrop)
22747     * @return {Boolean} True if in region, false if not.
22748     */
22749    inRegion: function(node, node2, all, altRegion) {
22750        var region = {},
22751            r = altRegion || DOM.region(node),
22752            n = node2,
22753            off;
22754
22755        if (n.tagName) {
22756            region = DOM.region(n);
22757        } else if (Y.Lang.isObject(node2)) {
22758            region = node2;
22759        } else {
22760            return false;
22761        }
22762
22763        if (all) {
22764            return (
22765                r[LEFT]   >= region[LEFT]   &&
22766                r[RIGHT]  <= region[RIGHT]  &&
22767                r[TOP]    >= region[TOP]    &&
22768                r[BOTTOM] <= region[BOTTOM]  );
22769        } else {
22770            off = getOffsets(region, r);
22771            if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
22772                return true;
22773            } else {
22774                return false;
22775            }
22776
22777        }
22778    },
22779
22780    /**
22781     * Check if any part of this element is in the viewport
22782     * @method inViewportRegion
22783     * @for DOM
22784     * @param {HTMLElement} element The DOM element.
22785     * @param {Boolean} all Should all of the node be inside the region
22786     * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance e.g. DragDrop)
22787     * @return {Boolean} True if in region, false if not.
22788     */
22789    inViewportRegion: function(node, all, altRegion) {
22790        return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
22791
22792    },
22793
22794    _getRegion: function(t, r, b, l) {
22795        var region = {};
22796
22797        region[TOP] = region[1] = t;
22798        region[LEFT] = region[0] = l;
22799        region[BOTTOM] = b;
22800        region[RIGHT] = r;
22801        region.width = region[RIGHT] - region[LEFT];
22802        region.height = region[BOTTOM] - region[TOP];
22803
22804        return region;
22805    },
22806
22807    /**
22808     * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
22809     * @method viewportRegion
22810     * @for DOM
22811     * @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
22812     */
22813    viewportRegion: function(node) {
22814        node = node || Y.config.doc.documentElement;
22815        var ret = false,
22816            scrollX,
22817            scrollY;
22818
22819        if (node) {
22820            scrollX = DOM.docScrollX(node);
22821            scrollY = DOM.docScrollY(node);
22822
22823            ret = DOM._getRegion(scrollY, // top
22824                DOM.winWidth(node) + scrollX, // right
22825                scrollY + DOM.winHeight(node), // bottom
22826                scrollX); // left
22827        }
22828
22829        return ret;
22830    }
22831});
22832})(Y);
22833
22834
22835}, '3.18.1', {"requires": ["dom-base", "dom-style"]});
22836YUI.add('node-screen', function (Y, NAME) {
22837
22838/**
22839 * Extended Node interface for managing regions and screen positioning.
22840 * Adds support for positioning elements and normalizes window size and scroll detection.
22841 * @module node
22842 * @submodule node-screen
22843 */
22844
22845// these are all "safe" returns, no wrapping required
22846Y.each([
22847    /**
22848     * Returns the inner width of the viewport (exludes scrollbar).
22849     * @config winWidth
22850     * @for Node
22851     * @type {Number}
22852     */
22853    'winWidth',
22854
22855    /**
22856     * Returns the inner height of the viewport (exludes scrollbar).
22857     * @config winHeight
22858     * @type {Number}
22859     */
22860    'winHeight',
22861
22862    /**
22863     * Document width
22864     * @config docWidth
22865     * @type {Number}
22866     */
22867    'docWidth',
22868
22869    /**
22870     * Document height
22871     * @config docHeight
22872     * @type {Number}
22873     */
22874    'docHeight',
22875
22876    /**
22877     * Pixel distance the page has been scrolled horizontally
22878     * @config docScrollX
22879     * @type {Number}
22880     */
22881    'docScrollX',
22882
22883    /**
22884     * Pixel distance the page has been scrolled vertically
22885     * @config docScrollY
22886     * @type {Number}
22887     */
22888    'docScrollY'
22889    ],
22890    function(name) {
22891        Y.Node.ATTRS[name] = {
22892            getter: function() {
22893                var args = Array.prototype.slice.call(arguments);
22894                args.unshift(Y.Node.getDOMNode(this));
22895
22896                return Y.DOM[name].apply(this, args);
22897            }
22898        };
22899    }
22900);
22901
22902Y.Node.ATTRS.scrollLeft = {
22903    getter: function() {
22904        var node = Y.Node.getDOMNode(this);
22905        return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
22906    },
22907
22908    setter: function(val) {
22909        var node = Y.Node.getDOMNode(this);
22910        if (node) {
22911            if ('scrollLeft' in node) {
22912                node.scrollLeft = val;
22913            } else if (node.document || node.nodeType === 9) {
22914                Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
22915            }
22916        } else {
22917        }
22918    }
22919};
22920
22921Y.Node.ATTRS.scrollTop = {
22922    getter: function() {
22923        var node = Y.Node.getDOMNode(this);
22924        return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
22925    },
22926
22927    setter: function(val) {
22928        var node = Y.Node.getDOMNode(this);
22929        if (node) {
22930            if ('scrollTop' in node) {
22931                node.scrollTop = val;
22932            } else if (node.document || node.nodeType === 9) {
22933                Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
22934            }
22935        } else {
22936        }
22937    }
22938};
22939
22940Y.Node.importMethod(Y.DOM, [
22941/**
22942 * Gets the current position of the node in page coordinates.
22943 * @method getXY
22944 * @for Node
22945 * @return {Array} The XY position of the node
22946*/
22947    'getXY',
22948
22949/**
22950 * Set the position of the node in page coordinates, regardless of how the node is positioned.
22951 * @method setXY
22952 * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
22953 * @chainable
22954 */
22955    'setXY',
22956
22957/**
22958 * Gets the current position of the node in page coordinates.
22959 * @method getX
22960 * @return {Number} The X position of the node
22961*/
22962    'getX',
22963
22964/**
22965 * Set the position of the node in page coordinates, regardless of how the node is positioned.
22966 * @method setX
22967 * @param {Number} x X value for new position (coordinates are page-based)
22968 * @chainable
22969 */
22970    'setX',
22971
22972/**
22973 * Gets the current position of the node in page coordinates.
22974 * @method getY
22975 * @return {Number} The Y position of the node
22976*/
22977    'getY',
22978
22979/**
22980 * Set the position of the node in page coordinates, regardless of how the node is positioned.
22981 * @method setY
22982 * @param {Number} y Y value for new position (coordinates are page-based)
22983 * @chainable
22984 */
22985    'setY',
22986
22987/**
22988 * Swaps the XY position of this node with another node.
22989 * @method swapXY
22990 * @param {Node | HTMLElement} otherNode The node to swap with.
22991 * @chainable
22992 */
22993    'swapXY'
22994]);
22995
22996/**
22997 * @module node
22998 * @submodule node-screen
22999 */
23000
23001/**
23002 * Returns a region object for the node
23003 * @config region
23004 * @for Node
23005 * @type Node
23006 */
23007Y.Node.ATTRS.region = {
23008    getter: function() {
23009        var node = this.getDOMNode(),
23010            region;
23011
23012        if (node && !node.tagName) {
23013            if (node.nodeType === 9) { // document
23014                node = node.documentElement;
23015            }
23016        }
23017        if (Y.DOM.isWindow(node)) {
23018            region = Y.DOM.viewportRegion(node);
23019        } else {
23020            region = Y.DOM.region(node);
23021        }
23022        return region;
23023    }
23024};
23025
23026/**
23027 * Returns a region object for the node's viewport
23028 * @config viewportRegion
23029 * @type Node
23030 */
23031Y.Node.ATTRS.viewportRegion = {
23032    getter: function() {
23033        return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
23034    }
23035};
23036
23037Y.Node.importMethod(Y.DOM, 'inViewportRegion');
23038
23039// these need special treatment to extract 2nd node arg
23040/**
23041 * Compares the intersection of the node with another node or region
23042 * @method intersect
23043 * @for Node
23044 * @param {Node|Object} node2 The node or region to compare with.
23045 * @param {Object} altRegion An alternate region to use (rather than this node's).
23046 * @return {Object} An object representing the intersection of the regions.
23047 */
23048Y.Node.prototype.intersect = function(node2, altRegion) {
23049    var node1 = Y.Node.getDOMNode(this);
23050    if (Y.instanceOf(node2, Y.Node)) { // might be a region object
23051        node2 = Y.Node.getDOMNode(node2);
23052    }
23053    return Y.DOM.intersect(node1, node2, altRegion);
23054};
23055
23056/**
23057 * Determines whether or not the node is within the given region.
23058 * @method inRegion
23059 * @param {Node|Object} node2 The node or region to compare with.
23060 * @param {Boolean} all Whether or not all of the node must be in the region.
23061 * @param {Object} altRegion An alternate region to use (rather than this node's).
23062 * @return {Boolean}
23062 True if in region, false if not.
23063 */
23064Y.Node.prototype.inRegion = function(node2, all, altRegion) {
23065    var node1 = Y.Node.getDOMNode(this);
23066    if (Y.instanceOf(node2, Y.Node)) { // might be a region object
23067        node2 = Y.Node.getDOMNode(node2);
23068    }
23069    return Y.DOM.inRegion(node1, node2, all, altRegion);
23070};
23071
23072
23073}, '3.18.1', {"requires": ["dom-screen", "node-base"]});
23074YUI.add('node-style', function (Y, NAME) {
23075
23076(function(Y) {
23077/**
23078 * Extended Node interface for managing node styles.
23079 * @module node
23080 * @submodule node-style
23081 */
23082
23083Y.mix(Y.Node.prototype, {
23084    /**
23085     * Sets a style property of the node.
23086     * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23087     * @method setStyle
23088     * @param {String} attr The style attribute to set.
23089     * @param {String|Number} val The value.
23090     * @chainable
23091     */
23092    setStyle: function(attr, val) {
23093        Y.DOM.setStyle(this._node, attr, val);
23094        return this;
23095    },
23096
23097    /**
23098     * Sets multiple style properties on the node.
23099     * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23100     * @method setStyles
23101     * @param {Object} hash An object literal of property:value pairs.
23102     * @chainable
23103     */
23104    setStyles: function(hash) {
23105        Y.DOM.setStyles(this._node, hash);
23106        return this;
23107    },
23108
23109    /**
23110     * Returns the style's current value.
23111     * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23112     * @method getStyle
23113     * @for Node
23114     * @param {String} attr The style attribute to retrieve.
23115     * @return {String} The current value of the style property for the element.
23116     */
23117
23118     getStyle: function(attr) {
23119        return Y.DOM.getStyle(this._node, attr);
23120     },
23121
23122    /**
23123     * Returns the computed value for the given style property.
23124     * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23125     * @method getComputedStyle
23126     * @param {String} attr The style attribute to retrieve.
23127     * @return {String} The computed value of the style property for the element.
23128     */
23129     getComputedStyle: function(attr) {
23130        return Y.DOM.getComputedStyle(this._node, attr);
23131     }
23132});
23133
23134/**
23135 * Returns an array of values for each node.
23136 * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23137 * @method getStyle
23138 * @for NodeList
23139 * @see Node.getStyle
23140 * @param {String} attr The style attribute to retrieve.
23141 * @return {Array} The current values of the style property for the element.
23142 */
23143
23144/**
23145 * Returns an array of the computed value for each node.
23146 * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23147 * @method getComputedStyle
23148 * @see Node.getComputedStyle
23149 * @param {String} attr The style attribute to retrieve.
23150 * @return {Array} The computed values for each node.
23151 */
23152
23153/**
23154 * Sets a style property on each node.
23155 * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23156 * @method setStyle
23157 * @see Node.setStyle
23158 * @param {String} attr The style attribute to set.
23159 * @param {String|Number} val The value.
23160 * @chainable
23161 */
23162
23163/**
23164 * Sets multiple style properties on each node.
23165 * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
23166 * @method setStyles
23167 * @see Node.setStyles
23168 * @param {Object} hash An object literal of property:value pairs.
23169 * @chainable
23170 */
23171
23172// These are broken out to handle undefined return (avoid false positive for
23173// chainable)
23174
23175Y.NodeList.importMethod(Y.Node.prototype, ['getStyle', 'getComputedStyle', 'setStyle', 'setStyles']);
23176})(Y);
23177/**
23178 * @module node
23179 * @submodule node-base
23180 */
23181
23182var Y_Node = Y.Node;
23183
23184Y.mix(Y_Node.prototype, {
23185    /**
23186     * Makes the node visible.
23187     * If the "transition" module is loaded, show optionally
23188     * animates the showing of the node using either the default
23189     * transition effect ('fadeIn'), or the given named effect.
23190     * @method show
23191     * @for Node
23192     * @param {String} name A named Transition effect to use as the show effect.
23193     * @param {Object} config Options to use with the transition.
23194     * @param {Function} callback An optional function to run after the transition completes.
23195     * @chainable
23196     */
23197    show: function(callback) {
23198        callback = arguments[arguments.length - 1];
23199        this.toggleView(true, callback);
23200        return this;
23201    },
23202
23203    /**
23204     * The implementation for showing nodes.
23205     * Default is to remove the hidden attribute and reset the CSS style.display property.
23206     * @method _show
23207     * @protected
23208     * @chainable
23209     */
23210    _show: function() {
23211        this.removeAttribute('hidden');
23212
23213        // For back-compat we need to leave this in for browsers that
23214        // do not visually hide a node via the hidden attribute
23215        // and for users that check visibility based on style display.
23216        this.setStyle('display', '');
23217
23218    },
23219
23220    /**
23221    Returns whether the node is hidden by YUI or not. The hidden status is
23222    determined by the 'hidden' attribute and the value of the 'display' CSS
23223    property.
23224
23225    @method _isHidden
23226    @return {Boolean} `true` if the node is hidden.
23227    @private
23228    **/
23229    _isHidden: function() {
23230        return  this.hasAttribute('hidden') || Y.DOM.getComputedStyle(this._node, 'display') === 'none';
23231    },
23232
23233    /**
23234     * Displays or hides the node.
23235     * If the "transition" module is loaded, toggleView optionally
23236     * animates the toggling of the node using given named effect.
23237     * @method toggleView
23238     * @for Node
23239     * @param {Boolean} [on] An optional boolean value to force the node to be shown or hidden
23240     * @param {Function} [callback] An optional function to run after the transition completes.
23241     * @chainable
23242     */
23243    toggleView: function(on, callback) {
23244        this._toggleView.apply(this, arguments);
23245        return this;
23246    },
23247
23248    _toggleView: function(on, callback) {
23249        callback = arguments[arguments.length - 1];
23250
23251        // base on current state if not forcing
23252        if (typeof on != 'boolean') {
23253            on = (this._isHidden()) ? 1 : 0;
23254        }
23255
23256        if (on) {
23257            this._show();
23258        }  else {
23259            this._hide();
23260        }
23261
23262        if (typeof callback == 'function') {
23263            callback.call(this);
23264        }
23265
23266        return this;
23267    },
23268
23269    /**
23270     * Hides the node.
23271     * If the "transition" module is loaded, hide optionally
23272     * animates the hiding of the node using either the default
23273     * transition effect ('fadeOut'), or the given named effect.
23274     * @method hide
23275     * @param {String} name A named Transition effect to use as the show effect.
23276     * @param {Object} config Options to use with the transition.
23277     * @param {Function} callback An optional function to run after the transition completes.
23278     * @chainable
23279     */
23280    hide: function(callback) {
23281        callback = arguments[arguments.length - 1];
23282        this.toggleView(false, callback);
23283        return this;
23284    },
23285
23286    /**
23287     * The implementation for hiding nodes.
23288     * Default is to set the hidden attribute to true and set the CSS style.display to 'none'.
23289     * @method _hide
23290     * @protected
23291     * @chainable
23292     */
23293    _hide: function() {
23294        this.setAttribute('hidden', 'hidden');
23295
23296        // For back-compat we need to leave this in for browsers that
23297        // do not visually hide a node via the hidden attribute
23298        // and for users that check visibility based on style display.
23299        this.setStyle('display', 'none');
23300    }
23301});
23302
23303Y.NodeList.importMethod(Y.Node.prototype, [
23304    /**
23305     * Makes each node visible.
23306     * If the "transition" module is loaded, show optionally
23307     * animates the showing of the node using either the default
23308     * transition effect ('fadeIn'), or the given named effect.
23309     * @method show
23310     * @param {String} name A named Transition effect to use as the show effect.
23311     * @param {Object} config Options to use with the transition.
23312     * @param {Function} callback An optional function to run after the transition completes.
23313     * @for NodeList
23314     * @chainable
23315     */
23316    'show',
23317
23318    /**
23319     * Hides each node.
23320     * If the "transition" module is loaded, hide optionally
23321     * animates the hiding of the node using either the default
23322     * transition effect ('fadeOut'), or the given named effect.
23323     * @method hide
23324     * @param {String} name A named Transition effect to use as the show effect.
23325     * @param {Object} config Options to use with the transition.
23326     * @param {Function} callback An optional function to run after the transition completes.
23327     * @chainable
23328     */
23329    'hide',
23330
23331    /**
23332     * Displays or hides each node.
23333     * If the "transition" module is loaded, toggleView optionally
23334     * animates the toggling of the nodes using given named effect.
23335     * @method toggleView
23336     * @param {Boolean} [on] An optional boolean value to force the nodes to be shown or hidden
23337     * @param {Function} [callback] An optional function to run after the transition completes.
23338     * @chainable
23339     */
23340    'toggleView'
23341]);
23342
23343
23344}, '3.18.1', {"requires": ["dom-style", "node-base"]});
23345YUI.add('querystring-stringify-simple', function (Y, NAME) {
23346
23347/*global Y */
23348/**
23349 * <p>Provides Y.QueryString.stringify method for converting objects to Query Strings.
23350 * This is a subset implementation of the full querystring-stringify.</p>
23351 * <p>This module provides the bare minimum functionality (encoding a hash of simple values),
23352 * without the additional support for nested data structures.  Every key-value pair is
23353 * encoded by encodeURIComponent.</p>
23354 * <p>This module provides a minimalistic way for io to handle  single-level objects
23355 * as transaction data.</p>
23356 *
23357 * @module querystring
23358 * @submodule querystring-stringify-simple
23359 */
23360
23361var QueryString = Y.namespace("QueryString"),
23362    EUC = encodeURIComponent;
23363
23364
23365QueryString.stringify = function (obj, c) {
23366    var qs = [],
23367        // Default behavior is false; standard key notation.
23368        s = c && c.arrayKey ? true : false,
23369        key, i, l;
23370
23371    for (key in obj) {
23372        if (obj.hasOwnProperty(key)) {
23373            if (Y.Lang.isArray(obj[key])) {
23374                for (i = 0, l = obj[key].length; i < l; i++) {
23375                    qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i]));
23376                }
23377            }
23378            else {
23379                qs.push(EUC(key) + '=' + EUC(obj[key]));
23380            }
23381        }
23382    }
23383
23384    return qs.join('&');
23385};
23386
23387
23388}, '3.18.1', {"requires": ["yui-base"]});
23389YUI.add('io-base', function (Y, NAME) {
23390
23391/**
23392Base IO functionality. Provides basic XHR transport support.
23393
23394@module io
23395@submodule io-base
23396@for IO
23397**/
23398
23399var // List of events that comprise the IO event lifecycle.
23400    EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'],
23401
23402    // Whitelist of used XHR response object properties.
23403    XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'],
23404
23405    win = Y.config.win,
23406    uid = 0;
23407
23408/**
23409The IO class is a utility that brokers HTTP requests through a simplified
23410interface.  Specifically, it allows JavaScript to make HTTP requests to
23411a resource without a page reload.  The underlying transport for making
23412same-domain requests is the XMLHttpRequest object.  IO can also use
23413Flash, if specified as a transport, for cross-domain requests.
23414
23415@class IO
23416@constructor
23417@param {Object} config Object of EventTarget's publish method configurations
23418                    used to configure IO's events.
23419
23420IO can be called statically using {{#crossLink "YUI/io:method"}}YUI.io{{/crossLink}}.
23421**/
23422function IO (config) {
23423    var io = this;
23424
23425    io._uid = 'io:' + uid++;
23426    io._init(config);
23427    Y.io._map[io._uid] = io;
23428}
23429
23430IO.prototype = {
23431    //--------------------------------------
23432    //  Properties
23433    //--------------------------------------
23434
23435   /**
23436    * A counter that increments for each transaction.
23437    *
23438    * @property _id
23439    * @private
23440    * @type {Number}
23441    */
23442    _id: 0,
23443
23444   /**
23445    * Object of IO HTTP headers sent with each transaction.
23446    *
23447    * @property _headers
23448    * @private
23449    * @type {Object}
23450    */
23451    _headers: {
23452        'X-Requested-With' : 'XMLHttpRequest'
23453    },
23454
23455   /**
23456    * Object that stores timeout values for any transaction with a defined
23457    * "timeout" configuration property.
23458    *
23459    * @property _timeout
23460    * @private
23461    * @type {Object}
23462    */
23463    _timeout: {},
23464
23465    //--------------------------------------
23466    //  Methods
23467    //--------------------------------------
23468
23469    _init: function(config) {
23470        var io = this, i, len;
23471
23472        io.cfg = config || {};
23473
23474        Y.augment(io, Y.EventTarget);
23475        for (i = 0, len = EVENTS.length; i < len; ++i) {
23476            // Publish IO global events with configurations, if any.
23477            // IO global events are set to broadcast by default.
23478            // These events use the "io:" namespace.
23479            io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config));
23480            // Publish IO transaction events with configurations, if
23481            // any.  These events use the "io-trn:" namespace.
23482            io.publish('io-trn:' + EVENTS[i], config);
23483        }
23484    },
23485
23486   /**
23487    * Method that creates a unique transaction object for each request.
23488    *
23489    * @method _create
23490    * @private
23491    * @param {Object} cfg Configuration object subset to determine if
23492    *                 the transaction is an XDR or file upload,
23493    *                 requiring an alternate transport.
23494    * @param {Number} id Transaction id
23495    * @return {Object} The transaction object
23496    */
23497    _create: function(config, id) {
23498        var io = this,
23499            transaction = {
23500                id : Y.Lang.isNumber(id) ? id : io._id++,
23501                uid: io._uid
23502            },
23503            alt = config.xdr ? config.xdr.use : null,
23504            form = config.form && config.form.upload ? 'iframe' : null,
23505            use;
23506
23507        if (alt === 'native') {
23508            // Non-IE and IE >= 10  can use XHR level 2 and not rely on an
23509            // external transport.
23510            alt = Y.UA.ie && !SUPPORTS_CORS ? 'xdr' : null;
23511
23512            // Prevent "pre-flight" OPTIONS request by removing the
23513            // `X-Requested-With` HTTP header from CORS requests. This header
23514            // can be added back on a per-request basis, if desired.
23515            io.setHeader('X-Requested-With');
23516        }
23517
23518        use = alt || form;
23519        transaction = use ? Y.merge(Y.IO.customTransport(use), transaction) :
23520                            Y.merge(Y.IO.defaultTransport(), transaction);
23521
23522        if (transaction.notify) {
23523            config.notify = function (e, t, c) { io.notify(e, t, c); };
23524        }
23525
23526        if (!use) {
23527            if (win && win.FormData && config.data instanceof win.FormData) {
23528                transaction.c.upload.onprogress = function (e) {
23529                    io.progress(transaction, e, config);
23530                };
23531                transaction.c.onload = function (e) {
23532                    io.load(transaction, e, config);
23533                };
23534                transaction.c.onerror = function (e) {
23535                    io.error(transaction, e, config);
23536                };
23537                transaction.upload = true;
23538            }
23539        }
23540
23541        return transaction;
23542    },
23543
23544    _destroy: function(transaction) {
23545        if (win && !transaction.notify && !transaction.xdr) {
23546            if (XHR && !transaction.upload) {
23547                transaction.c.onreadystatechange = null;
23548            } else if (transaction.upload) {
23549                transaction.c.upload.onprogress = null;
23550                transaction.c.onload = null;
23551                transaction.c.onerror = null;
23552            } else if (Y.UA.ie && !transaction.e) {
23553                // IE, when using XMLHttpRequest as an ActiveX Object, will throw
23554                // a "Type Mismatch" error if the event handler is set to "null".
23555                transaction.c.abort();
23556            }
23557        }
23558
23559        transaction = transaction.c = null;
23560    },
23561
23562   /**
23563    * Method for creating and firing events.
23564    *
23565    * @method _evt
23566    * @private
23567    * @param {String} eventName Event to be published.
23568    * @param {Object} transaction Transaction object.
23569    * @param {Object} config Configuration data subset for event subscription.
23570    */
23571    _evt: function(eventName, transaction, config) {
23572        var io          = this, params,
23573            args        = config['arguments'],
23574            emitFacade  = io.cfg.emitFacade,
23575            globalEvent = "io:" + eventName,
23576            trnEvent    = "io-trn:" + eventName;
23577
23578        // Workaround for #2532107
23579        this.detach(trnEvent);
23580
23581        if (transaction.e) {
23582            transaction.c = { status: 0, statusText: transaction.e };
23583        }
23584
23585        // Fire event with parameters or an Event Facade.
23586        params = [ emitFacade ?
23587            {
23588                id: transaction.id,
23589                data: transaction.c,
23590                cfg: config,
23591                'arguments': args
23592            } :
23593            transaction.id
23594        ];
23595
23596        if (!emitFacade) {
23597            if (eventName === EVENTS[0] || eventName === EVENTS[2]) {
23598                if (args) {
23599                    params.push(args);
23600                }
23601            } else {
23602                if (transaction.evt) {
23603                    params.push(transaction.evt);
23604                } else {
23605                    params.push(transaction.c);
23606                }
23607                if (args) {
23608                    params.push(args);
23609                }
23610            }
23611        }
23612
23613        params.unshift(globalEvent);
23614        // Fire global events.
23615        io.fire.apply(io, params);
23616        // Fire transaction events, if receivers are defined.
23617        if (config.on) {
23618            params[0] = trnEvent;
23619            io.once(trnEvent, config.on[eventName], config.context || Y);
23620            io.fire.apply(io, params);
23621        }
23622    },
23623
23624   /**
23625    * Fires event "io:start" and creates, fires a transaction-specific
23626    * start event, if `config.on.start` is defined.
23627    *
23628    * @method start
23629    * @param {Object} transaction Transaction object.
23630    * @param {Object} config Configuration object for the transaction.
23631    */
23632    start: function(transaction, config) {
23633       /**
23634        * Signals the start of an IO request.
23635        * @event io:start
23636        */
23637        this._evt(EVENTS[0], transaction, config);
23638    },
23639
23640   /**
23641    * Fires event "io:complete" and creates, fires a
23642    * transaction-specific "complete" event, if config.on.complete is
23643    * defined.
23644    *
23645    * @method complete
23646    * @param {Object} transaction Transaction object.
23647    * @param {Object} config Configuration object for the transaction.
23648    */
23649    complete: function(transaction, config) {
23650       /**
23651        * Signals the completion of the request-response phase of a
23652        * transaction. Response status and data are accessible, if
23653        * available, in this event.
23654        * @event io:complete
23655        */
23656        this._evt(EVENTS[1], transaction, config);
23657    },
23658
23659   /**
23660    * Fires event "io:end" and creates, fires a transaction-specific "end"
23661    * event, if config.on.end is defined.
23662    *
23663    * @method end
23664    * @param {Object} transaction Transaction object.
23665    * @param {Object} config Configuration object for the transaction.
23666    */
23667    end: function(transaction, config) {
23668       /**
23669        * Signals the end of the transaction lifecycle.
23670        * @event io:end
23671        */
23672        this._evt(EVENTS[2], transaction, config);
23673        this._destroy(transaction);
23674    },
23675
23676   /**
23677    * Fires event "io:success" and creates, fires a transaction-specific
23678    * "success" event, if config.on.success is defined.
23679    *
23680    * @method success
23681    * @param {Object} transaction Transaction object.
23682    * @param {Object} config Configuration object for the transaction.
23683    */
23684    success: function(transaction, config) {
23685       /**
23686        * Signals an HTTP response with status in the 2xx range.
23687        * Fires after io:complete.
23688        * @event io:success
23689        */
23690        this._evt(EVENTS[3], transaction, config);
23691        this.end(transaction, config);
23692    },
23693
23694   /**
23695    * Fires event "io:failure" and creates, fires a transaction-specific
23696    * "failure" event, if config.on.failure is defined.
23697    *
23698    * @method failure
23699    * @param {Object} transaction Transaction object.
23700    * @param {Object} config Configuration object for the transaction.
23701    */
23702    failure: function(transaction, config) {
23703       /**
23704        * Signals an HTTP response with status outside of the 2xx range.
23705        * Fires after io:complete.
23706        * @event io:failure
23707        */
23708        this._evt(EVENTS[4], transaction, config);
23709        this.end(transaction, config);
23710    },
23711
23712   /**
23713    * Fires event "io:progress" and creates, fires a transaction-specific
23714    * "progress" event -- for XMLHttpRequest file upload -- if
23715    * config.on.progress is defined.
23716    *
23717    * @method progress
23718    * @param {Object} transaction Transaction object.
23719    * @param {Object} progress event.
23720    * @param {Object} config Configuration object for the transaction.
23721    */
23722    progress: function(transaction, e, config) {
23723       /**
23724        * Signals the interactive state during a file upload transaction.
23725        * This event fires after io:start and before io:complete.
23726        * @event io:progress
23727        */
23728        transaction.evt = e;
23729        this._evt(EVENTS[5], transaction, config);
23730    },
23731
23732   /**
23733    * Fires event "io:complete" and creates, fires a transaction-specific
23734    * "complete" event -- for XMLHttpRequest file upload -- if
23735    * config.on.complete is defined.
23736    *
23737    * @method load
23738    * @param {Object} transaction Transaction object.
23739    * @param {Object} load event.
23740    * @param {Object} config Configuration object for the transaction.
23741    */
23742    load: function (transaction, e, config) {
23743        transaction.evt = e.target;
23744        this._evt(EVENTS[1], transaction, config);
23745    },
23746
23747   /**
23748    * Fires event "io:failure" and creates, fires a transaction-specific
23749    * "failure" event -- for XMLHttpRequest file upload -- if
23750    * config.on.failure is defined.
23751    *
23752    * @method error
23753    * @param {Object} transaction Transaction object.
23754    * @param {Object} error event.
23755    * @param {Object} config Configuration object for the transaction.
23756    */
23757    error: function (transaction, e, config) {
23758        transaction.evt = e;
23759        this._evt(EVENTS[4], transaction, config);
23760    },
23761
23762   /**
23763    * Retry an XDR transaction, using the Flash tranport, if the native
23764    * transport fails.
23765    *
23766    * @method _retry
23767    * @private
23768    * @param {Object} transaction Transaction object.
23769    * @param {String} uri Qualified path to transaction resource.
23770    * @param {Object} config Configuration object for the transaction.
23771    */
23772    _retry: function(transaction, uri, config) {
23773        this._destroy(transaction);
23774        config.xdr.use = 'flash';
23775        return this.send(uri, config, transaction.id);
23776    },
23777
23778   /**
23779    * Method that concatenates string data for HTTP GET transactions.
23780    *
23781    * @method _concat
23782    * @private
23783    * @param {String} uri URI or root data.
23784    * @param {String} data Data to be concatenated onto URI.
23785    * @return {String}
23786    */
23787    _concat: function(uri, data) {
23788        uri += (uri.indexOf('?') === -1 ? '?' : '&') + data;
23789        return uri;
23790    },
23791
23792   /**
23793    * Stores default client headers for all transactions. If a label is
23794    * passed with no value argument, the header will be deleted.
23795    *
23796    * @method setHeader
23797    * @param {String} name HTTP header
23798    * @param {String} value HTTP header value
23799    */
23800    setHeader: function(name, value) {
23801        if (value) {
23802            this._headers[name] = value;
23803        } else {
23804            delete this._headers[name];
23805        }
23806    },
23807
23808   /**
23809    * Method that sets all HTTP headers to be sent in a transaction.
23810    *
23811    * @method _setHeaders
23812    * @private
23813    * @param {Object} transaction - XHR instance for the specific transaction.
23814    * @param {Object} headers - HTTP headers for the specific transaction, as
23815    *                    defined in the configuration object passed to YUI.io().
23816    */
23817    _setHeaders: function(transaction, headers) {
23818        headers = Y.merge(this._headers, headers);
23819        Y.Object.each(headers, function(value, name) {
23820            if (value !== 'disable') {
23821                transaction.setRequestHeader(name, headers[name]);
23822            }
23823        });
23824    },
23825
23826   /**
23827    * Starts timeout count if the configuration object has a defined
23828    * timeout property.
23829    *
23830    * @method _startTimeout
23831    * @private
23832    * @param {Object} transaction Transaction object generated by _create().
23833    * @param {Object} timeout Timeout in milliseconds.
23834    */
23835    _startTimeout: function(transaction, timeout) {
23836        var io = this;
23837
23838        io._timeout[transaction.id] = setTimeout(function() {
23839            io._abort(transaction, 'timeout');
23840        }, timeout);
23841    },
23842
23843   /**
23844    * Clears the timeout interval started by _startTimeout().
23845    *
23846    * @method _clearTimeout
23847    * @private
23848    * @param {Number} id - Transaction id.
23849    */
23850    _clearTimeout: function(id) {
23851        clearTimeout(this._timeout[id]);
23852        delete this._timeout[id];
23853    },
23854
23855   /**
23856    * Method that determines if a transaction response qualifies as success
23857    * or failure, based on the response HTTP status code, and fires the
23858    * appropriate success or failure events.
23859    *
23860    * @method _result
23861    * @private
23862    * @static
23863    * @param {Object} transaction Transaction object generated by _create().
23864    * @param {Object} config Configuration object passed to io().
23865    */
23866    _result: function(transaction, config) {
23867        var status;
23868        // Firefox will throw an exception if attempting to access
23869        // an XHR object's status property, after a request is aborted.
23870        try {
23871            status = transaction.c.status;
23872        } catch(e) {
23873            status = 0;
23874        }
23875
23876        // IE reports HTTP 204 as HTTP 1223.
23877        if (status >= 200 && status < 300 || status === 304 || status === 1223) {
23878            this.success(transaction, config);
23879        } else {
23880            this.failure(transaction, config);
23881        }
23882    },
23883
23884   /**
23885    * Event handler bound to onreadystatechange.
23886    *
23887    * @method _rS
23888    * @private
23889    * @param {Object} transaction Transaction object generated by _create().
23890    * @param {Object} config Configuration object passed to YUI.io().
23891    */
23892    _rS: function(transaction, config) {
23893        var io = this;
23894
23895        if (transaction.c.readyState === 4) {
23896            if (config.timeout) {
23897                io._clearTimeout(transaction.id);
23898            }
23899
23900            // Yield in the event of request timeout or abort.
23901            setTimeout(function() {
23902                io.complete(transaction, config);
23903                io._result(transaction, config);
23904            }, 0);
23905        }
23906    },
23907
23908   /**
23909    * Terminates a transaction due to an explicit abort or timeout.
23910    *
23911    * @method _abort
23912    * @private
23913    * @param {Object} transaction Transaction object generated by _create().
23914    * @param {String} type Identifies timed out or aborted transaction.
23915    */
23916    _abort: function(transaction, type) {
23917        if (transaction && transaction.c) {
23918            transaction.e = type;
23919            transaction.c.abort();
23920        }
23921    },
23922
23923   /**
23924    * Requests a transaction. `send()` is implemented as `Y.io()`.  Each
23925    * transaction may include a configuration object.  Its properties are:
23926    *
23927    * <dl>
23928    *   <dt>method</dt>
23929    *     <dd>HTTP method verb (e.g., GET or POST). If this property is not
23930    *         not defined, the default value will be GET.</dd>
23931    *
23932    *   <dt>data</dt>
23933    *     <dd>This is the name-value string that will be sent as the
23934    *     transaction data. If the request is HTTP GET, the data become
23935    *     part of querystring. If HTTP POST, the data are sent in the
23936    *     message body.</dd>
23937    *
23938    *   <dt>xdr</dt>
23939    *     <dd>Defines the transport to be used for cross-domain requests.
23940    *     By setting this property, the transaction will use the specified
23941    *     transport instead of XMLHttpRequest. The properties of the
23942    *     transport object are:
23943    *     <dl>
23944    *       <dt>use</dt>
23945    *         <dd>The transport to be used: 'flash' or 'native'</dd>
23946    *       <dt>dataType</dt>
23947    *         <dd>Set the value to 'XML' if that is the expected response
23948    *         content type.</dd>
23949    *       <dt>credentials</dt>
23950    *         <dd>Set the value to 'true' to set XHR.withCredentials property to true.</dd>
23951    *     </dl></dd>
23952    *
23953    *   <dt>form</dt>
23954    *     <dd>Form serialization configuration object.  Its properties are:
23955    *     <dl>
23956    *       <dt>id</dt>
23957    *         <dd>Node object or id of HTML form</dd>
23958    *       <dt>useDisabled</dt>
23959    *         <dd>`true` to also serialize disabled form field values
23960    *         (defaults to `false`)</dd>
23961    *     </dl></dd>
23962    *
23963    *   <dt>on</dt>
23964    *     <dd>Assigns transaction event subscriptions. Available events are:
23965    *     <dl>
23966    *       <dt>start</dt>
23967    *         <dd>Fires when a request is sent to a resource.</dd>
23968    *       <dt>complete</dt>
23969    *         <dd>Fires when the transaction is complete.</dd>
23970    *       <dt>success</dt>
23971    *         <dd>Fires when the HTTP response status is within the 2xx
23972    *         range.</dd>
23973    *       <dt>failure</dt>
23974    *         <dd>Fires when the HTTP response status is outside the 2xx
23975    *         range, if an exception occurs, if the transation is aborted,
23976    *         or if the transaction exceeds a configured `timeout`.</dd>
23977    *       <dt>end</dt>
23978    *         <dd>Fires at the conclusion of the transaction
23979    *            lifecycle, after `success` or `failure`.</dd>
23980    *     </dl>
23981    *
23982    *     <p>Callback functions for `start` and `end` receive the id of the
23983    *     transaction as a first argument. For `complete`, `success`, and
23984    *     `failure`, callbacks receive the id and the response object
23985    *     (usually the XMLHttpRequest instance).  If the `arguments`
23986    *     property was included in the configuration object passed to
23987    *     `Y.io()`, the configured data will be passed to all callbacks as
23988    *     the last argument.</p>
23989    *     </dd>
23990    *
23991    *   <dt>sync</dt>
23992    *     <dd>Pass `true` to make a same-domain transaction synchronous.
23993    *     <strong>CAVEAT</strong>: This will negatively impact the user
23994    *     experience. Have a <em>very</em> good reason if you intend to use
23995    *     this.</dd>
23996    *
23997    *   <dt>context</dt>
23998    *     <dd>The "`this'" object for all configured event handlers. If a
23999    *     specific context is needed for individual callbacks, bind the
24000    *     callback to a context using `Y.bind()`.</dd>
24001    *
24002    *   <dt>headers</dt>
24003    *     <dd>Object map of transaction headers to send to the server. The
24004    *     object keys are the header names and the values are the header
24005    *     values.</dd>
24006    *
24007    *   <dt>username</dt>
24008    *     <dd>Username to use in a HTTP authentication.</dd>
24009    *
24010    *   <dt>password</dt>
24011    *     <dd>Password to use in a HTTP authentication.</dd>
24012    *
24013    *   <dt>timeout</dt>
24014    *     <dd>Millisecond threshold for the transaction before being
24015    *     automatically aborted.</dd>
24016    *
24017    *   <dt>arguments</dt>
24018    *     <dd>User-defined data passed to all registered event handlers.
24019    *     This value is available as the second argument in the "start" and
24020    *     "end" event handlers. It is the third argument in the "complete",
24021    *     "success", and "failure" event handlers. <strong>Be sure to quote
24022    *     this property name in the transaction configuration as
24023    *     "arguments" is a reserved word in JavaScript</strong> (e.g.
24024    *     `Y.io({ ..., "arguments": stuff })`).</dd>
24025    * </dl>
24026    *
24027    * @method send
24028    * @public
24029    * @param {String} uri Qualified path to transaction resource.
24030    * @param {Object} config Configuration object for the transaction.
24031    * @param {Number} id Transaction id, if already set.
24032    * @return {Object}
24032 An object containing:
24033    * <dl>
24034    *  <dt>`id`</dt>
24035    *  <dd>
24036    *    The transaction ID for this request.
24037    *  </dd>
24038    *  <dt>`abort`</dt>
24039    *  <dd>
24040    *    A function to abort the current transaction.
24041    *  </dd>
24042    *  <dt>`isInProgress`</dt>
24043    *  <dd>
24044    *    A helper to determine whether the current transaction is in progress.
24045    *  </dd>
24046    *  <dt>`io`</dt>
24047    *  <dd>
24048    *    A reference to the IO object for this transaction.
24049    *  </dd>
24050    * </dl>
24051    */
24052    send: function(uri, config, id) {
24053        var transaction, method, i, len, sync, data,
24054            io = this,
24055            u = uri,
24056            response = {};
24057
24058        config = config ? Y.Object(config) : {};
24059        transaction = io._create(config, id);
24060        method = config.method ? config.method.toUpperCase() : 'GET';
24061        sync = config.sync;
24062        data = config.data;
24063
24064        // Serialize a map object into a key-value string using
24065        // querystring-stringify-simple.
24066        if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) {
24067            if (Y.QueryString && Y.QueryString.stringify) {
24068                config.data = data = Y.QueryString.stringify(data);
24069            } else {
24070            }
24071        }
24072
24073        if (config.form) {
24074            if (config.form.upload) {
24075                // This is a file upload transaction, calling
24076                // upload() in io-upload-iframe.
24077                return io.upload(transaction, uri, config);
24078            } else {
24079                // Serialize HTML form data into a key-value string.
24080                data = io._serialize(config.form, data);
24081            }
24082        }
24083
24084        // Convert falsy values to an empty string. This way IE can't be
24085        // rediculous and translate `undefined` to "undefined".
24086        data || (data = '');
24087
24088        if (data) {
24089            switch (method) {
24090                case 'GET':
24091                case 'HEAD':
24092                case 'DELETE':
24093                    u = io._concat(u, data);
24094                    data = '';
24095                    break;
24096                case 'POST':
24097                case 'PUT':
24098                    // If Content-Type is defined in the configuration object, or
24099                    // or as a default header, it will be used instead of
24100                    // 'application/x-www-form-urlencoded; charset=UTF-8'
24101                    config.headers = Y.merge({
24102                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
24103                    }, config.headers);
24104                    break;
24105            }
24106        }
24107
24108        if (transaction.xdr) {
24109            // Route data to io-xdr module for flash and XDomainRequest.
24110            return io.xdr(u, transaction, config);
24111        }
24112        else if (transaction.notify) {
24113            // Route data to custom transport
24114            return transaction.c.send(transaction, uri, config);
24115        }
24116
24117        if (!sync && !transaction.upload) {
24118            transaction.c.onreadystatechange = function() {
24119                io._rS(transaction, config);
24120            };
24121        }
24122
24123        try {
24124            // Determine if request is to be set as
24125            // synchronous or asynchronous.
24126            transaction.c.open(method, u, !sync, config.username || null, config.password || null);
24127            io._setHeaders(transaction.c, config.headers || {});
24128            io.start(transaction, config);
24129
24130            // Will work only in browsers that implement the
24131            // Cross-Origin Resource Sharing draft.
24132            if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) {
24133                transaction.c.withCredentials = true;
24134            }
24135
24136            // Using "null" with HTTP POST will result in a request
24137            // with no Content-Length header defined.
24138            transaction.c.send(data);
24139
24140            if (sync) {
24141                // Create a response object for synchronous transactions,
24142                // mixing id and arguments properties with the xhr
24143                // properties whitelist.
24144                for (i = 0, len = XHR_PROPS.length; i < len; ++i) {
24145                    response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]];
24146                }
24147
24148                response.getAllResponseHeaders = function() {
24149                    return transaction.c.getAllResponseHeaders();
24150                };
24151
24152                response.getResponseHeader = function(name) {
24153                    return transaction.c.getResponseHeader(name);
24154                };
24155
24156                io.complete(transaction, config);
24157                io._result(transaction, config);
24158
24159                return response;
24160            }
24161        } catch(e) {
24162            if (transaction.xdr) {
24163                // This exception is usually thrown by browsers
24164                // that do not support XMLHttpRequest Level 2.
24165                // Retry the request with the XDR transport set
24166                // to 'flash'.  If the Flash transport is not
24167                // initialized or available, the transaction
24168                // will resolve to a transport error.
24169                return io._retry(transaction, uri, config);
24170            } else {
24171                io.complete(transaction, config);
24172                io._result(transaction, config);
24173            }
24174        }
24175
24176        // If config.timeout is defined, and the request is standard XHR,
24177        // initialize timeout polling.
24178        if (config.timeout) {
24179            io._startTimeout(transaction, config.timeout);
24180        }
24181
24182        return {
24183            id: transaction.id,
24184            abort: function() {
24185                return transaction.c ? io._abort(transaction, 'abort') : false;
24186            },
24187            isInProgress: function() {
24188                return transaction.c ? (transaction.c.readyState % 4) : false;
24189            },
24190            io: io
24191        };
24192    }
24193};
24194
24195/**
24196Method for initiating an ajax call.  The first argument is the url end
24197point for the call.  The second argument is an object to configure the
24198transaction and attach event subscriptions.  The configuration object
24199supports the following properties:
24200
24201<dl>
24202  <dt>method</dt>
24203    <dd>HTTP method verb (e.g., GET or POST). If this property is not
24204        not defined, the default value will be GET.</dd>
24205
24206  <dt>data</dt>
24207    <dd>This is the name-value string that will be sent as the
24208    transaction data. If the request is HTTP GET, the data become
24209    part of querystring. If HTTP POST, the data are sent in the
24210    message body.</dd>
24211
24212  <dt>xdr</dt>
24213    <dd>Defines the transport to be used for cross-domain requests.
24214    By setting this property, the transaction will use the specified
24215    transport instead of XMLHttpRequest. The properties of the
24216    transport object are:
24217    <dl>
24218      <dt>use</dt>
24219        <dd>The transport to be used: 'flash' or 'native'</dd>
24220      <dt>dataType</dt>
24221        <dd>Set the value to 'XML' if that is the expected response
24222        content type.</dd>
24223    </dl></dd>
24224
24225  <dt>form</dt>
24226    <dd>Form serialization configuration object.  Its properties are:
24227    <dl>
24228      <dt>id</dt>
24229        <dd>Node object or id of HTML form</dd>
24230      <dt>useDisabled</dt>
24231        <dd>`true` to also serialize disabled form field values
24232        (defaults to `false`)</dd>
24233    </dl></dd>
24234
24235  <dt>on</dt>
24236    <dd>Assigns transaction event subscriptions. Available events are:
24237    <dl>
24238      <dt>start</dt>
24239        <dd>Fires when a request is sent to a resource.</dd>
24240      <dt>complete</dt>
24241        <dd>Fires when the transaction is complete.</dd>
24242      <dt>success</dt>
24243        <dd>Fires when the HTTP response status is within the 2xx
24244        range.</dd>
24245      <dt>failure</dt>
24246        <dd>Fires when the HTTP response status is outside the 2xx
24247        range, if an exception occurs, if the transation is aborted,
24248        or if the transaction exceeds a configured `timeout`.</dd>
24249      <dt>end</dt>
24250        <dd>Fires at the conclusion of the transaction
24251           lifecycle, after `success` or `failure`.</dd>
24252    </dl>
24253
24254    <p>Callback functions for `start` and `end` receive the id of the
24255    transaction as a first argument. For `complete`, `success`, and
24256    `failure`, callbacks receive the id and the response object
24257    (usually the XMLHttpRequest instance).  If the `arguments`
24258    property was included in the configuration object passed to
24259    `Y.io()`, the configured data will be passed to all callbacks as
24260    the last argument.</p>
24261    </dd>
24262
24263  <dt>sync</dt>
24264    <dd>Pass `true` to make a same-domain transaction synchronous.
24265    <strong>CAVEAT</strong>: This will negatively impact the user
24266    experience. Have a <em>very</em> good reason if you intend to use
24267    this.</dd>
24268
24269  <dt>context</dt>
24270    <dd>The "`this'" object for all configured event handlers. If a
24271    specific context is needed for individual callbacks, bind the
24272    callback to a context using `Y.bind()`.</dd>
24273
24274  <dt>headers</dt>
24275    <dd>Object map of transaction headers to send to the server. The
24276    object keys are the header names and the values are the header
24277    values.</dd>
24278
24279  <dt>timeout</dt>
24280    <dd>Millisecond threshold for the transaction before being
24281    automatically aborted.</dd>
24282
24283  <dt>arguments</dt>
24284    <dd>User-defined data passed to all registered event handlers.
24285    This value is available as the second argument in the "start" and
24286    "end" event handlers. It is the third argument in the "complete",
24287    "success", and "failure" event handlers. <strong>Be sure to quote
24288    this property name in the transaction configuration as
24289    "arguments" is a reserved word in JavaScript</strong> (e.g.
24290    `Y.io({ ..., "arguments": stuff })`).</dd>
24291</dl>
24292
24293@method io
24294@static
24295@param {String} url qualified path to transaction resource.
24296@param {Object} config configuration object for the transaction.
24297@return {Object} An object containing:
24298<dl>
24299 <dt>`id`</dt>
24300 <dd>
24301   The transaction ID for this request.
24302 </dd>
24303 <dt>`abort`</dt>
24304 <dd>
24305   A function to abort the current transaction.
24306 </dd>
24307 <dt>`isInProgress`</dt>
24308 <dd>
24309   A helper to determine whether the current transaction is in progress.
24310 </dd>
24311 <dt>`io`</dt>
24312 <dd>
24313   A reference to the IO object for this transaction.
24314 </dd>
24315</dl>
24316
24317@for YUI
24318**/
24319Y.io = function(url, config) {
24320    // Calling IO through the static interface will use and reuse
24321    // an instance of IO.
24322    var transaction = Y.io._map['io:0'] || new IO();
24323    return transaction.send.apply(transaction, [url, config]);
24324};
24325
24326/**
24327Method for setting and deleting IO HTTP headers to be sent with every
24328request.
24329
24330Hosted as a property on the `io` function (e.g. `Y.io.header`).
24331
24332@method header
24333@param {String} name HTTP header
24334@param {String} value HTTP header value
24335@static
24336**/
24337Y.io.header = function(name, value) {
24338    // Calling IO through the static interface will use and reuse
24339    // an instance of IO.
24340    var transaction = Y.io._map['io:0'] || new IO();
24341    transaction.setHeader(name, value);
24342};
24343
24344Y.IO = IO;
24345// Map of all IO instances created.
24346Y.io._map = {};
24347var XHR = win && win.XMLHttpRequest,
24348    XDR = win && win.XDomainRequest,
24349    AX = win && win.ActiveXObject,
24350
24351    // Checks for the presence of the `withCredentials` in an XHR instance
24352    // object, which will be present if the environment supports CORS.
24353    SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest());
24354
24355
24356Y.mix(Y.IO, {
24357    /**
24358    * The ID of the default IO transport, defaults to `xhr`
24359    * @property _default
24360    * @type {String}
24361    * @static
24362    */
24363    _default: 'xhr',
24364    /**
24365    *
24366    * @method defaultTransport
24367    * @static
24368    * @param {String} [id] The transport to set as the default, if empty a new transport is created.
24369    * @return {Object} The transport object with a `send` method
24370    */
24371    defaultTransport: function(id) {
24372        if (id) {
24373            Y.IO._default = id;
24374        } else {
24375            var o = {
24376                c: Y.IO.transports[Y.IO._default](),
24377                notify: Y.IO._default === 'xhr' ? false : true
24378            };
24379            return o;
24380        }
24381    },
24382    /**
24383    * An object hash of custom transports available to IO
24384    * @property transports
24385    * @type {Object}
24386    * @static
24387    */
24388    transports: {
24389        xhr: function () {
24390            return XHR ? new XMLHttpRequest() :
24391                AX ? new ActiveXObject('Microsoft.XMLHTTP') : null;
24392        },
24393        xdr: function () {
24394            return XDR ? new XDomainRequest() : null;
24395        },
24396        iframe: function () { return {}; },
24397        flash: null,
24398        nodejs: null
24399    },
24400    /**
24401    * Create a custom transport of type and return it's object
24402    * @method customTransport
24403    * @param {String} id The id of the transport to create.
24404    * @static
24405    */
24406    customTransport: function(id) {
24407        var o = { c: Y.IO.transports[id]() };
24408
24409        o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true;
24410        return o;
24411    }
24412});
24413
24414Y.mix(Y.IO.prototype, {
24415    /**
24416    * Fired from the notify method of the transport which in turn fires
24417    * the event on the IO object.
24418    * @method notify
24419    * @param {String} event The name of the event
24420    * @param {Object} transaction The transaction object
24421    * @param {Object} config The configuration object for this transaction
24422    */
24423    notify: function(event, transaction, config) {
24424        var io = this;
24425
24426        switch (event) {
24427            case 'timeout':
24428            case 'abort':
24429            case 'transport error':
24430                transaction.c = { status: 0, statusText: event };
24431                event = 'failure';
24432            default:
24433                io[event].apply(io, [transaction, config]);
24434        }
24435    }
24436});
24437
24438
24439
24440
24441}, '3.18.1', {"requires": ["event-custom-base", "querystring-stringify-simple"]});
24442YUI.add('json-parse', function (Y, NAME) {
24443
24444var _JSON = Y.config.global.JSON;
24445
24446Y.namespace('JSON').parse = function (obj, reviver, space) {
24447    return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space);
24448};
24449
24450
24451}, '3.18.1', {"requires": ["yui-base"]});
24452YUI.add('transition', function (Y, NAME) {
24453
24454/**
24455* Provides the transition method for Node.
24456* Transition has no API of its own, but adds the transition method to Node.
24457*
24458* @module transition
24459* @requires node-style
24460*/
24461
24462var CAMEL_VENDOR_PREFIX = '',
24463    VENDOR_PREFIX = '',
24464    DOCUMENT = Y.config.doc,
24465    DOCUMENT_ELEMENT = 'documentElement',
24466    DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style,
24467    TRANSITION_CAMEL = 'transition',
24468    TRANSITION_PROPERTY_CAMEL = 'transitionProperty',
24469    TRANSITION_PROPERTY,
24470    TRANSITION_DURATION,
24471    TRANSITION_TIMING_FUNCTION,
24472    TRANSITION_DELAY,
24473    TRANSITION_END,
24474    ON_TRANSITION_END,
24475
24476    EMPTY_OBJ = {},
24477
24478    VENDORS = [
24479        'Webkit',
24480        'Moz'
24481    ],
24482
24483    VENDOR_TRANSITION_END = {
24484        Webkit: 'webkitTransitionEnd'
24485    },
24486
24487/**
24488 * A class for constructing transition instances.
24489 * Adds the "transition" method to Node.
24490 * @class Transition
24491 * @constructor
24492 */
24493
24494Transition = function() {
24495    this.init.apply(this, arguments);
24496};
24497
24498// One off handling of transform-prefixing.
24499Transition._TRANSFORM = 'transform';
24500
24501Transition._toCamel = function(property) {
24502    property = property.replace(/-([a-z])/gi, function(m0, m1) {
24503        return m1.toUpperCase();
24504    });
24505
24506    return property;
24507};
24508
24509Transition._toHyphen = function(property) {
24510    property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
24511        var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2;
24512
24513        if (m3) {
24514            str += '-' + m3.toLowerCase();
24515        }
24516
24517        return str;
24518    });
24519
24520    return property;
24521};
24522
24523Transition.SHOW_TRANSITION = 'fadeIn';
24524Transition.HIDE_TRANSITION = 'fadeOut';
24525
24526Transition.useNative = false;
24527
24528// Map transition properties to vendor-specific versions.
24529if ('transition' in DOCUMENT_STYLE
24530    && 'transitionProperty' in DOCUMENT_STYLE
24531    && 'transitionDuration' in DOCUMENT_STYLE
24532    && 'transitionTimingFunction' in DOCUMENT_STYLE
24533    && 'transitionDelay' in DOCUMENT_STYLE) {
24534    Transition.useNative = true;
24535    Transition.supported = true; // TODO: remove
24536} else {
24537    Y.Array.each(VENDORS, function(val) { // then vendor specific
24538        var property = val + 'Transition';
24539        if (property in DOCUMENT[DOCUMENT_ELEMENT].style) {
24540            CAMEL_VENDOR_PREFIX = val;
24541            VENDOR_PREFIX       = Transition._toHyphen(val) + '-';
24542
24543            Transition.useNative = true;
24544            Transition.supported = true; // TODO: remove
24545            Transition._VENDOR_PREFIX = val;
24546        }
24547    });
24548}
24549
24550// Map transform property to vendor-specific versions.
24551// One-off required for cssText injection.
24552if (typeof DOCUMENT_STYLE.transform === 'undefined') {
24553    Y.Array.each(VENDORS, function(val) { // then vendor specific
24554        var property = val + 'Transform';
24555        if (typeof DOCUMENT_STYLE[property] !== 'undefined') {
24556            Transition._TRANSFORM = property;
24557        }
24558    });
24559}
24560
24561if (CAMEL_VENDOR_PREFIX) {
24562    TRANSITION_CAMEL          = CAMEL_VENDOR_PREFIX + 'Transition';
24563    TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty';
24564}
24565
24566TRANSITION_PROPERTY        = VENDOR_PREFIX + 'transition-property';
24567TRANSITION_DURATION        = VENDOR_PREFIX + 'transition-duration';
24568TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function';
24569TRANSITION_DELAY           = VENDOR_PREFIX + 'transition-delay';
24570
24571TRANSITION_END    = 'transitionend';
24572ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend';
24573TRANSITION_END    = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END;
24574
24575Transition.fx = {};
24576Transition.toggles = {};
24577
24578Transition._hasEnd = {};
24579
24580Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
24581
24582Y.Node.DOM_EVENTS[TRANSITION_END] = 1;
24583
24584Transition.NAME = 'transition';
24585
24586Transition.DEFAULT_EASING = 'ease';
24587Transition.DEFAULT_DURATION = 0.5;
24588Transition.DEFAULT_DELAY = 0;
24589
24590Transition._nodeAttrs = {};
24591
24592Transition.prototype = {
24593    constructor: Transition,
24594    init: function(node, config) {
24595        var anim = this;
24596        anim._node = node;
24597        if (!anim._running && config) {
24598            anim._config = config;
24599            node._transition = anim; // cache for reuse
24600
24601            anim._duration = ('duration' in config) ?
24602                config.duration: anim.constructor.DEFAULT_DURATION;
24603
24604            anim._delay = ('delay' in config) ?
24605                config.delay: anim.constructor.DEFAULT_DELAY;
24606
24607            anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
24608            anim._count = 0; // track number of animated properties
24609            anim._running = false;
24610
24611        }
24612
24613        return anim;
24614    },
24615
24616    addProperty: function(prop, config) {
24617        var anim = this,
24618            node = this._node,
24619            uid = Y.stamp(node),
24620            nodeInstance = Y.one(node),
24621            attrs = Transition._nodeAttrs[uid],
24622            computed,
24623            compareVal,
24624            dur,
24625            attr,
24626            val;
24627
24628        if (!attrs) {
24629            attrs = Transition._nodeAttrs[uid] = {};
24630        }
24631
24632        attr = attrs[prop];
24633
24634        // might just be a value
24635        if (config && config.value !== undefined) {
24636            val = config.value;
24637        } else if (config !== undefined) {
24638            val = config;
24639            config = EMPTY_OBJ;
24640        }
24641
24642        if (typeof val === 'function') {
24643            val = val.call(nodeInstance, nodeInstance);
24644        }
24645
24646        if (attr && attr.transition) {
24647            // take control if another transition owns this property
24648            if (attr.transition !== anim) {
24649                attr.transition._count--; // remapping attr to this transition
24650            }
24651        }
24652
24653        anim._count++; // properties per transition
24654
24655        // make 0 async and fire events
24656        dur = ((typeof config.duration !== 'undefined') ? config.duration :
24657                    anim._duration) || 0.0001;
24658
24659        attrs[prop] = {
24660            value: val,
24661            duration: dur,
24662            delay: (typeof config.delay !== 'undefined') ? config.delay :
24663                    anim._delay,
24664
24665            easing: config.easing || anim._easing,
24666
24667            transition: anim
24668        };
24669
24670        // native end event doesnt fire when setting to same value
24671        // supplementing with timer
24672        // val may be a string or number (height: 0, etc), but computedStyle is always string
24673        computed = Y.DOM.getComputedStyle(node, prop);
24674        compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
24675
24676        if (Transition.useNative && compareVal === val) {
24677            setTimeout(function() {
24678                anim._onNativeEnd.call(node, {
24679                    propertyName: prop,
24680                    elapsedTime: dur
24681                });
24682            }, dur * 1000);
24683        }
24684    },
24685
24686    removeProperty: function(prop) {
24687        var anim = this,
24688            attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
24689
24690        if (attrs && attrs[prop]) {
24691            delete attrs[prop];
24692            anim._count--;
24693        }
24694
24695    },
24696
24697    initAttrs: function(config) {
24698        var attr,
24699            node = this._node;
24700
24701        if (config.transform && !config[Transition._TRANSFORM]) {
24702            config[Transition._TRANSFORM] = config.transform;
24703            delete config.transform; // TODO: copy
24704        }
24705
24706        for (attr in config) {
24707            if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
24708                this.addProperty(attr, config[attr]);
24709
24710                // when size is auto or % webkit starts from zero instead of computed
24711                // (https://bugs.webkit.org/show_bug.cgi?id=16020)
24712                // TODO: selective set
24713                if (node.style[attr] === '') {
24714                    Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
24715                }
24716            }
24717        }
24718    },
24719
24720    /**
24721     * Starts or an animation.
24722     * @method run
24723     * @chainable
24724     * @private
24725     */
24726    run: function(callback) {
24727        var anim = this,
24728            node = anim._node,
24729            config = anim._config,
24730            data = {
24731                type: 'transition:start',
24732                config: config
24733            };
24734
24735
24736        if (!anim._running) {
24737            anim._running = true;
24738
24739            if (config.on && config.on.start) {
24740                config.on.start.call(Y.one(node), data);
24741            }
24742
24743            anim.initAttrs(anim._config);
24744
24745            anim._callback = callback;
24746            anim._start();
24747        }
24748
24749
24750        return anim;
24751    },
24752
24753    _start: function() {
24754        this._runNative();
24755    },
24756
24757    _prepDur: function(dur) {
24758        dur = parseFloat(dur) * 1000;
24759
24760        return dur + 'ms';
24761    },
24762
24763    _runNative: function() {
24764        var anim = this,
24765            node = anim._node,
24766            uid = Y.stamp(node),
24767            style = node.style,
24768            computed = node.ownerDocument.defaultView.getComputedStyle(node),
24769            attrs = Transition._nodeAttrs[uid],
24770            cssText = '',
24771            cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)],
24772
24773            transitionText = TRANSITION_PROPERTY + ': ',
24774            duration = TRANSITION_DURATION + ': ',
24775            easing = TRANSITION_TIMING_FUNCTION + ': ',
24776            delay = TRANSITION_DELAY + ': ',
24777            hyphy,
24778            attr,
24779            name;
24780
24781        // preserve existing transitions
24782        if (cssTransition !== 'all') {
24783            transitionText += cssTransition + ',';
24784            duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ',';
24785            easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ',';
24786            delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ',';
24787
24788        }
24789
24790        // run transitions mapped to this instance
24791        for (name in attrs) {
24792            hyphy = Transition._toHyphen(name);
24793            attr = attrs[name];
24794            if ((attr = attrs[name]) && attr.transition === anim) {
24795                if (name in node.style) { // only native styles allowed
24796                    duration += anim._prepDur(attr.duration) + ',';
24797                    delay += anim._prepDur(attr.delay) + ',';
24798                    easing += (attr.easing) + ',';
24799
24800                    transitionText += hyphy + ',';
24801                    cssText += hyphy + ': ' + attr.value + '; ';
24802                } else {
24803                    this.removeProperty(name);
24804                }
24805            }
24806        }
24807
24808        transitionText = transitionText.replace(/,$/, ';');
24809        duration = duration.replace(/,$/, ';');
24810        easing = easing.replace(/,$/, ';');
24811        delay = delay.replace(/,$/, ';');
24812
24813        // only one native end event per node
24814        if (!Transition._hasEnd[uid]) {
24815            node.addEventListener(TRANSITION_END, anim._onNativeEnd, '');
24816            Transition._hasEnd[uid] = true;
24817
24818        }
24819
24820        style.cssText += transitionText + duration + easing + delay + cssText;
24821
24822    },
24823
24824    _end: function(elapsed) {
24825        var anim = this,
24826            node = anim._node,
24827            callback = anim._callback,
24828            config = anim._config,
24829            data = {
24830                type: 'transition:end',
24831                config: config,
24832                elapsedTime: elapsed
24833            },
24834
24835            nodeInstance = Y.one(node);
24836
24837        anim._running = false;
24838        anim._callback = null;
24839
24840        if (node) {
24841            if (config.on && config.on.end) {
24842                setTimeout(function() { // IE: allow previous update to finish
24843                    config.on.end.call(nodeInstance, data);
24844
24845                    // nested to ensure proper fire order
24846                    if (callback) {
24847                        callback.call(nodeInstance, data);
24848                    }
24849
24850                }, 1);
24851            } else if (callback) {
24852                setTimeout(function() { // IE: allow previous update to finish
24853                    callback.call(nodeInstance, data);
24854                }, 1);
24855            }
24856        }
24857
24858    },
24859
24860    _endNative: function(name) {
24861        var node = this._node,
24862            value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)];
24863
24864        name = Transition._toHyphen(name);
24865        if (typeof value === 'string') {
24866            value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
24867            value = value.replace(/^,|,$/, '');
24868            node.style[TRANSITION_CAMEL] = value;
24869        }
24870    },
24871
24872    _onNativeEnd: function(e) {
24873        var node = this,
24874            uid = Y.stamp(node),
24875            event = e,//e._event,
24876            name = Transition._toCamel(event.propertyName),
24877            elapsed = event.elapsedTime,
24878            attrs = Transition._nodeAttrs[uid],
24879            attr = attrs[name],
24880            anim = (attr) ? attr.transition : null,
24881            data,
24882            config;
24883
24884        if (anim) {
24885            anim.removeProperty(name);
24886            anim._endNative(name);
24887            config = anim._config[name];
24888
24889            data = {
24890                type: 'propertyEnd',
24891                propertyName: name,
24892                elapsedTime: elapsed,
24893                config: config
24894            };
24895
24896            if (config && config.on && config.on.end) {
24897                config.on.end.call(Y.one(node), data);
24898            }
24899
24900            if (anim._count <= 0)  { // after propertyEnd fires
24901                anim._end(elapsed);
24902                node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style
24903            }
24904        }
24905    },
24906
24907    destroy: function() {
24908        var anim = this,
24909            node = anim._node;
24910
24911        if (node) {
24912            node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
24913            anim._node = null;
24914        }
24915    }
24916};
24917
24918Y.Transition = Transition;
24919Y.TransitionNative = Transition; // TODO: remove
24920
24921/**
24922 *   Animate one or more css properties to a given value. Requires the "transition" module.
24923 *   <pre>example usage:
24924 *       Y.one('#demo').transition({
24925 *           duration: 1, // in seconds, default is 0.5
24926 *           easing: 'ease-out', // default is 'ease'
24927 *           delay: '1', // delay start for 1 second, default is 0
24928 *
24929 *           height: '10px',
24930 *           width: '10px',
24931 *
24932 *           opacity: { // per property
24933 *               value: 0,
24934 *               duration: 2,
24935 *               delay: 2,
24936 *               easing: 'ease-in'
24937 *           }
24938 *       });
24939 *   </pre>
24940 *   @for Node
24941 *   @method transition
24942 *   @param {Object} config An object containing one or more style properties, a duration and an easing.
24943 *   @param {Function} callback A function to run after the transition has completed.
24944 *   @chainable
24945*/
24946Y.Node.prototype.transition = function(name, config, callback) {
24947    var
24948        transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
24949        anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
24950        fxConfig,
24951        prop;
24952
24953    if (typeof name === 'string') { // named effect, pull config from registry
24954        if (typeof config === 'function') {
24955            callback = config;
24956            config = null;
24957        }
24958
24959        fxConfig = Transition.fx[name];
24960
24961        if (config && typeof config === 'object') {
24962            config = Y.clone(config);
24963
24964            for (prop in fxConfig) {
24965                if (fxConfig.hasOwnProperty(prop)) {
24966                    if (! (prop in config)) {
24967                        config[prop] = fxConfig[prop];
24968                    }
24969                }
24970            }
24971        } else {
24972            config = fxConfig;
24973        }
24974
24975    } else { // name is a config, config is a callback or undefined
24976        callback = config;
24977        config = name;
24978    }
24979
24980    if (anim && !anim._running) {
24981        anim.init(this, config);
24982    } else {
24983        anim = new Transition(this._node, config);
24984    }
24985
24986    anim.run(callback);
24987    return this;
24988};
24989
24990Y.Node.prototype.show = function(name, config, callback) {
24991    this._show(); // show prior to transition
24992    if (name && Y.Transition) {
24993        if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
24994            if (typeof config === 'function') {
24995                callback = config;
24996                config = name;
24997            }
24998            name = Transition.SHOW_TRANSITION;
24999        }
25000        this.transition(name, config, callback);
25001    }
25002    return this;
25003};
25004
25005Y.NodeList.prototype.show = function(name, config, callback) {
25006    var nodes = this._nodes,
25007        i = 0,
25008        node;
25009
25010    while ((node = nodes[i++])) {
25011        Y.one(node).show(name, config, callback);
25012    }
25013
25014    return this;
25015};
25016
25017
25018
25019var _wrapCallBack = function(anim, fn, callback) {
25020    return function() {
25021        if (fn) {
25022            fn.call(anim);
25023        }
25024        if (callback && typeof callback === 'function') {
25025            callback.apply(anim._node, arguments);
25026        }
25027    };
25028};
25029
25030Y.Node.prototype.hide = function(name, config, callback) {
25031    if (name && Y.Transition) {
25032        if (typeof config === 'function') {
25033            callback = config;
25034            config = null;
25035        }
25036
25037        callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
25038        if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
25039            if (typeof config === 'function') {
25040                callback = config;
25041                config = name;
25042            }
25043            name = Transition.HIDE_TRANSITION;
25044        }
25045        this.transition(name, config, callback);
25046    } else {
25047        this._hide();
25048    }
25049    return this;
25050};
25051
25052Y.NodeList.prototype.hide = function(name, config, callback) {
25053    var nodes = this._nodes,
25054        i = 0,
25055        node;
25056
25057    while ((node = nodes[i++])) {
25058        Y.one(node).hide(name, config, callback);
25059    }
25060
25061    return this;
25062};
25063
25064/**
25065 *   Animate one or more css properties to a given value. Requires the "transition" module.
25066 *   <pre>example usage:
25067 *       Y.all('.demo').transition({
25068 *           duration: 1, // in seconds, default is 0.5
25069 *           easing: 'ease-out', // default is 'ease'
25070 *           delay: '1', // delay start for 1 second, default is 0
25071 *
25072 *           height: '10px',
25073 *           width: '10px',
25074 *
25075 *           opacity: { // per property
25076 *               value: 0,
25077 *               duration: 2,
25078 *               delay: 2,
25079 *               easing: 'ease-in'
25080 *           }
25081 *       });
25082 *   </pre>
25083 *   @for NodeList
25084 *   @method transition
25085 *   @param {Object} config An object containing one or more style properties, a duration and an easing.
25086 *   @param {Function} callback A function to run after the transition has completed. The callback fires
25087 *       once per item in the NodeList.
25088 *   @param {Boolean} callbackOnce If true, the callback will be called only after the
25089 *       last transition has completed
25090 *   @chainable
25091*/
25092Y.NodeList.prototype.transition = function(config, callback, callbackOnce) {
25093    var nodes = this._nodes,
25094        size = this.size(),
25095         i = 0,
25096        callbackOnce = callbackOnce === true,
25097        node;
25098
25099    while ((node = nodes[i++])) {
25100        if (i < size && callbackOnce){
25101            Y.one(node).transition(config);
25102        } else {
25103            Y.one(node).transition(config, callback);
25104        }
25105    }
25106
25107    return this;
25108};
25109
25110Y.Node.prototype.toggleView = function(name, on, callback) {
25111    this._toggles = this._toggles || [];
25112    callback = arguments[arguments.length - 1];
25113
25114    if (typeof name !== 'string') { // no transition, just toggle
25115        on = name;
25116        this._toggleView(on, callback); // call original _toggleView in Y.Node
25117        return;
25118    }
25119
25120    if (typeof on === 'function') { // Ignore "on" if used for callback argument.
25121        on = undefined;
25122    }
25123
25124    if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle
25125        on = ! this._toggles[name];
25126    }
25127
25128    on = (on) ? 1 : 0;
25129    if (on) {
25130        this._show();
25131    }  else {
25132        callback = _wrapCallBack(this, this._hide, callback);
25133    }
25134
25135    this._toggles[name] = on;
25136    this.transition(Y.Transition.toggles[name][on], callback);
25137
25138    return this;
25139};
25140
25141Y.NodeList.prototype.toggleView = function(name, on, callback) {
25142    var nodes = this._nodes,
25143        i = 0,
25144        node;
25145
25146    while ((node = nodes[i++])) {
25147        node = Y.one(node);
25148        node.toggleView.apply(node, arguments);
25149    }
25150
25151    return this;
25152};
25153
25154Y.mix(Transition.fx, {
25155    fadeOut: {
25156        opacity: 0,
25157        duration: 0.5,
25158        easing: 'ease-out'
25159    },
25160
25161    fadeIn: {
25162        opacity: 1,
25163        duration: 0.5,
25164        easing: 'ease-in'
25165    },
25166
25167    sizeOut: {
25168        height: 0,
25169        width: 0,
25170        duration: 0.75,
25171        easing: 'ease-out'
25172    },
25173
25174    sizeIn: {
25175        height: function(node) {
25176            return node.get('scrollHeight') + 'px';
25177        },
25178        width: function(node) {
25179            return node.get('scrollWidth') + 'px';
25180        },
25181        duration: 0.5,
25182        easing: 'ease-in',
25183
25184        on: {
25185            start: function() {
25186                var overflow = this.getStyle('overflow');
25187                if (overflow !== 'hidden') { // enable scrollHeight/Width
25188                    this.setStyle('overflow', 'hidden');
25189                    this._transitionOverflow = overflow;
25190                }
25191            },
25192
25193            end: function() {
25194                if (this._transitionOverflow) { // revert overridden value
25195                    this.setStyle('overflow', this._transitionOverflow);
25196                    delete this._transitionOverflow;
25197                }
25198            }
25199        }
25200    }
25201});
25202
25203Y.mix(Transition.toggles, {
25204    size: ['sizeOut', 'sizeIn'],
25205    fade: ['fadeOut', 'fadeIn']
25206});
25207
25208
25209}, '3.18.1', {"requires": ["node-style"]});
25210YUI.add('selector-css2', function (Y, NAME) {
25211
25212/**
25213 * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
25214 * @module dom
25215 * @submodule selector-css2
25216 * @for Selector
25217 */
25218
25219/*
25220 * Provides helper methods for collecting and filtering DOM elements.
25221 */
25222
25223var PARENT_NODE = 'parentNode',
25224    TAG_NAME = 'tagName',
25225    ATTRIBUTES = 'attributes',
25226    COMBINATOR = 'combinator',
25227    PSEUDOS = 'pseudos',
25228
25229    Selector = Y.Selector,
25230
25231    SelectorCSS2 = {
25232        _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,
25233        SORT_RESULTS: true,
25234
25235        // TODO: better detection, document specific
25236        _isXML: (function() {
25237            var isXML = (Y.config.doc.createElement('div').tagName !== 'DIV');
25238            return isXML;
25239        }()),
25240
25241        /**
25242         * Mapping of shorthand tokens to corresponding attribute selector
25243         * @property shorthand
25244         * @type object
25245         */
25246        shorthand: {
25247            '\\#(-?[_a-z0-9]+[-\\w\\uE000]*)': '[id=$1]',
25248            '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]'
25249        },
25250
25251        /**
25252         * List of operators and corresponding boolean functions.
25253         * These functions are passed the attribute and the current node's value of the attribute.
25254         * @property operators
25255         * @type object
25256         */
25257        operators: {
25258            '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
25259            '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
25260            '|=': '^{val}-?' // optional hyphen-delimited
25261        },
25262
25263        pseudos: {
25264           'first-child': function(node) {
25265                return Y.DOM._children(node[PARENT_NODE])[0] === node;
25266            }
25267        },
25268
25269        _bruteQuery: function(selector, root, firstOnly) {
25270            var ret = [],
25271                nodes = [],
25272                visited,
25273                tokens = Selector._tokenize(selector),
25274                token = tokens[tokens.length - 1],
25275                rootDoc = Y.DOM._getDoc(root),
25276                child,
25277                id,
25278                className,
25279                tagName,
25280                isUniversal;
25281
25282            if (token) {
25283                // prefilter nodes
25284                id = token.id;
25285                className = token.className;
25286                tagName = token.tagName || '*';
25287
25288                if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
25289                    // try ID first, unless no root.all && root not in document
25290                    // (root.all works off document, but not getElementById)
25291                    if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) {
25292                        nodes = Y.DOM.allById(id, root);
25293                    // try className
25294                    } else if (className) {
25295                        nodes = root.getElementsByClassName(className);
25296                    } else { // default to tagName
25297                        nodes = root.getElementsByTagName(tagName);
25298                    }
25299
25300                } else { // brute getElementsByTagName()
25301                    visited = [];
25302                    child = root.firstChild;
25303                    isUniversal = tagName === "*";
25304                    while (child) {
25305                        while (child) {
25306                            // IE 6-7 considers comment nodes as element nodes, and gives them the tagName "!".
25307                            // We can filter them out by checking if its tagName is > "@".
25308                            // This also avoids a superflous nodeType === 1 check.
25309                            if (child.tagName > "@" && (isUniversal || child.tagName === tagName)) {
25310                                nodes.push(child);
25311                            }
25312
25313                            // We may need to traverse back up the tree to find more unvisited subtrees.
25314                            visited.push(child);
25315                            child = child.firstChild;
25316                        }
25317
25318                        // Find the most recently visited node who has a next sibling.
25319                        while (visited.length > 0 && !child) {
25320                            child = visited.pop().nextSibling;
25321                        }
25322                    }
25323                }
25324
25325                if (nodes.length) {
25326                    ret = Selector._filterNodes(nodes, tokens, firstOnly);
25327                }
25328            }
25329
25330            return ret;
25331        },
25332
25333        _filterNodes: function(nodes, tokens, firstOnly) {
25334            var i = 0,
25335                j,
25336                len = tokens.length,
25337                n = len - 1,
25338                result = [],
25339                node = nodes[0],
25340                tmpNode = node,
25341                getters = Y.Selector.getters,
25342                operator,
25343                combinator,
25344                token,
25345                path,
25346                pass,
25347                value,
25348                tests,
25349                test;
25350
25351            for (i = 0; (tmpNode = node = nodes[i++]);) {
25352                n = len - 1;
25353                path = null;
25354
25355                testLoop:
25356                while (tmpNode && tmpNode.tagName) {
25357                    token = tokens[n];
25358                    tests = token.tests;
25359                    j = tests.length;
25360                    if (j && !pass) {
25361                        while ((test = tests[--j])) {
25362                            operator = test[1];
25363                            if (getters[test[0]]) {
25364                                value = getters[test[0]](tmpNode, test[0]);
25365                            } else {
25366                                value = tmpNode[test[0]];
25367                                if (test[0] === 'tagName' && !Selector._isXML) {
25368                                    value = value.toUpperCase();
25369                                }
25370                                if (typeof value != 'string' && value !== undefined && value.toString) {
25371                                    value = value.toString(); // coerce for comparison
25372                                } else if (value === undefined && tmpNode.getAttribute) {
25373                                    // use getAttribute for non-standard attributes
25374                                    value = tmpNode.getAttribute(test[0], 2); // 2 === force string for IE
25375                                }
25376                            }
25377
25378                            if ((operator === '=' && value !== test[2]) ||  // fast path for equality
25379                                (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
25380                                operator.test && !operator.test(value)) ||  // regex test
25381                                (!operator.test && // protect against RegExp as function (webkit)
25382                                        typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test
25383
25384                                // skip non element nodes or non-matching tags
25385                                if ((tmpNode = tmpNode[path])) {
25386                                    while (tmpNode &&
25387                                        (!tmpNode.tagName ||
25388                                            (token.tagName && token.tagName !== tmpNode.tagName))
25389                                    ) {
25390                                        tmpNode = tmpNode[path];
25391                                    }
25392                                }
25393                                continue testLoop;
25394                            }
25395                        }
25396                    }
25397
25398                    n--; // move to next token
25399                    // now that we've passed the test, move up the tree by combinator
25400                    if (!pass && (combinator = token.combinator)) {
25401                        path = combinator.axis;
25402                        tmpNode = tmpNode[path];
25403
25404                        // skip non element nodes
25405                        while (tmpNode && !tmpNode.tagName) {
25406                            tmpNode = tmpNode[path];
25407                        }
25408
25409                        if (combinator.direct) { // one pass only
25410                            path = null;
25411                        }
25412
25413                    } else { // success if we made it this far
25414                        result.push(node);
25415                        if (firstOnly) {
25416                            return result;
25417                        }
25418                        break;
25419                    }
25420                }
25421            }
25422            node = tmpNode = null;
25423            return result;
25424        },
25425
25426        combinators: {
25427            ' ': {
25428                axis: 'parentNode'
25429            },
25430
25431            '>': {
25432                axis: 'parentNode',
25433                direct: true
25434            },
25435
25436
25437            '+': {
25438                axis: 'previousSibling',
25439                direct: true
25440            }
25441        },
25442
25443        _parsers: [
25444            {
25445                name: ATTRIBUTES,
25446                re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
25447                fn: function(match, token) {
25448                    var operator = match[2] || '',
25449                        operators = Selector.operators,
25450                        escVal = (match[3]) ? match[3].replace(/\\/g, '') : '',
25451                        test;
25452
25453                    // add prefiltering for ID and CLASS
25454                    if ((match[1] === 'id' && operator === '=') ||
25455                            (match[1] === 'className' &&
25456                            Y.config.doc.documentElement.getElementsByClassName &&
25457                            (operator === '~=' || operator === '='))) {
25458                        token.prefilter = match[1];
25459
25460
25461                        match[3] = escVal;
25462
25463                        // escape all but ID for prefilter, which may run through QSA (via Dom.allById)
25464                        token[match[1]] = (match[1] === 'id') ? match[3] : escVal;
25465
25466                    }
25467
25468                    // add tests
25469                    if (operator in operators) {
25470                        test = operators[operator];
25471                        if (typeof test === 'string') {
25472                            match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1');
25473                            test = new RegExp(test.replace('{val}', match[3]));
25474                        }
25475                        match[2] = test;
25476                    }
25477                    if (!token.last || token.prefilter !== match[1]) {
25478                        return match.slice(1);
25479                    }
25480                }
25481            },
25482            {
25483                name: TAG_NAME,
25484                re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
25485                fn: function(match, token) {
25486                    var tag = match[1];
25487
25488                    if (!Selector._isXML) {
25489                        tag = tag.toUpperCase();
25490                    }
25491
25492                    token.tagName = tag;
25493
25494                    if (tag !== '*' && (!token.last || token.prefilter)) {
25495                        return [TAG_NAME, '=', tag];
25496                    }
25497                    if (!token.prefilter) {
25498                        token.prefilter = 'tagName';
25499                    }
25500                }
25501            },
25502            {
25503                name: COMBINATOR,
25504                re: /^\s*([>+~]|\s)\s*/,
25505                fn: function(match, token) {
25506                }
25507            },
25508            {
25509                name: PSEUDOS,
25510                re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,
25511                fn: function(match, token) {
25512                    var test = Selector[PSEUDOS][match[1]];
25513                    if (test) { // reorder match array and unescape special chars for tests
25514                        if (match[2]) {
25515                            match[2] = match[2].replace(/\\/g, '');
25516                        }
25517                        return [match[2], test];
25518                    } else { // selector token not supported (possibly missing CSS3 module)
25519                        return false;
25520                    }
25521                }
25522            }
25523            ],
25524
25525        _getToken: function(token) {
25526            return {
25527                tagName: null,
25528                id: null,
25529                className: null,
25530                attributes: {},
25531                combinator: null,
25532                tests: []
25533            };
25534        },
25535
25536        /*
25537            Break selector into token units per simple selector.
25538            Combinator is attached to the previous token.
25539         */
25540        _tokenize: function(selector) {
25541            selector = selector || '';
25542            selector = Selector._parseSelector(Y.Lang.trim(selector));
25543            var token = Selector._getToken(),     // one token per simple selector (left selector holds combinator)
25544                query = selector, // original query for debug report
25545                tokens = [],    // array of tokens
25546                found = false,  // whether or not any matches were found this pass
25547                match,         // the regex match
25548                test,
25549                i, parser;
25550
25551            /*
25552                Search for selector patterns, store, and strip them from the selector string
25553                until no patterns match (invalid selector) or we run out of chars.
25554
25555                Multiple attributes and pseudos are allowed, in any order.
25556                for example:
25557                    'form:first-child[type=button]:not(button)[lang|=en]'
25558            */
25559            outer:
25560            do {
25561                found = false; // reset after full pass
25562                for (i = 0; (parser = Selector._parsers[i++]);) {
25563                    if ( (match = parser.re.exec(selector)) ) { // note assignment
25564                        if (parser.name !== COMBINATOR ) {
25565                            token.selector = selector;
25566                        }
25567                        selector = selector.replace(match[0], ''); // strip current match from selector
25568                        if (!selector.length) {
25569                            token.last = true;
25570                        }
25571
25572                        if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
25573                            match[1] = Selector._attrFilters[match[1]];
25574                        }
25575
25576                        test = parser.fn(match, token);
25577                        if (test === false) { // selector not supported
25578                            found = false;
25579                            break outer;
25580                        } else if (test) {
25581                            token.tests.push(test);
25582                        }
25583
25584                        if (!selector.length || parser.name === COMBINATOR) {
25585                            tokens.push(token);
25586                            token = Selector._getToken(token);
25587                            if (parser.name === COMBINATOR) {
25588                                token.combinator = Y.Selector.combinators[match[1]];
25589                            }
25590                        }
25591                        found = true;
25592                    }
25593                }
25594            } while (found && selector.length);
25595
25596            if (!found || selector.length) { // not fully parsed
25597                tokens = [];
25598            }
25599            return tokens;
25600        },
25601
25602        _replaceMarkers: function(selector) {
25603            selector = selector.replace(/\[/g, '\uE003');
25604            selector = selector.replace(/\]/g, '\uE004');
25605
25606            selector = selector.replace(/\(/g, '\uE005');
25607            selector = selector.replace(/\)/g, '\uE006');
25608            return selector;
25609        },
25610
25611        _replaceShorthand: function(selector) {
25612            var shorthand = Y.Selector.shorthand,
25613                re;
25614
25615            for (re in shorthand) {
25616                if (shorthand.hasOwnProperty(re)) {
25617                    selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]);
25618                }
25619            }
25620
25621            return selector;
25622        },
25623
25624        _parseSelector: function(selector) {
25625            var replaced = Y.Selector._replaceSelector(selector),
25626                selector = replaced.selector;
25627
25628            // replace shorthand (".foo, #bar") after pseudos and attrs
25629            // to avoid replacing unescaped chars
25630            selector = Y.Selector._replaceShorthand(selector);
25631
25632            selector = Y.Selector._restore('attr', selector, replaced.attrs);
25633            selector = Y.Selector._restore('pseudo', selector, replaced.pseudos);
25634
25635            // replace braces and parens before restoring escaped chars
25636            // to avoid replacing ecaped markers
25637            selector = Y.Selector._replaceMarkers(selector);
25638            selector = Y.Selector._restore('esc', selector, replaced.esc);
25639
25640            return selector;
25641        },
25642
25643        _attrFilters: {
25644            'class': 'className',
25645            'for': 'htmlFor'
25646        },
25647
25648        getters: {
25649            href: function(node, attr) {
25650                return Y.DOM.getAttribute(node, attr);
25651            },
25652
25653            id: function(node, attr) {
25654                return Y.DOM.getId(node);
25655            }
25656        }
25657    };
25658
25659Y.mix(Y.Selector, SelectorCSS2, true);
25660Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
25661
25662// IE wants class with native queries
25663if (Y.Selector.useNative && Y.config.doc.querySelector) {
25664    Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
25665}
25666
25667
25668}, '3.18.1', {"requires": ["selector-native"]});
25669YUI.add('selector-css3', function (Y, NAME) {
25670
25671/**
25672 * The selector css3 module provides support for css3 selectors.
25673 * @module dom
25674 * @submodule selector-css3
25675 * @for Selector
25676 */
25677
25678/*
25679    an+b = get every _a_th node starting at the _b_th
25680    0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element
25681    1n+b =  get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
25682    an+0 = get every _a_th element, "0" may be omitted
25683*/
25684
25685Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
25686
25687Y.Selector._getNth = function(node, expr, tag, reverse) {
25688    Y.Selector._reNth.test(expr);
25689    var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
25690        n = RegExp.$2, // "n"
25691        oddeven = RegExp.$3, // "odd" or "even"
25692        b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
25693        result = [],
25694        siblings = Y.DOM._children(node.parentNode, tag),
25695        op;
25696
25697    if (oddeven) {
25698        a = 2; // always every other
25699        op = '+';
25700        n = 'n';
25701        b = (oddeven === 'odd') ? 1 : 0;
25702    } else if ( isNaN(a) ) {
25703        a = (n) ? 1 : 0; // start from the first or no repeat
25704    }
25705
25706    if (a === 0) { // just the first
25707        if (reverse) {
25708            b = siblings.length - b + 1;
25709        }
25710
25711        if (siblings[b - 1] === node) {
25712            return true;
25713        } else {
25714            return false;
25715        }
25716
25717    } else if (a < 0) {
25718        reverse = !!reverse;
25719        a = Math.abs(a);
25720    }
25721
25722    if (!reverse) {
25723        for (var i = b - 1, len = siblings.length; i < len; i += a) {
25724            if ( i >= 0 && siblings[i] === node ) {
25725                return true;
25726            }
25727        }
25728    } else {
25729        for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
25730            if ( i < len && siblings[i] === node ) {
25731                return true;
25732            }
25733        }
25734    }
25735    return false;
25736};
25737
25738Y.mix(Y.Selector.pseudos, {
25739    'root': function(node) {
25740        return node === node.ownerDocument.documentElement;
25741    },
25742
25743    'nth-child': function(node, expr) {
25744        return Y.Selector._getNth(node, expr);
25745    },
25746
25747    'nth-last-child': function(node, expr) {
25748        return Y.Selector._getNth(node, expr, null, true);
25749    },
25750
25751    'nth-of-type': function(node, expr) {
25752        return Y.Selector._getNth(node, expr, node.tagName);
25753    },
25754
25755    'nth-last-of-type': function(node, expr) {
25756        return Y.Selector._getNth(node, expr, node.tagName, true);
25757    },
25758
25759    'last-child': function(node) {
25760        var children = Y.DOM._children(node.parentNode);
25761        return children[children.length - 1] === node;
25762    },
25763
25764    'first-of-type': function(node) {
25765        return Y.DOM._children(node.parentNode, node.tagName)[0] === node;
25766    },
25767
25768    'last-of-type': function(node) {
25769        var children = Y.DOM._children(node.parentNode, node.tagName);
25770        return children[children.length - 1] === node;
25771    },
25772
25773    'only-child': function(node) {
25774        var children = Y.DOM._children(node.parentNode);
25775        return children.length === 1 && children[0] === node;
25776    },
25777
25778    'only-of-type': function(node) {
25779        var children = Y.DOM._children(node.parentNode, node.tagName);
25780        return children.length === 1 && children[0] === node;
25781    },
25782
25783    'empty': function(node) {
25784        return node.childNodes.length === 0;
25785    },
25786
25787    'not': function(node, expr) {
25788        return !Y.Selector.test(node, expr);
25789    },
25790
25791    'contains': function(node, expr) {
25792        var text = node.innerText || node.textContent || '';
25793        return text.indexOf(expr) > -1;
25794    },
25795
25796    'checked': function(node) {
25797        return (node.checked === true || node.selected === true);
25798    },
25799
25800    enabled: function(node) {
25801        return (node.disabled !== undefined && !node.disabled);
25802    },
25803
25804    disabled: function(node) {
25805        return (node.disabled);
25806    }
25807});
25808
25809Y.mix(Y.Selector.operators, {
25810    '^=': '^{val}', // Match starts with value
25811    '$=': '{val}$', // Match ends with value
25812    '*=': '{val}' // Match contains value as substring
25813});
25814
25815Y.Selector.combinators['~'] = {
25816    axis: 'previousSibling'
25817};
25818
25819
25820}, '3.18.1', {"requires": ["selector-native", "selector-css2"]});
25821YUI.add('dom-style-ie', function (Y, NAME) {
25822
25823var HAS_LAYOUT = 'hasLayout',
25824    PX = 'px',
25825    FILTER = 'filter',
25826    FILTERS = 'filters',
25827    OPACITY = 'opacity',
25828    AUTO = 'auto',
25829
25830    BORDER_WIDTH = 'borderWidth',
25831    BORDER_TOP_WIDTH = 'borderTopWidth',
25832    BORDER_RIGHT_WIDTH = 'borderRightWidth',
25833    BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
25834    BORDER_LEFT_WIDTH = 'borderLeftWidth',
25835    WIDTH = 'width',
25836    HEIGHT = 'height',
25837    TRANSPARENT = 'transparent',
25838    VISIBLE = 'visible',
25839    GET_COMPUTED_STYLE = 'getComputedStyle',
25840    documentElement = Y.config.doc.documentElement,
25841
25842    testFeature = Y.Features.test,
25843    addFeature = Y.Features.add,
25844
25845    // TODO: unit-less lineHeight (e.g. 1.22)
25846    re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
25847
25848    isIE8 = (Y.UA.ie >= 8),
25849
25850    _getStyleObj = function(node) {
25851        return node.currentStyle || node.style;
25852    },
25853
25854    ComputedStyle = {
25855        CUSTOM_STYLES: {},
25856
25857        get: function(el, property) {
25858            var value = '',
25859                current;
25860
25861            if (el) {
25862                    current = _getStyleObj(el)[property];
25863
25864                if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
25865                    value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
25866                } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
25867                    value = current;
25868                } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
25869                    value = Y.DOM.IE.COMPUTED[property](el, property);
25870                } else if (re_unit.test(current)) { // convert to pixel
25871                    value = ComputedStyle.getPixel(el, property) + PX;
25872                } else {
25873                    value = current;
25874                }
25875            }
25876
25877            return value;
25878        },
25879
25880        sizeOffsets: {
25881            width: ['Left', 'Right'],
25882            height: ['Top', 'Bottom'],
25883            top: ['Top'],
25884            bottom: ['Bottom']
25885        },
25886
25887        getOffset: function(el, prop) {
25888            var current = _getStyleObj(el)[prop],                     // value of "width", "top", etc.
25889                capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
25890                pixel = 'pixel' + capped,                               // "pixelWidth", "pixelTop", etc.
25891                sizeOffsets = ComputedStyle.sizeOffsets[prop],
25892                mode = el.ownerDocument.compatMode,
25893                value = '';
25894
25895            // IE pixelWidth incorrect for percent
25896            // manually compute by subtracting padding and border from offset size
25897            // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
25898            // reverting to auto from auto causes position stacking issues (old impl)
25899            if (current === AUTO || current.indexOf('%') > -1) {
25900                value = el['offset' + capped];
25901
25902                if (mode !== 'BackCompat') {
25903                    if (sizeOffsets[0]) {
25904                        value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
25905                        value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
25906                    }
25907
25908                    if (sizeOffsets[1]) {
25909                        value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
25910                        value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
25911                    }
25912                }
25913
25914            } else { // use style.pixelWidth, etc. to convert to pixels
25915                // need to map style.width to currentStyle (no currentStyle.pixelWidth)
25916                if (!el.style[pixel] && !el.style[prop]) {
25917                    el.style[prop] = current;
25918                }
25919                value = el.style[pixel];
25920
25921            }
25922            return value + PX;
25923        },
25924
25925        borderMap: {
25926            thin: (isIE8) ? '1px' : '2px',
25927            medium: (isIE8) ? '3px': '4px',
25928            thick: (isIE8) ? '5px' : '6px'
25929        },
25930
25931        getBorderWidth: function(el, property, omitUnit) {
25932            var current = el.currentStyle[property];
25933
25934            if (current.indexOf(PX) < 0) { // look up keywords if a border exists
25935                if (ComputedStyle.borderMap[current] &&
25936                        el.currentStyle.borderStyle !== 'none') {
25937                    current = ComputedStyle.borderMap[current];
25938                } else { // otherwise no border (default is "medium")
25939                    current = 0;
25940                }
25941            }
25942            return (omitUnit) ? parseFloat(current) : current;
25943        },
25944
25945        getPixel: function(node, att) {
25946            // use pixelRight to convert to px
25947            var val = null,
25948                style = _getStyleObj(node),
25949                styleRight = style.right,
25950                current = style[att];
25951
25952            node.style.right = current;
25953            val = node.style.pixelRight;
25954            node.style.right = styleRight; // revert
25955
25956            return val;
25957        },
25958
25959        getMargin: function(node, att) {
25960            var val,
25961                style = _getStyleObj(node);
25962
25963            if (style[att] === AUTO) {
25964                val = 0;
25965            } else {
25966                val = ComputedStyle.getPixel(node, att);
25967            }
25968            return val + PX;
25969        },
25970
25971        getVisibility: function(node, att) {
25972            var current;
25973            while ( (current = node.currentStyle) && current[att] === 'inherit') { // NOTE: assignment in test
25974                node = node.parentNode;
25975            }
25976            return (current) ? current[att] : VISIBLE;
25977        },
25978
25979        getColor: function(node, att) {
25980            var current = _getStyleObj(node)[att];
25981
25982            if (!current || current === TRANSPARENT) {
25983                Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
25984                    current = _getStyleObj(parent)[att];
25985                    if (current && current !== TRANSPARENT) {
25986                        node = parent;
25987                        return true;
25988                    }
25989                });
25990            }
25991
25992            return Y.Color.toRGB(current);
25993        },
25994
25995        getBorderColor: function(node, att) {
25996            var current = _getStyleObj(node),
25997                val = current[att] || current.color;
25998            return Y.Color.toRGB(Y.Color.toHex(val));
25999        }
26000    },
26001
26002    //fontSize: getPixelFont,
26003    IEComputed = {};
26004
26005addFeature('style', 'computedStyle', {
26006    test: function() {
26007        return 'getComputedStyle' in Y.config.win;
26008    }
26009});
26010
26011addFeature('style', 'opacity', {
26012    test: function() {
26013        return 'opacity' in documentElement.style;
26014    }
26015});
26016
26017addFeature('style', 'filter', {
26018    test: function() {
26019        return 'filters' in documentElement;
26020    }
26021});
26022
26023// use alpha filter for IE opacity
26024if (!testFeature('style', 'opacity') && testFeature('style', 'filter')) {
26025    Y.DOM.CUSTOM_STYLES[OPACITY] = {
26026        get: function(node) {
26027            var val = 100;
26028            try { // will error if no DXImageTransform
26029                val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
26030
26031            } catch(e) {
26032                try { // make sure its in the document
26033                    val = node[FILTERS]('alpha')[OPACITY];
26034                } catch(err) {
26035                }
26036            }
26037            return val / 100;
26038        },
26039
26040        set: function(node, val, style) {
26041            var current,
26042                styleObj = _getStyleObj(node),
26043                currentFilter = styleObj[FILTER];
26044
26045            style = style || node.style;
26046            if (val === '') { // normalize inline style behavior
26047                current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
26048                val = current;
26049            }
26050
26051            if (typeof currentFilter === 'string') { // in case not appended
26052                style[FILTER] = currentFilter.replace(/alpha([^)]*\))/gi, '') +
26053                        ((val <= 1) ? 'alpha(' + OPACITY + '=' + val * 100 + ')' : '');
26054
26055                if (!style[FILTER]) {
26056                    style.removeAttribute(FILTER);
26057                }
26058
26059                if (!styleObj[HAS_LAYOUT]) {
26060                    style.zoom = 1; // needs layout
26061                }
26062            }
26063        }
26064    };
26065}
26066
26067try {
26068    Y.config.doc.createElement('div').style.height = '-1px';
26069} catch(e) { // IE throws error on invalid style set; trap common cases
26070    Y.DOM.CUSTOM_STYLES.height = {
26071        set: function(node, val, style) {
26072            var floatVal = parseFloat(val);
26073            if (floatVal >= 0 || val === 'auto' || val === '') {
26074                style.height = val;
26075            } else {
26076            }
26077        }
26078    };
26079
26080    Y.DOM.CUSTOM_STYLES.width = {
26081        set: function(node, val, style) {
26082            var floatVal = parseFloat(val);
26083            if (floatVal >= 0 || val === 'auto' || val === '') {
26084                style.width = val;
26085            } else {
26086            }
26087        }
26088    };
26089}
26090
26091if (!testFeature('style', 'computedStyle')) {
26092    // TODO: top, right, bottom, left
26093    IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
26094
26095    IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
26096
26097    IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
26098            IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
26099            ComputedStyle.getBorderWidth;
26100
26101    IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
26102            IEComputed.marginLeft = ComputedStyle.getMargin;
26103
26104    IEComputed.visibility = ComputedStyle.getVisibility;
26105    IEComputed.borderColor = IEComputed.borderTopColor =
26106            IEComputed.borderRightColor = IEComputed.borderBottomColor =
26107            IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
26108
26109    Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
26110
26111    Y.namespace('DOM.IE');
26112    Y.DOM.IE.COMPUTED = IEComputed;
26113    Y.DOM.IE.ComputedStyle = ComputedStyle;
26114}
26115
26116
26117}, '3.18.1', {"requires": ["dom-style", "color-base"]});
26118YUI.add('escape', function (Y, NAME) {
26119
26120/**
26121Provides utility methods for escaping strings.
26122
26123@module escape
26124@class Escape
26125@static
26126@since 3.3.0
26127**/
26128
26129var HTML_CHARS = {
26130        '&': '&amp;',
26131        '<': '&lt;',
26132        '>': '&gt;',
26133        '"': '&quot;',
26134        "'": '&#x27;',
26135        '/': '&#x2F;',
26136        '`': '&#x60;'
26137    },
26138
26139Escape = {
26140    // -- Public Static Methods ------------------------------------------------
26141
26142    /**
26143    Returns a copy of the specified string with special HTML characters
26144    escaped. The following characters will be converted to their
26145    corresponding character entities:
26146
26147        & < > " ' / `
26148
26149    This implementation is based on the [OWASP HTML escaping
26150    recommendations][1]. In addition to the characters in the OWASP
26151    recommendations, we also escape the <code>&#x60;</code> character, since IE
26152    interprets it as an attribute delimiter.
26153
26154    If _string_ is not already a string, it will be coerced to a string.
26155
26156    [1]: http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
26157
26158    @method html
26159    @param {String} string String to escape.
26160    @return {String} Escaped string.
26161    @static
26162    **/
26163    html: function (string) {
26164        return (string + '').replace(/[&<>"'\/`]/g, Escape._htmlReplacer);
26165    },
26166
26167    /**
26168    Returns a copy of the specified string with special regular expression
26169    characters escaped, allowing the string to be used safely inside a regex.
26170    The following characters, and all whitespace characters, are escaped:
26171
26172        - $ ^ * ( ) + [ ] { } | \ , . ?
26173
26174    If _string_ is not already a string, it will be coerced to a string.
26175
26176    @method regex
26177    @param {String} string String to escape.
26178    @return {String} Escaped string.
26179    @static
26180    **/
26181    regex: function (string) {
26182        // There's no need to escape !, =, and : since they only have meaning
26183        // when they follow a parenthesized ?, as in (?:...), and we already
26184        // escape parens and question marks.
26185        return (string + '').replace(/[\-$\^*()+\[\]{}|\\,.?\s]/g, '\\$&');
26186    },
26187
26188    // -- Protected Static Methods ---------------------------------------------
26189
26190    /**
26191     * Regex replacer for HTML escaping.
26192     *
26193     * @method _htmlReplacer
26194     * @param {String} match Matched character (must exist in HTML_CHARS).
26195     * @return {String} HTML entity.
26196     * @static
26197     * @protected
26198     */
26199    _htmlReplacer: function (match) {
26200        return HTML_CHARS[match];
26201    }
26202};
26203
26204Escape.regexp = Escape.regex;
26205
26206Y.Escape = Escape;
26207
26208
26209}, '3.18.1', {"requires": ["yui-base"]});
26210YUI.add('attribute-core', function (Y, NAME) {
26211
26212    /**
26213     * The State class maintains state for a collection of named items, with
26214     * a varying number of properties defined.
26215     *
26216     * It avoids the need to create a separate class for the item, and separate instances
26217     * of these classes for each item, by storing the state in a 2 level hash table,
26218     * improving performance when the number of items is likely to be large.
26219     *
26220     * @constructor
26221     * @class State
26222     */
26223    Y.State = function() {
26224        /**
26225         * Hash of attributes
26226         * @property data
26227         */
26228        this.data = {};
26229    };
26230
26231    Y.State.prototype = {
26232
26233        /**
26234         * Adds a property to an item.
26235         *
26236         * @method add
26237         * @param name {String} The name of the item.
26238         * @param key {String} The name of the property.
26239         * @param val {Any} The value of the property.
26240         */
26241        add: function(name, key, val) {
26242            var item = this.data[name];
26243
26244            if (!item) {
26245                item = this.data[name] = {};
26246            }
26247
26248            item[key] = val;
26249        },
26250
26251        /**
26252         * Adds multiple properties to an item.
26253         *
26254         * @method addAll
26255         * @param name {String} The name of the item.
26256         * @param obj {Object} A hash of property/value pairs.
26257         */
26258        addAll: function(name, obj) {
26259            var item = this.data[name],
26260                key;
26261
26262            if (!item) {
26263                item = this.data[name] = {};
26264            }
26265
26266            for (key in obj) {
26267                if (obj.hasOwnProperty(key)) {
26268                    item[key] = obj[key];
26269                }
26270            }
26271        },
26272
26273        /**
26274         * Removes a property from an item.
26275         *
26276         * @method remove
26277         * @param name {String} The name of the item.
26278         * @param key {String} The property to remove.
26279         */
26280        remove: function(name, key) {
26281            var item = this.data[name];
26282
26283            if (item) {
26284                delete item[key];
26285            }
26286        },
26287
26288        /**
26289         * Removes multiple properties from an item, or removes the item completely.
26290         *
26291         * @method removeAll
26292         * @param name {String} The name of the item.
26293         * @param obj {Object|Array} Collection of properties to delete. If not provided, the entire item is removed.
26294         */
26295        removeAll: function(name, obj) {
26296            var data;
26297
26298            if (!obj) {
26299                data = this.data;
26300
26301                if (name in data) {
26302                    delete data[name];
26303                }
26304            } else {
26305                Y.each(obj, function(value, key) {
26306                    this.remove(name, typeof key === 'string' ? 
26306key : value);
26307                }, this);
26308            }
26309        },
26310
26311        /**
26312         * For a given item, returns the value of the property requested, or undefined if not found.
26313         *
26314         * @method get
26315         * @param name {String} The name of the item
26316         * @param key {String} Optional. The property value to retrieve.
26317         * @return {Any} The value of the supplied property.
26318         */
26319        get: function(name, key) {
26320            var item = this.data[name];
26321
26322            if (item) {
26323                return item[key];
26324            }
26325        },
26326
26327        /**
26328         * For the given item, returns an object with all of the
26329         * item's property/value pairs. By default the object returned
26330         * is a shallow copy of the stored data, but passing in true
26331         * as the second parameter will return a reference to the stored
26332         * data.
26333         *
26334         * @method getAll
26335         * @param name {String} The name of the item
26336         * @param reference {boolean} true, if you want a reference to the stored
26337         * object
26338         * @return {Object} An object with property/value pairs for the item.
26339         */
26340        getAll : function(name, reference) {
26341            var item = this.data[name],
26342                key, obj;
26343
26344            if (reference) {
26345                obj = item;
26346            } else if (item) {
26347                obj = {};
26348
26349                for (key in item) {
26350                    if (item.hasOwnProperty(key)) {
26351                        obj[key] = item[key];
26352                    }
26353                }
26354            }
26355
26356            return obj;
26357        }
26358    };
26359    /*For log lines*/
26360    /*jshint maxlen:200*/
26361
26362    /**
26363     * The attribute module provides an augmentable Attribute implementation, which
26364     * adds configurable attributes and attribute change events to the class being
26365     * augmented. It also provides a State class, which is used internally by Attribute,
26366     * but can also be used independently to provide a name/property/value data structure to
26367     * store state.
26368     *
26369     * @module attribute
26370     */
26371
26372    /**
26373     * The attribute-core submodule provides the lightest level of attribute handling support
26374     * without Attribute change events, or lesser used methods such as reset(), modifyAttrs(),
26375     * and removeAttr().
26376     *
26377     * @module attribute
26378     * @submodule attribute-core
26379     */
26380    var O = Y.Object,
26381        Lang = Y.Lang,
26382
26383        DOT = ".",
26384
26385        // Externally configurable props
26386        GETTER = "getter",
26387        SETTER = "setter",
26388        READ_ONLY = "readOnly",
26389        WRITE_ONCE = "writeOnce",
26390        INIT_ONLY = "initOnly",
26391        VALIDATOR = "validator",
26392        VALUE = "value",
26393        VALUE_FN = "valueFn",
26394        LAZY_ADD = "lazyAdd",
26395
26396        // Used for internal state management
26397        ADDED = "added",
26398        BYPASS_PROXY = "_bypassProxy",
26399        INIT_VALUE = "initValue",
26400        LAZY = "lazy",
26401
26402        INVALID_VALUE;
26403
26404    /**
26405     * <p>
26406     * AttributeCore provides the lightest level of configurable attribute support. It is designed to be
26407     * augmented on to a host class, and provides the host with the ability to configure
26408     * attributes to store and retrieve state, <strong>but without support for attribute change events</strong>.
26409     * </p>
26410     * <p>For example, attributes added to the host can be configured:</p>
26411     * <ul>
26412     *     <li>As read only.</li>
26413     *     <li>As write once.</li>
26414     *     <li>With a setter function, which can be used to manipulate
26415     *     values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li>
26416     *     <li>With a getter function, which can be used to manipulate stored values,
26417     *     before they are returned by Attribute's <a href="#method_get">get</a> method.</li>
26418     *     <li>With a validator function, to validate values before they are stored.</li>
26419     * </ul>
26420     *
26421     * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration
26422     * options available for attributes.</p>
26423     *
26424     * <p>Object/Classes based on AttributeCore can augment <a href="AttributeObservable.html">AttributeObservable</a>
26425     * (with true for overwrite) and <a href="AttributeExtras.html">AttributeExtras</a> to add attribute event and
26426     * additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p>
26427     *
26428     * @class AttributeCore
26429     * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
26430     *        These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
26431     * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
26432     *        These are not merged/cloned. The caller is responsible for isolating user provided values if required.
26433     * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
26434     */
26435    function AttributeCore(attrs, values, lazy) {
26436        // HACK: Fix #2531929
26437        // Complete hack, to make sure the first clone of a node value in IE doesn't doesn't hurt state - maintains 3.4.1 behavior.
26438        // Too late in the release cycle to do anything about the core problem.
26439        // The root issue is that cloning a Y.Node instance results in an object which barfs in IE, when you access it's properties (since 3.3.0).
26440        this._yuievt = null;
26441
26442        this._initAttrHost(attrs, values, lazy);
26443    }
26444
26445    /**
26446     * <p>The value to return from an attribute setter in order to prevent the set from going through.</p>
26447     *
26448     * <p>You can return this value from your setter if you wish to combine validator and setter
26449     * functionality into a single setter function, which either returns the massaged value to be stored or
26450     * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p>
26451     *
26452     * @property INVALID_VALUE
26453     * @type Object
26454     * @static
26455     * @final
26456     */
26457    AttributeCore.INVALID_VALUE = {};
26458    INVALID_VALUE = AttributeCore.INVALID_VALUE;
26459
26460    /**
26461     * The list of properties which can be configured for
26462     * each attribute (e.g. setter, getter, writeOnce etc.).
26463     *
26464     * This property is used internally as a whitelist for faster
26465     * Y.mix operations.
26466     *
26467     * @property _ATTR_CFG
26468     * @type Array
26469     * @static
26470     * @protected
26471     */
26472    AttributeCore._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BYPASS_PROXY];
26473
26474    /**
26475     * Utility method to protect an attribute configuration hash, by merging the
26476     * entire object and the individual attr config objects.
26477     *
26478     * @method protectAttrs
26479     * @static
26480     * @param {Object} attrs A hash of attribute to configuration object pairs.
26481     * @return {Object} A protected version of the `attrs` argument.
26482     */
26483    AttributeCore.protectAttrs = function (attrs) {
26484        if (attrs) {
26485            attrs = Y.merge(attrs);
26486            for (var attr in attrs) {
26487                if (attrs.hasOwnProperty(attr)) {
26488                    attrs[attr] = Y.merge(attrs[attr]);
26489                }
26490            }
26491        }
26492
26493        return attrs;
26494    };
26495
26496    AttributeCore.prototype = {
26497
26498        /**
26499         * Constructor logic for attributes. Initializes the host state, and sets up the inital attributes passed to the
26500         * constructor.
26501         *
26502         * @method _initAttrHost
26503         * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
26504         *        These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
26505         * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
26506         *        These are not merged/cloned. The caller is responsible for isolating user provided values if required.
26507         * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
26508         * @private
26509         */
26510        _initAttrHost : function(attrs, values, lazy) {
26511            this._state = new Y.State();
26512            this._initAttrs(attrs, values, lazy);
26513        },
26514
26515        /**
26516         * <p>
26517         * Adds an attribute with the provided configuration to the host object.
26518         * </p>
26519         * <p>
26520         * The config argument object supports the following properties:
26521         * </p>
26522         *
26523         * <dl>
26524         *    <dt>value &#60;Any&#62;</dt>
26525         *    <dd>The initial value to set on the attribute</dd>
26526         *
26527         *    <dt>valueFn &#60;Function | String&#62;</dt>
26528         *    <dd>
26529         *    <p>A function, which will return the initial value to set on the attribute. This is useful
26530         *    for cases where the attribute configuration is defined statically, but needs to
26531         *    reference the host instance ("this") to obtain an initial value. If both the value and valueFn properties are defined,
26532         *    the value returned by the valueFn has precedence over the value property, unless it returns undefined, in which
26533         *    case the value property is used.</p>
26534         *
26535         *    <p>valueFn can also be set to a string, representing the name of the instance method to be used to retrieve the value.</p>
26536         *    </dd>
26537         *
26538         *    <dt>readOnly &#60;boolean&#62;</dt>
26539         *    <dd>Whether or not the attribute is read only. Attributes having readOnly set to true
26540         *        cannot be modified by invoking the set method.</dd>
26541         *
26542         *    <dt>writeOnce &#60;boolean&#62; or &#60;string&#62;</dt>
26543         *    <dd>
26544         *        Whether or not the attribute is "write once". Attributes having writeOnce set to true,
26545         *        can only have their values set once, be it through the default configuration,
26546         *        constructor configuration arguments, or by invoking set.
26547         *        <p>The writeOnce attribute can also be set to the string "initOnly",
26548         *         in which case the attribute can only be set during initialization
26549         *        (when used with Base, this means it can only be set during construction)</p>
26550         *    </dd>
26551         *
26552         *    <dt>setter &#60;Function | String&#62;</dt>
26553         *    <dd>
26554         *    <p>The setter function used to massage or normalize the value passed to the set method for the attribute.
26555         *    The value returned by the setter will be the final stored value. Returning
26556         *    <a href="#property_Attribute.INVALID_VALUE">Attribute.INVALID_VALUE</a>, from the setter will prevent
26557         *    the value from being stored.
26558         *    </p>
26559         *
26560         *    <p>setter can also be set to a string, representing the name of the instance method to be used as the setter function.</p>
26561         *    </dd>
26562         *
26563         *    <dt>getter &#60;Function | String&#62;</dt>
26564         *    <dd>
26565         *    <p>
26566         *    The getter function used to massage or normalize the value returned by the get method for the attribute.
26567         *    The value returned by the getter function is the value which will be returned to the user when they
26568         *    invoke get.
26569         *    </p>
26570         *
26571         *    <p>getter can also be set to a string, representing the name of the instance method to be used as the getter function.</p>
26572         *    </dd>
26573         *
26574         *    <dt>validator &#60;Function | String&#62;</dt>
26575         *    <dd>
26576         *    <p>
26577         *    The validator function invoked prior to setting the stored value. Returning
26578         *    false from the validator function will prevent the value from being stored.
26579         *    </p>
26580         *
26581         *    <p>validator can also be set to a string, representing the name of the instance method to be used as the validator function.</p>
26582         *    </dd>
26583         *
26584         *    <dt>lazyAdd &#60;boolean&#62;</dt>
26585         *    <dd>Whether or not to delay initialization of the attribute until the first call to get/set it.
26586         *    This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
26587         *    the <a href="#method_addAttrs">addAttrs</a> method.</dd>
26588         *
26589         * </dl>
26590         *
26591         * <p>The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
26592         * the context ("this") set to the host object.</p>
26593         *
26594         * <p>Configuration properties outside of the list mentioned above are considered private properties used internally by attribute,
26595         * and are not intended for public use.</p>
26596         *
26597         * @method addAttr
26598         *
26599         * @param {String} name The name of the attribute.
26600         * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
26601         *
26602         * <p>
26603         * <strong>NOTE:</strong> The configuration object is modified when adding an attribute, so if you need
26604         * to protect the original values, you will need to merge the object.
26605         * </p>
26606         *
26607         * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
26608         *
26609         * @return {Object} A reference to the host object.
26610         *
26611         * @chainable
26612         */
26613        addAttr : function(name, config, lazy) {
26614
26615
26616            var host = this, // help compression
26617                state = host._state,
26618                data = state.data,
26619                value,
26620                added,
26621                hasValue;
26622
26623            config = config || {};
26624
26625            if (LAZY_ADD in config) {
26626                lazy = config[LAZY_ADD];
26627            }
26628
26629            added = state.get(name, ADDED);
26630
26631            if (lazy && !added) {
26632                state.data[name] = {
26633                    lazy : config,
26634                    added : true
26635                };
26636            } else {
26637
26638
26639                if (!added || config.isLazyAdd) {
26640
26641                    hasValue = (VALUE in config);
26642
26643
26644                    if (hasValue) {
26645
26646                        // We'll go through set, don't want to set value in config directly
26647
26648                        // PERF TODO: VALIDATE: See if setting this to undefined is sufficient. We use to delete before.
26649                        // In certain code paths/use cases, undefined may not be the same as not present.
26650                        // If not, we can set it to some known fixed value (like INVALID_VALUE, say INITIALIZING_VALUE) for performance,
26651                        // to avoid a delete which seems to help a lot.
26652
26653                        value = config.value;
26654                        config.value = undefined;
26655                    }
26656
26657                    config.added = true;
26658                    config.initializing = true;
26659
26660                    data[name] = config;
26661
26662                    if (hasValue) {
26663                        // Go through set, so that raw values get normalized/validated
26664                        host.set(name, value);
26665                    }
26666
26667                    config.initializing = false;
26668                }
26669            }
26670
26671            return host;
26672        },
26673
26674        /**
26675         * Checks if the given attribute has been added to the host
26676         *
26677         * @method attrAdded
26678         * @param {String} name The name of the attribute to check.
26679         * @return {boolean} true if an attribute with the given name has been added, false if it hasn't.
26680         *         This method will return true for lazily added attributes.
26681         */
26682        attrAdded: function(name) {
26683            return !!(this._state.get(name, ADDED));
26684        },
26685
26686        /**
26687         * Returns the current value of the attribute. If the attribute
26688         * has been configured with a 'getter' function, this method will delegate
26689         * to the 'getter' to obtain the value of the attribute.
26690         *
26691         * @method get
26692         *
26693         * @param {String} name The name of the attribute. If the value of the attribute is an Object,
26694         * dot notation can be used to obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>)
26695         *
26696         * @return {Any} The value of the attribute
26697         */
26698        get : function(name) {
26699            return this._getAttr(name);
26700        },
26701
26702        /**
26703         * Checks whether or not the attribute is one which has been
26704         * added lazily and still requires initialization.
26705         *
26706         * @method _isLazyAttr
26707         * @private
26708         * @param {String} name The name of the attribute
26709         * @return {boolean} true if it's a lazily added attribute, false otherwise.
26710         */
26711        _isLazyAttr: function(name) {
26712            return this._state.get(name, LAZY);
26713        },
26714
26715        /**
26716         * Finishes initializing an attribute which has been lazily added.
26717         *
26718         * @method _addLazyAttr
26719         * @private
26720         * @param {Object} name The name of the attribute
26721         * @param {Object} [lazyCfg] Optional config hash for the attribute. This is added for performance
26722         * along the critical path, where the calling method has already obtained lazy config from state.
26723         */
26724        _addLazyAttr: function(name, lazyCfg) {
26725            var state = this._state;
26726
26727            lazyCfg = lazyCfg || state.get(name, LAZY);
26728
26729            if (lazyCfg) {
26730
26731                // PERF TODO: For App's id override, otherwise wouldn't be
26732                // needed. It expects to find it in the cfg for it's
26733                // addAttr override. Would like to remove, once App override is
26734                // removed.
26735                state.data[name].lazy = undefined;
26736
26737                lazyCfg.isLazyAdd = true;
26738
26739                this.addAttr(name, lazyCfg);
26740            }
26741        },
26742
26743        /**
26744         * Sets the value of an attribute.
26745         *
26746         * @method set
26747         * @chainable
26748         *
26749         * @param {String} name The name of the attribute. If the
26750         * current value of the attribute is an Object, dot notation can be used
26751         * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>).
26752         * @param {Any} value The value to set the attribute to.
26753         * @param {Object} [opts] Optional data providing the circumstances for the change.
26754         * @return {Object} A reference to the host object.
26755         */
26756        set : function(name, val, opts) {
26757            return this._setAttr(name, val, opts);
26758        },
26759
26760        /**
26761         * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details.
26762         *
26763         * @method _set
26764         * @protected
26765         * @chainable
26766         *
26767         * @param {String} name The name of the attribute.
26768         * @param {Any} val The value to set the attribute to.
26769         * @param {Object} [opts] Optional data providing the circumstances for the change.
26770         * @return {Object} A reference to the host object.
26771         */
26772        _set : function(name, val, opts) {
26773            return this._setAttr(name, val, opts, true);
26774        },
26775
26776        /**
26777         * Provides the common implementation for the public set and protected _set methods.
26778         *
26779         * See <a href="#method_set">set</a> for argument details.
26780         *
26781         * @method _setAttr
26782         * @protected
26783         * @chainable
26784         *
26785         * @param {String} name The name of the attribute.
26786         * @param {Any} value The value to set the attribute to.
26787         * @param {Object} [opts] Optional data providing the circumstances for the change.
26788         * @param {boolean} force If true, allows the caller to set values for
26789         * readOnly or writeOnce attributes which have already been set.
26790         *
26791         * @return {Object} A reference to the host object.
26792         */
26793        _setAttr : function(name, val, opts, force)  {
26794            var allowSet = true,
26795                state = this._state,
26796                stateProxy = this._stateProxy,
26797                tCfgs = this._tCfgs,
26798                cfg,
26799                initialSet,
26800                strPath,
26801                path,
26802                currVal,
26803                writeOnce,
26804                initializing;
26805
26806            if (name.indexOf(DOT) !== -1) {
26807                strPath = name;
26808
26809                path = name.split(DOT);
26810                name = path.shift();
26811            }
26812
26813            // On Demand - Should be rare - handles out of order valueFn, setter, getter references
26814            if (tCfgs && tCfgs[name]) {
26815                this._addOutOfOrder(name, tCfgs[name]);
26816            }
26817
26818            cfg = state.data[name] || {};
26819
26820            if (cfg.lazy) {
26821                cfg = cfg.lazy;
26822                this._addLazyAttr(name, cfg);
26823            }
26824
26825            initialSet = (cfg.value === undefined);
26826
26827            if (stateProxy && name in stateProxy && !cfg._bypassProxy) {
26828                // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set?
26829                initialSet = false;
26830            }
26831
26832            writeOnce = cfg.writeOnce;
26833            initializing = cfg.initializing;
26834
26835            if (!initialSet && !force) {
26836
26837                if (writeOnce) {
26838                    allowSet = false;
26839                }
26840
26841                if (cfg.readOnly) {
26842                    allowSet = false;
26843                }
26844            }
26845
26846            if (!initializing && !force && writeOnce === INIT_ONLY) {
26847                allowSet = false;
26848            }
26849
26850            if (allowSet) {
26851                // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
26852                if (!initialSet) {
26853                    currVal =  this.get(name);
26854                }
26855
26856                if (path) {
26857                   val = O.setValue(Y.clone(currVal), path, val);
26858
26859                   if (val === undefined) {
26860                       allowSet = false;
26861                   }
26862                }
26863
26864                if (allowSet) {
26865                    if (!this._fireAttrChange || initializing) {
26866                        this._setAttrVal(name, strPath, currVal, val, opts, cfg);
26867                    } else {
26868                        // HACK - no real reason core needs to know about _fireAttrChange, but
26869                        // it adds fn hops if we want to break it out. Not sure it's worth it for this critical path
26870                        this._fireAttrChange(name, strPath, currVal, val, opts, cfg);
26871                    }
26872                }
26873            }
26874
26875            return this;
26876        },
26877
26878        /**
26879         * Utility method used by get/set to add attributes
26880         * encountered out of order when calling addAttrs().
26881         *
26882         * For example, if:
26883         *
26884         *     this.addAttrs({
26885         *          foo: {
26886         *              setter: function() {
26887         *                 // make sure this bar is available when foo is added
26888         *                 this.get("bar");
26889         *              }
26890         *          },
26891         *          bar: {
26892         *              value: ...
26893         *          }
26894         *     });
26895         *
26896         * @method _addOutOfOrder
26897         * @private
26898         * @param name {String} attribute name
26899         * @param cfg {Object} attribute configuration
26900         */
26901        _addOutOfOrder : function(name, cfg) {
26902
26903            var attrs = {};
26904            attrs[name] = cfg;
26905
26906            delete this._tCfgs[name];
26907
26908            // TODO: The original code went through addAttrs, so
26909            // sticking with it for this pass. Seems like we could
26910            // just jump straight to _addAttr() and get some perf
26911            // improvement.
26912            this._addAttrs(attrs, this._tVals);
26913        },
26914
26915        /**
26916         * Provides the common implementation for the public get method,
26917         * allowing Attribute hosts to over-ride either method.
26918         *
26919         * See <a href="#method_get">get</a> for argument details.
26920         *
26921         * @method _getAttr
26922         * @protected
26923         * @chainable
26924         *
26925         * @param {String} name The name of the attribute.
26926         * @return {Any} The value of the attribute.
26927         */
26928        _getAttr : function(name) {
26929            var fullName = name,
26930                tCfgs = this._tCfgs,
26931                path,
26932                getter,
26933                val,
26934                attrCfg;
26935
26936            if (name.indexOf(DOT) !== -1) {
26937                path = name.split(DOT);
26938                name = path.shift();
26939            }
26940
26941            // On Demand - Should be rare - handles out of
26942            // order valueFn, setter, getter references
26943            if (tCfgs && tCfgs[name]) {
26944                this._addOutOfOrder(name, tCfgs[name]);
26945            }
26946
26947            attrCfg = this._state.data[name] || {};
26948
26949            // Lazy Init
26950            if (attrCfg.lazy) {
26951                attrCfg = attrCfg.lazy;
26952                this._addLazyAttr(name, attrCfg);
26953            }
26954
26955            val = this._getStateVal(name, attrCfg);
26956
26957            getter = attrCfg.getter;
26958
26959            if (getter && !getter.call) {
26960                getter = this[getter];
26961            }
26962
26963            val = (getter) ? getter.call(this, val, fullName) : val;
26964            val = (path) ? O.getValue(val, path) : val;
26965
26966            return val;
26967        },
26968
26969        /**
26970         * Gets the stored value for the attribute, from either the
26971         * internal state object, or the state proxy if it exits
26972         *
26973         * @method _getStateVal
26974         * @private
26975         * @param {String} name The name of the attribute
26976         * @param {Object} [cfg] Optional config hash for the attribute. This is added for performance along the critical path,
26977         * where the calling method has already obtained the config from state.
26978         *
26979         * @return {Any} The stored value of the attribute
26980         */
26981        _getStateVal : function(name, cfg) {
26982            var stateProxy = this._stateProxy;
26983
26984            if (!cfg) {
26985                cfg = this._state.getAll(name) || {};
26986            }
26987
26988            return (stateProxy && (name in stateProxy) && !(cfg._bypassProxy)) ? stateProxy[name] : cfg.value;
26989        },
26990
26991        /**
26992         * Sets the stored value for the attribute, in either the
26993         * internal state object, or the state proxy if it exits
26994         *
26995         * @method _setStateVal
26996         * @private
26997         * @param {String} name The name of the attribute
26998         * @param {Any} value The value of the attribute
26999         */
27000        _setStateVal : function(name, value) {
27001            var stateProxy = this._stateProxy;
27002            if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
27003                stateProxy[name] = value;
27004            } else {
27005                this._state.add(name, VALUE, value);
27006            }
27007        },
27008
27009        /**
27010         * Updates the stored value of the attribute in the privately held State object,
27011         * if validation and setter passes.
27012         *
27013         * @method _setAttrVal
27014         * @private
27015         * @param {String} attrName The attribute name.
27016         * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
27017         * @param {Any} prevVal The currently stored value of the attribute.
27018         * @param {Any} newVal The value which is going to be stored.
27019         * @param {Object} [opts] Optional data providing the circumstances for the change.
27020         * @param {Object} [attrCfg] Optional config hash for the attribute. This is added for performance along the critical path,
27021         * where the calling method has already obtained the config from state.
27022         *
27023         * @return {Boolean} true if the new attribute value was stored, false if not.
27024         */
27025        _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts, attrCfg) {
27026
27027            var host = this,
27028                allowSet = true,
27029                cfg = attrCfg || this._state.data[attrName] || {},
27030                validator = cfg.validator,
27031                setter = cfg.setter,
27032                initializing = cfg.initializing,
27033                prevRawVal = this._getStateVal(attrName, cfg),
27034                name = subAttrName || attrName,
27035                retVal,
27036                valid;
27037
27038            if (validator) {
27039                if (!validator.call) {
27040                    // Assume string - trying to keep critical path tight, so avoiding Lang check
27041                    validator = this[validator];
27042                }
27043                if (validator) {
27044                    valid = validator.call(host, newVal, name, opts);
27045
27046                    if (!valid && initializing) {
27047                        newVal = cfg.defaultValue;
27048                        valid = true; // Assume it's valid, for perf.
27049                    }
27050                }
27051            }
27052
27053            if (!validator || valid) {
27054                if (setter) {
27055                    if (!setter.call) {
27056                        // Assume string - trying to keep critical path tight, so avoiding Lang check
27057                        setter = this[setter];
27058                    }
27059                    if (setter) {
27060                        retVal = setter.call(host, newVal, name, opts);
27061
27062                        if (retVal === INVALID_VALUE) {
27063                            if (initializing) {
27064                                newVal = cfg.defaultValue;
27065                            } else {
27066                                allowSet = false;
27067                            }
27068                        } else if (retVal !== undefined){
27069                            newVal = retVal;
27070                        }
27071                    }
27072                }
27073
27074                if (allowSet) {
27075                    if(!subAttrName && (newVal === prevRawVal) && !Lang.isObject(newVal)) {
27076                        allowSet = false;
27077                    } else {
27078                        // Store value
27079                        if (!(INIT_VALUE in cfg)) {
27080                            cfg.initValue = newVal;
27081                        }
27082                        host._setStateVal(attrName, newVal);
27083                    }
27084                }
27085
27086            } else {
27087                allowSet = false;
27088            }
27089
27090            return allowSet;
27091        },
27092
27093        /**
27094         * Sets multiple attribute values.
27095         *
27096         * @method setAttrs
27097         * @param {Object} attrs  An object with attributes name/value pairs.
27098         * @param {Object} [opts] Optional data providing the circumstances for the change.
27099         * @return {Object} A reference to the host object.
27100         * @chainable
27101         */
27102        setAttrs : function(attrs, opts) {
27103            return this._setAttrs(attrs, opts);
27104        },
27105
27106        /**
27107         * Implementation behind the public setAttrs method, to set multiple attribute values.
27108         *
27109         * @method _setAttrs
27110         * @protected
27111         * @param {Object} attrs  An object with attributes name/value pairs.
27112         * @param {Object} [opts] Optional data providing the circumstances for the change
27113         * @return {Object} A reference to the host object.
27114         * @chainable
27115         */
27116        _setAttrs : function(attrs, opts) {
27117            var attr;
27118            for (attr in attrs) {
27119                if ( attrs.hasOwnProperty(attr) ) {
27120                    this.set(attr, attrs[attr], opts);
27121                }
27122            }
27123            return this;
27124        },
27125
27126        /**
27127         * Gets multiple attribute values.
27128         *
27129         * @method getAttrs
27130         * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
27131         * returned. If set to true, all attributes modified from their initial values are returned.
27132         * @return {Object} An object with attribute name/value pairs.
27133         */
27134        getAttrs : function(attrs) {
27135            return this._getAttrs(attrs);
27136        },
27137
27138        /**
27139         * Implementation behind the public getAttrs method, to get multiple attribute values.
27140         *
27141         * @method _getAttrs
27142         * @protected
27143         * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
27144         * returned. If set to true, all attributes modified from their initial values are returned.
27145         * @return {Object} An object with attribute name/value pairs.
27146         */
27147        _getAttrs : function(attrs) {
27148            var obj = {},
27149                attr, i, len,
27150                modifiedOnly = (attrs === true);
27151
27152            // TODO - figure out how to get all "added"
27153            if (!attrs || modifiedOnly) {
27154                attrs = O.keys(this._state.data);
27155            }
27156
27157            for (i = 0, len = attrs.length; i < len; i++) {
27158                attr = attrs[i];
27159
27160                if (!modifiedOnly || this._getStateVal(attr) != this._state.get(attr, INIT_VALUE)) {
27161                    // Go through get, to honor cloning/normalization
27162                    obj[attr] = this.get(attr);
27163                }
27164            }
27165
27166            return obj;
27167        },
27168
27169        /**
27170         * Configures a group of attributes, and sets initial values.
27171         *
27172         * <p>
27173         * <strong>NOTE:</strong> This method does not isolate the configuration object by merging/cloning.
27174         * The caller is responsible for merging/cloning the configuration object if required.
27175         * </p>
27176         *
27177         * @method addAttrs
27178         * @chainable
27179         *
27180         * @param {Object} cfgs An object with attribute name/configuration pairs.
27181         * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
27182         * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
27183         * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
27184         * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
27185         * See <a href="#method_addAttr">addAttr</a>.
27186         *
27187         * @return {Object} A reference to the host object.
27188         */
27189        addAttrs : function(cfgs, values, lazy) {
27190            if (cfgs) {
27191                this._tCfgs = cfgs;
27192                this._tVals = (values) ? this._normAttrVals(values) : null;
27193                this._addAttrs(cfgs, this._tVals, lazy);
27194                this._tCfgs = this._tVals = null;
27195            }
27196
27197            return this;
27198        },
27199
27200        /**
27201         * Implementation behind the public addAttrs method.
27202         *
27203         * This method is invoked directly by get if it encounters a scenario
27204         * in which an attribute's valueFn attempts to obtain the
27205         * value an attribute in the same group of attributes, which has not yet
27206         * been added (on demand initialization).
27207         *
27208         * @method _addAttrs
27209         * @private
27210         * @param {Object} cfgs An object with attribute name/configuration pairs.
27211         * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
27212         * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
27213         * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
27214         * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
27215         * See <a href="#method_addAttr">addAttr</a>.
27216         */
27217        _addAttrs : function(cfgs, values, lazy) {
27218            var tCfgs = this._tCfgs,
27219                tVals = this._tVals,
27220                attr,
27221                attrCfg,
27222                value;
27223
27224            for (attr in cfgs) {
27225                if (cfgs.hasOwnProperty(attr)) {
27226
27227                    // Not Merging. Caller is responsible for isolating configs
27228                    attrCfg = cfgs[attr];
27229                    attrCfg.defaultValue = attrCfg.value;
27230
27231                    // Handle simple, complex and user values, accounting for read-only
27232                    value = this._getAttrInitVal(attr, attrCfg, tVals);
27233
27234                    if (value !== undefined) {
27235                        attrCfg.value = value;
27236                    }
27237
27238                    if (tCfgs[attr]) {
27239                        tCfgs[attr] = undefined;
27240                    }
27241
27242                    this.addAttr(attr, attrCfg, lazy);
27243                }
27244            }
27245        },
27246
27247        /**
27248         * Utility method to protect an attribute configuration
27249         * hash, by merging the entire object and the individual
27250         * attr config objects.
27251         *
27252         * @method _protectAttrs
27253         * @protected
27254         * @param {Object} attrs A hash of attribute to configuration object pairs.
27255         * @return {Object} A protected version of the attrs argument.
27256         * @deprecated Use `AttributeCore.protectAttrs()` or
27257         *   `Attribute.protectAttrs()` which are the same static utility method.
27258         */
27259        _protectAttrs : AttributeCore.protectAttrs,
27260
27261        /**
27262         * Utility method to normalize attribute values. The base implementation
27263         * simply merges the hash to protect the original.
27264         *
27265         * @method _normAttrVals
27266         * @param {Object} valueHash An object with attribute name/value pairs
27267         *
27268         * @return {Object} An object literal with 2 properties - "simple" and "complex",
27269         * containing simple and complex attribute values respectively keyed
27270         * by the top level attribute name, or null, if valueHash is falsey.
27271         *
27272         * @private
27273         */
27274        _normAttrVals : function(valueHash) {
27275            var vals,
27276                subvals,
27277                path,
27278                attr,
27279                v, k;
27280
27281            if (!valueHash) {
27282                return null;
27283            }
27284
27285            vals = {};
27286
27287            for (k in valueHash) {
27288                if (valueHash.hasOwnProperty(k)) {
27289                    if (k.indexOf(DOT) !== -1) {
27290                        path = k.split(DOT);
27291                        attr = path.shift();
27292
27293                        subvals = subvals || {};
27294
27295                        v = subvals[attr] = subvals[attr] || [];
27296                        v[v.length] = {
27297                            path : path,
27298                            value: valueHash[k]
27299                        };
27300                    } else {
27301                        vals[k] = valueHash[k];
27302                    }
27303                }
27304            }
27305
27306            return { simple:vals, complex:subvals };
27307        },
27308
27309        /**
27310         * Returns the initial value of the given attribute from
27311         * either the default configuration provided, or the
27312         * over-ridden value if it exists in the set of initValues
27313         * provided and the attribute is not read-only.
27314         *
27315         * @param {String} attr The name of the attribute
27316         * @param {Object} cfg The attribute configuration object
27317         * @param {Object}
27317 initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
27318         *
27319         * @return {Any} The initial value of the attribute.
27320         *
27321         * @method _getAttrInitVal
27322         * @private
27323         */
27324        _getAttrInitVal : function(attr, cfg, initValues) {
27325            var val = cfg.value,
27326                valFn = cfg.valueFn,
27327                tmpVal,
27328                initValSet = false,
27329                readOnly = cfg.readOnly,
27330                simple,
27331                complex,
27332                i,
27333                l,
27334                path,
27335                subval,
27336                subvals;
27337
27338            if (!readOnly && initValues) {
27339                // Simple Attributes
27340                simple = initValues.simple;
27341                if (simple && simple.hasOwnProperty(attr)) {
27342                    val = simple[attr];
27343                    initValSet = true;
27344                }
27345            }
27346
27347            if (valFn && !initValSet) {
27348                if (!valFn.call) {
27349                    valFn = this[valFn];
27350                }
27351                if (valFn) {
27352                    tmpVal = valFn.call(this, attr);
27353                    val = tmpVal;
27354                }
27355            }
27356
27357            if (!readOnly && initValues) {
27358
27359                // Complex Attributes (complex values applied, after simple, in case both are set)
27360                complex = initValues.complex;
27361
27362                if (complex && complex.hasOwnProperty(attr) && (val !== undefined) && (val !== null)) {
27363                    subvals = complex[attr];
27364                    for (i = 0, l = subvals.length; i < l; ++i) {
27365                        path = subvals[i].path;
27366                        subval = subvals[i].value;
27367                        O.setValue(val, path, subval);
27368                    }
27369                }
27370            }
27371
27372            return val;
27373        },
27374
27375        /**
27376         * Utility method to set up initial attributes defined during construction,
27377         * either through the constructor.ATTRS property, or explicitly passed in.
27378         *
27379         * @method _initAttrs
27380         * @protected
27381         * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
27382         *        These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
27383         * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
27384         *        These are not merged/cloned. The caller is responsible for isolating user provided values if required.
27385         * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
27386         */
27387        _initAttrs : function(attrs, values, lazy) {
27388            // ATTRS support for Node, which is not Base based
27389            attrs = attrs || this.constructor.ATTRS;
27390
27391            var Base = Y.Base,
27392                BaseCore = Y.BaseCore,
27393                baseInst = (Base && Y.instanceOf(this, Base)),
27394                baseCoreInst = (!baseInst && BaseCore && Y.instanceOf(this, BaseCore));
27395
27396            if (attrs && !baseInst && !baseCoreInst) {
27397                this.addAttrs(Y.AttributeCore.protectAttrs(attrs), values, lazy);
27398            }
27399        }
27400    };
27401
27402    Y.AttributeCore = AttributeCore;
27403
27404
27405}, '3.18.1', {"requires": ["oop"]});
27406YUI.add('event-custom-complex', function (Y, NAME) {
27407
27408
27409/**
27410 * Adds event facades, preventable default behavior, and bubbling.
27411 * events.
27412 * @module event-custom
27413 * @submodule event-custom-complex
27414 */
27415
27416var FACADE,
27417    FACADE_KEYS,
27418    YObject = Y.Object,
27419    key,
27420    EMPTY = {},
27421    CEProto = Y.CustomEvent.prototype,
27422    ETProto = Y.EventTarget.prototype,
27423
27424    mixFacadeProps = function(facade, payload) {
27425        var p;
27426
27427        for (p in payload) {
27428            if (!(FACADE_KEYS.hasOwnProperty(p))) {
27429                facade[p] = payload[p];
27430            }
27431        }
27432    };
27433
27434/**
27435 * Wraps and protects a custom event for use when emitFacade is set to true.
27436 * Requires the event-custom-complex module
27437 * @class EventFacade
27438 * @param e {Event} the custom event
27439 * @param currentTarget {HTMLElement} the element the listener was attached to
27440 */
27441
27442Y.EventFacade = function(e, currentTarget) {
27443
27444    if (!e) {
27445        e = EMPTY;
27446    }
27447
27448    this._event = e;
27449
27450    /**
27451     * The arguments passed to fire
27452     * @property details
27453     * @type Array
27454     */
27455    this.details = e.details;
27456
27457    /**
27458     * The event type, this can be overridden by the fire() payload
27459     * @property type
27460     * @type string
27461     */
27462    this.type = e.type;
27463
27464    /**
27465     * The real event type
27466     * @property _type
27467     * @type string
27468     * @private
27469     */
27470    this._type = e.type;
27471
27472    //////////////////////////////////////////////////////
27473
27474    /**
27475     * Node reference for the targeted eventtarget
27476     * @property target
27477     * @type Node
27478     */
27479    this.target = e.target;
27480
27481    /**
27482     * Node reference for the element that the listener was attached to.
27483     * @property currentTarget
27484     * @type Node
27485     */
27486    this.currentTarget = currentTarget;
27487
27488    /**
27489     * Node reference to the relatedTarget
27490     * @property relatedTarget
27491     * @type Node
27492     */
27493    this.relatedTarget = e.relatedTarget;
27494
27495};
27496
27497Y.mix(Y.EventFacade.prototype, {
27498
27499    /**
27500     * Stops the propagation to the next bubble target
27501     * @method stopPropagation
27502     */
27503    stopPropagation: function() {
27504        this._event.stopPropagation();
27505        this.stopped = 1;
27506    },
27507
27508    /**
27509     * Stops the propagation to the next bubble target and
27510     * prevents any additional listeners from being exectued
27511     * on the current target.
27512     * @method stopImmediatePropagation
27513     */
27514    stopImmediatePropagation: function() {
27515        this._event.stopImmediatePropagation();
27516        this.stopped = 2;
27517    },
27518
27519    /**
27520     * Prevents the event's default behavior
27521     * @method preventDefault
27522     */
27523    preventDefault: function() {
27524        this._event.preventDefault();
27525        this.prevented = 1;
27526    },
27527
27528    /**
27529     * Stops the event propagation and prevents the default
27530     * event behavior.
27531     * @method halt
27532     * @param immediate {boolean} if true additional listeners
27533     * on the current target will not be executed
27534     */
27535    halt: function(immediate) {
27536        this._event.halt(immediate);
27537        this.prevented = 1;
27538        this.stopped = (immediate) ? 2 : 1;
27539    }
27540
27541});
27542
27543CEProto.fireComplex = function(args) {
27544
27545    var es,
27546        ef,
27547        q,
27548        queue,
27549        ce,
27550        ret = true,
27551        events,
27552        subs,
27553        ons,
27554        afters,
27555        afterQueue,
27556        postponed,
27557        prevented,
27558        preventedFn,
27559        defaultFn,
27560        self = this,
27561        host = self.host || self,
27562        next,
27563        oldbubble,
27564        stack = self.stack,
27565        yuievt = host._yuievt,
27566        hasPotentialSubscribers;
27567
27568    if (stack) {
27569
27570        // queue this event if the current item in the queue bubbles
27571        if (self.queuable && self.type !== stack.next.type) {
27572
27573            if (!stack.queue) {
27574                stack.queue = [];
27575            }
27576            stack.queue.push([self, args]);
27577
27578            return true;
27579        }
27580    }
27581
27582    hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast;
27583
27584    self.target = self.target || host;
27585    self.currentTarget = host;
27586
27587    self.details = args.concat();
27588
27589    if (hasPotentialSubscribers) {
27590
27591        es = stack || {
27592
27593           id: self.id, // id of the first event in the stack
27594           next: self,
27595           silent: self.silent,
27596           stopped: 0,
27597           prevented: 0,
27598           bubbling: null,
27599           type: self.type,
27600           // defaultFnQueue: new Y.Queue(),
27601           defaultTargetOnly: self.defaultTargetOnly
27602
27603        };
27604
27605        subs = self.getSubs();
27606        ons = subs[0];
27607        afters = subs[1];
27608
27609        self.stopped = (self.type !== es.type) ? 0 : es.stopped;
27610        self.prevented = (self.type !== es.type) ? 0 : es.prevented;
27611
27612        if (self.stoppedFn) {
27613            // PERF TODO: Can we replace with callback, like preventedFn. Look into history
27614            events = new Y.EventTarget({
27615                fireOnce: true,
27616                context: host
27617            });
27618            self.events = events;
27619            events.on('stopped', self.stoppedFn);
27620        }
27621
27622
27623        self._facade = null; // kill facade to eliminate stale properties
27624
27625        ef = self._createFacade(args);
27626
27627        if (ons) {
27628            self._procSubs(ons, args, ef);
27629        }
27630
27631        // bubble if this is hosted in an event target and propagation has not been stopped
27632        if (self.bubbles && host.bubble && !self.stopped) {
27633            oldbubble = es.bubbling;
27634
27635            es.bubbling = self.type;
27636
27637            if (es.type !== self.type) {
27638                es.stopped = 0;
27639                es.prevented = 0;
27640            }
27641
27642            ret = host.bubble(self, args, null, es);
27643
27644            self.stopped = Math.max(self.stopped, es.stopped);
27645            self.prevented = Math.max(self.prevented, es.prevented);
27646
27647            es.bubbling = oldbubble;
27648        }
27649
27650        prevented = self.prevented;
27651
27652        if (prevented) {
27653            preventedFn = self.preventedFn;
27654            if (preventedFn) {
27655                preventedFn.apply(host, args);
27656            }
27657        } else {
27658            defaultFn = self.defaultFn;
27659
27660            if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) {
27661                defaultFn.apply(host, args);
27662            }
27663        }
27664
27665        // broadcast listeners are fired as discreet events on the
27666        // YUI instance and potentially the YUI global.
27667        if (self.broadcast) {
27668            self._broadcast(args);
27669        }
27670
27671        if (afters && !self.prevented && self.stopped < 2) {
27672
27673            // Queue the after
27674            afterQueue = es.afterQueue;
27675
27676            if (es.id === self.id || self.type !== yuievt.bubbling) {
27677
27678                self._procSubs(afters, args, ef);
27679
27680                if (afterQueue) {
27681                    while ((next = afterQueue.last())) {
27682                        next();
27683                    }
27684                }
27685            } else {
27686                postponed = afters;
27687
27688                if (es.execDefaultCnt) {
27689                    postponed = Y.merge(postponed);
27690
27691                    Y.each(postponed, function(s) {
27692                        s.postponed = true;
27693                    });
27694                }
27695
27696                if (!afterQueue) {
27697                    es.afterQueue = new Y.Queue();
27698                }
27699
27700                es.afterQueue.add(function() {
27701                    self._procSubs(postponed, args, ef);
27702                });
27703            }
27704
27705        }
27706
27707        self.target = null;
27708
27709        if (es.id === self.id) {
27710
27711            queue = es.queue;
27712
27713            if (queue) {
27714                while (queue.length) {
27715                    q = queue.pop();
27716                    ce = q[0];
27717                    // set up stack to allow the next item to be processed
27718                    es.next = ce;
27719                    ce._fire(q[1]);
27720                }
27721            }
27722
27723            self.stack = null;
27724        }
27725
27726        ret = !(self.stopped);
27727
27728        if (self.type !== yuievt.bubbling) {
27729            es.stopped = 0;
27730            es.prevented = 0;
27731            self.stopped = 0;
27732            self.prevented = 0;
27733        }
27734
27735    } else {
27736        defaultFn = self.defaultFn;
27737
27738        if(defaultFn) {
27739            ef = self._createFacade(args);
27740
27741            if ((!self.defaultTargetOnly) || (host === ef.target)) {
27742                defaultFn.apply(host, args);
27743            }
27744        }
27745    }
27746
27747    // Kill the cached facade to free up memory.
27748    // Otherwise we have the facade from the last fire, sitting around forever.
27749    self._facade = null;
27750
27751    return ret;
27752};
27753
27754/**
27755 * @method _hasPotentialSubscribers
27756 * @for CustomEvent
27757 * @private
27758 * @return {boolean} Whether the event has potential subscribers or not
27759 */
27760CEProto._hasPotentialSubscribers = function() {
27761    return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast;
27762};
27763
27764/**
27765 * Internal utility method to create a new facade instance and
27766 * insert it into the fire argument list, accounting for any payload
27767 * merging which needs to happen.
27768 *
27769 * This used to be called `_getFacade`, but the name seemed inappropriate
27770 * when it was used without a need for the return value.
27771 *
27772 * @method _createFacade
27773 * @private
27774 * @param fireArgs {Array} The arguments passed to "fire", which need to be
27775 * shifted (and potentially merged) when the facade is added.
27776 * @return {EventFacade} The event facade created.
27777 */
27778
27779// TODO: Remove (private) _getFacade alias, once synthetic.js is updated.
27780CEProto._createFacade = CEProto._getFacade = function(fireArgs) {
27781
27782    var userArgs = this.details,
27783        firstArg = userArgs && userArgs[0],
27784        firstArgIsObj = (firstArg && (typeof firstArg === "object")),
27785        ef = this._facade;
27786
27787    if (!ef) {
27788        ef = new Y.EventFacade(this, this.currentTarget);
27789    }
27790
27791    if (firstArgIsObj) {
27792        // protect the event facade properties
27793        mixFacadeProps(ef, firstArg);
27794
27795        // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376
27796        if (firstArg.type) {
27797            ef.type = firstArg.type;
27798        }
27799
27800        if (fireArgs) {
27801            fireArgs[0] = ef;
27802        }
27803    } else {
27804        if (fireArgs) {
27805            fireArgs.unshift(ef);
27806        }
27807    }
27808
27809    // update the details field with the arguments
27810    ef.details = this.details;
27811
27812    // use the original target when the event bubbled to this target
27813    ef.target = this.originalTarget || this.target;
27814
27815    ef.currentTarget = this.currentTarget;
27816    ef.stopped = 0;
27817    ef.prevented = 0;
27818
27819    this._facade = ef;
27820
27821    return this._facade;
27822};
27823
27824/**
27825 * Utility method to manipulate the args array passed in, to add the event facade,
27826 * if it's not already the first arg.
27827 *
27828 * @method _addFacadeToArgs
27829 * @private
27830 * @param {Array} The arguments to manipulate
27831 */
27832CEProto._addFacadeToArgs = function(args) {
27833    var e = args[0];
27834
27835    // Trying not to use instanceof, just to avoid potential cross Y edge case issues.
27836    if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) {
27837        this._createFacade(args);
27838    }
27839};
27840
27841/**
27842 * Stop propagation to bubble targets
27843 * @for CustomEvent
27844 * @method stopPropagation
27845 */
27846CEProto.stopPropagation = function() {
27847    this.stopped = 1;
27848    if (this.stack) {
27849        this.stack.stopped = 1;
27850    }
27851    if (this.events) {
27852        this.events.fire('stopped', this);
27853    }
27854};
27855
27856/**
27857 * Stops propagation to bubble targets, and prevents any remaining
27858 * subscribers on the current target from executing.
27859 * @method stopImmediatePropagation
27860 */
27861CEProto.stopImmediatePropagation = function() {
27862    this.stopped = 2;
27863    if (this.stack) {
27864        this.stack.stopped = 2;
27865    }
27866    if (this.events) {
27867        this.events.fire('stopped', this);
27868    }
27869};
27870
27871/**
27872 * Prevents the execution of this event's defaultFn
27873 * @method preventDefault
27874 */
27875CEProto.preventDefault = function() {
27876    if (this.preventable) {
27877        this.prevented = 1;
27878        if (this.stack) {
27879            this.stack.prevented = 1;
27880        }
27881    }
27882};
27883
27884/**
27885 * Stops the event propagation and prevents the default
27886 * event behavior.
27887 * @method halt
27888 * @param immediate {boolean} if true additional listeners
27889 * on the current target will not be executed
27890 */
27891CEProto.halt = function(immediate) {
27892    if (immediate) {
27893        this.stopImmediatePropagation();
27894    } else {
27895        this.stopPropagation();
27896    }
27897    this.preventDefault();
27898};
27899
27900/**
27901 * Registers another EventTarget as a bubble target.  Bubble order
27902 * is determined by the order registered.  Multiple targets can
27903 * be specified.
27904 *
27905 * Events can only bubble if emitFacade is true.
27906 *
27907 * Included in the event-custom-complex submodule.
27908 *
27909 * @method addTarget
27910 * @chainable
27911 * @param o {EventTarget} the target to add
27912 * @for EventTarget
27913 */
27914ETProto.addTarget = function(o) {
27915    var etState = this._yuievt;
27916
27917    if (!etState.targets) {
27918        etState.targets = {};
27919    }
27920
27921    etState.targets[Y.stamp(o)] = o;
27922    etState.hasTargets = true;
27923
27924    return this;
27925};
27926
27927/**
27928 * Returns an array of bubble targets for this object.
27929 * @method getTargets
27930 * @return EventTarget[]
27931 */
27932ETProto.getTargets = function() {
27933    var targets = this._yuievt.targets;
27934    return targets ? YObject.values(targets) : [];
27935};
27936
27937/**
27938 * Removes a bubble target
27939 * @method removeTarget
27940 * @chainable
27941 * @param o {EventTarget} the target to remove
27942 * @for EventTarget
27943 */
27944ETProto.removeTarget = function(o) {
27945    var targets = this._yuievt.targets;
27946
27947    if (targets) {
27948        delete targets[Y.stamp(o, true)];
27949
27950        if (YObject.size(targets) === 0) {
27951            this._yuievt.hasTargets = false;
27952        }
27953    }
27954
27955    return this;
27956};
27957
27958/**
27959 * Propagate an event.  Requires the event-custom-complex module.
27960 * @method bubble
27961 * @param evt {CustomEvent} the custom event to propagate
27962 * @return {boolean} the aggregated return value from Event.Custom.fire
27963 * @for EventTarget
27964 */
27965ETProto.bubble = function(evt, args, target, es) {
27966
27967    var targs = this._yuievt.targets,
27968        ret = true,
27969        t,
27970        ce,
27971        i,
27972        bc,
27973        ce2,
27974        type = evt && evt.type,
27975        originalTarget = target || (evt && evt.target) || this,
27976        oldbubble;
27977
27978    if (!evt || ((!evt.stopped) && targs)) {
27979
27980        for (i in targs) {
27981            if (targs.hasOwnProperty(i)) {
27982
27983                t = targs[i];
27984
27985                ce = t._yuievt.events[type];
27986
27987                if (t._hasSiblings) {
27988                    ce2 = t.getSibling(type, ce);
27989                }
27990
27991                if (ce2 && !ce) {
27992                    ce = t.publish(type);
27993                }
27994
27995                oldbubble = t._yuievt.bubbling;
27996                t._yuievt.bubbling = type;
27997
27998                // if this event was not published on the bubble target,
27999                // continue propagating the event.
28000                if (!ce) {
28001                    if (t._yuievt.hasTargets) {
28002                        t.bubble(evt, args, originalTarget, es);
28003                    }
28004                } else {
28005
28006                    if (ce2) {
28007                        ce.sibling = ce2;
28008                    }
28009
28010                    // set the original target to that the target payload on the facade is correct.
28011                    ce.target = originalTarget;
28012                    ce.originalTarget = originalTarget;
28013                    ce.currentTarget = t;
28014                    bc = ce.broadcast;
28015                    ce.broadcast = false;
28016
28017                    // default publish may not have emitFacade true -- that
28018                    // shouldn't be what the implementer meant to do
28019                    ce.emitFacade = true;
28020
28021                    ce.stack = es;
28022
28023                    // TODO: See what's getting in the way of changing this to use
28024                    // the more performant ce._fire(args || evt.details || []).
28025
28026                    // Something in Widget Parent/Child tests is not happy if we
28027                    // change it - maybe evt.details related?
28028                    ret = ret && ce.fire.apply(ce, args || evt.details || []);
28029
28030                    ce.broadcast = bc;
28031                    ce.originalTarget = null;
28032
28033                    // stopPropagation() was called
28034                    if (ce.stopped) {
28035                        break;
28036                    }
28037                }
28038
28039                t._yuievt.bubbling = oldbubble;
28040            }
28041        }
28042    }
28043
28044    return ret;
28045};
28046
28047/**
28048 * @method _hasPotentialSubscribers
28049 * @for EventTarget
28050 * @private
28051 * @param {String} fullType The fully prefixed type name
28052 * @return {boolean} Whether the event has potential subscribers or not
28053 */
28054ETProto._hasPotentialSubscribers = function(fullType) {
28055
28056    var etState = this._yuievt,
28057        e = etState.events[fullType];
28058
28059    if (e) {
28060        return e.hasSubs() || etState.hasTargets  || e.broadcast;
28061    } else {
28062        return false;
28063    }
28064};
28065
28066FACADE = new Y.EventFacade();
28067FACADE_KEYS = {};
28068
28069// Flatten whitelist
28070for (key in FACADE) {
28071    FACADE_KEYS[key] = true;
28072}
28073
28074
28075}, '3.18.1', {"requires": ["event-custom-base"]});
28076YUI.add('base-core', function (Y, NAME) {
28077
28078    /**
28079     * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
28080     * The module also provides two ways to reuse code - It augments Base with the Plugin.Host interface which provides
28081     * plugin support and also provides the BaseCore.build method which provides a way to build custom classes using extensions.
28082     *
28083     * @module base
28084     */
28085
28086    /**
28087     * <p>The base-core module provides the BaseCore class, the lightest version of Base,
28088     * which provides Base's basic lifecycle management and ATTRS construction support,
28089     * but doesn't fire init/destroy or attribute change events.</p>
28090     *
28091     * <p>It mixes in AttributeCore, which is the lightest version of Attribute</p>
28092     *
28093     * @module base
28094     * @submodule base-core
28095     */
28096    var O = Y.Object,
28097        L = Y.Lang,
28098        DOT = ".",
28099        INITIALIZED = "initialized",
28100        DESTROYED = "destroyed",
28101        INITIALIZER = "initializer",
28102        VALUE = "value",
28103        OBJECT_CONSTRUCTOR = Object.prototype.constructor,
28104        DEEP = "deep",
28105        SHALLOW = "shallow",
28106        DESTRUCTOR = "destructor",
28107
28108        AttributeCore = Y.AttributeCore,
28109
28110        _wlmix = function(r, s, wlhash) {
28111            var p;
28112            for (p in s) {
28113                if(wlhash[p]) {
28114                    r[p] = s[p];
28115                }
28116            }
28117            return r;
28118        };
28119
28120    /**
28121     * The BaseCore class, is the lightest version of Base, and provides Base's
28122     * basic lifecycle management and ATTRS construction support, but doesn't
28123     * fire init/destroy or attribute change events.
28124     *
28125     * BaseCore also handles the chaining of initializer and destructor methods across
28126     * the hierarchy as part of object construction and destruction. Additionally, attributes
28127     * configured through the static <a href="#property_BaseCore.ATTRS">ATTRS</a>
28128     * property for each class in the hierarchy will be initialized by BaseCore.
28129     *
28130     * Classes which require attribute support, but don't intend to use/expose attribute
28131     * change events can extend BaseCore instead of Base for optimal kweight and
28132     * runtime performance.
28133     *
28134     * **3.11.0 BACK COMPAT NOTE FOR COMPONENT DEVELOPERS**
28135     *
28136     * Prior to version 3.11.0, ATTRS would get added a class at a time. That is:
28137     *
28138     * <pre>
28139     *    for each (class in the hierarchy) {
28140     *       Call the class Extension constructors.
28141     *
28142     *       Add the class ATTRS.
28143     *
28144     *       Call the class initializer
28145     *       Call the class Extension initializers.
28146     *    }
28147     * </pre>
28148     *
28149     * As of 3.11.0, ATTRS from all classes in the hierarchy are added in one `addAttrs` call
28150     * before **any** initializers are called. That is, the flow becomes:
28151     *
28152     * <pre>
28153     *    for each (class in the hierarchy) {
28154     *       Call the class Extension constructors.
28155     *    }
28156     *
28157     *    Add ATTRS for all classes
28158     *
28159     *    for each (class in the hierarchy) {
28160     *       Call the class initializer.
28161     *       Call the class Extension initializers.
28162     *    }
28163     * </pre>
28164     *
28165     * Adding all ATTRS at once fixes subtle edge-case issues with subclass ATTRS overriding
28166     * superclass `setter`, `getter` or `valueFn` definitions and being unable to get/set attributes
28167     * defined by the subclass. It also leaves us with a cleaner order of operation flow moving
28168     * forward.
28169     *
28170     * However, it may require component developers to upgrade their components, for the following
28171     * scenarios:
28172     *
28173     * 1. It impacts components which may have `setter`, `getter` or `valueFn` code which
28174     * expects a superclass' initializer to have run.
28175     *
28176     * This is expected to be rare, but to support it, Base now supports a `_preAddAttrs()`, method
28177     * hook (same signature as `addAttrs`). Components can implement this method on their prototype
28178     * for edge cases which do require finer control over the order in which attributes are added
28179     * (see widget-htmlparser for example).
28180     *
28181     * 2. Extension developers may need to move code from Extension constructors to `initializer`s
28182     *
28183     * Older extensions, which were written before `initializer` support was added, had a lot of
28184     * initialization code in their constructors. For example, code which acccessed superclass
28185     * attributes. With the new flow this code would not be able to see attributes. The recommendation
28186     * is to move this initialization code to an `initializer` on the Extension, which was the
28187     * recommendation for anything created after `initializer` support for Extensions was added.
28188     *
28189     * @class BaseCore
28190     * @constructor
28191     * @uses AttributeCore
28192     * @param {Object} cfg Object with configuration property name/value pairs.
28193     * The object can be used to provide initial values for the objects published
28194     * attributes.
28195     */
28196    function BaseCore(cfg) {
28197        if (!this._BaseInvoked) {
28198            this._BaseInvoked = true;
28199
28200            this._initBase(cfg);
28201        }
28202    }
28203
28204    /**
28205     * The list of properties which can be configured for each attribute
28206     * (e.g. setter, getter, writeOnce, readOnly etc.)
28207     *
28208     * @property _ATTR_CFG
28209     * @type Array
28210     * @static
28211     * @private
28212     */
28213    BaseCore._ATTR_CFG = AttributeCore._ATTR_CFG.concat("cloneDefaultValue");
28214
28215    /**
28216     * The array of non-attribute configuration properties supported by this class.
28217     *
28218     * For example `BaseCore` defines a "plugins" configuration property which
28219     * should not be set up as an attribute. This property is primarily required so
28220     * that when <a href="#property__allowAdHocAttrs">`_allowAdHocAttrs`</a> is enabled by a class,
28221     * non-attribute configuration properties don't get added as ad-hoc attributes.
28222     *
28223     * @property _NON_ATTRS_CFG
28224     * @type Array
28225     * @static
28226     * @private
28227     */
28228    BaseCore._NON_ATTRS_CFG = ["plugins"];
28229
28230    /**
28231     * This property controls whether or not instances of this class should
28232     * allow users to add ad-hoc attributes through the constructor configuration
28233     * hash.
28234     *
28235     * AdHoc attributes are attributes which are not defined by the class, and are
28236     * not handled by the MyClass._NON_ATTRS_CFG
28237     *
28238     * @property _allowAdHocAttrs
28239     * @type boolean
28240     * @default undefined (false)
28241     * @protected
28242     */
28243
28244    /**
28245     * The string to be used to identify instances of this class.
28246     *
28247     * Classes extending BaseCore, should define their own
28248     * static NAME property, which should be camelCase by
28249     * convention (e.g. MyClass.NAME = "myClass";).
28250     *
28251     * @property NAME
28252     * @type String
28253     * @static
28254     */
28255    BaseCore.NAME = "baseCore";
28256
28257    /**
28258     * The default set of attributes which will be available for instances of this class, and
28259     * their configuration. In addition to the configuration properties listed by
28260     * AttributeCore's <a href="AttributeCore.html#method_addAttr">addAttr</a> method,
28261     * the attribute can also be configured with a "cloneDefaultValue" property, which
28262     * defines how the statically defined value field should be protected
28263     * ("shallow", "deep" and false are supported values).
28264     *
28265     * By default if the value is an object literal or an array it will be "shallow"
28266     * cloned, to protect the default value.
28267     *
28268     * @property ATTRS
28269     * @type Object
28270     * @static
28271     */
28272    BaseCore.ATTRS = {
28273        /**
28274         * Flag indicating whether or not this object
28275         * has been through the init lifecycle phase.
28276         *
28277         * @attribute initialized
28278         * @readonly
28279         * @default false
28280         * @type boolean
28281         */
28282        initialized: {
28283            readOnly:true,
28284            value:false
28285        },
28286
28287        /**
28288         * Flag indicating whether or not this object
28289         * has been through the destroy lifecycle phase.
28290         *
28291         * @attribute destroyed
28292         * @readonly
28293         * @default false
28294         * @type boolean
28295         */
28296        destroyed: {
28297            readOnly:true,
28298            value:false
28299        }
28300    };
28301
28302    /**
28303    Provides a way to safely modify a `Y.BaseCore` subclass' static `ATTRS`
28304    after the class has been defined or created.
28305
28306    BaseCore-based classes cache information about the class hierarchy in order
28307    to efficiently create instances. This cache includes includes the aggregated
28308    `ATTRS` configs. If the static `ATTRS` configs need to be modified after the
28309    class has been defined or create, then use this method which will make sure
28310    to clear any cached data before making any modifications.
28311
28312    @method modifyAttrs
28313    @param {Function} [ctor] The constructor function whose `ATTRS` should be
28314        modified. If a `ctor` function is not specified, then `this` is assumed
28315        to be the constructor which hosts the `ATTRS`.
28316    @param {Object} configs The collection of `ATTRS` configs to mix with the
28317        existing attribute configurations.
28318    @static
28319    @since 3.10.0
28320    **/
28321    BaseCore.modifyAttrs = function (ctor, configs) {
28322        // When called without a constructor, assume `this` is the constructor.
28323        if (typeof ctor !== 'function') {
28324            configs = ctor;
28325            ctor    = this;
28326        }
28327
28328        var attrs, attr, name;
28329
28330        // Eagerly create the `ATTRS` object if it doesn't already exist.
28331        attrs = ctor.ATTRS || (ctor.ATTRS = {});
28332
28333        if (configs) {
28334            // Clear cache because it has ATTRS aggregation data which is about
28335            // to be modified.
28336            ctor._CACHED_CLASS_DATA = null;
28337
28338            for (name in configs) {
28339                if (configs.hasOwnProperty(name)) {
28340                    attr = attrs[name] || (attrs[name] = {});
28341                    Y.mix(attr, configs[name], true);
28342                }
28343            }
28344        }
28345    };
28346
28347    BaseCore.prototype = {
28348
28349        /**
28350         * Internal construction logic for BaseCore.
28351         *
28352         * @method _initBase
28353         * @param {Object} config The constructor configuration object
28354         * @private
28355         */
28356        _initBase : function(config) {
28357
28358            Y.stamp(this);
28359
28360            this._initAttribute(config);
28361
28362            // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
28363            // initial state, but don't initialize Plugins yet. That's done after initialization.
28364            var PluginHost = Y.Plugin && Y.Plugin.Host;
28365            if (this._initPlugins && PluginHost) {
28366                PluginHost.call(this);
28367            }
28368
28369            if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
28370
28371            /**
28372             * The string used to identify the class of this object.
28373             *
28374             * @deprecated Use this.constructor.NAME
28375             * @property name
28376             * @type String
28377             */
28378            this.name = this.constructor.NAME;
28379
28380            this.init.apply(this, arguments);
28381        },
28382
28383        /**
28384         * Initializes AttributeCore
28385         *
28386         * @method _initAttribute
28387         * @private
28388         */
28389        _initAttribute: function() {
28390            AttributeCore.call(this);
28391        },
28392
28393        /**
28394         * Init lifecycle method, invoked during construction. Sets up attributes
28395         * and invokes initializers for the class hierarchy.
28396         *
28397         * @method init
28398         * @chainable
28399         * @param {Object} cfg Object with configuration property name/value pairs
28400         * @return {BaseCore} A reference to this object
28401         */
28402        init: function(cfg) {
28403
28404            this._baseInit(cfg);
28405
28406            return this;
28407        },
28408
28409        /**
28410         * Internal initialization implementation for BaseCore
28411         *
28412         * @method _baseInit
28413         * @private
28414         */
28415        _baseInit: function(cfg) {
28416            this._initHierarchy(cfg);
28417
28418            if (this._initPlugins) {
28419                // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
28420                this._initPlugins(cfg);
28421            }
28422            this._set(INITIALIZED, true);
28423        },
28424
28425        /**
28426         * Destroy lifecycle method. Invokes destructors for the class hierarchy.
28427         *
28428         * @method destroy
28429         * @return {BaseCore} A reference to this object
28430         * @chainable
28431         */
28432        destroy: function() {
28433            this._baseDestroy();
28434            return this;
28435        },
28436
28437        /**
28438         * Internal destroy implementation for BaseCore
28439         *
28440         * @method _baseDestroy
28441         * @private
28442         */
28443        _baseDestroy : function() {
28444            if (this._destroyPlugins) {
28445                this._destroyPlugins();
28446            }
28447            this._destroyHierarchy();
28448            this._set(DESTROYED, true);
28449        },
28450
28451        /**
28452         * Returns the class hierarchy for this object, with BaseCore being the last class in the array.
28453         *
28454         * @method _getClasses
28455         * @protected
28456         * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
28457         * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
28458         * cached value.
28459         */
28460        _getClasses : function() {
28461            if (!this._classes) {
28462                this._initHierarchyData();
28463            }
28464            return this._classes;
28465        },
28466
28467        /**
28468         * Returns an aggregated set of attribute configurations, by traversing
28469         * the class hierarchy.
28470         *
28471         * @method _getAttrCfgs
28472         * @protected
28473         * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
28474         * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
28475         * the cached value.
28476         */
28477        _getAttrCfgs : function() {
28478            if (!this._attrs) {
28479                this._initHierarchyData();
28480            }
28481            return this._attrs;
28482        },
28483
28484        /**
28485         * A helper method used to isolate the attrs config for this instance to pass to `addAttrs`,
28486         * from the static cached ATTRS for the class.
28487         *
28488         * @method _getInstanceAttrCfgs
28489         * @private
28490         *
28491         * @param {Object} allCfgs The set of all attribute configurations for this instance.
28492         * Attributes will be removed from this set, if they belong to the filtered class, so
28493         * that by the time all classes are processed, allCfgs will be empty.
28494         *
28495         * @return {Object} The set of attributes to be added for this instance, suitable
28496         * for passing through to `addAttrs`.
28497         */
28498        _getInstanceAttrCfgs : function(allCfgs) {
28499
28500            var cfgs = {},
28501                cfg,
28502                val,
28503                subAttr,
28504                subAttrs,
28505                subAttrPath,
28506                attr,
28507                attrCfg,
28508                allSubAttrs = allCfgs._subAttrs,
28509                attrCfgProperties = this._attrCfgHash();
28510
28511            for (attr in allCfgs) {
28512
28513                if (allCfgs.hasOwnProperty(attr) && attr !== "_subAttrs") {
28514
28515                    attrCfg = allCfgs[attr];
28516
28517                    // Need to isolate from allCfgs, because we're going to set values etc.
28518                    cfg = cfgs[attr] = _wlmix({}, attrCfg, attrCfgProperties);
28519
28520                    val = cfg.value;
28521
28522                    if (val && (typeof val === "object")) {
28523                        this._cloneDefaultValue(attr, cfg);
28524                    }
28525
28526                    if (allSubAttrs && allSubAttrs.hasOwnProperty(attr)) {
28527                        subAttrs = allCfgs._subAttrs[attr];
28528
28529                        for (subAttrPath in subAttrs) {
28530                            subAttr = subAttrs[subAttrPath];
28531
28532                            if (subAttr.path) {
28533                                O.setValue(cfg.value, subAttr.path, subAttr.value);
28534                            }
28535                        }
28536                    }
28537                }
28538            }
28539
28540            return cfgs;
28541        },
28542
28543        /**
28544         * @method _filterAdHocAttrs
28545         * @private
28546         *
28547         * @param {Object} allAttrs The set of all attribute configurations for this instance.
28548         * Attributes will be removed from this set, if they belong to the filtered class, so
28549         * that by the time all classes are processed, allCfgs will be empty.
28550         * @param {Object} userVals The config object passed in by the user, from which adhoc attrs are to be filtered.
28551         * @return {Object} The set of adhoc attributes passed in, in the form
28552         * of an object with attribute name/configuration pairs.
28553         */
28554        _filterAdHocAttrs : function(allAttrs, userVals) {
28555            var adHocs,
28556                nonAttrs = this._nonAttrs,
28557                attr;
28558
28559            if (userVals) {
28560                adHocs = {};
28561                for (attr in userVals) {
28562                    if (!allAttrs[attr] && !nonAttrs[attr] && userVals.hasOwnProperty(attr)) {
28563                        adHocs[attr] = {
28564                            value:userVals[attr]
28565                        };
28566                    }
28567                }
28568            }
28569
28570            return adHocs;
28571        },
28572
28573        /**
28574         * A helper method used by _getClasses and _getAttrCfgs, which determines both
28575         * the array of classes and aggregate set of attribute configurations
28576         * across the class hierarchy for the instance.
28577         *
28578         * @method _initHierarchyData
28579         * @private
28580         */
28581        _initHierarchyData : function() {
28582
28583            var ctor = this.constructor,
28584                cachedClassData = ctor._CACHED_CLASS_DATA,
28585                c,
28586                i,
28587                l,
28588                attrCfg,
28589                attrCfgHash,
28590                needsAttrCfgHash = !ctor._ATTR_CFG_HASH,
28591                nonAttrsCfg,
28592                nonAttrs = {},
28593                classes = [],
28594                attrs = [];
28595
28596            // Start with `this` instance's constructor.
28597            c = ctor;
28598
28599            if (!cachedClassData) {
28600
28601                while (c) {
28602                    // Add to classes
28603                    classes[classes.length] = c;
28604
28605                    // Add to attributes
28606                    if (c.ATTRS) {
28607                        attrs[attrs.length] = c.ATTRS;
28608                    }
28609
28610                    // Aggregate ATTR cfg whitelist.
28611                    if (needsAttrCfgHash) {
28612                        attrCfg     = c._ATTR_CFG;
28613                        attrCfgHash = attrCfgHash || {};
28614
28615                        if (attrCfg) {
28616                            for (i = 0, l = attrCfg.length; i < l; i += 1) {
28617                                attrCfgHash[attrCfg[i]] = true;
28618                            }
28619                        }
28620                    }
28621
28622                    // Commenting out the if. We always aggregate, since we don't
28623                    // know if we'll be needing this on the instance or not.
28624                    // if (this._allowAdHocAttrs) {
28625                        nonAttrsCfg = c._NON_ATTRS_CFG;
28626                        if (nonAttrsCfg) {
28627                            for (i = 0, l = nonAttrsCfg.length; i < l; i++) {
28628                                nonAttrs[nonAttrsCfg[i]] = true;
28629                            }
28630                        }
28631                    //}
28632
28633                    c = c.superclass ? c.superclass.constructor : null;
28634                }
28635
28636                // Cache computed `_ATTR_CFG_HASH` on the constructor.
28637                if (needsAttrCfgHash) {
28638                    ctor._ATTR_CFG_HASH = attrCfgHash;
28639                }
28640
28641                cachedClassData = ctor._CACHED_CLASS_DATA = {
28642                    classes : classes,
28643                    nonAttrs : nonAttrs,
28644                    attrs : this._aggregateAttrs(attrs)
28645                };
28646
28647            }
28648
28649            this._classes = cachedClassData.classes;
28650            this._attrs = cachedClassData.attrs;
28651            this._nonAttrs = cachedClassData.nonAttrs;
28652        },
28653
28654        /**
28655         * Utility method to define the attribute hash used to filter/whitelist property mixes for
28656         * this class for iteration performance reasons.
28657         *
28658         * @method _attrCfgHash
28659         * @private
28660         */
28661        _attrCfgHash: function() {
28662            return this.constructor._ATTR_CFG_HASH;
28663        },
28664
28665        /**
28666         * This method assumes that the value has already been checked to be an object.
28667         * Since it's on a critical path, we don't want to re-do the check.
28668         *
28669         * @method _cloneDefaultValue
28670         * @param {Object} cfg
28671         * @private
28672         */
28673        _cloneDefaultValue : function(attr, cfg) {
28674
28675            var val = cfg.value,
28676                clone = cfg.cloneDefaultValue;
28677
28678            if (clone === DEEP || clone === true) {
28679                cfg.value = Y.clone(val);
28680            } else if (clone === SHALLOW) {
28681                cfg.value = Y.merge(val);
28682            } else if ((clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val)))) {
28683                cfg.value = Y.clone(val);
28684            }
28685            // else if (clone === false), don't clone the static default value.
28686            // It's intended to be used by reference.
28687        },
28688
28689        /**
28690         * A helper method, used by _initHierarchyData to aggregate
28691         * attribute configuration across the instances class hierarchy.
28692         *
28693         * The method will protect the attribute configuration value to protect the statically defined
28694         * default value in ATTRS if required (if the value is an object literal, array or the
28695         * attribute configuration has cloneDefaultValue set to shallow or deep).
28696         *
28697         * @method _aggregateAttrs
28698         * @private
28699         * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
28700         * (subclass first, Base last)
28701         * @return {Object} The aggregate set of ATTRS definitions for the instance
28702         */
28703        _aggregateAttrs : function(allAttrs) {
28704
28705            var attr,
28706                attrs,
28707                subAttrsHash,
28708                cfg,
28709                path,
28710                i,
28711                cfgPropsHash = this._attrCfgHash(),
28712                aggAttr,
28713                aggAttrs = {};
28714
28715            if (allAttrs) {
28716                for (i = allAttrs.length-1; i >= 0; --i) {
28717
28718                    attrs = allAttrs[i];
28719
28720                    for (attr in attrs) {
28721                        if (attrs.hasOwnProperty(attr)) {
28722
28723                            // PERF TODO: Do we need to merge here, since we're merging later in getInstanceAttrCfgs
28724                            // Should we move this down to only merge if we hit the path or valueFn ifs below?
28725                            cfg = _wlmix({}, attrs[attr], cfgPropsHash);
28726
28727                            path = null;
28728                            if (attr.indexOf(DOT) !== -1) {
28729                                path = attr.split(DOT);
28730                                attr = path.shift();
28731                            }
28732
28733                            aggAttr = aggAttrs[attr];
28734
28735                            if (path && aggAttr && aggAttr.value) {
28736
28737                                subAttrsHash = aggAttrs._subAttrs;
28738
28739                                if (!subAttrsHash) {
28740                                    subAttrsHash = aggAttrs._subAttrs = {};
28741                                }
28742
28743                                if (!subAttrsHash[attr]) {
28744                                    subAttrsHash[attr] = {};
28745                                }
28746
28747                                subAttrsHash[attr][path.join(DOT)] = {
28748                                    value: cfg.value,
28749                                    path : path
28750                                };
28751
28752                            } else if (!path) {
28753
28754                                if (!aggAttr) {
28755                                    aggAttrs[attr] = cfg;
28756                                } else {
28757                                    if (aggAttr.valueFn && VALUE in cfg) {
28758                                        aggAttr.valueFn = null;
28759                                    }
28760
28761                                    // Mix into existing config.
28762                                    _wlmix(aggAttr, cfg, cfgPropsHash);
28763                                }
28764                            }
28765                        }
28766                    }
28767                }
28768            }
28769
28770            return aggAttrs;
28771        },
28772
28773        /**
28774         * Initializes the class hierarchy for the instance, which includes
28775         * initializing attributes for each class defined in the class's
28776         * static <a href="#property_BaseCore.ATTRS">ATTRS</a> property and
28777         * invoking the initializer method on the prototype of each class in the hierarchy.
28778         *
28779         * @method _initHierarchy
28780         * @param {Object} userVals Object with configuration property name/value pairs
28781         * @private
28782         */
28783        _initHierarchy : function(userVals) {
28784
28785            var lazy = this._lazyAddAttrs,
28786                constr,
28787                constrProto,
28788                i,
28789                l,
28790                ci,
28791                ei,
28792                el,
28793                ext,
28794                extProto,
28795                exts,
28796                instanceAttrs,
28797                initializers = [],
28798                classes = this._getClasses(),
28799                attrCfgs = this._getAttrCfgs(),
28800                cl = classes.length - 1;
28801
28802            // Constructors
28803            for (ci = cl; ci >= 0; ci--) {
28804
28805                constr = classes[ci];
28806                constrProto = constr.prototype;
28807                exts = constr._yuibuild && constr._yuibuild.exts;
28808
28809                // Using INITIALIZER in hasOwnProperty check, for performance reasons (helps IE6 avoid GC thresholds when
28810                // referencing string literals). Not using it in apply, again, for performance "." is faster.
28811
28812                if (constrProto.hasOwnProperty(INITIALIZER)) {
28813                    // Store initializer while we're here and looping
28814                    initializers[initializers.length] = constrProto.initializer;
28815                }
28816
28817                if (exts) {
28818                    for (ei = 0, el = exts.length; ei < el; ei++) {
28819
28820                        ext = exts[ei];
28821
28822                        // Ext Constructor
28823                        ext.apply(this, arguments);
28824
28825                        extProto = ext.prototype;
28826                        if (extProto.hasOwnProperty(INITIALIZER)) {
28827                            // Store initializer while we're here and looping
28828                            initializers[initializers.length] = extProto.initializer;
28829                        }
28830                    }
28831                }
28832            }
28833
28834            // ATTRS
28835            instanceAttrs = this._getInstanceAttrCfgs(attrCfgs);
28836
28837            if (this._preAddAttrs) {
28838                this._preAddAttrs(instanceAttrs, userVals, lazy);
28839            }
28840
28841            if (this._allowAdHocAttrs) {
28842                this.addAttrs(this._filterAdHocAttrs(attrCfgs, userVals), userVals, lazy);
28843            }
28844
28845            this.addAttrs(instanceAttrs, userVals, lazy);
28846
28847            // Initializers
28848            for (i = 0, l = initializers.length; i < l; i++) {
28849                initializers[i].apply(this, arguments);
28850            }
28851        },
28852
28853        /**
28854         * Destroys the class hierarchy for this instance by invoking
28855         * the destructor method on the prototype of each class in the hierarchy.
28856         *
28857         * @method _destroyHierarchy
28858         * @private
28859         */
28860        _destroyHierarchy : function() {
28861            var constr,
28862                constrProto,
28863                ci, cl, ei, el, exts, extProto,
28864                classes = this._getClasses();
28865
28866            for (ci = 0, cl = classes.length; ci < cl; ci++) {
28867                constr = classes[ci];
28868                constrProto = constr.prototype;
28869                exts = constr._yuibuild && constr._yuibuild.exts;
28870
28871                if (exts) {
28872                    for (ei = 0, el = exts.length; ei < el; ei++) {
28873                        extProto = exts[ei].prototype;
28874                        if (extProto.hasOwnProperty(DESTRUCTOR)) {
28875                            extProto.destructor.apply(this, arguments);
28876                        }
28877                    }
28878                }
28879
28880                if (constrProto.hasOwnProperty(DESTRUCTOR)) {
28881                    constrProto.destructor.apply(this, arguments);
28882                }
28883            }
28884        },
28885
28886        /**
28887         * Default toString implementation. Provides the constructor NAME
28888         * and the instance guid, if set.
28889         *
28890         * @method toString
28891         * @return {String} String representation for this object
28892         */
28893        toString: function() {
28894            return this.name + "[" + Y.stamp(this, true) + "]";
28895        }
28896    };
28897
28898    // Straightup augment, no wrapper functions
28899    Y.mix(BaseCore, AttributeCore, false, null, 1);
28900
28901    // Fix constructor
28902    BaseCore.prototype.constructor = BaseCore;
28903
28904    Y.BaseCore = BaseCore;
28905
28906
28907}, '3.18.1', {"requires": ["attribute-core"]});
28908YUI.add('attribute-base', function (Y, NAME) {
28909
28910    /**
28911     * The attribute module provides an augmentable Attribute implementation, which
28912     * adds configurable attributes and attribute change events to the class being
28913     * augmented. It also provides a State class, which is used internally by Attribute,
28914     * but can also be used independently to provide a name/property/value data structure to
28915     * store state.
28916     *
28917     * @module attribute
28918     */
28919
28920    /**
28921     * The attribute-base submodule provides core attribute handling support, with everything
28922     * aside from complex attribute handling in the provider's constructor.
28923     *
28924     * @module attribute
28925     * @submodule attribute-base
28926     */
28927
28928    /**
28929     * <p>
28930     * Attribute provides configurable attribute support along with attribute change events. It is designed to be
28931     * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state,
28932     * along with attribute change events.
28933     * </p>
28934     * <p>For example, attributes added to the host can be configured:</p>
28935     * <ul>
28936     *     <li>As read only.</li>
28937     *     <li>As write once.</li>
28938     *     <li>With a setter function, which can be used to manipulate
28939     *     values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li>
28940     *     <li>With a getter function, which can be used to manipulate stored values,
28941     *     before they are returned by Attribute's <a href="#method_get">get</a> method.</li>
28942     *     <li>With a validator function, to validate values before they are stored.</li>
28943     * </ul>
28944     *
28945     * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration
28946     * options available for attributes.</p>
28947     *
28948     * <p><strong>NOTE:</strong> Most implementations will be better off extending the <a href="Base.html">Base</a> class,
28949     * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration
28950     * of attributes for derived classes, accounting for values passed into the constructor.</p>
28951     *
28952     * @class Attribute
28953     * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
28954     *        These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
28955     * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
28956     *        These are not merged/cloned. The caller is responsible for isolating user provided values if required.
28957     * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
28958     * @uses AttributeCore
28959     * @uses AttributeObservable
28960     * @uses EventTarget
28961     * @uses AttributeExtras
28962     */
28963    function Attribute() {
28964        Y.AttributeCore.apply(this, arguments);
28965        Y.AttributeObservable.apply(this, arguments);
28966        Y.AttributeExtras.apply(this, arguments);
28967    }
28968
28969    Y.mix(Attribute, Y.AttributeCore, false, null, 1);
28970    Y.mix(Attribute, Y.AttributeExtras, false, null, 1);
28971
28972    // Needs to be `true`, to overwrite methods from AttributeCore
28973    Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
28974
28975    /**
28976     * <p>The value to return from an attribute setter in order to prevent the set from going through.</p>
28977     *
28978     * <p>You can return this value from your setter if you wish to combine validator and setter
28979     * functionality into a single setter function, which either returns the massaged value to be stored or
28980     * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p>
28981     *
28982     * @property INVALID_VALUE
28983     * @type Object
28984     * @static
28985     * @final
28986     */
28987    Attribute.INVALID_VALUE = Y.AttributeCore.INVALID_VALUE;
28988
28989    /**
28990     * The list of properties which can be configured for
28991     * each attribute (e.g. setter, getter, writeOnce etc.).
28992     *
28993     * This property is used internally as a whitelist for faster
28994     * Y.mix operations.
28995     *
28996     * @property _ATTR_CFG
28997     * @type Array
28998     * @static
28999     * @protected
29000     */
29001    Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._ATTR_CFG);
29002
29003    /**
29004     * Utility method to protect an attribute configuration hash, by merging the
29005     * entire object and the individual attr config objects.
29006     *
29007     * @method protectAttrs
29008     * @static
29009     * @param {Object} attrs A hash of attribute to configuration object pairs.
29010     * @return {Object} A protected version of the `attrs` argument.
29011     */
29012    Attribute.protectAttrs = Y.AttributeCore.protectAttrs;
29013
29014    Y.Attribute = Attribute;
29015
29016
29017}, '3.18.1', {"requires": ["attribute-core", "attribute-observable", "attribute-extras"]});
29018YUI.add('attribute-extras', function (Y, NAME) {
29019
29020    /**
29021     * The attribute module provides an augmentable Attribute implementation, which
29022     * adds configurable attributes and attribute change events to the class being
29023     * augmented. It also provides a State class, which is used internally by Attribute,
29024     * but can also be used independently to provide a name/property/value data structure to
29025     * store state.
29026     *
29027     * @module attribute
29028     */
29029
29030    /**
29031     * The attribute-extras submodule provides less commonly used attribute methods, and can
29032     * be augmented/mixed into an implemention which used attribute-core.
29033     *
29034     * @module attribute
29035     * @submodule attribute-extras
29036     */
29037    var BROADCAST = "broadcast",
29038        PUBLISHED = "published",
29039        INIT_VALUE = "initValue",
29040
29041        MODIFIABLE = {
29042            readOnly:1,
29043            writeOnce:1,
29044            getter:1,
29045            broadcast:1
29046        };
29047
29048    /**
29049     * A augmentable implementation for AttributeCore, providing less frequently used
29050     * methods for Attribute management such as modifyAttrs(), removeAttr and reset()
29051     *
29052     * @class AttributeExtras
29053     * @extensionfor AttributeCore
29054     */
29055    function AttributeExtras() {}
29056
29057    AttributeExtras.prototype = {
29058
29059        /**
29060         * Updates the configuration of an attribute which has already been added.
29061         * <p>
29062         * The properties which can be modified through this interface are limited
29063         * to the following subset of attributes, which can be safely modified
29064         * after a value has already been set on the attribute:
29065         * </p>
29066         * <dl>
29067         *  <dt>readOnly;</dt>
29068         *  <dt>writeOnce;</dt>
29069         *  <dt>broadcast; and</dt>
29070         *  <dt>getter.</dt>
29071         * </dl>
29072         * <p>
29073         * Note: New attributes cannot be added using this interface. New attributes must be
29074         * added using {{#crossLink "AttributeCore/addAttr:method"}}addAttr{{/crossLink}}, or an
29075         * appropriate manner for a class which utilises Attributes (e.g. the
29076         * {{#crossLink "Base/ATTRS:property"}}ATTRS{{/crossLink}} property in
29077         * {{#crossLink "Base"}}Base{{/crossLink}}).
29078         * </p>
29079         * @method modifyAttr
29080         * @param {String} name The name of the attribute whose configuration is to be updated.
29081         * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify.
29082         */
29083        modifyAttr: function(name, config) {
29084            var host = this, // help compression
29085                prop, state;
29086
29087            if (host.attrAdded(name)) {
29088
29089                if (host._isLazyAttr(name)) {
29090                    host._addLazyAttr(name);
29091                }
29092
29093                state = host._state;
29094                for (prop in config) {
29095                    if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) {
29096                        state.add(name, prop, config[prop]);
29097
29098                        // If we reconfigured broadcast, need to republish
29099                        if (prop === BROADCAST) {
29100                            state.remove(name, PUBLISHED);
29101                        }
29102                    }
29103                }
29104            } else {
29105            }
29106        },
29107
29108        /**
29109         * Removes an attribute from the host object
29110         *
29111         * @method removeAttr
29112         * @param {String} name The name of the attribute to be removed.
29113         */
29114        removeAttr: function(name) {
29115            this._state.removeAll(name);
29116        },
29117
29118        /**
29119         * Resets the attribute (or all attributes) to its initial value, as long as
29120         * the attribute is not readOnly, or writeOnce.
29121         *
29122         * @method reset
29123         * @param {String} name Optional. The name of the attribute to reset.  If omitted, all attributes are reset.
29124         * @return {Object} A reference to the host object.
29125         * @chainable
29126         */
29127        reset : function(name) {
29128            var host = this;  // help compression
29129
29130            if (name) {
29131                if (host._isLazyAttr(name)) {
29132                    host._addLazyAttr(name);
29133                }
29134                host.set(name, host._state.get(name, INIT_VALUE));
29135            } else {
29136                Y.Object.each(host._state.data, function(v, n) {
29137                    host.reset(n);
29138                });
29139            }
29140            return host;
29141        },
29142
29143        /**
29144         * Returns an object with the configuration properties (and value)
29145         * for the given attribute. If attrName is not provided, returns the
29146         * configuration properties for all attributes.
29147         *
29148         * @method _getAttrCfg
29149         * @protected
29150         * @param {String} name Optional. The attribute name. If not provided, the method will return the configuration for all attributes.
29151         * @return {Object} The configuration properties for the given attribute, or all attributes.
29152         */
29153        _getAttrCfg : function(name) {
29154            var o,
29155                state = this._state;
29156
29157            if (name) {
29158                o = state.getAll(name) || {};
29159            } else {
29160                o = {};
29161                Y.each(state.data, function(v, n) {
29162                    o[n] = state.getAll(n);
29163                });
29164            }
29165
29166            return o;
29167        }
29168    };
29169
29170    Y.AttributeExtras = AttributeExtras;
29171
29172
29173}, '3.18.1', {"requires": ["oop"]});
29174YUI.add('attribute-observable', function (Y, NAME) {
29175
29176    /*For log lines*/
29177    /*jshint maxlen:200*/
29178
29179
29180    /**
29181     * The attribute module provides an augmentable Attribute implementation, which
29182     * adds configurable attributes and attribute change events to the class being
29183     * augmented. It also provides a State class, which is used internally by Attribute,
29184     * but can also be used independently to provide a name/property/value data structure to
29185     * store state.
29186     *
29187     * @module attribute
29188     */
29189
29190    /**
29191     * The `attribute-observable` submodule provides augmentable attribute change event support
29192     * for AttributeCore based implementations.
29193     *
29194     * @module attribute
29195     * @submodule attribute-observable
29196     */
29197    var EventTarget = Y.EventTarget,
29198
29199        CHANGE = "Change",
29200        BROADCAST = "broadcast";
29201
29202    /**
29203     * Provides an augmentable implementation of attribute change events for
29204     * AttributeCore.
29205     *
29206     * @class AttributeObservable
29207     * @extensionfor AttributeCore
29208     * @uses EventTarget
29209     */
29210    function AttributeObservable() {
29211        // Perf tweak - avoid creating event literals if not required.
29212        this._ATTR_E_FACADE = {};
29213
29214        EventTarget.call(this, {emitFacade:true});
29215    }
29216
29217    AttributeObservable._ATTR_CFG = [BROADCAST];
29218
29219    AttributeObservable.prototype = {
29220
29221        /**
29222         * Sets the value of an attribute.
29223         *
29224         * @method set
29225         * @chainable
29226         *
29227         * @param {String} name The name of the attribute. If the
29228         * current value of the attribute is an Object, dot notation can be used
29229         * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>).
29230         *
29231         * @param {Any} value The value to set the attribute to.
29232         *
29233         * @param {Object} opts (Optional) Optional event data to be mixed into
29234         * the event facade passed to subscribers of the attribute's change event. This
29235         * can be used as a flexible way to identify the source of a call to set, allowing
29236         * the developer to distinguish between set called internally by the host, vs.
29237         * set called externally by the application developer.
29238         *
29239         * @return {Object} A reference to the host object.
29240         */
29241        set : function(name, val, opts) {
29242            return this._setAttr(name, val, opts);
29243        },
29244
29245        /**
29246         * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details.
29247         *
29248         * @method _set
29249         * @protected
29250         * @chainable
29251         *
29252         * @param {String} name The name of the attribute.
29253         * @param {Any} val The value to set the attribute to.
29254         * @param {Object} opts (Optional) Optional event data to be mixed into
29255         * the event facade passed to subscribers of the attribute's change event.
29256         * @return {Object} A reference to the host object.
29257         */
29258        _set : function(name, val, opts) {
29259            return this._setAttr(name, val, opts, true);
29260        },
29261
29262        /**
29263         * Sets multiple attribute values.
29264         *
29265         * @method setAttrs
29266         * @param {Object} attrs  An object with attributes name/value pairs.
29267         * @param {Object} opts  Properties to mix into the event payload. These are shared and mixed into each set
29268         * @return {Object} A reference to the host object.
29269         * @chainable
29270         */
29271        setAttrs : function(attrs, opts) {
29272            return this._setAttrs(attrs, opts);
29273        },
29274
29275        /**
29276         * Implementation behind the public setAttrs method, to set multiple attribute values.
29277         *
29278         * @method _setAttrs
29279         * @protected
29280         * @param {Object} attrs  An object with attributes name/value pairs.
29281         * @param {Object} opts  Properties to mix into the event payload. These are shared and mixed into each set
29282         * @return {Object} A reference to the host object.
29283         * @chainable
29284         */
29285        _setAttrs : function(attrs, opts) {
29286            var attr;
29287            for (attr in attrs) {
29288                if ( attrs.hasOwnProperty(attr) ) {
29289                    this.set(attr, attrs[attr], opts);
29290                }
29291            }
29292            return this;
29293        },
29294
29295        /**
29296         * Utility method to help setup the event payload and fire the attribute change event.
29297         *
29298         * @method _fireAttrChange
29299         * @private
29300         * @param {String} attrName The name of the attribute
29301         * @param {String} subAttrName The full path of the property being changed,
29302         * if this is a sub-attribute value being change. Otherwise null.
29303         * @param {Any} currVal The current value of the attribute
29304         * @param {Any} newVal The new value of the attribute
29305         * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
29306         * @param {Object} [cfg] The attribute config stored in State, if already available.
29307         */
29308        _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts, cfg) {
29309            var host = this,
29310                eventName = this._getFullType(attrName + CHANGE),
29311                state = host._state,
29312                facade,
29313                broadcast,
29314                e;
29315
29316            if (!cfg) {
29317                cfg = state.data[attrName] || {};
29318            }
29319
29320            if (!cfg.published) {
29321
29322                // PERF: Using lower level _publish() for
29323                // critical path performance
29324                e = host._publish(eventName);
29325
29326                e.emitFacade = true;
29327                e.defaultTargetOnly = true;
29328                e.defaultFn = host._defAttrChangeFn;
29329
29330                broadcast = cfg.broadcast;
29331                if (broadcast !== undefined) {
29332                    e.broadcast = broadcast;
29333                }
29334
29335                cfg.published = true;
29336            }
29337
29338            if (opts) {
29339                facade = Y.merge(opts);
29340                facade._attrOpts = opts;
29341            } else {
29342                facade = host._ATTR_E_FACADE;
29343            }
29344
29345            // Not using the single object signature for fire({type:..., newVal:...}), since
29346            // we don't want to override type. Changed to the fire(type, {newVal:...}) signature.
29347
29348            facade.attrName = attrName;
29349            facade.subAttrName = subAttrName;
29350            facade.prevVal = currVal;
29351            facade.newVal = newVal;
29352
29353            if (host._hasPotentialSubscribers(eventName)) {
29354                host.fire(eventName, facade);
29355            } else {
29356                this._setAttrVal(attrName, subAttrName, currVal, newVal, opts, cfg);
29357            }
29358        },
29359
29360        /**
29361         * Default function for attribute change events.
29362         *
29363         * @private
29364         * @method _defAttrChangeFn
29365         * @param {EventFacade} e The event object for attribute change events.
29366         * @param {boolean} eventFastPath Whether or not we're using this as a fast path in the case of no listeners or not
29367         */
29368        _defAttrChangeFn : function(e, eventFastPath) {
29369
29370            var opts = e._attrOpts;
29371            if (opts) {
29372                delete e._attrOpts;
29373            }
29374
29375            if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, opts)) {
29376
29377
29378                if (!eventFastPath) {
29379                    // Prevent "after" listeners from being invoked since nothing changed.
29380                    e.stopImmediatePropagation();
29381                }
29382
29383            } else {
29384                if (!eventFastPath) {
29385                    e.newVal = this.get(e.attrName);
29386                }
29387            }
29388        }
29389    };
29390
29391    // Basic prototype augment - no lazy constructor invocation.
29392    Y.mix(AttributeObservable, EventTarget, false, null, 1);
29393
29394    Y.AttributeObservable = AttributeObservable;
29395
29396    /**
29397    The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now
29398    an alias for the `AttributeObservable` class extension. Use that class
29399    extnesion instead. This alias will be removed in a future version of YUI.
29400
29401    @class AttributeEvents
29402    @uses EventTarget
29403    @deprecated Use `AttributeObservable` instead.
29404    @see AttributeObservable
29405    **/
29406    Y.AttributeEvents = AttributeObservable;
29407
29408
29409}, '3.18.1', {"requires": ["event-custom"]});
29410YUI.add('base-observable', function (Y, NAME) {
29411
29412    /**
29413    The `base-observable` submodule adds observability to Base's lifecycle and
29414    attributes, and also make it an `EventTarget`.
29415
29416    @module base
29417    @submodule base-observable
29418    **/
29419    var L = Y.Lang,
29420
29421        DESTROY = "destroy",
29422        INIT = "init",
29423
29424        BUBBLETARGETS = "bubbleTargets",
29425        _BUBBLETARGETS = "_bubbleTargets",
29426
29427        AttributeObservable = Y.AttributeObservable,
29428        BaseCore            = Y.BaseCore;
29429
29430    /**
29431    Provides an augmentable implementation of lifecycle and attribute events for
29432    `BaseCore`.
29433
29434    @class BaseObservable
29435    @extensionfor BaseCore
29436    @uses AttributeObservable
29437    @uses EventTarget
29438    @since 3.8.0
29439    **/
29440    function BaseObservable() {}
29441
29442    BaseObservable._ATTR_CFG      = AttributeObservable._ATTR_CFG.concat();
29443    BaseObservable._NON_ATTRS_CFG = ["on", "after", "bubbleTargets"];
29444
29445    BaseObservable.prototype = {
29446
29447        /**
29448         * Initializes Attribute
29449         *
29450         * @method _initAttribute
29451         * @private
29452         */
29453        _initAttribute: function() {
29454            BaseCore.prototype._initAttribute.apply(this, arguments);
29455            AttributeObservable.call(this);
29456
29457            this._eventPrefix = this.constructor.EVENT_PREFIX || this.constructor.NAME;
29458            this._yuievt.config.prefix = this._eventPrefix;
29459        },
29460
29461        /**
29462         * Init lifecycle method, invoked during construction.
29463         * Fires the init event prior to setting up attributes and
29464         * invoking initializers for the class hierarchy.
29465         *
29466         * @method init
29467         * @chainable
29468         * @param {Object} config Object with configuration property name/value pairs
29469         * @return {Base} A reference to this object
29470         */
29471        init: function(config) {
29472
29473            /**
29474             * <p>
29475             * Lifecycle event for the init phase, fired prior to initialization.
29476             * Invoking the preventDefault() method on the event object provided
29477             * to subscribers will prevent initialization from occuring.
29478             * </p>
29479             * <p>
29480             * Subscribers to the "after" momemt of this event, will be notified
29481             * after initialization of the object is complete (and therefore
29482             * cannot prevent initialization).
29483             * </p>
29484             *
29485             * @event init
29486             * @preventable _defInitFn
29487             * @param {EventFacade} e Event object, with a cfg property which
29488             * refers to the configuration object passed to the constructor.
29489             */
29490
29491            // PERF: Using lower level _publish() for
29492            // critical path performance
29493
29494            var type = this._getFullType(INIT),
29495                e = this._publish(type);
29496
29497            e.emitFacade = true;
29498            e.fireOnce = true;
29499            e.defaultTargetOnly = true;
29500            e.defaultFn = this._defInitFn;
29501
29502            this._preInitEventCfg(config);
29503
29504            if (e._hasPotentialSubscribers()) {
29505                this.fire(type, {cfg: config});
29506            } else {
29507
29508                this._baseInit(config);
29509
29510                // HACK. Major hack actually. But really fast for no-listeners.
29511                // Since it's fireOnce, subscribers may come along later, so since we're
29512                // bypassing the event stack the first time, we need to tell the published
29513                // event that it's been "fired". Could extract it into a CE method?
29514                e.fired = true;
29515                e.firedWith = [{cfg:config}];
29516            }
29517
29518            return this;
29519        },
29520
29521        /**
29522         * Handles the special on, after and target properties which allow the user to
29523         * easily configure on and after listeners as well as bubble targets during
29524         * construction, prior to init.
29525         *
29526         * @private
29527         * @method _preInitEventCfg
29528         * @param {Object} config The user configuration object
29529         */
29530        _preInitEventCfg : function(config) {
29531            if (config) {
29532                if (config.on) {
29533                    this.on(config.on);
29534                }
29535                if (config.after) {
29536                    this.after(config.after);
29537                }
29538            }
29539
29540            var i, l, target,
29541                userTargets = (config && BUBBLETARGETS in config);
29542
29543            if (userTargets || _BUBBLETARGETS in this) {
29544                target = userTargets ? (config && config.bubbleTargets) : this._bubbleTargets;
29545
29546                if (L.isArray(target)) {
29547                    for (i = 0, l = target.length; i < l; i++) {
29548                        this.addTarget(target[i]);
29549                    }
29550                } else if (target) {
29551                    this.addTarget(target);
29552                }
29553            }
29554        },
29555
29556        /**
29557         * <p>
29558         * Destroy lifecycle method. Fires the destroy
29559         * event, prior to invoking destructors for the
29560         * class hierarchy.
29561         * </p>
29562         * <p>
29563         * Subscribers to the destroy
29564         * event can invoke preventDefault on the event object, to prevent destruction
29565         * from proceeding.
29566         * </p>
29567         * @method destroy
29568         * @return {Base} A reference to this object
29569         * @chainable
29570         */
29571        destroy: function() {
29572
29573            /**
29574             * <p>
29575             * Lifecycle event for the destroy phase,
29576             * fired prior to destruction. Invoking the preventDefault
29577             * method on the event object provided to subscribers will
29578             * prevent destruction from proceeding.
29579             * </p>
29580             * <p>
29581             * Subscribers to the "after" moment of this event, will be notified
29582             * after destruction is complete (and as a result cannot prevent
29583             * destruction).
29584             * </p>
29585             * @event destroy
29586             * @preventable _defDestroyFn
29587             * @param {EventFacade} e Event object
29588             */
29589            this.publish(DESTROY, {
29590                fireOnce:true,
29591                defaultTargetOnly:true,
29592                defaultFn: this._defDestroyFn
29593            });
29594            this.fire(DESTROY);
29595
29596            this.detachAll();
29597            return this;
29598        },
29599
29600        /**
29601         * Default init event handler
29602         *
29603         * @method _defInitFn
29604         * @param {EventFacade} e Event object, with a cfg property which
29605         * refers to the configuration object passed to the constructor.
29606         * @protected
29607         */
29608        _defInitFn : function(e) {
29609            this._baseInit(e.cfg);
29610        },
29611
29612        /**
29613         * Default destroy event handler
29614         *
29615         * @method _defDestroyFn
29616         * @param {EventFacade} e Event object
29617         * @protected
29618         */
29619        _defDestroyFn : function(e) {
29620            this._baseDestroy(e.cfg);
29621        }
29622    };
29623
29624    Y.mix(BaseObservable, AttributeObservable, false, null, 1);
29625
29626    Y.BaseObservable = BaseObservable;
29627
29628
29629}, '3.18.1', {"requires": ["attribute-observable", "base-core"]});
29630YUI.add('base-base', function (Y, NAME) {
29631
29632    /**
29633     * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
29634     * The module also provides two ways to reuse code - It augments Base with the Plugin.Host interface which provides
29635     * plugin support and also provides the BaseCore.build method which provides a way to build custom classes using extensions.
29636     *
29637     * @module base
29638     */
29639
29640    /**
29641     * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host,
29642     * and without the extension support provided by BaseCore.build.
29643     *
29644     * @module base
29645     * @submodule base-base
29646     */
29647
29648    var AttributeCore   = Y.AttributeCore,
29649        AttributeExtras = Y.AttributeExtras,
29650        BaseCore        = Y.BaseCore,
29651        BaseObservable  = Y.BaseObservable;
29652
29653    /**
29654     * <p>
29655     * A base class which objects requiring attributes and custom event support can
29656     * extend. Base also handles the chaining of initializer and destructor methods across
29657     * the hierarchy as part of object construction and destruction. Additionally, attributes configured
29658     * through the static <a href="#property_ATTRS">ATTRS</a> property for each class
29659     * in the hierarchy will be initialized by Base.
29660     * </p>
29661     *
29662     * <p>
29663     * **NOTE:** Prior to version 3.11.0, ATTRS would get added a class at a time. That is,
29664     * Base would loop through each class in the hierarchy, and add the class' ATTRS, and
29665     * then call it's initializer, and move on to the subclass' ATTRS and initializer. As of
29666     * 3.11.0, ATTRS from all classes in the hierarchy are added in one `addAttrs` call before
29667     * any initializers are called. This fixes subtle edge-case issues with subclass ATTRS overriding
29668     * superclass `setter`, `getter` or `valueFn` definitions and being unable to get/set attributes
29669     * defined by the subclass. This order of operation change may impact `setter`, `getter` or `valueFn`
29670     * code which expects a superclass' initializer to have run. This is expected to be rare, but to support
29671     * it, Base supports a `_preAddAttrs()`, method hook (same signature as `addAttrs`). Components can
29672     * implement this method on their prototype for edge cases which do require finer control over
29673     * the order in which attributes are added (see widget-htmlparser).
29674     * </p>
29675     *
29676     * <p>
29677     * The static <a href="#property_NAME">NAME</a> property of each class extending
29678     * from Base will be used as the identifier for the class, and is used by Base to prefix
29679     * all events fired by instances of that class.
29680     * </p>
29681     *
29682     * @class Base
29683     * @constructor
29684     * @uses BaseCore
29685     * @uses BaseObservable
29686     * @uses AttributeCore
29687     * @uses AttributeObservable
29688     * @uses AttributeExtras
29689     * @uses EventTarget
29690     *
29691     * @param {Object} config Object with configuration property name/value pairs. The object can be
29692     * used to provide default values for the objects published attributes.
29693     *
29694     * <p>
29695     * The config object can also contain the following non-attribute properties, providing a convenient
29696     * way to configure events listeners and plugins for the instance, as part of the constructor call:
29697     * </p>
29698     *
29699     * <dl>
29700     *   <dt>on</dt>
29701     *   <dd>An event name to listener function map, to register event listeners for the "on" moment of the event.
29702     *       A constructor convenience property for the <a href="Base.html#method_on">on</a> method.</dd>
29703     *   <dt>after</dt>
29704     *   <dd>An event name to listener function map, to register event listeners for the "after" moment of the event.
29705     *       A constructor convenience property for the <a href="Base.html#method_after">after</a> method.</dd>
29706     *   <dt>bubbleTargets</dt>
29707     *   <dd>An object, or array of objects, to register as bubble targets for bubbled events fired by this instance.
29708     *       A constructor convenience property for the <a href="EventTarget.html#method_addTarget">addTarget</a> method.</dd>
29709     *   <dt>plugins</dt>
29710     *   <dd>A plugin, or array of plugins to be plugged into the instance (see PluginHost's plug method for signature details).
29711     *       A constructor convenience property for the <a href="Plugin.Host.html#method_plug">plug</a> method.</dd>
29712     * </dl>
29713     */
29714    function Base() {
29715        BaseCore.apply(this, arguments);
29716        BaseObservable.apply(this, arguments);
29717        AttributeExtras.apply(this, arguments);
29718    }
29719
29720    /**
29721     * The list of properties which can be configured for
29722     * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
29723     *
29724     * @property _ATTR_CFG
29725     * @type Array
29726     * @static
29727     * @private
29728     */
29729    Base._ATTR_CFG = BaseCore._ATTR_CFG.concat(BaseObservable._ATTR_CFG);
29730
29731    /**
29732     * The array of non-attribute configuration properties supported by this class.
29733     *
29734     * `Base` supports "on", "after", "plugins" and "bubbleTargets" properties,
29735     * which are not set up as attributes.
29736     *
29737     * This property is primarily required so that when
29738     * <a href="#property__allowAdHocAttrs">`_allowAdHocAttrs`</a> is enabled by
29739     * a class, non-attribute configurations don't get added as ad-hoc attributes.
29740     *
29741     * @property _NON_ATTRS_CFG
29742     * @type Array
29743     * @static
29744     * @private
29745     */
29746    Base._NON_ATTRS_CFG = BaseCore._NON_ATTRS_CFG.concat(BaseObservable._NON_ATTRS_CFG);
29747
29748    /**
29749     * <p>
29750     * The string to be used to identify instances of
29751     * this class, for example in prefixing events.
29752     * </p>
29753     * <p>
29754     * Classes extending Base, should define their own
29755     * static NAME property, which should be camelCase by
29756     * convention (e.g. MyClass.NAME = "myClass";).
29757     * </p>
29758     * @property NAME
29759     * @type String
29760     * @static
29761     */
29762    Base.NAME = 'base';
29763
29764    /**
29765     * The default set of attributes which will be available for instances of this class, and
29766     * their configuration. In addition to the configuration properties listed by
29767     * Attribute's <a href="Attribute.html#method_addAttr">addAttr</a> method, the attribute
29768     * can also be configured with a "cloneDefaultValue" property, which defines how the statically
29769     * defined value field should be protected ("shallow", "deep" and false are supported values).
29770     *
29771     * By default if the value is an object literal or an array it will be "shallow" cloned, to
29772     * protect the default value.
29773     *
29774     * @property ATTRS
29775     * @type Object
29776     * @static
29777     */
29778    Base.ATTRS = AttributeCore.protectAttrs(BaseCore.ATTRS);
29779
29780    /**
29781    Provides a way to safely modify a `Y.Base` subclass' static `ATTRS` after
29782    the class has been defined or created.
29783
29784    Base-based classes cache information about the class hierarchy in order to
29785    efficiently create instances. This cache includes includes the aggregated
29786    `ATTRS` configs. If the static `ATTRS` configs need to be modified after the
29787    class has been defined or create, then use this method which will make sure
29788    to clear any cached data before making any modifications.
29789
29790    @method modifyAttrs
29791    @param {Function} [ctor] The constructor function whose `ATTRS` should be
29792        modified. If a `ctor` function is not specified, then `this` is assumed
29793        to be the constructor which hosts the `ATTRS`.
29794    @param {Object} configs The collection of `ATTRS` configs to mix with the
29795        existing attribute configurations.
29796    @static
29797    @since 3.10.0
29798    **/
29799    Base.modifyAttrs = BaseCore.modifyAttrs;
29800
29801    Y.mix(Base, BaseCore, false, null, 1);
29802    Y.mix(Base, AttributeExtras, false, null, 1);
29803
29804    // Needs to be `true`, to overwrite methods from `BaseCore`.
29805    Y.mix(Base, BaseObservable, true, null, 1);
29806
29807    // Fix constructor
29808    Base.prototype.constructor = Base;
29809
29810    Y.Base = Base;
29811
29812
29813}, '3.18.1', {"requires": ["attribute-base", "base-core", "base-observable"]});
29814YUI.add('base-pluginhost', function (Y, NAME) {
29815
29816    /**
29817     * The base-pluginhost submodule adds Plugin support to Base, by augmenting Base with
29818     * Plugin.Host and setting up static (class level) Base.plug and Base.unplug methods.
29819     *
29820     * @module base
29821     * @submodule base-pluginhost
29822     * @for Base
29823     */
29824
29825    var Base = Y.Base,
29826        PluginHost = Y.Plugin.Host;
29827
29828    Y.mix(Base, PluginHost, false, null, 1);
29829
29830    /**
29831     * Alias for <a href="Plugin.Host.html#method_Plugin.Host.plug">Plugin.Host.plug</a>. See aliased
29832     * method for argument and return value details.
29833     *
29834     * @method plug
29835     * @static
29836     */
29837    Base.plug = PluginHost.plug;
29838
29839    /**
29840     * Alias for <a href="Plugin.Host.html#method_Plugin.Host.unplug">Plugin.Host.unplug</a>. See the
29841     * aliased method for argument and return value details.
29842     *
29843     * @method unplug
29844     * @static
29845     */
29846    Base.unplug = PluginHost.unplug;
29847
29848
29849}, '3.18.1', {"requires": ["base-base", "pluginhost"]});
29850YUI.add('base-build', function (Y, NAME) {
29851
29852    /**
29853     * The base-build submodule provides Base.build functionality, which
29854     * can be used to create custom classes, by aggregating extensions onto
29855     * a main class.
29856     *
29857     * @module base
29858     * @submodule base-build
29859     * @for Base
29860     */
29861    var BaseCore = Y.BaseCore,
29862        Base     = Y.Base,
29863        L        = Y.Lang,
29864
29865        INITIALIZER = "initializer",
29866        DESTRUCTOR  = "destructor",
29867        AGGREGATES  = ["_PLUG", "_UNPLUG"],
29868
29869        build;
29870
29871    // Utility function used in `_buildCfg` to aggregate array values into a new
29872    // array from the sender constructor to the receiver constructor.
29873    function arrayAggregator(prop, r, s) {
29874        if (s[prop]) {
29875            r[prop] = (r[prop] || []).concat(s[prop]);
29876        }
29877    }
29878
29879    // Utility function used in `_buildCfg` to aggregate `_ATTR_CFG` array
29880    // values from the sender constructor into a new array on receiver's
29881    // constructor, and clear the cached hash.
29882    function attrCfgAggregator(prop, r, s) {
29883        if (s._ATTR_CFG) {
29884            // Clear cached hash.
29885            r._ATTR_CFG_HASH = null;
29886
29887            arrayAggregator.apply(null, arguments);
29888        }
29889    }
29890
29891    // Utility function used in `_buildCfg` to aggregate ATTRS configs from one
29892    // the sender constructor to the receiver constructor.
29893    function attrsAggregator(prop, r, s) {
29894        BaseCore.modifyAttrs(r, s.ATTRS);
29895    }
29896
29897    Base._build = function(name, main, extensions, px, sx, cfg) {
29898
29899        var build = Base._build,
29900
29901            builtClass = build._ctor(main, cfg),
29902            buildCfg = build._cfg(main, cfg, extensions),
29903
29904            _mixCust = build._mixCust,
29905
29906            dynamic = builtClass._yuibuild.dynamic,
29907
29908            i, l, extClass, extProto,
29909            initializer,
29910            destructor;
29911
29912        // Augment/Aggregate
29913        for (i = 0, l = extensions.length; i < l; i++) {
29914            extClass = extensions[i];
29915
29916            extProto = extClass.prototype;
29917
29918            initializer = extProto[INITIALIZER];
29919            destructor = extProto[DESTRUCTOR];
29920            delete extProto[INITIALIZER];
29921            delete extProto[DESTRUCTOR];
29922
29923            // Prototype, old non-displacing augment
29924            Y.mix(builtClass, extClass, true, null, 1);
29925
29926            // Custom Statics
29927            _mixCust(builtClass, extClass, buildCfg);
29928
29929            if (initializer) {
29930                extProto[INITIALIZER] = initializer;
29931            }
29932
29933            if (destructor) {
29934                extProto[DESTRUCTOR] = destructor;
29935            }
29936
29937            builtClass._yuibuild.exts.push(extClass);
29938        }
29939
29940        if (px) {
29941            Y.mix(builtClass.prototype, px, true);
29942        }
29943
29944        if (sx) {
29945            Y.mix(builtClass, build._clean(sx, buildCfg), true);
29946            _mixCust(builtClass, sx, buildCfg);
29947        }
29948
29949        builtClass.prototype.hasImpl = build._impl;
29950
29951        if (dynamic) {
29952            builtClass.NAME = name;
29953            builtClass.prototype.constructor = builtClass;
29954
29955            // Carry along the reference to `modifyAttrs()` from `main`.
29956            builtClass.modifyAttrs = main.modifyAttrs;
29957        }
29958
29959        return builtClass;
29960    };
29961
29962    build = Base._build;
29963
29964    Y.mix(build, {
29965
29966        _mixCust: function(r, s, cfg) {
29967
29968            var aggregates,
29969                custom,
29970                statics,
29971                aggr,
29972                l,
29973                i;
29974
29975            if (cfg) {
29976                aggregates = cfg.aggregates;
29977                custom = cfg.custom;
29978                statics = cfg.statics;
29979            }
29980
29981            if (statics) {
29982                Y.mix(r, s, true, statics);
29983            }
29984
29985            if (aggregates) {
29986                for (i = 0, l = aggregates.length; i < l; i++) {
29987                    aggr = aggregates[i];
29988                    if (!r.hasOwnProperty(aggr) && s.hasOwnProperty(aggr)) {
29989                        r[aggr] = L.isArray(s[aggr]) ? [] : {};
29990                    }
29991                    Y.aggregate(r, s, true, [aggr]);
29992                }
29993            }
29994
29995            if (custom) {
29996                for (i in custom) {
29997                    if (custom.hasOwnProperty(i)) {
29998                        custom[i](i, r, s);
29999                    }
30000                }
30001            }
30002
30003        },
30004
30005        _tmpl: function(main) {
30006
30007            function BuiltClass() {
30008                BuiltClass.superclass.constructor.apply(this, arguments);
30009            }
30010            Y.extend(BuiltClass, main);
30011
30012            return BuiltClass;
30013        },
30014
30015        _impl : function(extClass) {
30016            var classes = this._getClasses(), i, l, cls, exts, ll, j;
30017            for (i = 0, l = classes.length; i < l; i++) {
30018                cls = classes[i];
30019                if (cls._yuibuild) {
30020                    exts = cls._yuibuild.exts;
30021                    ll = exts.length;
30022
30023                    for (j = 0; j < ll; j++) {
30024                        if (exts[j] === extClass) {
30025                            return true;
30026                        }
30027                    }
30028                }
30029            }
30030            return false;
30031        },
30032
30033        _ctor : function(main, cfg) {
30034
30035           var dynamic = (cfg && false === cfg.dynamic) ? false : true,
30036               builtClass = (dynamic) ? build._tmpl(main) : main,
30037               buildCfg = builtClass._yuibuild;
30038
30039            if (!buildCfg) {
30040                buildCfg = builtClass._yuibuild = {};
30041            }
30042
30043            buildCfg.id = buildCfg.id || null;
30044            buildCfg.exts = buildCfg.exts || [];
30045            buildCfg.dynamic = dynamic;
30046
30047            return builtClass;
30048        },
30049
30050        _cfg : function(main, cfg, exts) {
30051            var aggr = [],
30052                cust = {},
30053                statics = [],
30054                buildCfg,
30055                cfgAggr = (cfg && cfg.aggregates),
30056                cfgCustBuild = (cfg && cfg.custom),
30057                cfgStatics = (cfg && cfg.statics),
30058                c = main,
30059                i,
30060                l;
30061
30062            // Prototype Chain
30063            while (c && c.prototype) {
30064                buildCfg = c._buildCfg;
30065                if (buildCfg) {
30066                    if (buildCfg.aggregates) {
30067                        aggr = aggr.concat(buildCfg.aggregates);
30068                    }
30069                    if (buildCfg.custom) {
30070                        Y.mix(cust, buildCfg.custom, true);
30071                    }
30072                    if (buildCfg.statics) {
30073                        statics = statics.concat(buildCfg.statics);
30074                    }
30075                }
30076                c = c.superclass ? c.superclass.constructor : null;
30077            }
30078
30079            // Exts
30080            if (exts) {
30081                for (i = 0, l = exts.length; i < l; i++) {
30082                    c = exts[i];
30083                    buildCfg = c._buildCfg;
30084                    if (buildCfg) {
30085                        if (buildCfg.aggregates) {
30086                            aggr = aggr.concat(buildCfg.aggregates);
30087                        }
30088                        if (buildCfg.custom) {
30089                            Y.mix(cust, buildCfg.custom, true);
30090                        }
30091                        if (buildCfg.statics) {
30092                            statics = statics.concat(buildCfg.statics);
30093                        }
30094                    }
30095                }
30096            }
30097
30098            if (cfgAggr) {
30099                aggr = aggr.concat(cfgAggr);
30100            }
30101
30102            if (cfgCustBuild) {
30103                Y.mix(cust, cfg.cfgBuild, true);
30104            }
30105
30106            if (cfgStatics) {
30107                statics = statics.concat(cfgStatics);
30108            }
30109
30110            return {
30111                aggregates: aggr,
30112                custom: cust,
30113                statics: statics
30114            };
30115        },
30116
30117        _clean : function(sx, cfg) {
30118            var prop, i, l, sxclone = Y.merge(sx),
30119                aggregates = cfg.aggregates,
30120                custom = cfg.custom;
30121
30122            for (prop in custom) {
30123                if (sxclone.hasOwnProperty(prop)) {
30124                    delete sxclone[prop];
30125                }
30126            }
30127
30128            for (i = 0, l = aggregates.length; i < l; i++) {
30129                prop = aggregates[i];
30130                if (sxclone.hasOwnProperty(prop)) {
30131                    delete sxclone[prop];
30132                }
30133            }
30134
30135            return sxclone;
30136        }
30137    });
30138
30139    /**
30140     * <p>
30141     * Builds a custom constructor function (class) from the
30142     * main function, and array of extension functions (classes)
30143     * provided. The NAME field for the constructor function is
30144     * defined by the first argument passed in.
30145     * </p>
30146     * <p>
30147     * The cfg object supports the following properties
30148     * </p>
30149     * <dl>
30150     *    <dt>dynamic &#60;boolean&#62;</dt>
30151     *    <dd>
30152     *    <p>If true (default), a completely new class
30153     *    is created which extends the main class, and acts as the
30154     *    host on which the extension classes are augmented.</p>
30155     *    <p>If false, the extensions classes are augmented directly to
30156     *    the main class, modifying the main class' prototype.</p>
30157     *    </dd>
30158     *    <dt>aggregates &#60;String[]&#62;</dt>
30159     *    <dd>An array of static property names, which will get aggregated
30160     *    on to the built class, in addition to the default properties build
30161     *    will always aggregate as defined by the main class' static _buildCfg
30162     *    property.
30163     *    </dd>
30164     * </dl>
30165     *
30166     * @method build
30167     * @deprecated Use the more convenient Base.create and Base.mix methods instead
30168     * @static
30169     * @param {Function} name The name of the new class. Used to define the NAME property for the new class.
30170     * @param {Function} main The main class on which to base the built class
30171     * @param {Function[]} extensions The set of extension classes which will be
30172     * augmented/aggregated to the built class.
30173     * @param {Object} cfg Optional. Build configuration for the class (see description).
30174     * @return {Function} A custom class, created from the provided main and extension classes
30175     */
30176    Base.build = function(name, main, extensions, cfg) {
30177        return build(name, main, extensions, null, null, cfg);
30178    };
30179
30180    /**
30181     * Creates a new class (constructor function) which extends the base class passed in as the second argument,
30182     * and mixes in the array of extensions provided.
30183     *
30184     * Prototype properties or methods can be added to the new class, using the px argument (similar to Y.extend).
30185     *
30186     * Static properties or methods can be added to the new class, using the sx argument (similar to Y.extend).
30187     *
30188     * **NOTE FOR COMPONENT DEVELOPERS**: Both the `base` class, and `extensions` can define static a `_buildCfg`
30189     * property, which acts as class creation meta-data, and drives how special static properties from the base
30190     * class, or extensions should be copied, aggregated or (custom) mixed into the newly created class.
30191     *
30192     * The `_buildCfg` property is a hash with 3 supported properties: `statics`, `aggregates` and `custom`, e.g:
30193     *
30194     *     // If the Base/Main class is the thing introducing the property:
30195     *
30196     *     MyBaseClass._buildCfg = {
30197     *
30198     *        // Static properties/methods to copy (Alias) to the built class.
30199     *        statics: ["CopyThisMethod", "CopyThisProperty"],
30200     *
30201     *        // Static props to aggregate onto the built class.
30202     *        aggregates: ["AggregateThisProperty"],
30203     *
30204     *        // Static properties which need custom handling (e.g. deep merge etc.)
30205     *        custom: {
30206     *           "CustomProperty" : function(property, Receiver, Supplier) {
30207     *              ...
30208     *              var triggers = Receiver.CustomProperty.triggers;
30209     *              Receiver.CustomProperty.triggers = triggers.concat(Supplier.CustomProperty.triggers);
30210     *              ...
30211     *           }
30212     *        }
30213     *     };
30214     *
30215     *     MyBaseClass.CopyThisMethod = function() {...};
30216     *     MyBaseClass.CopyThisProperty = "foo";
30217     *     MyBaseClass.AggregateThisProperty = {...};
30218     *     MyBaseClass.CustomProperty = {
30219     *        triggers: [...]
30220     *     }
30221     *
30222     *     // Or, if the Extension is the thing introducing the property:
30223     *
30224     *     MyExtension._buildCfg = {
30225     *         statics : ...
30226     *         aggregates : ...
30227     *         custom : ...
30228     *     }
30229     *
30230     * This way, when users pass your base or extension class to `Y.Base.create` or `Y.Base.mix`, they don't need to
30231     * know which properties need special handling. `Y.Base` has a buildCfg which defines `ATTRS` for custom mix handling
30232     * (to protect the static config objects), and `Y.Widget` has a buildCfg which specifies `HTML_PARSER` for
30233     * straight up aggregation.
30234     *
30235     * @method create
30236     * @static
30237     * @param {String} name The name of the newly created class. Used to define the NAME property for the new class.
30238     * @param {Function} main The base class which the new class should extend.
30239     * This class needs to be Base or a class derived from base (e.g. Widget).
30240     * @param {Function[]} extensions The list of extensions which will be mixed into the built class.
30241     * @param {Object} px The set of prototype properties/methods to add to the built class.
30242     * @param {Object} sx The set of static properties/methods to add to the built class.
30243     * @return {Function} The newly created class.
30244     */
30245    Base.create = function(name, base, extensions, px, sx) {
30246        return build(name, base, extensions, px, sx);
30247    };
30248
30249    /**
30250     * <p>Mixes in a list of extensions to an existing class.</p>
30251     * @method mix
30252     * @static
30253     * @param {Function} main The existing class into which the extensions should be mixed.
30254     * The class needs to be Base or a class derived from Base (e.g. Widget)
30255     * @param {Function[]} extensions The set of extension classes which will mixed into the existing main class.
30256     * @return {Function} The modified main class, with extensions mixed in.
30257     */
30258    Base.mix = function(main, extensions) {
30259
30260        if (main._CACHED_CLASS_DATA) {
30261            main._CACHED_CLASS_DATA = null;
30262        }
30263
30264        return build(null, main, extensions, null, null, {dynamic:false});
30265    };
30266
30267    /**
30268     * The build configuration for the Base class.
30269     *
30270     * Defines the static fields which need to be aggregated when the Base class
30271     * is used as the main class passed to the
30272     * <a href="#method_Base.build">Base.build</a> method.
30273     *
30274     * @property _buildCfg
30275     * @type Object
30276     * @static
30277     * @final
30278     * @private
30279     */
30280    BaseCore._buildCfg = {
30281        aggregates: AGGREGATES.concat(),
30282
30283        custom: {
30284            ATTRS         : attrsAggregator,
30285            _ATTR_CFG     : attrCfgAggregator,
30286            _NON_ATTRS_CFG: arrayAggregator
30287        }
30288    };
30289
30290    // Makes sure Base and BaseCore use separate `_buildCfg` objects.
30291    Base._buildCfg = {
30292        aggregates: AGGREGATES.concat(),
30293
30294        custom: {
30295            ATTRS         : attrsAggregator,
30296            _ATTR_CFG     : attrCfgAggregator,
30297            _NON_ATTRS_CFG: arrayAggregator
30298        }
30299    };
30300
30301
30302}, '3.18.1', {"requires": ["base-base"]});
30303YUI.add('event-synthetic', function (Y, NAME) {
30304
30305/**
30306 * Define new DOM events that can be subscribed to from Nodes.
30307 *
30308 * @module event
30309 * @submodule event-synthetic
30310 */
30311var CustomEvent = Y.CustomEvent,
30312    DOMMap   = Y.Env.evt.dom_map,
30313    toArray  = Y.Array,
30314    YLang    = Y.Lang,
30315    isObject = YLang.isObject,
30316    isString = YLang.isString,
30317    isArray  = YLang.isArray,
30318    query    = Y.Selector.query,
30319    noop     = function () {};
30320
30321/**
30322 * <p>The triggering mechanism used by SyntheticEvents.</p>
30323 *
30324 * <p>Implementers should not instantiate these directly.  Use the Notifier
30325 * provided to the event's implemented <code>on(node, sub, notifier)</code> or
30326 * <code>delegate(node, sub, notifier, filter)</code> methods.</p>
30327 *
30328 * @class SyntheticEvent.Notifier
30329 * @constructor
30330 * @param handle {EventHandle} the detach handle for the subscription to an
30331 *              internal custom event used to execute the callback passed to
30332 *              on(..) or delegate(..)
30333 * @param emitFacade {Boolean} take steps to ensure the first arg received by
30334 *              the subscription callback is an event facade
30335 * @private
30336 * @since 3.2.0
30337 */
30338function Notifier(handle, emitFacade) {
30339    this.handle     = handle;
30340    this.emitFacade = emitFacade;
30341}
30342
30343/**
30344 * <p>Executes the subscription callback, passing the firing arguments as the
30345 * first parameters to that callback. For events that are configured with
30346 * emitFacade=true, it is common practice to pass the triggering DOMEventFacade
30347 * as the first parameter.  Barring a proper DOMEventFacade or EventFacade
30348 * (from a CustomEvent), a new EventFacade will be generated.  In that case, if
30349 * fire() is called with a simple object, it will be mixed into the facade.
30350 * Otherwise, the facade will be prepended to the callback parameters.</p>
30351 *
30352 * <p>For notifiers provided to delegate logic, the first argument should be an
30353 * object with a &quot;currentTarget&quot; property to identify what object to
30354 * default as 'this' in the callback.  Typically this is gleaned from the
30355 * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an
30356 * object must be provided.  In that case, the object will be removed from the
30357 * callback parameters.</p>
30358 *
30359 * <p>Additional arguments passed during event subscription will be
30360 * automatically added after those passed to fire().</p>
30361 *
30362 * @method fire
30363 * @param {EventFacade|DOMEventFacade|any} e (see description)
30364 * @param {any[]} [arg*] additional arguments received by all subscriptions
30365 * @private
30366 */
30367Notifier.prototype.fire = function (e) {
30368    // first arg to delegate notifier should be an object with currentTarget
30369    var args     = toArray(arguments, 0, true),
30370        handle   = this.handle,
30371        ce       = handle.evt,
30372        sub      = handle.sub,
30373        thisObj  = sub.context,
30374        delegate = sub.filter,
30375        event    = e || {},
30376        ret;
30377
30378    if (this.emitFacade) {
30379        if (!e || !e.preventDefault) {
30380            event = ce._getFacade();
30381
30382            if (isObject(e) && !e.preventDefault) {
30383                Y.mix(event, e, true);
30384                args[0] = event;
30385            } else {
30386                args.unshift(event);
30387            }
30388        }
30389
30390        event.type    = ce.type;
30391        event.details = args.slice();
30392
30393        if (delegate) {
30394            event.container = ce.host;
30395        }
30396    } else if (delegate && isObject(e) && e.currentTarget) {
30397        args.shift();
30398    }
30399
30400    sub.context = thisObj || event.currentTarget || ce.host;
30401    ret = ce.fire.apply(ce, args);
30402
30403    // have to handle preventedFn and stoppedFn manually because
30404    // Notifier CustomEvents are forced to emitFacade=false
30405    if (e.prevented && ce.preventedFn) {
30406        ce.preventedFn.apply(ce, args);
30407    }
30408
30409    if (e.stopped && ce.stoppedFn) {
30410        ce.stoppedFn.apply(ce, args);
30411    }
30412
30413    sub.context = thisObj; // reset for future firing
30414
30415    // to capture callbacks that return false to stopPropagation.
30416    // Useful for delegate implementations
30417    return ret;
30418};
30419
30420/**
30421 * Manager object for synthetic event subscriptions to aggregate multiple synths on the
30422 * same node without colliding with actual DOM subscription entries in the global map of
30423 * DOM subscriptions.  Also facilitates proper cleanup on page unload.
30424 *
30425 * @class SynthRegistry
30426 * @constructor
30427 * @param el {HTMLElement} the DOM element
30428 * @param yuid {String} the yuid stamp for the element
30429 * @param key {String} the generated id token used to identify an event type +
30430 *                     element in the global DOM subscription map.
30431 * @private
30432 */
30433function SynthRegistry(el, yuid, key) {
30434    this.handles = [];
30435    this.el      = el;
30436    this.key     = key;
30437    this.domkey  = yuid;
30438}
30439
30440SynthRegistry.prototype = {
30441    constructor: SynthRegistry,
30442
30443    // A few object properties to fake the CustomEvent interface for page
30444    // unload cleanup.  DON'T TOUCH!
30445    type      : '_synth',
30446    fn        : noop,
30447    capture   : false,
30448
30449    /**
30450     * Adds a subscription from the Notifier registry.
30451     *
30452     * @method register
30453     * @param handle {EventHandle} the subscription
30454     * @since 3.4.0
30455     */
30456    register: function (handle) {
30457        handle.evt.registry = this;
30458        this.handles.push(handle);
30459    },
30460
30461    /**
30462     * Removes the subscription from the Notifier registry.
30463     *
30464     * @method _unregisterSub
30465     * @param sub {Subscription} the subscription
30466     * @since 3.4.0
30467     */
30468    unregister: function (sub) {
30469        var handles = this.handles,
30470            events = DOMMap[this.domkey],
30471            i;
30472
30473        for (i = handles.length - 1; i >= 0; --i) {
30474            if (handles[i].sub === sub) {
30475                handles.splice(i, 1);
30476                break;
30477            }
30478        }
30479
30480        // Clean up left over objects when there are no more subscribers.
30481        if (!handles.length) {
30482            delete events[this.key];
30483            if (!Y.Object.size(events)) {
30484                delete DOMMap[this.domkey];
30485            }
30486        }
30487    },
30488
30489    /**
30490     * Used by the event system's unload cleanup process.  When navigating
30491     * away from the page, the event system iterates the global map of element
30492     * subscriptions and detaches everything using detachAll().  Normally,
30493     * the map is populated with custom events, so this object needs to
30494     * at least support the detachAll method to duck type its way to
30495     * cleanliness.
30496     *
30497     * @method detachAll
30498     * @private
30499     * @since 3.4.0
30500     */
30501    detachAll : function () {
30502        var handles = this.handles,
30503            i = handles.length;
30504
30505        while (--i >= 0) {
30506            handles[i].detach();
30507        }
30508    }
30509};
30510
30511/**
30512 * <p>Wrapper class for the integration of new events into the YUI event
30513 * infrastructure.  Don't instantiate this object directly, use
30514 * <code>Y.Event.define(type, config)</code>.  See that method for details.</p>
30515 *
30516 * <p>Properties that MAY or SHOULD be specified in the configuration are noted
30517 * below and in the description of <code>Y.Event.define</code>.</p>
30518 *
30519 * @class SyntheticEvent
30520 * @constructor
30521 * @param cfg {Object} Implementation pieces and configuration
30522 * @since 3.1.0
30523 * @in event-synthetic
30524 */
30525function SyntheticEvent() {
30526    this._init.apply(this, arguments);
30527}
30528
30529Y.mix(SyntheticEvent, {
30530    Notifier: Notifier,
30531    SynthRegistry: SynthRegistry,
30532
30533    /**
30534     * Returns the array of subscription handles for a node for the given event
30535     * type.  Passing true as the third argument will create a registry entry
30536     * in the event system's DOM map to host the array if one doesn't yet exist.
30537     *
30538     * @method getRegistry
30539     * @param node {Node} the node
30540     * @param type {String} the event
30541     * @param create {Boolean} create a registration entry to host a new array
30542     *                  if one doesn't exist.
30543     * @return {Array}
30544     * @static
30545     * @protected
30546     * @since 3.2.0
30547     */
30548    getRegistry: function (node, type, create) {
30549        var el     = node._node,
30550            yuid   = Y.stamp(el),
30551            key    = 'event:' + yuid + type + '_synth',
30552            events = DOMMap[yuid];
30553
30554        if (create) {
30555            if (!events) {
30556                events = DOMMap[yuid] = {};
30557            }
30558            if (!events[key]) {
30559                events[key] = new SynthRegistry(el, yuid, key);
30560            }
30561        }
30562
30563        return (events && events[key]) || null;
30564    },
30565
30566    /**
30567     * Alternate <code>_delete()</code> method for the CustomEvent object
30568     * created to manage SyntheticEvent subscriptions.
30569     *
30570     * @method _deleteSub
30571     * @param sub {Subscription} the subscription to clean up
30572     * @private
30573     * @since 3.2.0
30574     */
30575    _deleteSub: function (sub) {
30576        if (sub && sub.fn) {
30577            var synth = this.eventDef,
30578                method = (sub.filter) ? 'detachDelegate' : 'detach';
30579
30580            this._subscribers = [];
30581
30582            if (CustomEvent.keepDeprecatedSubs) {
30583                this.subscribers = {};
30584            }
30585
30586            synth[method](sub.node, sub, this.notifier, sub.filter);
30587            this.registry.unregister(sub);
30588
30589            delete sub.fn;
30590            delete sub.node;
30591            delete sub.context;
30592        }
30593    },
30594
30595    prototype: {
30596        constructor: SyntheticEvent,
30597
30598        /**
30599         * Construction logic for the event.
30600         *
30601         * @method _init
30602         * @protected
30603         */
30604        _init: function () {
30605            var config = this.publishConfig || (this.publishConfig = {});
30606
30607            // The notification mechanism handles facade creation
30608            this.emitFacade = ('emitFacade' in config) ?
30609                                config.emitFacade :
30610                                true;
30611            config.emitFacade  = false;
30612        },
30613
30614        /**
30615         * <p>Implementers MAY provide this method definition.</p>
30616         *
30617         * <p>Implement this function if the event supports a different
30618         * subscription signature.  This function is used by both
30619         * <code>on()</code> and <code>delegate()</code>.  The second parameter
30620         * indicates that the event is being subscribed via
30621         * <code>delegate()</code>.</p>
30622         *
30623         * <p>Implementations must remove extra arguments from the args list
30624         * before returning.  The required args for <code>on()</code>
30625         * subscriptions are</p>
30626         * <pre><code>[type, callback, target, context, argN...]</code></pre>
30627         *
30628         * <p>The required args for <code>delegate()</code>
30629         * subscriptions are</p>
30630         *
30631         * <pre><code>[type, callback, target, filter, context, argN...]</code></pre>
30632         *
30633         * <p>The return value from this function will be stored on the
30634         * subscription in the '_extra' property for reference elsewhere.</p>
30635         *
30636         * @method processArgs
30637         * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..)
30638         * @param delegate {Boolean} true if the subscription is from Y.delegate
30639         * @return {any}
30640         */
30641        processArgs: noop,
30642
30643        /**
30644         * <p>Implementers MAY override this property.</p>
30645         *
30646         * <p>Whether to prevent multiple subscriptions to this event that are
30647         * classified as being the same.  By default, this means the subscribed
30648         * callback is the same function.  See the <code>subMatch</code>
30649         * method.  Setting this to true will impact performance for high volume
30650         * events.</p>
30651         *
30652         * @property preventDups
30653         * @type {Boolean}
30654         * @default false
30655         */
30656        //preventDups  : false,
30657
30658        /**
30659         * <p>Implementers SHOULD provide this method definition.</p>
30660         *
30661         * Implementation logic for subscriptions done via <code>node.on(type,
30662         * fn)</code> or <code>Y.on(type, fn, target)</code>.  This
30663         * function should set up the monitor(s) that will eventually fire the
30664         * event.  Typically this involves subscribing to at least one DOM
30665         * event.  It is recommended to store detach handles from any DOM
30666         * subscriptions to make for easy cleanup in the <code>detach</code>
30667         * method.  Typically these handles are added to the <code>sub</code>
30668         * object.  Also for SyntheticEvents that leverage a single DOM
30669         * subscription under the hood, it is recommended to pass the DOM event
30670         * object to <code>notifier.fire(e)</code>.  (The event name on the
30671         * object will be updated).
30672         *
30673         * @method on
30674         * @param node {Node} the node the subscription is being applied to
30675         * @param sub {Subscription} the object to track this subscription
30676         * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
30677         *              trigger the execution of the subscribers
30678         */
30679        on: noop,
30680
30681        /**
30682         * <p>Implementers SHOULD provide this method definition.</p>
30683         *
30684         * <p>Implementation logic for detaching subscriptions done via
30685         * <code>
30685node.on(type, fn)</code>.  This function should clean up any
30686         * subscriptions made in the <code>on()</code> phase.</p>
30687         *
30688         * @method detach
30689         * @param node {Node} the node the subscription was applied to
30690         * @param sub {Subscription} the object tracking this subscription
30691         * @param notifier {SyntheticEvent.Notifier} the Notifier used to
30692         *              trigger the execution of the subscribers
30693         */
30694        detach: noop,
30695
30696        /**
30697         * <p>Implementers SHOULD provide this method definition.</p>
30698         *
30699         * <p>Implementation logic for subscriptions done via
30700         * <code>node.delegate(type, fn, filter)</code> or
30701         * <code>Y.delegate(type, fn, container, filter)</code>.  Like with
30702         * <code>on()</code> above, this function should monitor the environment
30703         * for the event being fired, and trigger subscription execution by
30704         * calling <code>notifier.fire(e)</code>.</p>
30705         *
30706         * <p>This function receives a fourth argument, which is the filter
30707         * used to identify which Node's are of interest to the subscription.
30708         * The filter will be either a boolean function that accepts a target
30709         * Node for each hierarchy level as the event bubbles, or a selector
30710         * string.  To translate selector strings into filter functions, use
30711         * <code>Y.delegate.compileFilter(filter)</code>.</p>
30712         *
30713         * @method delegate
30714         * @param node {Node} the node the subscription is being applied to
30715         * @param sub {Subscription} the object to track this subscription
30716         * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
30717         *              trigger the execution of the subscribers
30718         * @param filter {String|Function} Selector string or function that
30719         *              accepts an event object and returns null, a Node, or an
30720         *              array of Nodes matching the criteria for processing.
30721         * @since 3.2.0
30722         */
30723        delegate       : noop,
30724
30725        /**
30726         * <p>Implementers SHOULD provide this method definition.</p>
30727         *
30728         * <p>Implementation logic for detaching subscriptions done via
30729         * <code>node.delegate(type, fn, filter)</code> or
30730         * <code>Y.delegate(type, fn, container, filter)</code>.  This function
30731         * should clean up any subscriptions made in the
30732         * <code>delegate()</code> phase.</p>
30733         *
30734         * @method detachDelegate
30735         * @param node {Node} the node the subscription was applied to
30736         * @param sub {Subscription} the object tracking this subscription
30737         * @param notifier {SyntheticEvent.Notifier} the Notifier used to
30738         *              trigger the execution of the subscribers
30739         * @param filter {String|Function} Selector string or function that
30740         *              accepts an event object and returns null, a Node, or an
30741         *              array of Nodes matching the criteria for processing.
30742         * @since 3.2.0
30743         */
30744        detachDelegate : noop,
30745
30746        /**
30747         * Sets up the boilerplate for detaching the event and facilitating the
30748         * execution of subscriber callbacks.
30749         *
30750         * @method _on
30751         * @param args {Array} array of arguments passed to
30752         *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
30753         * @param delegate {Boolean} true if called from
30754         * <code>Y.delegate(...)</code>
30755         * @return {EventHandle} the detach handle for this subscription
30756         * @private
30757         * since 3.2.0
30758         */
30759        _on: function (args, delegate) {
30760            var handles  = [],
30761                originalArgs = args.slice(),
30762                extra    = this.processArgs(args, delegate),
30763                selector = args[2],
30764                method   = delegate ? 'delegate' : 'on',
30765                nodes, handle;
30766
30767            // Can't just use Y.all because it doesn't support window (yet?)
30768            nodes = (isString(selector)) ?
30769                query(selector) :
30770                toArray(selector || Y.one(Y.config.win));
30771
30772            if (!nodes.length && isString(selector)) {
30773                handle = Y.on('available', function () {
30774                    Y.mix(handle, Y[method].apply(Y, originalArgs), true);
30775                }, selector);
30776
30777                return handle;
30778            }
30779
30780            Y.Array.each(nodes, function (node) {
30781                var subArgs = args.slice(),
30782                    filter;
30783
30784                node = Y.one(node);
30785
30786                if (node) {
30787                    if (delegate) {
30788                        filter = subArgs.splice(3, 1)[0];
30789                    }
30790
30791                    // (type, fn, el, thisObj, ...) => (fn, thisObj, ...)
30792                    subArgs.splice(0, 4, subArgs[1], subArgs[3]);
30793
30794                    if (!this.preventDups ||
30795                        !this.getSubs(node, args, null, true))
30796                    {
30797                        handles.push(this._subscribe(node, method, subArgs, extra, filter));
30798                    }
30799                }
30800            }, this);
30801
30802            return (handles.length === 1) ?
30803                handles[0] :
30804                new Y.EventHandle(handles);
30805        },
30806
30807        /**
30808         * Creates a new Notifier object for use by this event's
30809         * <code>on(...)</code> or <code>delegate(...)</code> implementation
30810         * and register the custom event proxy in the DOM system for cleanup.
30811         *
30812         * @method _subscribe
30813         * @param node {Node} the Node hosting the event
30814         * @param method {String} "on" or "delegate"
30815         * @param args {Array} the subscription arguments passed to either
30816         *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
30817         *              after running through <code>processArgs(args)</code> to
30818         *              normalize the argument signature
30819         * @param extra {any} Extra data parsed from
30820         *              <code>processArgs(args)</code>
30821         * @param filter {String|Function} the selector string or function
30822         *              filter passed to <code>Y.delegate(...)</code> (not
30823         *              present when called from <code>Y.on(...)</code>)
30824         * @return {EventHandle}
30825         * @private
30826         * @since 3.2.0
30827         */
30828        _subscribe: function (node, method, args, extra, filter) {
30829            var dispatcher = new Y.CustomEvent(this.type, this.publishConfig),
30830                handle     = dispatcher.on.apply(dispatcher, args),
30831                notifier   = new Notifier(handle, this.emitFacade),
30832                registry   = SyntheticEvent.getRegistry(node, this.type, true),
30833                sub        = handle.sub;
30834
30835            sub.node   = node;
30836            sub.filter = filter;
30837            if (extra) {
30838                this.applyArgExtras(extra, sub);
30839            }
30840
30841            Y.mix(dispatcher, {
30842                eventDef     : this,
30843                notifier     : notifier,
30844                host         : node,       // I forget what this is for
30845                currentTarget: node,       // for generating facades
30846                target       : node,       // for generating facades
30847                el           : node._node, // For category detach
30848
30849                _delete      : SyntheticEvent._deleteSub
30850            }, true);
30851
30852            handle.notifier = notifier;
30853
30854            registry.register(handle);
30855
30856            // Call the implementation's "on" or "delegate" method
30857            this[method](node, sub, notifier, filter);
30858
30859            return handle;
30860        },
30861
30862        /**
30863         * <p>Implementers MAY provide this method definition.</p>
30864         *
30865         * <p>Implement this function if you want extra data extracted during
30866         * processArgs to be propagated to subscriptions on a per-node basis.
30867         * That is to say, if you call <code>Y.on('xyz', fn, xtra, 'div')</code>
30868         * the data returned from processArgs will be shared
30869         * across the subscription objects for all the divs.  If you want each
30870         * subscription to receive unique information, do that processing
30871         * here.</p>
30872         *
30873         * <p>The default implementation adds the data extracted by processArgs
30874         * to the subscription object as <code>sub._extra</code>.</p>
30875         *
30876         * @method applyArgExtras
30877         * @param extra {any} Any extra data extracted from processArgs
30878         * @param sub {Subscription} the individual subscription
30879         */
30880        applyArgExtras: function (extra, sub) {
30881            sub._extra = extra;
30882        },
30883
30884        /**
30885         * Removes the subscription(s) from the internal subscription dispatch
30886         * mechanism.  See <code>SyntheticEvent._deleteSub</code>.
30887         *
30888         * @method _detach
30889         * @param args {Array} The arguments passed to
30890         *                  <code>node.detach(...)</code>
30891         * @private
30892         * @since 3.2.0
30893         */
30894        _detach: function (args) {
30895            // Can't use Y.all because it doesn't support window (yet?)
30896            // TODO: Does Y.all support window now?
30897            var target = args[2],
30898                els    = (isString(target)) ?
30899                            query(target) : toArray(target),
30900                node, i, len, handles, j;
30901
30902            // (type, fn, el, context, filter?) => (type, fn, context, filter?)
30903            args.splice(2, 1);
30904
30905            for (i = 0, len = els.length; i < len; ++i) {
30906                node = Y.one(els[i]);
30907
30908                if (node) {
30909                    handles = this.getSubs(node, args);
30910
30911                    if (handles) {
30912                        for (j = handles.length - 1; j >= 0; --j) {
30913                            handles[j].detach();
30914                        }
30915                    }
30916                }
30917            }
30918        },
30919
30920        /**
30921         * Returns the detach handles of subscriptions on a node that satisfy a
30922         * search/filter function.  By default, the filter used is the
30923         * <code>subMatch</code> method.
30924         *
30925         * @method getSubs
30926         * @param node {Node} the node hosting the event
30927         * @param args {Array} the array of original subscription args passed
30928         *              to <code>Y.on(...)</code> (before
30929         *              <code>processArgs</code>
30930         * @param filter {Function} function used to identify a subscription
30931         *              for inclusion in the returned array
30932         * @param first {Boolean} stop after the first match (used to check for
30933         *              duplicate subscriptions)
30934         * @return {EventHandle[]} detach handles for the matching subscriptions
30935         */
30936        getSubs: function (node, args, filter, first) {
30937            var registry = SyntheticEvent.getRegistry(node, this.type),
30938                handles  = [],
30939                allHandles, i, len, handle;
30940
30941            if (registry) {
30942                allHandles = registry.handles;
30943
30944                if (!filter) {
30945                    filter = this.subMatch;
30946                }
30947
30948                for (i = 0, len = allHandles.length; i < len; ++i) {
30949                    handle = allHandles[i];
30950                    if (filter.call(this, handle.sub, args)) {
30951                        if (first) {
30952                            return handle;
30953                        } else {
30954                            handles.push(allHandles[i]);
30955                        }
30956                    }
30957                }
30958            }
30959
30960            return handles.length && handles;
30961        },
30962
30963        /**
30964         * <p>Implementers MAY override this to define what constitutes a
30965         * &quot;same&quot; subscription.  Override implementations should
30966         * consider the lack of a comparator as a match, so calling
30967         * <code>getSubs()</code> with no arguments will return all subs.</p>
30968         *
30969         * <p>Compares a set of subscription arguments against a Subscription
30970         * object to determine if they match.  The default implementation
30971         * compares the callback function against the second argument passed to
30972         * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
30973         *
30974         * @method subMatch
30975         * @param sub {Subscription} the existing subscription
30976         * @param args {Array} the calling arguments passed to
30977         *                  <code>Y.on(...)</code> etc.
30978         * @return {Boolean} true if the sub can be described by the args
30979         *                  present
30980         * @since 3.2.0
30981         */
30982        subMatch: function (sub, args) {
30983            // Default detach cares only about the callback matching
30984            return !args[1] || sub.fn === args[1];
30985        }
30986    }
30987}, true);
30988
30989Y.SyntheticEvent = SyntheticEvent;
30990
30991/**
30992 * <p>Defines a new event in the DOM event system.  Implementers are
30993 * responsible for monitoring for a scenario whereby the event is fired.  A
30994 * notifier object is provided to the functions identified below.  When the
30995 * criteria defining the event are met, call notifier.fire( [args] ); to
30996 * execute event subscribers.</p>
30997 *
30998 * <p>The first parameter is the name of the event.  The second parameter is a
30999 * configuration object which define the behavior of the event system when the
31000 * new event is subscribed to or detached from.  The methods that should be
31001 * defined in this configuration object are <code>on</code>,
31002 * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>.
31003 * You are free to define any other methods or properties needed to define your
31004 * event.  Be aware, however, that since the object is used to subclass
31005 * SyntheticEvent, you should avoid method names used by SyntheticEvent unless
31006 * your intention is to override the default behavior.</p>
31007 *
31008 * <p>This is a list of properties and methods that you can or should specify
31009 * in the configuration object:</p>
31010 *
31011 * <dl>
31012 *   <dt><code>on</code></dt>
31013 *       <dd><code>function (node, subscription, notifier)</code> The
31014 *       implementation logic for subscription.  Any special setup you need to
31015 *       do to create the environment for the event being fired--E.g. native
31016 *       DOM event subscriptions.  Store subscription related objects and
31017 *       state on the <code>subscription</code> object.  When the
31018 *       criteria have been met to fire the synthetic event, call
31019 *       <code>notifier.fire(e)</code>.  See Notifier's <code>fire()</code>
31020 *       method for details about what to pass as parameters.</dd>
31021 *
31022 *   <dt><code>detach</code></dt>
31023 *       <dd><code>function (node, subscription, notifier)</code> The
31024 *       implementation logic for cleaning up a detached subscription. E.g.
31025 *       detach any DOM subscriptions added in <code>on</code>.</dd>
31026 *
31027 *   <dt><code>delegate</code></dt>
31028 *       <dd><code>function (node, subscription, notifier, filter)</code> The
31029 *       implementation logic for subscription via <code>Y.delegate</code> or
31030 *       <code>node.delegate</code>.  The filter is typically either a selector
31031 *       string or a function.  You can use
31032 *       <code>Y.delegate.compileFilter(selectorString)</code> to create a
31033 *       filter function from a selector string if needed.  The filter function
31034 *       expects an event object as input and should output either null, a
31035 *       matching Node, or an array of matching Nodes.  Otherwise, this acts
31036 *       like <code>on</code> DOM event subscriptions.  Store subscription
31037 *       related objects and information on the <code>subscription</code>
31038 *       object.  When the criteria have been met to fire the synthetic event,
31039 *       call <code>notifier.fire(e)</code> as noted above.</dd>
31040 *
31041 *   <dt><code>detachDelegate</code></dt>
31042 *       <dd><code>function (node, subscription, notifier)</code> The
31043 *       implementation logic for cleaning up a detached delegate subscription.
31044 *       E.g. detach any DOM delegate subscriptions added in
31045 *       <code>delegate</code>.</dd>
31046 *
31047 *   <dt><code>publishConfig</code></dt>
31048 *       <dd>(Object) The configuration object that will be used to instantiate
31049 *       the underlying CustomEvent. See Notifier's <code>fire</code> method
31050 *       for details.</dd>
31051 *
31052 *   <dt><code>processArgs</code></dt
31053 *       <dd>
31054 *          <p><code>function (argArray, fromDelegate)</code> Optional method
31055 *          to extract any additional arguments from the subscription
31056 *          signature.  Using this allows <code>on</code> or
31057 *          <code>delegate</code> signatures like
31058 *          <code>node.on(&quot;hover&quot;, overCallback,
31059 *          outCallback)</code>.</p>
31060 *          <p>When processing an atypical argument signature, make sure the
31061 *          args array is returned to the normal signature before returning
31062 *          from the function.  For example, in the &quot;hover&quot; example
31063 *          above, the <code>outCallback</code> needs to be <code>splice</code>d
31064 *          out of the array.  The expected signature of the args array for
31065 *          <code>on()</code> subscriptions is:</p>
31066 *          <pre>
31067 *              <code>[type, callback, target, contextOverride, argN...]</code>
31068 *          </pre>
31069 *          <p>And for <code>delegate()</code>:</p>
31070 *          <pre>
31071 *              <code>[type, callback, target, filter, contextOverride, argN...]</code>
31072 *          </pre>
31073 *          <p>where <code>target</code> is the node the event is being
31074 *          subscribed for.  You can see these signatures documented for
31075 *          <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p>
31076 *          <p>Whatever gets returned from the function will be stored on the
31077 *          <code>subscription</code> object under
31078 *          <code>subscription._extra</code>.</p></dd>
31079 *   <dt><code>subMatch</code></dt>
31080 *       <dd>
31081 *           <p><code>function (sub, args)</code>  Compares a set of
31082 *           subscription arguments against a Subscription object to determine
31083 *           if they match.  The default implementation compares the callback
31084 *           function against the second argument passed to
31085 *           <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
31086 *       </dd>
31087 * </dl>
31088 *
31089 * @method define
31090 * @param type {String} the name of the event
31091 * @param config {Object} the prototype definition for the new event (see above)
31092 * @param force {Boolean} override an existing event (use with caution)
31093 * @return {SyntheticEvent} the subclass implementation instance created to
31094 *              handle event subscriptions of this type
31095 * @static
31096 * @for Event
31097 * @since 3.1.0
31098 * @in event-synthetic
31099 */
31100Y.Event.define = function (type, config, force) {
31101    var eventDef, Impl, synth;
31102
31103    if (type && type.type) {
31104        eventDef = type;
31105        force = config;
31106    } else if (config) {
31107        eventDef = Y.merge({ type: type }
31107, config);
31108    }
31109
31110    if (eventDef) {
31111        if (force || !Y.Node.DOM_EVENTS[eventDef.type]) {
31112            Impl = function () {
31113                SyntheticEvent.apply(this, arguments);
31114            };
31115            Y.extend(Impl, SyntheticEvent, eventDef);
31116            synth = new Impl();
31117
31118            type = synth.type;
31119
31120            Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = {
31121                eventDef: synth,
31122
31123                on: function () {
31124                    return synth._on(toArray(arguments));
31125                },
31126
31127                delegate: function () {
31128                    return synth._on(toArray(arguments), true);
31129                },
31130
31131                detach: function () {
31132                    return synth._detach(toArray(arguments));
31133                }
31134            };
31135
31136        }
31137    } else if (isString(type) || isArray(type)) {
31138        Y.Array.each(toArray(type), function (t) {
31139            Y.Node.DOM_EVENTS[t] = 1;
31140        });
31141    }
31142
31143    return synth;
31144};
31145
31146
31147}, '3.18.1', {"requires": ["node-base", "event-custom-complex"]});
31148YUI.add('attribute-complex', function (Y, NAME) {
31149
31150    /**
31151     * Adds support for attribute providers to handle complex attributes in the constructor
31152     *
31153     * @module attribute
31154     * @submodule attribute-complex
31155     * @for Attribute
31156     * @deprecated AttributeComplex's overrides are now part of AttributeCore.
31157     */
31158
31159    var Attribute = Y.Attribute;
31160
31161    Attribute.Complex = function() {};
31162    Attribute.Complex.prototype = {
31163
31164        /**
31165         * Utility method to split out simple attribute name/value pairs ("x")
31166         * from complex attribute name/value pairs ("x.y.z"), so that complex
31167         * attributes can be keyed by the top level attribute name.
31168         *
31169         * @method _normAttrVals
31170         * @param {Object} valueHash An object with attribute name/value pairs
31171         *
31172         * @return {Object} An object literal with 2 properties - "simple" and "complex",
31173         * containing simple and complex attribute values respectively keyed
31174         * by the top level attribute name, or null, if valueHash is falsey.
31175         *
31176         * @private
31177         */
31178        _normAttrVals : Attribute.prototype._normAttrVals,
31179
31180        /**
31181         * Returns the initial value of the given attribute from
31182         * either the default configuration provided, or the
31183         * over-ridden value if it exists in the set of initValues
31184         * provided and the attribute is not read-only.
31185         *
31186         * @param {String} attr The name of the attribute
31187         * @param {Object} cfg The attribute configuration object
31188         * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
31189         *
31190         * @return {Any} The initial value of the attribute.
31191         *
31192         * @method _getAttrInitVal
31193         * @private
31194         */
31195        _getAttrInitVal : Attribute.prototype._getAttrInitVal
31196
31197    };
31198
31199    // Consistency with the rest of the Attribute addons for now.
31200    Y.AttributeComplex = Attribute.Complex;
31201
31202
31203}, '3.18.1', {"requires": ["attribute-base"]});
31204YUI.add('event-mouseenter', function (Y, NAME) {
31205
31206/**
31207 * <p>Adds subscription and delegation support for mouseenter and mouseleave
31208 * events.  Unlike mouseover and mouseout, these events aren't fired from child
31209 * elements of a subscribed node.</p>
31210 *
31211 * <p>This avoids receiving three mouseover notifications from a setup like</p>
31212 *
31213 * <pre><code>div#container > p > a[href]</code></pre>
31214 *
31215 * <p>where</p>
31216 *
31217 * <pre><code>Y.one('#container').on('mouseover', callback)</code></pre>
31218 *
31219 * <p>When the mouse moves over the link, one mouseover event is fired from
31220 * #container, then when the mouse moves over the p, another mouseover event is
31221 * fired and bubbles to #container, causing a second notification, and finally
31222 * when the mouse moves over the link, a third mouseover event is fired and
31223 * bubbles to #container for a third notification.</p>
31224 *
31225 * <p>By contrast, using mouseenter instead of mouseover, the callback would be
31226 * executed only once when the mouse moves over #container.</p>
31227 *
31228 * @module event
31229 * @submodule event-mouseenter
31230 */
31231
31232var domEventProxies = Y.Env.evt.dom_wrappers,
31233    contains = Y.DOM.contains,
31234    toArray = Y.Array,
31235    noop = function () {},
31236
31237    config = {
31238        proxyType: "mouseover",
31239        relProperty: "fromElement",
31240
31241        _notify: function (e, property, notifier) {
31242            var el = this._node,
31243                related = e.relatedTarget || e[property];
31244
31245            if (el !== related && !contains(el, related)) {
31246                notifier.fire(new Y.DOMEventFacade(e, el,
31247                    domEventProxies['event:' + Y.stamp(el) + e.type]));
31248            }
31249        },
31250
31251        on: function (node, sub, notifier) {
31252            var el = Y.Node.getDOMNode(node),
31253                args = [
31254                    this.proxyType,
31255                    this._notify,
31256                    el,
31257                    null,
31258                    this.relProperty,
31259                    notifier];
31260
31261            sub.handle = Y.Event._attach(args, { facade: false });
31262            // node.on(this.proxyType, notify, null, notifier);
31263        },
31264
31265        detach: function (node, sub) {
31266            sub.handle.detach();
31267        },
31268
31269        delegate: function (node, sub, notifier, filter) {
31270            var el = Y.Node.getDOMNode(node),
31271                args = [
31272                    this.proxyType,
31273                    noop,
31274                    el,
31275                    null,
31276                    notifier
31277                ];
31278
31279            sub.handle = Y.Event._attach(args, { facade: false });
31280            sub.handle.sub.filter = filter;
31281            sub.handle.sub.relProperty = this.relProperty;
31282            sub.handle.sub._notify = this._filterNotify;
31283        },
31284
31285        _filterNotify: function (thisObj, args, ce) {
31286            args = args.slice();
31287            if (this.args) {
31288                args.push.apply(args, this.args);
31289            }
31290
31291            var currentTarget = Y.delegate._applyFilter(this.filter, args, ce),
31292                related = args[0].relatedTarget || args[0][this.relProperty],
31293                e, i, len, ret, ct;
31294
31295            if (currentTarget) {
31296                currentTarget = toArray(currentTarget);
31297
31298                for (i = 0, len = currentTarget.length && (!e || !e.stopped); i < len; ++i) {
31299                    ct = currentTarget[0];
31300                    if (!contains(ct, related)) {
31301                        if (!e) {
31302                            e = new Y.DOMEventFacade(args[0], ct, ce);
31303                            e.container = Y.one(ce.el);
31304                        }
31305                        e.currentTarget = Y.one(ct);
31306
31307                        // TODO: where is notifier? args? this.notifier?
31308                        ret = args[1].fire(e);
31309
31310                        if (ret === false) {
31311                            break;
31312                        }
31313                    }
31314                }
31315            }
31316
31317            return ret;
31318        },
31319
31320        detachDelegate: function (node, sub) {
31321            sub.handle.detach();
31322        }
31323    };
31324
31325Y.Event.define("mouseenter", config, true);
31326Y.Event.define("mouseleave", Y.merge(config, {
31327    proxyType: "mouseout",
31328    relProperty: "toElement"
31329}), true);
31330
31331
31332}, '3.18.1', {"requires": ["event-synthetic"]});
31333YUI.add('event-key', function (Y, NAME) {
31334
31335/**
31336 * Functionality to listen for one or more specific key combinations.
31337 * @module event
31338 * @submodule event-key
31339 */
31340
31341var ALT      = "+alt",
31342    CTRL     = "+ctrl",
31343    META     = "+meta",
31344    SHIFT    = "+shift",
31345
31346    trim     = Y.Lang.trim,
31347
31348    eventDef = {
31349        KEY_MAP: {
31350            enter    : 13,
31351            space    : 32,
31352            esc      : 27,
31353            backspace: 8,
31354            tab      : 9,
31355            pageup   : 33,
31356            pagedown : 34
31357        },
31358
31359        _typeRE: /^(up|down|press):/,
31360        _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g,
31361
31362        processArgs: function (args) {
31363            var spec = args.splice(3,1)[0],
31364                mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []),
31365                config = {
31366                    type: this._typeRE.test(spec) ? RegExp.$1 : null,
31367                    mods: mods,
31368                    keys: null
31369                },
31370                // strip type and modifiers from spec, leaving only keyCodes
31371                bits = spec.replace(this._keysRE, ''),
31372                chr, uc, lc, i;
31373
31374            if (bits) {
31375                bits = bits.split(',');
31376
31377                config.keys = {};
31378
31379                // FIXME: need to support '65,esc' => keypress, keydown
31380                for (i = bits.length - 1; i >= 0; --i) {
31381                    chr = trim(bits[i]);
31382
31383                    // catch sloppy filters, trailing commas, etc 'a,,'
31384                    if (!chr) {
31385                        continue;
31386                    }
31387
31388                    // non-numerics are single characters or key names
31389                    if (+chr == chr) {
31390                        config.keys[chr] = mods;
31391                    } else {
31392                        lc = chr.toLowerCase();
31393
31394                        if (this.KEY_MAP[lc]) {
31395                            config.keys[this.KEY_MAP[lc]] = mods;
31396                            // FIXME: '65,enter' defaults keydown for both
31397                            if (!config.type) {
31398                                config.type = "down"; // safest
31399                            }
31400                        } else {
31401                            // FIXME: Character mapping only works for keypress
31402                            // events. Otherwise, it uses String.fromCharCode()
31403                            // from the keyCode, which is wrong.
31404                            chr = chr.charAt(0);
31405                            uc  = chr.toUpperCase();
31406
31407                            if (mods["+shift"]) {
31408                                chr = uc;
31409                            }
31410
31411                            // FIXME: stupid assumption that
31412                            // the keycode of the lower case == the
31413                            // charCode of the upper case
31414                            // a (key:65,char:97), A (key:65,char:65)
31415                            config.keys[chr.charCodeAt(0)] =
31416                                (chr === uc) ?
31417                                    // upper case chars get +shift free
31418                                    Y.merge(mods, { "+shift": true }) :
31419                                    mods;
31420                        }
31421                    }
31422                }
31423            }
31424
31425            if (!config.type) {
31426                config.type = "press";
31427            }
31428
31429            return config;
31430        },
31431
31432        on: function (node, sub, notifier, filter) {
31433            var spec   = sub._extra,
31434                type   = "key" + spec.type,
31435                keys   = spec.keys,
31436                method = (filter) ? "delegate" : "on";
31437
31438            // Note: without specifying any keyCodes, this becomes a
31439            // horribly inefficient alias for 'keydown' (et al), but I
31440            // can't abort this subscription for a simple
31441            // Y.on('keypress', ...);
31442            // Please use keyCodes or just subscribe directly to keydown,
31443            // keyup, or keypress
31444            sub._detach = node[method](type, function (e) {
31445                var key = keys ? keys[e.which] : spec.mods;
31446
31447                if (key &&
31448                    (!key[ALT]   || (key[ALT]   && e.altKey)) &&
31449                    (!key[CTRL]  || (key[CTRL]  && e.ctrlKey)) &&
31450                    (!key[META]  || (key[META]  && e.metaKey)) &&
31451                    (!key[SHIFT] || (key[SHIFT] && e.shiftKey)))
31452                {
31453                    notifier.fire(e);
31454                }
31455            }, filter);
31456        },
31457
31458        detach: function (node, sub, notifier) {
31459            sub._detach.detach();
31460        }
31461    };
31462
31463eventDef.delegate = eventDef.on;
31464eventDef.detachDelegate = eventDef.detach;
31465
31466/**
31467 * <p>Add a key listener.  The listener will only be notified if the
31468 * keystroke detected meets the supplied specification.  The
31469 * specification is a string that is defined as:</p>
31470 *
31471 * <dl>
31472 *   <dt>spec</dt>
31473 *   <dd><code>[{type}:]{code}[,{code}]*</code></dd>
31474 *   <dt>type</dt>
31475 *   <dd><code>"down", "up", or "press"</code></dd>
31476 *   <dt>code</dt>
31477 *   <dd><code>{keyCode|character|keyName}[+{modifier}]*</code></dd>
31478 *   <dt>modifier</dt>
31479 *   <dd><code>"shift", "ctrl", "alt", or "meta"</code></dd>
31480 *   <dt>keyName</dt>
31481 *   <dd><code>"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"</code></dd>
31482 * </dl>
31483 *
31484 * <p>Examples:</p>
31485 * <ul>
31486 *   <li><code>Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");</code></li>
31487 *   <li><code>Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");</code></li>
31488 *   <li><code>Y.one("doc").on("key", viNav, "j,k,l,;");</code></li>
31489 * </ul>
31490 *
31491 * @event key
31492 * @for YUI
31493 * @param type {string} 'key'
31494 * @param fn {function} the function to execute
31495 * @param id {string|HTMLElement|collection}
31495 the element(s) to bind
31496 * @param spec {string} the keyCode and modifier specification
31497 * @param o optional context object
31498 * @param args 0..n additional arguments to provide to the listener.
31499 * @return {Event.Handle} the detach handle
31500 */
31501Y.Event.define('key', eventDef, true);
31502
31503
31504}, '3.18.1', {"requires": ["event-synthetic"]});
31505YUI.add('event-outside', function (Y, NAME) {
31506
31507/**
31508 * Outside events are synthetic DOM events that fire when a corresponding native
31509 * or synthetic DOM event occurs outside a bound element.
31510 *
31511 * The following outside events are pre-defined by this module:
31512 * <ul>
31513 *   <li>blur</li>
31514 *   <li>change</li>
31515 *   <li>click</li>
31516 *   <li>dblclick</li>
31517 *   <li>focus</li>
31518 *   <li>keydown</li>
31519 *   <li>keypress</li>
31520 *   <li>keyup</li>
31521 *   <li>mousedown</li>
31522 *   <li>mousemove</li>
31523 *   <li>mouseout</li>
31524 *   <li>mouseover</li>
31525 *   <li>mouseup</li>
31526 *   <li>select</li>
31527 *   <li>submit</li>
31528 * </ul>
31529 *
31530 * Define new outside events with
31531 * <code>Y.Event.defineOutside(eventType);</code>.
31532 * By default, the created synthetic event name will be the name of the event
31533 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want
31534 * a different name for the created Event, pass it as a second argument like so:
31535 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>.
31536 *
31537 * This module was contributed by Brett Stimmerman, promoted from his
31538 * gallery-outside-events module at
31539 * http://yuilibrary.com/gallery/show/outside-events
31540 *
31541 * @module event
31542 * @submodule event-outside
31543 * @author brettstimmerman
31544 * @since 3.4.0
31545 */
31546
31547// Outside events are pre-defined for each of these native DOM events
31548var nativeEvents = [
31549        'blur', 'change', 'click', 'dblclick', 'focus', 'keydown', 'keypress',
31550        'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup',
31551        'select', 'submit'
31552    ];
31553
31554/**
31555 * Defines a new outside event to correspond with the given DOM event.
31556 *
31557 * By default, the created synthetic event name will be the name of the event
31558 * with "outside" appended (e.g. "click" becomes "clickoutside"). If you want
31559 * a different name for the created Event, pass it as a second argument like so:
31560 * <code>Y.Event.defineOutside(eventType, "yonderclick")</code>.
31561 *
31562 * @method defineOutside
31563 * @param {String} event DOM event
31564 * @param {String} name (optional) custom outside event name
31565 * @static
31566 * @for Event
31567 */
31568Y.Event.defineOutside = function (event, name) {
31569    name = name || (event + 'outside');
31570
31571    var config = {
31572
31573        on: function (node, sub, notifier) {
31574            sub.handle = Y.one('doc').on(event, function(e) {
31575                if (this.isOutside(node, e.target)) {
31576                    e.currentTarget = node;
31577                    notifier.fire(e);
31578                }
31579            }, this);
31580        },
31581
31582        detach: function (node, sub, notifier) {
31583            sub.handle.detach();
31584        },
31585
31586        delegate: function (node, sub, notifier, filter) {
31587            sub.handle = Y.one('doc').delegate(event, function (e) {
31588                if (this.isOutside(node, e.target)) {
31589                    notifier.fire(e);
31590                }
31591            }, filter, this);
31592        },
31593
31594        isOutside: function (node, target) {
31595            return target !== node && !target.ancestor(function (p) {
31596                    return p === node;
31597                });
31598        }
31599    };
31600    config.detachDelegate = config.detach;
31601
31602    Y.Event.define(name, config);
31603};
31604
31605// Define outside events for some common native DOM events
31606Y.Array.each(nativeEvents, function (event) {
31607    Y.Event.defineOutside(event);
31608});
31609
31610
31611}, '3.18.1', {"requires": ["event-synthetic"]});
31612YUI.add('event-focus', function (Y, NAME) {
31613
31614/**
31615 * Adds bubbling and delegation support to DOM events focus and blur.
31616 *
31617 * @module event
31618 * @submodule event-focus
31619 */
31620var Event    = Y.Event,
31621
31622    YLang    = Y.Lang,
31623
31624    isString = YLang.isString,
31625
31626    arrayIndex = Y.Array.indexOf,
31627
31628    useActivate = (function() {
31629
31630        // Changing the structure of this test, so that it doesn't use inline JS in HTML,
31631        // which throws an exception in Win8 packaged apps, due to additional security restrictions:
31632        // http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences
31633
31634        var supported = false,
31635            doc = Y.config.doc,
31636            p;
31637
31638        if (doc) {
31639
31640            p = doc.createElement("p");
31641            p.setAttribute("onbeforeactivate", ";");
31642
31643            // onbeforeactivate is a function in IE8+.
31644            // onbeforeactivate is a string in IE6,7 (unfortunate, otherwise we could have just checked for function below).
31645            // onbeforeactivate is a function in IE10, in a Win8 App environment (no exception running the test).
31646
31647            // onbeforeactivate is undefined in Webkit/Gecko.
31648            // onbeforeactivate is a function in Webkit/Gecko if it's a supported event (e.g. onclick).
31649
31650            supported = (p.onbeforeactivate !== undefined);
31651        }
31652
31653        return supported;
31654    }());
31655
31656function define(type, proxy, directEvent) {
31657    var nodeDataKey = '_' + type + 'Notifiers';
31658
31659    Y.Event.define(type, {
31660
31661        _useActivate : useActivate,
31662
31663        _attach: function (el, notifier, delegate) {
31664            if (Y.DOM.isWindow(el)) {
31665                return Event._attach([type, function (e) {
31666                    notifier.fire(e);
31667                }, el]);
31668            } else {
31669                return Event._attach(
31670                    [proxy, this._proxy, el, this, notifier, delegate],
31671                    { capture: true });
31672            }
31673        },
31674
31675        _proxy: function (e, notifier, delegate) {
31676            var target        = e.target,
31677                currentTarget = e.currentTarget,
31678                notifiers     = target.getData(nodeDataKey),
31679                yuid          = Y.stamp(currentTarget._node),
31680                defer         = (useActivate || target !== currentTarget),
31681                directSub;
31682
31683            notifier.currentTarget = (delegate) ? target : currentTarget;
31684            notifier.container     = (delegate) ? currentTarget : null;
31685
31686            // Maintain a list to handle subscriptions from nested
31687            // containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
31688            // use one focus or blur subscription that fires notifiers from
31689            // #b then #a to emulate bubble sequence.
31690            if (!notifiers) {
31691                notifiers = {};
31692                target.setData(nodeDataKey, notifiers);
31693
31694                // only subscribe to the element's focus if the target is
31695                // not the current target (
31696                if (defer) {
31697                    directSub = Event._attach(
31698                        [directEvent, this._notify, target._node]).sub;
31699                    directSub.once = true;
31700                }
31701            } else {
31702                // In old IE, defer is always true.  In capture-phase browsers,
31703                // The delegate subscriptions will be encountered first, which
31704                // will establish the notifiers data and direct subscription
31705                // on the node.  If there is also a direct subscription to the
31706                // node's focus/blur, it should not call _notify because the
31707                // direct subscription from the delegate sub(s) exists, which
31708                // will call _notify.  So this avoids _notify being called
31709                // twice, unnecessarily.
31710                defer = true;
31711            }
31712
31713            if (!notifiers[yuid]) {
31714                notifiers[yuid] = [];
31715            }
31716
31717            notifiers[yuid].push(notifier);
31718
31719            if (!defer) {
31720                this._notify(e);
31721            }
31722        },
31723
31724        _notify: function (e, container) {
31725            var currentTarget = e.currentTarget,
31726                notifierData  = currentTarget.getData(nodeDataKey),
31727                axisNodes     = currentTarget.ancestors(),
31728                doc           = currentTarget.get('ownerDocument'),
31729                delegates     = [],
31730                                // Used to escape loops when there are no more
31731                                // notifiers to consider
31732                count         = notifierData ?
31733                                    Y.Object.keys(notifierData).length :
31734                                    0,
31735                target, notifiers, notifier, yuid, match, tmp, i, len, sub, ret;
31736
31737            // clear the notifications list (mainly for delegation)
31738            currentTarget.clearData(nodeDataKey);
31739
31740            // Order the delegate subs by their placement in the parent axis
31741            axisNodes.push(currentTarget);
31742            // document.get('ownerDocument') returns null
31743            // which we'll use to prevent having duplicate Nodes in the list
31744            if (doc) {
31745                axisNodes.unshift(doc);
31746            }
31747
31748            // ancestors() returns the Nodes from top to bottom
31749            axisNodes._nodes.reverse();
31750
31751            if (count) {
31752                // Store the count for step 2
31753                tmp = count;
31754                axisNodes.some(function (node) {
31755                    var yuid      = Y.stamp(node),
31756                        notifiers = notifierData[yuid],
31757                        i, len;
31758
31759                    if (notifiers) {
31760                        count--;
31761                        for (i = 0, len = notifiers.length; i < len; ++i) {
31762                            if (notifiers[i].handle.sub.filter) {
31763                                delegates.push(notifiers[i]);
31764                            }
31765                        }
31766                    }
31767
31768                    return !count;
31769                });
31770                count = tmp;
31771            }
31772
31773            // Walk up the parent axis, notifying direct subscriptions and
31774            // testing delegate filters.
31775            while (count && (target = axisNodes.shift())) {
31776                yuid = Y.stamp(target);
31777
31778                notifiers = notifierData[yuid];
31779
31780                if (notifiers) {
31781                    for (i = 0, len = notifiers.length; i < len; ++i) {
31782                        notifier = notifiers[i];
31783                        sub      = notifier.handle.sub;
31784                        match    = true;
31785
31786                        e.currentTarget = target;
31787
31788                        if (sub.filter) {
31789                            match = sub.filter.apply(target,
31790                                [target, e].concat(sub.args || []));
31791
31792                            // No longer necessary to test against this
31793                            // delegate subscription for the nodes along
31794                            // the parent axis.
31795                            delegates.splice(
31796                                arrayIndex(delegates, notifier), 1);
31797                        }
31798
31799                        if (match) {
31800                            // undefined for direct subs
31801                            e.container = notifier.container;
31802                            ret = notifier.fire(e);
31803                        }
31804
31805                        if (ret === false || e.stopped === 2) {
31806                            break;
31807                        }
31808                    }
31809
31810                    delete notifiers[yuid];
31811                    count--;
31812                }
31813
31814                if (e.stopped !== 2) {
31815                    // delegates come after subs targeting this specific node
31816                    // because they would not normally report until they'd
31817                    // bubbled to the container node.
31818                    for (i = 0, len = delegates.length; i < len; ++i) {
31819                        notifier = delegates[i];
31820                        sub = notifier.handle.sub;
31821
31822                        if (sub.filter.apply(target,
31823                            [target, e].concat(sub.args || []))) {
31824
31825                            e.container = notifier.container;
31826                            e.currentTarget = target;
31827                            ret = notifier.fire(e);
31828                        }
31829
31830                        if (ret === false || e.stopped === 2 ||
31831                            // If e.stopPropagation() is called, notify any
31832                            // delegate subs from the same container, but break
31833                            // once the container changes. This emulates
31834                            // delegate() behavior for events like 'click' which
31835                            // won't notify delegates higher up the parent axis.
31836                            (e.stopped && delegates[i+1] &&
31837                             delegates[i+1].container !== notifier.container)) {
31838                            break;
31839                        }
31840                    }
31841                }
31842
31843                if (e.stopped) {
31844                    break;
31845                }
31846            }
31847        },
31848
31849        on: function (node, sub, notifier) {
31850            sub.handle = this._attach(node._node, notifier);
31851        },
31852
31853        detach: function (node, sub) {
31854            sub.handle.detach();
31855        },
31856
31857        delegate: function (node, sub, notifier, filter) {
31858            if (isString(filter)) {
31859                sub.filter = function (target) {
31860                    return Y.Selector.test(target._node, filter,
31861                        node === target ? null : node._node);
31862                };
31863            }
31864
31865            sub.handle = this._attach(node._node, notifier, true);
31866        },
31867
31868        detachDelegate: function (node, sub) {
31869            sub.handle.detach();
31870        }
31871    }, true);
31872}
31873
31874// For IE, we need to defer to focusin rather than focus because
31875// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
31876// el.onfocusin, doSomething, then el.onfocus.  All others support capture
31877// phase focus, which executes before doSomething.  To guarantee consistent
31878// behavior for this use case, IE's direct subscriptions are made against
31879// focusin so subscribers will be notified before js following el.focus() is
31880// executed.
31881if (useActivate) {
31882    //     name     capture phase       direct subscription
31883    define("focus", "beforeactivate",   "focusin");
31884    define("blur",  "beforedeactivate", "focusout");
31885} else {
31886    define("focus", "focus", "focus");
31887    define("blur",  "blur",  "blur");
31888}
31889
31890
31891}, '3.18.1', {"requires": ["event-synthetic"]});
31892YUI.add('classnamemanager', function (Y, NAME) {
31893
31894/**
31895* Contains a singleton (ClassNameManager) that enables easy creation and caching of
31896* prefixed class names.
31897* @module classnamemanager
31898*/
31899
31900/**
31901 * A singleton class providing:
31902 *
31903 * <ul>
31904 *    <li>Easy creation of prefixed class names</li>
31905 *    <li>Caching of previously created class names for improved performance.</li>
31906 * </ul>
31907 *
31908 * @class ClassNameManager
31909 * @static
31910 */
31911
31912// String constants
31913var CLASS_NAME_PREFIX = 'classNamePrefix',
31914	CLASS_NAME_DELIMITER = 'classNameDelimiter',
31915    CONFIG = Y.config;
31916
31917// Global config
31918
31919/**
31920 * Configuration property indicating the prefix for all CSS class names in this YUI instance.
31921 *
31922 * @property classNamePrefix
31923 * @type {String}
31924 * @default "yui"
31925 * @static
31926 */
31927CONFIG[CLASS_NAME_PREFIX] = CONFIG[CLASS_NAME_PREFIX] || 'yui3';
31928
31929/**
31930 * Configuration property indicating the delimiter used to compose all CSS class names in
31931 * this YUI instance.
31932 *
31933 * @property classNameDelimiter
31934 * @type {String}
31935 * @default "-"
31936 * @static
31937 */
31938CONFIG[CLASS_NAME_DELIMITER] = CONFIG[CLASS_NAME_DELIMITER] || '-';
31939
31940Y.ClassNameManager = function () {
31941
31942	var sPrefix    = CONFIG[CLASS_NAME_PREFIX],
31943		sDelimiter = CONFIG[CLASS_NAME_DELIMITER];
31944
31945	return {
31946
31947		/**
31948		 * Returns a class name prefixed with the value of the
31949		 * <code>Y.config.classNamePrefix</code> attribute + the provided strings.
31950		 * Uses the <code>Y.config.classNameDelimiter</code> attribute to delimit the
31951		 * provided strings. E.g. Y.ClassNameManager.getClassName('foo','bar'); // yui-foo-bar
31952		 *
31953		 * @method getClassName
31954		 * @param {String} [classnameSection*] one or more classname sections to be joined
31955		 * @param {Boolean} skipPrefix If set to true, the classname will not be prefixed with the default Y.config.classNameDelimiter value.
31956		 */
31957		getClassName: Y.cached(function () {
31958
31959            var args = Y.Array(arguments);
31960
31961            if (args[args.length-1] !== true) {
31962                args.unshift(sPrefix);
31963            } else {
31964                args.pop();
31965            }
31966
31967			return args.join(sDelimiter);
31968		})
31969
31970	};
31971
31972}();
31973
31974
31975}, '3.18.1', {"requires": ["yui-base"]});
31976YUI.add('widget-base', function (Y, NAME) {
31977
31978/**
31979 * Provides the base Widget class, with HTML Parser support
31980 *
31981 * @module widget
31982 * @main widget
31983 */
31984
31985/**
31986 * Provides the base Widget class
31987 *
31988 * @module widget
31989 * @submodule widget-base
31990 */
31991var L = Y.Lang,
31992    Node = Y.Node,
31993
31994    ClassNameManager = Y.ClassNameManager,
31995
31996    _getClassName = ClassNameManager.getClassName,
31997    _getWidgetClassName,
31998
31999    _toInitialCap = Y.cached(function(str) {
32000        return str.substring(0, 1).toUpperCase() + str.substring(1);
32001    }),
32002
32003    // K-Weight, IE GC optimizations
32004    CONTENT = "content",
32005    VISIBLE = "visible",
32006    HIDDEN = "hidden",
32007    DISABLED = "disabled",
32008    FOCUSED = "focused",
32009    WIDTH = "width",
32010    HEIGHT = "height",
32011    BOUNDING_BOX = "boundingBox",
32012    CONTENT_BOX = "contentBox",
32013    PARENT_NODE = "parentNode",
32014    OWNER_DOCUMENT = "ownerDocument",
32015    AUTO = "auto",
32016    SRC_NODE = "srcNode",
32017    BODY = "body",
32018    TAB_INDEX = "tabIndex",
32019    ID = "id",
32020    RENDER = "render",
32021    RENDERED = "rendered",
32022    DESTROYED = "destroyed",
32023    STRINGS = "strings",
32024    DIV = "<div></div>",
32025    CHANGE = "Change",
32026    LOADING = "loading",
32027
32028    _UISET = "_uiSet",
32029
32030    EMPTY_STR = "",
32031    EMPTY_FN = function() {},
32032
32033    TRUE = true,
32034    FALSE = false,
32035
32036    UI,
32037    ATTRS = {},
32038    UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX],
32039
32040    WEBKIT = Y.UA.webkit,
32041
32042    // Widget nodeid-to-instance map.
32043    _instances = {};
32044
32045/**
32046 * A base class for widgets, providing:
32047 * <ul>
32048 *    <li>The render lifecycle method, in addition to the init and destroy
32049 *        lifecycle methods provide by Base</li>
32050 *    <li>Abstract methods to support consistent MVC structure across
32051 *        widgets: renderer, renderUI, bindUI, syncUI</li>
32052 *    <li>Support for common widget attributes, such as boundingBox, contentBox, visible,
32053 *        disabled, focused, strings</li>
32054 * </ul>
32055 *
32056 * @param config {Object} Object literal specifying widget configuration properties.
32057 *
32058 * @class Widget
32059 * @constructor
32060 * @extends Base
32061 */
32062function Widget(config) {
32063
32064    // kweight
32065    var widget = this,
32066        parentNode,
32067        render,
32068        constructor = widget.constructor;
32069
32070    widget._strs = {};
32071    widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase());
32072
32073    // We need a config for HTML_PARSER to work.
32074    config = config || {};
32075
32076    Widget.superclass.constructor.call(widget, config);
32077
32078    render = widget.get(RENDER);
32079
32080    if (render) {
32081        // Render could be a node or boolean
32082        if (render !== TRUE) {
32083            parentNode = render;
32084        }
32085        widget.render(parentNode);
32086    }
32087}
32088
32089/**
32090 * Static property provides a string to identify the class.
32091 * <p>
32092 * Currently used to apply class identifiers to the bounding box
32093 * and to classify events fired by the widget.
32094 * </p>
32095 *
32096 * @property NAME
32097 * @type String
32098 * @static
32099 */
32100Widget.NAME = "widget";
32101
32102/**
32103 * Constant used to identify state changes originating from
32104 * the DOM (as opposed to the JavaScript model).
32105 *
32106 * @property UI_SRC
32107 * @type String
32108 * @static
32109 * @final
32110 */
32111UI = Widget.UI_SRC = "ui";
32112
32113/**
32114 * Static property used to define the default attribute
32115 * configuration for the Widget.
32116 *
32117 * @property ATTRS
32118 * @type Object
32119 * @static
32120 */
32121Widget.ATTRS = ATTRS;
32122
32123// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd
32124
32125/**
32126 * @attribute id
32127 * @writeOnce
32128 * @default Generated using guid()
32129 * @type String
32130 */
32131
32132ATTRS[ID] = {
32133    valueFn: "_guid",
32134    writeOnce: TRUE
32135};
32136
32137/**
32138 * Flag indicating whether or not this Widget
32139 * has been through the render lifecycle phase.
32140 *
32141 * @attribute rendered
32142 * @readOnly
32143 * @default false
32144 * @type boolean
32145 */
32146ATTRS[RENDERED] = {
32147    value:FALSE,
32148    readOnly: TRUE
32149};
32150
32151/**
32152 * @attribute boundingBox
32153 * @description The outermost DOM node for the Widget, used for sizing and positioning
32154 * of a Widget as well as a containing element for any decorator elements used
32155 * for skinning.
32156 * @type String | Node
32157 * @writeOnce
32158 */
32159ATTRS[BOUNDING_BOX] = {
32160    valueFn:"_defaultBB",
32161    setter: "_setBB",
32162    writeOnce: TRUE
32163};
32164
32165/**
32166 * @attribute contentBox
32167 * @description A DOM node that is a direct descendant of a Widget's bounding box that
32168 * houses its content.
32169 * @type String | Node
32170 * @writeOnce
32171 */
32172ATTRS[CONTENT_BOX] = {
32173    valueFn:"_defaultCB",
32174    setter: "_setCB",
32175    writeOnce: TRUE
32176};
32177
32178/**
32179 * @attribute tabIndex
32180 * @description Number (between -32767 to 32767) indicating the widget's
32181 * position in the default tab flow.  The value is used to set the
32182 * "tabIndex" attribute on the widget's bounding box.  Negative values allow
32183 * the widget to receive DOM focus programmatically (by calling the focus
32184 * method), while being removed from the default tab flow.  A value of
32185 * null removes the "tabIndex" attribute from the widget's bounding box.
32186 * @type Number
32187 * @default null
32188 */
32189ATTRS[TAB_INDEX] = {
32190    value: null,
32191    validator: "_validTabIndex"
32192};
32193
32194/**
32195 * @attribute focused
32196 * @description Boolean indicating if the Widget, or one of its descendants,
32197 * has focus.
32198 * @readOnly
32199 * @default false
32200 * @type boolean
32201 */
32202ATTRS[FOCUSED] = {
32203    value: FALSE,
32204    readOnly:TRUE
32205};
32206
32207/**
32208 * @attribute disabled
32209 * @description Boolean indicating if the Widget should be disabled. The disabled implementation
32210 * is left to the specific classes extending widget.
32211 * @default false
32212 * @type boolean
32213 */
32214ATTRS[DISABLED] = {
32215    value: FALSE
32216};
32217
32218/**
32219 * @attribute visible
32220 * @description Boolean indicating whether or not the Widget is visible.
32221 * @default TRUE
32222 * @type boolean
32223 */
32224ATTRS[VISIBLE] = {
32225    value: TRUE
32226};
32227
32228/**
32229 * @attribute height
32230 * @description String with units, or number, representing the height of the Widget. If a number is provided,
32231 * the default unit, defined by the Widgets DEF_UNIT, property is used.
32232 * @default EMPTY_STR
32233 * @type {String | Number}
32234 */
32235ATTRS[HEIGHT] = {
32236    value: EMPTY_STR
32237};
32238
32239/**
32240 * @attribute width
32241 * @description String with units, or number, representing the width of the Widget. If a number is provided,
32242 * the default unit, defined by the Widgets DEF_UNIT, property is used.
32243 * @default EMPTY_STR
32244 * @type {String | Number}
32245 */
32246ATTRS[WIDTH] = {
32247    value: EMPTY_STR
32248};
32249
32250/**
32251 * @attribute strings
32252 * @description Collection of strings used to label elements of the Widget's UI.
32253 * @default null
32254 * @type Object
32255 */
32256ATTRS[STRINGS] = {
32257    value: {},
32258    setter: "_strSetter",
32259    getter: "_strGetter"
32260};
32261
32262/**
32263 * Whether or not to render the widget automatically after init, and optionally, to which parent node.
32264 *
32265 * @attribute render
32266 * @type boolean | Node
32267 * @writeOnce
32268 */
32269ATTRS[RENDER] = {
32270    value:FALSE,
32271    writeOnce:TRUE
32272};
32273
32274/**
32275 * The css prefix which the static Widget.getClassName method should use when constructing class names
32276 *
32277 * @property CSS_PREFIX
32278 * @type String
32279 * @default Widget.NAME.toLowerCase()
32280 * @private
32281 * @static
32282 */
32283Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase());
32284
32285/**
32286 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined
32287 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and
32288 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for
32289 * the prefix and widget class name).
32290 * <p>
32291 * The instance based version of this method can be used to generate standard prefixed classnames,
32292 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you
32293 * need to use a constant class name across different types instances.
32294 * </p>
32295 * @method getClassName
32296 * @param {String*}
32296 args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name
32297 */
32298Widget.getClassName = function() {
32299    // arguments needs to be array'fied to concat
32300    return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true));
32301};
32302
32303_getWidgetClassName = Widget.getClassName;
32304
32305/**
32306 * Returns the widget instance whose bounding box contains, or is, the given node.
32307 * <p>
32308 * In the case of nested widgets, the nearest bounding box ancestor is used to
32309 * return the widget instance.
32310 * </p>
32311 * @method getByNode
32312 * @static
32313 * @param node {Node | String} The node for which to return a Widget instance. If a selector
32314 * string is passed in, which selects more than one node, the first node found is used.
32315 * @return {Widget} Widget instance, or null if not found.
32316 */
32317Widget.getByNode = function(node) {
32318    var widget,
32319        widgetMarker = _getWidgetClassName();
32320
32321    node = Node.one(node);
32322    if (node) {
32323        node = node.ancestor("." + widgetMarker, true);
32324        if (node) {
32325            widget = _instances[Y.stamp(node, true)];
32326        }
32327    }
32328
32329    return widget || null;
32330};
32331
32332Y.extend(Widget, Y.Base, {
32333
32334    /**
32335     * Returns a class name prefixed with the the value of the
32336     * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property.
32337     * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings.
32338     * e.g.
32339     * <code>
32340     * <pre>
32341     *    // returns "yui-slider-foo-bar", for a slider instance
32342     *    var scn = slider.getClassName('foo','bar');
32343     *
32344     *    // returns "yui-overlay-foo-bar", for an overlay instance
32345     *    var ocn = overlay.getClassName('foo','bar');
32346     * </pre>
32347     * </code>
32348     *
32349     * @method getClassName
32350     * @param {String} [classnames*] One or more classname bits to be joined and prefixed
32351     */
32352    getClassName: function () {
32353        return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true));
32354    },
32355
32356    /**
32357     * Initializer lifecycle implementation for the Widget class. Registers the
32358     * widget instance, and runs through the Widget's HTML_PARSER definition.
32359     *
32360     * @method initializer
32361     * @protected
32362     * @param  config {Object} Configuration object literal for the widget
32363     */
32364    initializer: function(config) {
32365
32366        var bb = this.get(BOUNDING_BOX);
32367
32368        if (bb instanceof Node) {
32369            this._mapInstance(Y.stamp(bb));
32370        }
32371
32372        /**
32373         * Notification event, which widget implementations can fire, when
32374         * they change the content of the widget. This event has no default
32375         * behavior and cannot be prevented, so the "on" or "after"
32376         * moments are effectively equivalent (with on listeners being invoked before
32377         * after listeners).
32378         *
32379         * @event widget:contentUpdate
32380         * @preventable false
32381         * @param {EventFacade} e The Event Facade
32382         */
32383    },
32384
32385    /**
32386     * Utility method used to add an entry to the boundingBox id to instance map.
32387     *
32388     * This method can be used to populate the instance with lazily created boundingBox Node references.
32389     *
32390     * @method _mapInstance
32391     * @param {String} The boundingBox id
32392     * @protected
32393     */
32394    _mapInstance : function(id) {
32395        _instances[id] = this;
32396    },
32397
32398    /**
32399     * Destructor lifecycle implementation for the Widget class. Purges events attached
32400     * to the bounding box and content box, removes them from the DOM and removes
32401     * the Widget from the list of registered widgets.
32402     *
32403     * @method destructor
32404     * @protected
32405     */
32406    destructor: function() {
32407
32408        var boundingBox = this.get(BOUNDING_BOX),
32409            bbGuid;
32410
32411        if (boundingBox instanceof Node) {
32412            bbGuid = Y.stamp(boundingBox,true);
32413
32414            if (bbGuid in _instances) {
32415                delete _instances[bbGuid];
32416            }
32417
32418            this._destroyBox();
32419        }
32420    },
32421
32422    /**
32423     * <p>
32424     * Destroy lifecycle method. Fires the destroy
32425     * event, prior to invoking destructors for the
32426     * class hierarchy.
32427     *
32428     * Overrides Base's implementation, to support arguments to destroy
32429     * </p>
32430     * <p>
32431     * Subscribers to the destroy
32432     * event can invoke preventDefault on the event object, to prevent destruction
32433     * from proceeding.
32434     * </p>
32435     * @method destroy
32436     * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are
32437     * removed and destroyed. Defaults to false due to potentially high run-time cost.
32438     * @return {Widget} A reference to this object
32439     * @chainable
32440     */
32441    destroy: function(destroyAllNodes) {
32442        this._destroyAllNodes = destroyAllNodes;
32443        return Widget.superclass.destroy.apply(this);
32444    },
32445
32446    /**
32447     * Removes and destroys the widgets rendered boundingBox, contentBox,
32448     * and detaches bound UI events.
32449     *
32450     * @method _destroyBox
32451     * @protected
32452     */
32453    _destroyBox : function() {
32454
32455        var boundingBox = this.get(BOUNDING_BOX),
32456            contentBox = this.get(CONTENT_BOX),
32457            deep = this._destroyAllNodes,
32458            same;
32459
32460        same = boundingBox && boundingBox.compareTo(contentBox);
32461
32462        if (this.UI_EVENTS) {
32463            this._destroyUIEvents();
32464        }
32465
32466        this._unbindUI(boundingBox);
32467
32468        if (contentBox) {
32469            if (deep) {
32470                contentBox.empty();
32471            }
32472            contentBox.remove(TRUE);
32473        }
32474
32475        if (!same) {
32476            if (deep) {
32477                boundingBox.empty();
32478            }
32479            boundingBox.remove(TRUE);
32480        }
32481    },
32482
32483    /**
32484     * Establishes the initial DOM for the widget. Invoking this
32485     * method will lead to the creating of all DOM elements for
32486     * the widget (or the manipulation of existing DOM elements
32487     * for the progressive enhancement use case).
32488     * <p>
32489     * This method should only be invoked once for an initialized
32490     * widget.
32491     * </p>
32492     * <p>
32493     * It delegates to the widget specific renderer method to do
32494     * the actual work.
32495     * </p>
32496     *
32497     * @method render
32498     * @chainable
32499     * @final
32500     * @param  parentNode {Object | String} Optional. The Node under which the
32501     * Widget is to be rendered. This can be a Node instance or a CSS selector string.
32502     * <p>
32503     * If the selector string returns more than one Node, the first node will be used
32504     * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox
32505     * are not currently in the document. If it's not provided, the Widget will be rendered
32506     * to the body of the current document in this case.
32507     * </p>
32508     */
32509    render: function(parentNode) {
32510
32511        if (!this.get(DESTROYED) && !this.get(RENDERED)) {
32512             /**
32513              * Lifecycle event for the render phase, fired prior to rendering the UI
32514              * for the widget (prior to invoking the widget's renderer method).
32515              * <p>
32516              * Subscribers to the "on" moment of this event, will be notified
32517              * before the widget is rendered.
32518              * </p>
32519              * <p>
32520              * Subscribers to the "after" moment of this event, will be notified
32521              * after rendering is complete.
32522              * </p>
32523              *
32524              * @event render
32525              * @preventable _defRenderFn
32526              * @param {EventFacade} e The Event Facade
32527              */
32528            this.publish(RENDER, {
32529                queuable:FALSE,
32530                fireOnce:TRUE,
32531                defaultTargetOnly:TRUE,
32532                defaultFn: this._defRenderFn
32533            });
32534
32535            this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null});
32536        }
32537        return this;
32538    },
32539
32540    /**
32541     * Default render handler
32542     *
32543     * @method _defRenderFn
32544     * @protected
32545     * @param {EventFacade} e The Event object
32546     * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method
32547     */
32548    _defRenderFn : function(e) {
32549        this._parentNode = e.parentNode;
32550
32551        this.renderer();
32552        this._set(RENDERED, TRUE);
32553
32554        this._removeLoadingClassNames();
32555    },
32556
32557    /**
32558     * Creates DOM (or manipulates DOM for progressive enhancement)
32559     * This method is invoked by render() and is not chained
32560     * automatically for the class hierarchy (unlike initializer, destructor)
32561     * so it should be chained manually for subclasses if required.
32562     *
32563     * @method renderer
32564     * @protected
32565     */
32566    renderer: function() {
32567        // kweight
32568        var widget = this;
32569
32570        widget._renderUI();
32571        widget.renderUI();
32572
32573        widget._bindUI();
32574        widget.bindUI();
32575
32576        widget._syncUI();
32577        widget.syncUI();
32578    },
32579
32580    /**
32581     * Configures/Sets up listeners to bind Widget State to UI/DOM
32582     *
32583     * This method is not called by framework and is not chained
32584     * automatically for the class hierarchy.
32585     *
32586     * @method bindUI
32587     * @protected
32588     */
32589    bindUI: EMPTY_FN,
32590
32591    /**
32592     * Adds nodes to the DOM
32593     *
32594     * This method is not called by framework and is not chained
32595     * automatically for the class hierarchy.
32596     *
32597     * @method renderUI
32598     * @protected
32599     */
32600    renderUI: EMPTY_FN,
32601
32602    /**
32603     * Refreshes the rendered UI, based on Widget State
32604     *
32605     * This method is not called by framework and is not chained
32606     * automatically for the class hierarchy.
32607     *
32608     * @method syncUI
32609     * @protected
32610     *
32611     */
32612    syncUI: EMPTY_FN,
32613
32614    /**
32615     * @method hide
32616     * @description Hides the Widget by setting the "visible" attribute to "false".
32617     * @chainable
32618     */
32619    hide: function() {
32620        return this.set(VISIBLE, FALSE);
32621    },
32622
32623    /**
32624     * @method show
32625     * @description Shows the Widget by setting the "visible" attribute to "true".
32626     * @chainable
32627     */
32628    show: function() {
32629        return this.set(VISIBLE, TRUE);
32630    },
32631
32632    /**
32633     * @method focus
32634     * @description Causes the Widget to receive the focus by setting the "focused"
32635     * attribute to "true".
32636     * @chainable
32637     */
32638    focus: function () {
32639        return this._set(FOCUSED, TRUE);
32640    },
32641
32642    /**
32643     * @method blur
32644     * @description Causes the Widget to lose focus by setting the "focused" attribute
32645     * to "false"
32646     * @chainable
32647     */
32648    blur: function () {
32649        return this._set(FOCUSED, FALSE);
32650    },
32651
32652    /**
32653     * @method enable
32654     * @description Set the Widget's "disabled" attribute to "false".
32655     * @chainable
32656     */
32657    enable: function() {
32658        return this.set(DISABLED, FALSE);
32659    },
32660
32661    /**
32662     * @method disable
32663     * @description Set the Widget's "disabled" attribute to "true".
32664     * @chainable
32665     */
32666    disable: function() {
32667        return this.set(DISABLED, TRUE);
32668    },
32669
32670    /**
32671     * @method _uiSizeCB
32672     * @protected
32673     * @param {boolean} expand
32674     */
32675    _uiSizeCB : function(expand) {
32676        this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand);
32677    },
32678
32679    /**
32680     * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not
32681     * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used
32682     * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and
32683     * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered
32684     * to the current document's body.
32685     *
32686     * @method _renderBox
32687     * @private
32688     * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and
32689     * the contentBox are not currently in the document, the widget will be rendered to the current document's body.
32690     */
32691    _renderBox: function(parentNode) {
32692
32693        // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ]
32694
32695        var widget = this, // kweight
32696            contentBox = widget.get(CONTENT_BOX),
32697            boundingBox = widget.get(BOUNDING_BOX),
32698            srcNode = widget.get(SRC_NODE),
32699            defParentNode = widget.DEF_PARENT_NODE,
32700
32701            doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT);
32702
32703        // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents)
32704        if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) {
32705            srcNode.replace(contentBox);
32706        }
32707
32708        if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) {
32709            // If contentBox box is already in the document, have boundingBox box take it's place
32710            if (contentBox.inDoc(doc)) {
32711                contentBox.replace(boundingBox);
32712            }
32713            boundingBox.appendChild(contentBox);
32714        }
32715
32716        parentNode = parentNode || (defParentNode && Node.one(defParentNode));
32717
32718        if (parentNode) {
32719            parentNode.appendChild(boundingBox);
32720        } else if (!boundingBox.inDoc(doc)) {
32721            Node.one(BODY).insert(boundingBox, 0);
32722        }
32723    },
32724
32725    /**
32726     * Setter for the boundingBox attribute
32727     *
32728     * @method _setBB
32729     * @private
32730     * @param {Node|String} node
32731     * @return Node
32732     */
32733    _setBB: function(node) {
32734        return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE, true);
32735    },
32736
32737    /**
32738     * Setter for the contentBox attribute
32739     *
32740     * @method _setCB
32741     * @private
32742     * @param {Node|String}
32742 node
32743     * @return Node
32744     */
32745    _setCB: function(node) {
32746        return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false);
32747    },
32748
32749    /**
32750     * Returns the default value for the boundingBox attribute.
32751     *
32752     * For the Widget class, this will most commonly be null (resulting in a new
32753     * boundingBox node instance being created), unless a srcNode was provided
32754     * and CONTENT_TEMPLATE is null, in which case it will be srcNode.
32755     * This behavior was introduced in 3.18.1 to accomodate single-box widgets
32756     * whose BB & CB both point to srcNode (e.g. Y.Button).
32757     *
32758     * @method _defaultBB
32759     * @protected
32760     */
32761    _defaultBB : function() {
32762        var node = this.get(SRC_NODE),
32763            nullCT = (this.CONTENT_TEMPLATE === null);
32764
32765        return ((node && nullCT) ? node : null);
32766    },
32767
32768    /**
32769     * Returns the default value for the contentBox attribute.
32770     *
32771     * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in
32772     * a new contentBox node instance being created)
32773     *
32774     * @method _defaultCB
32775     * @protected
32776     */
32777    _defaultCB : function(node) {
32778        return this.get(SRC_NODE) || null;
32779    },
32780
32781    /**
32782     * Helper method to set the bounding/content box, or create it from
32783     * the provided template if not found.
32784     *
32785     * @method _setBox
32786     * @private
32787     *
32788     * @param {String} id The node's id attribute
32789     * @param {Node|String} node The node reference
32790     * @param {String} template HTML string template for the node
32791     * @param {boolean} isBounding true if this is the boundingBox, false if it's the contentBox
32792     * @return {Node} The node
32793     */
32794    _setBox : function(id, node, template, isBounding) {
32795
32796        node = Node.one(node);
32797
32798        if (!node) {
32799            node = Node.create(template);
32800
32801            if (isBounding) {
32802                this._bbFromTemplate = true;
32803            } else {
32804                this._cbFromTemplate = true;
32805            }
32806        }
32807
32808        if (!node.get(ID)) {
32809            node.set(ID, id || Y.guid());
32810        }
32811
32812        return node;
32813    },
32814
32815    /**
32816     * Initializes the UI state for the Widget's bounding/content boxes.
32817     *
32818     * @method _renderUI
32819     * @protected
32820     */
32821    _renderUI: function() {
32822        this._renderBoxClassNames();
32823        this._renderBox(this._parentNode);
32824    },
32825
32826    /**
32827     * Applies standard class names to the boundingBox and contentBox
32828     *
32829     * @method _renderBoxClassNames
32830     * @protected
32831     */
32832    _renderBoxClassNames : function() {
32833        var classes = this._getClasses(),
32834            cl,
32835            boundingBox = this.get(BOUNDING_BOX),
32836            i;
32837
32838        boundingBox.addClass(_getWidgetClassName());
32839
32840        // Start from Widget Sub Class
32841        for (i = classes.length-3; i >= 0; i--) {
32842            cl = classes[i];
32843            boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase()));
32844        }
32845
32846        // Use instance based name for content box
32847        this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT));
32848    },
32849
32850    /**
32851     * Removes class names representative of the widget's loading state from
32852     * the boundingBox.
32853     *
32854     * @method _removeLoadingClassNames
32855     * @protected
32856     */
32857    _removeLoadingClassNames: function () {
32858
32859        var boundingBox = this.get(BOUNDING_BOX),
32860            contentBox = this.get(CONTENT_BOX),
32861            instClass = this.getClassName(LOADING),
32862            widgetClass = _getWidgetClassName(LOADING);
32863
32864        boundingBox.removeClass(widgetClass)
32865                   .removeClass(instClass);
32866
32867        contentBox.removeClass(widgetClass)
32868                  .removeClass(instClass);
32869    },
32870
32871    /**
32872     * Sets up DOM and CustomEvent listeners for the widget.
32873     *
32874     * @method _bindUI
32875     * @protected
32876     */
32877    _bindUI: function() {
32878        this._bindAttrUI(this._UI_ATTRS.BIND);
32879        this._bindDOM();
32880    },
32881
32882    /**
32883     * @method _unbindUI
32884     * @protected
32885     */
32886    _unbindUI : function(boundingBox) {
32887        this._unbindDOM(boundingBox);
32888    },
32889
32890    /**
32891     * Sets up DOM listeners, on elements rendered by the widget.
32892     *
32893     * @method _bindDOM
32894     * @protected
32895     */
32896    _bindDOM : function() {
32897        var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT),
32898            focusHandle = Widget._hDocFocus;
32899
32900        // Shared listener across all Widgets.
32901        if (!focusHandle) {
32902            focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this);
32903            focusHandle.listeners = {
32904                count: 0
32905            };
32906        }
32907
32908        focusHandle.listeners[Y.stamp(this, true)] = true;
32909        focusHandle.listeners.count++;
32910
32911        //	Fix for Webkit:
32912        //	Document doesn't receive focus in Webkit when the user mouses
32913        //	down on it, so the "focused" attribute won't get set to the
32914        //	correct value. Keeping this instance based for now, potential better performance.
32915        //  Otherwise we'll end up looking up widgets from the DOM on every mousedown.
32916        if (WEBKIT){
32917            this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this);
32918        }
32919    },
32920
32921    /**
32922     * @method _unbindDOM
32923     * @protected
32924     */
32925    _unbindDOM : function(boundingBox) {
32926
32927        var focusHandle = Widget._hDocFocus,
32928            yuid = Y.stamp(this, true),
32929            focusListeners,
32930            mouseHandle = this._hDocMouseDown;
32931
32932        if (focusHandle) {
32933
32934            focusListeners = focusHandle.listeners;
32935
32936            if (focusListeners[yuid]) {
32937                delete focusListeners[yuid];
32938                focusListeners.count--;
32939            }
32940
32941            if (focusListeners.count === 0) {
32942                focusHandle.detach();
32943                Widget._hDocFocus = null;
32944            }
32945        }
32946
32947        if (WEBKIT && mouseHandle) {
32948            mouseHandle.detach();
32949        }
32950    },
32951
32952    /**
32953     * Updates the widget UI to reflect the attribute state.
32954     *
32955     * @method _syncUI
32956     * @protected
32957     */
32958    _syncUI: function() {
32959        this._syncAttrUI(this._UI_ATTRS.SYNC);
32960    },
32961
32962    /**
32963     * Sets the height on the widget's bounding box element
32964     *
32965     * @method _uiSetHeight
32966     * @protected
32967     * @param {String | Number} val
32968     */
32969    _uiSetHeight: function(val) {
32970        this._uiSetDim(HEIGHT, val);
32971        this._uiSizeCB((val !== EMPTY_STR && val !== AUTO));
32972    },
32973
32974    /**
32975     * Sets the width on the widget's bounding box element
32976     *
32977     * @method _uiSetWidth
32978     * @protected
32979     * @param {String | Number} val
32980     */
32981    _uiSetWidth: function(val) {
32982        this._uiSetDim(WIDTH, val);
32983    },
32984
32985    /**
32986     * @method _uiSetDim
32987     * @private
32988     * @param {String} dim The dimension - "width" or "height"
32989     * @param {Number | String} val The value to set
32990     */
32991    _uiSetDim: function(dimension, val) {
32992        this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val);
32993    },
32994
32995    /**
32996     * Sets the visible state for the UI
32997     *
32998     * @method _uiSetVisible
32999     * @protected
33000     * @param {boolean} val
33001     */
33002    _uiSetVisible: function(val) {
33003        this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val);
33004    },
33005
33006    /**
33007     * Sets the disabled state for the UI
33008     *
33009     * @method _uiSetDisabled
33010     * @protected
33011     * @param {boolean} val
33012     */
33013    _uiSetDisabled: function(val) {
33014        this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val);
33015    },
33016
33017    /**
33018     * Sets the focused state for the UI
33019     *
33020     * @method _uiSetFocused
33021     * @protected
33022     * @param {boolean} val
33023     * @param {string} src String representing the source that triggered an update to
33024     * the UI.
33025     */
33026    _uiSetFocused: function(val, src) {
33027         var boundingBox = this.get(BOUNDING_BOX);
33028         boundingBox.toggleClass(this.getClassName(FOCUSED), val);
33029
33030         if (src !== UI) {
33031            if (val) {
33032                boundingBox.focus();
33033            } else {
33034                boundingBox.blur();
33035            }
33036         }
33037    },
33038
33039    /**
33040     * Set the tabIndex on the widget's rendered UI
33041     *
33042     * @method _uiSetTabIndex
33043     * @protected
33044     * @param Number
33045     */
33046    _uiSetTabIndex: function(index) {
33047        var boundingBox = this.get(BOUNDING_BOX);
33048
33049        if (L.isNumber(index)) {
33050            boundingBox.set(TAB_INDEX, index);
33051        } else {
33052            boundingBox.removeAttribute(TAB_INDEX);
33053        }
33054    },
33055
33056    /**
33057     * @method _onDocMouseDown
33058     * @description "mousedown" event handler for the owner document of the
33059     * widget's bounding box.
33060     * @protected
33061     * @param {EventFacade} evt The event facade for the DOM focus event
33062     */
33063    _onDocMouseDown: function (evt) {
33064        if (this._domFocus) {
33065            this._onDocFocus(evt);
33066        }
33067    },
33068
33069    /**
33070     * DOM focus event handler, used to sync the state of the Widget with the DOM
33071     *
33072     * @method _onDocFocus
33073     * @protected
33074     * @param {EventFacade} evt The event facade for the DOM focus event
33075     */
33076    _onDocFocus: function (evt) {
33077        var widget = Widget.getByNode(evt.target),
33078            activeWidget = Widget._active;
33079
33080        if (activeWidget && (activeWidget !== widget)) {
33081            activeWidget._domFocus = false;
33082            activeWidget._set(FOCUSED, false, {src:UI});
33083
33084            Widget._active = null;
33085        }
33086
33087        if (widget) {
33088            widget._domFocus = true;
33089            widget._set(FOCUSED, true, {src:UI});
33090
33091            Widget._active = widget;
33092        }
33093    },
33094
33095    /**
33096     * Generic toString implementation for all widgets.
33097     *
33098     * @method toString
33099     * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ]
33100     */
33101    toString: function() {
33102        // Using deprecated name prop for kweight squeeze.
33103        return this.name + "[" + this.get(ID) + "]";
33104    },
33105
33106    /**
33107     * Default unit to use for dimension values
33108     *
33109     * @property DEF_UNIT
33110     * @type String
33111     */
33112    DEF_UNIT : "px",
33113
33114    /**
33115     * Default node to render the bounding box to. If not set,
33116     * will default to the current document body.
33117     *
33118     * @property DEF_PARENT_NODE
33119     * @type String | Node
33120     */
33121    DEF_PARENT_NODE : null,
33122
33123    /**
33124     * Property defining the markup template for content box. If your Widget doesn't
33125     * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null,
33126     * and contentBox and boundingBox will both point to the same Node.
33127     *
33128     * @property CONTENT_TEMPLATE
33129     * @type String
33130     */
33131    CONTENT_TEMPLATE : DIV,
33132
33133    /**
33134     * Property defining the markup template for bounding box.
33135     *
33136     * @property BOUNDING_TEMPLATE
33137     * @type String
33138     */
33139    BOUNDING_TEMPLATE : DIV,
33140
33141    /**
33142     * @method _guid
33143     * @protected
33144     */
33145    _guid : function() {
33146        return Y.guid();
33147    },
33148
33149    /**
33150     * @method _validTabIndex
33151     * @protected
33152     * @param {Number} tabIndex
33153     */
33154    _validTabIndex : function (tabIndex) {
33155        return (L.isNumber(tabIndex) || L.isNull(tabIndex));
33156    },
33157
33158    /**
33159     * Binds after listeners for the list of attributes provided
33160     *
33161     * @method _bindAttrUI
33162     * @private
33163     * @param {Array} attrs
33164     */
33165    _bindAttrUI : function(attrs) {
33166        var i,
33167            l = attrs.length;
33168
33169        for (i = 0; i < l; i++) {
33170            this.after(attrs[i] + CHANGE, this._setAttrUI);
33171        }
33172    },
33173
33174    /**
33175     * Invokes the _uiSet&#61;ATTR NAME&#62; method for the list of attributes provided
33176     *
33177     * @method _syncAttrUI
33178     * @private
33179     * @param {Array} attrs
33180     */
33181    _syncAttrUI : function(attrs) {
33182        var i, l = attrs.length, attr;
33183        for (i = 0; i < l; i++) {
33184            attr = attrs[i];
33185            this[_UISET + _toInitialCap(attr)](this.get(attr));
33186        }
33187    },
33188
33189    /**
33190     * @method _setAttrUI
33191     * @private
33192     * @param {EventFacade} e
33193     */
33194    _setAttrUI : function(e) {
33195        if (e.target === this) {
33196            this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src);
33197        }
33198    },
33199
33200    /**
33201     * The default setter for the strings attribute. Merges partial sets
33202     * into the full string set, to allow users to partial sets of strings
33203     *
33204     * @method _strSetter
33205     * @protected
33206     * @param {Object} strings
33207     * @return {String} The full set of strings to set
33208     */
33209    _strSetter : function(strings) {
33210        return Y.merge(this.get(STRINGS), strings);
33211    },
33212
33213    /**
33214     * Helper method to get a specific string value
33215     *
33216     * @deprecated Used by deprecated WidgetLocale implementations.
33217     * @method getString
33218     * @param {String} key
33219     * @return {String} The string
33220     */
33221    getString : function(key) {
33222        return this.get(STRINGS)[key];
33223    },
33224
33225    /**
33226     * Helper method to get the complete set of strings for the widget
33227     *
33228     * @deprecated  Used by deprecated WidgetLocale implementations.
33229     * @method getStrings
33230     * @param {String} key
33231     * @return {String} The strings
33232     */
33233    getStrings : function() {
33234        return this.get(STRINGS);
33235    },
33236
33237    /**
33238     * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations
33239     *
33240     * @property _UI_ATTRS
33241     * @type Object
33242     * @private
33243     */
33244    _UI_ATTRS : {
33245        BIND: UI_ATTRS,
33246        SYNC: UI_ATTRS
33247    }
33248});
33249
33250Y.Widget = Widget;
33251
33252
33253}, '3.18.1', {
33254    "requires": [
33255        "attribute",
33256        "base-base",
33257        "base-pluginhost",
33258        "classnamemanager",
33259        "event-focus",
33260        "node-base",
33261        "node-style"
33262    ],
33263    "skinnable": true
33264});
33265YUI.add('widget-htmlparser', function (Y, NAME) {
33266
33267/**
33268 * Adds HTML Parser support to the base Widget class
33269 *
33270 * @module widget
33271 * @submodule widget-htmlparser
33272 * @for Widget
33273 */
33274
33275var Widget = Y.Widget,
33276    Node = Y.Node,
33277    Lang = Y.Lang,
33278
33279    SRC_NODE = "srcNode",
33280    CONTENT_BOX = "contentBox";
33281
33282/**
33283 * Object hash, defining how attribute values are to be parsed from
33284 * markup contained in the widget's content box. e.g.:
33285 * <pre>
33286 *   {
33287 *       // Set single Node references using selector syntax
33288 *       // (selector is run through node.one)
33289 *       titleNode: "span.yui-title",
33290 *       // Set NodeList references using selector syntax
33291 *       // (array indicates selector is to be run through node.all)
33292 *       listNodes: ["li.yui-item"],
33293 *       // Set other attribute types, using a parse function.
33294 *       // Context is set to the widget instance.
33295 *       label: function(contentBox) {
33296 *           return contentBox.one("span.title").get("innerHTML");
33297 *       }
33298 *   }
33299 * </pre>
33300 *
33301 * @property HTML_PARSER
33302 * @type Object
33303 * @static
33304 */
33305Widget.HTML_PARSER = {};
33306
33307/**
33308 * The build configuration for the Widget class.
33309 * <p>
33310 * Defines the static fields which need to be aggregated,
33311 * when this class is used as the main class passed to
33312 * the <a href="Base.html#method_build">Base.build</a> method.
33313 * </p>
33314 * @property _buildCfg
33315 * @type Object
33316 * @static
33317 * @final
33318 * @private
33319 */
33320Widget._buildCfg = {
33321    aggregates : ["HTML_PARSER"]
33322};
33323
33324/**
33325 * The DOM node to parse for configuration values, passed to the Widget's HTML_PARSER definition
33326 *
33327 * @attribute srcNode
33328 * @type String | Node
33329 * @writeOnce
33330 */
33331Widget.ATTRS[SRC_NODE] = {
33332    value: null,
33333    setter: Node.one,
33334    getter: "_getSrcNode",
33335    writeOnce: true
33336};
33337
33338Y.mix(Widget.prototype, {
33339
33340    /**
33341     * @method _getSrcNode
33342     * @protected
33343     * @return {Node} The Node to apply HTML_PARSER to
33344     */
33345    _getSrcNode : function(val) {
33346        return val || this.get(CONTENT_BOX);
33347    },
33348
33349    /**
33350     * Implement the BaseCore _preAddAttrs method hook, to add
33351     * the srcNode and related attributes, so that HTML_PARSER
33352     * (which relies on `this.get("srcNode")`) can merge in it's
33353     * results before the rest of the attributes are added.
33354     *
33355     * @method _preAddAttrs
33356     * @protected
33357     *
33358     * @param attrs {Object} The full hash of statically defined ATTRS
33359     * attributes being added for this instance
33360     *
33361     * @param userVals {Object} The hash of user values passed to
33362     * the constructor
33363     *
33364     * @param lazy {boolean} Whether or not to add the attributes lazily
33365     */
33366    _preAddAttrs : function(attrs, userVals, lazy) {
33367
33368        var preAttrs = {
33369            id : attrs.id,
33370            boundingBox : attrs.boundingBox,
33371            contentBox : attrs.contentBox,
33372            srcNode : attrs.srcNode
33373        };
33374
33375        this.addAttrs(preAttrs, userVals, lazy);
33376
33377        delete attrs.boundingBox;
33378        delete attrs.contentBox;
33379        delete attrs.srcNode;
33380        delete attrs.id;
33381
33382        if (this._applyParser) {
33383            this._applyParser(userVals);
33384        }
33385    },
33386
33387    /**
33388     * @method _applyParsedConfig
33389     * @protected
33390     * @return {Object} The merged configuration literal
33391     */
33392    _applyParsedConfig : function(node, cfg, parsedCfg) {
33393        return (parsedCfg) ? Y.mix(cfg, parsedCfg, false) : cfg;
33394    },
33395
33396    /**
33397     * Utility method used to apply the <code>HTML_PARSER</code> configuration for the
33398     * instance, to retrieve config data values.
33399     *
33400     * @method _applyParser
33401     * @protected
33402     * @param config {Object} User configuration object (will be populated with values from Node)
33403     */
33404    _applyParser : function(config) {
33405
33406        var widget = this,
33407            srcNode = this._getNodeToParse(),
33408            schema = widget._getHtmlParser(),
33409            parsedConfig,
33410            val;
33411
33412        if (schema && srcNode) {
33413            Y.Object.each(schema, function(v, k, o) {
33414                val = null;
33415
33416                if (Lang.isFunction(v)) {
33417                    val = v.call(widget, srcNode);
33418                } else {
33419                    if (Lang.isArray(v)) {
33420                        val = srcNode.all(v[0]);
33421                        if (val.isEmpty()) {
33422                            val = null;
33423                        }
33424                    } else {
33425                        val = srcNode.one(v);
33426                    }
33427                }
33428
33429                if (val !== null && val !== undefined) {
33430                    parsedConfig = parsedConfig || {};
33431                    parsedConfig[k] = val;
33432                }
33433            });
33434        }
33435        config = widget._applyParsedConfig(srcNode, config, parsedConfig);
33436    },
33437
33438    /**
33439     * Determines whether we have a node reference which we should try and parse.
33440     *
33441     * The current implementation does not parse nodes generated from CONTENT_TEMPLATE,
33442     * only explicitly set srcNode, or contentBox attributes.
33443     *
33444     * @method _getNodeToParse
33445     * @return {Node} The node reference to apply HTML_PARSER to.
33446     * @private
33447     */
33448    _getNodeToParse : function() {
33449        var srcNode = this.get("srcNode");
33450        return (!this._cbFromTemplate) ? srcNode : null;
33451    },
33452
33453    /**
33454     * Gets the HTML_PARSER definition for this instance, by merging HTML_PARSER
33455     * definitions across the class hierarchy.
33456     *
33457     * @private
33458     * @method _getHtmlParser
33459     * @return {Object} HTML_PARSER definition for this instance
33460     */
33461    _getHtmlParser : function() {
33462        // Removed caching for kweight. This is a private method
33463        // and only called once so don't need to cache HTML_PARSER
33464        var classes = this._getClasses(),
33465            parser = {},
33466            i, p;
33467
33468        for (i = classes.length - 1; i >= 0; i--) {
33469            p = classes[i].HTML_PARSER;
33470            if (p) {
33471                Y.mix(parser, p, true);
33472            }
33473        }
33474        return parser;
33475    }
33476});
33477
33478
33479}, '3.18.1', {"requires": ["widget-base"]});
33480YUI.add('widget-skin', function (Y, NAME) {
33481
33482/**
33483 * Provides skin related utlility methods.
33484 *
33485 * @module widget
33486 * @submodule widget-skin
33487 */
33488var BOUNDING_BOX = "boundingBox",
33489    CONTENT_BOX = "contentBox",
33490    SKIN = "skin",
33491    _getClassName = Y.ClassNameManager.getClassName;
33492
33493/**
33494 * Returns the name of the skin that's currently applied to the widget.
33495 *
33496 * Searches up the Widget's ancestor axis for, by default, a class
33497 * yui3-skin-(name), and returns the (name) portion. Otherwise, returns null.
33498 *
33499 * This is only really useful after the widget's DOM structure is in the
33500 * document, either by render or by progressive enhancement.
33501 *
33502 * @method getSkinName
33503 * @for Widget
33504 * @param {String} [skinPrefix] The prefix which the implementation uses for the skin
33505 * ("yui3-skin-" is the default).
33506 *
33507 * NOTE: skinPrefix will be used as part of a regular expression:
33508 *
33509 *     new RegExp('\\b' + skinPrefix + '(\\S+)')
33510 *
33511 * Although an unlikely use case, literal characters which may result in an invali
33511d
33512 * regular expression should be escaped.
33513 *
33514 * @return {String} The name of the skin, or null, if a matching skin class is not found.
33515 */
33516
33517Y.Widget.prototype.getSkinName = function (skinPrefix) {
33518
33519    var root = this.get( CONTENT_BOX ) || this.get( BOUNDING_BOX ),
33520        match,
33521        search;
33522
33523    skinPrefix = skinPrefix || _getClassName(SKIN, "");
33524
33525    search = new RegExp( '\\b' + skinPrefix + '(\\S+)' );
33526
33527    if ( root ) {
33528        root.ancestor( function ( node ) {
33529            match = node.get( 'className' ).match( search );
33530            return match;
33531        } );
33532    }
33533
33534    return ( match ) ? match[1] : null;
33535};
33536
33537
33538}, '3.18.1', {"requires": ["widget-base"]});
33539YUI.add('widget-uievents', function (Y, NAME) {
33540
33541/**
33542 * Support for Widget UI Events (Custom Events fired by the widget, which wrap the underlying DOM events - e.g. widget:click, widget:mousedown)
33543 *
33544 * @module widget
33545 * @submodule widget-uievents
33546 */
33547
33548var BOUNDING_BOX = "boundingBox",
33549    Widget = Y.Widget,
33550    RENDER = "render",
33551    L = Y.Lang,
33552    EVENT_PREFIX_DELIMITER = ":",
33553
33554    //  Map of Node instances serving as a delegation containers for a specific
33555    //  event type to Widget instances using that delegation container.
33556    _uievts = Y.Widget._uievts = Y.Widget._uievts || {};
33557
33558Y.mix(Widget.prototype, {
33559
33560    /**
33561     * Destructor logic for UI event infrastructure,
33562     * invoked during Widget destruction.
33563     *
33564     * @method _destroyUIEvents
33565     * @for Widget
33566     * @private
33567     */
33568    _destroyUIEvents: function() {
33569
33570        var widgetGuid = Y.stamp(this, true);
33571
33572        Y.each(_uievts, function (info, key) {
33573            if (info.instances[widgetGuid]) {
33574                //  Unregister this Widget instance as needing this delegated
33575                //  event listener.
33576                delete info.instances[widgetGuid];
33577
33578                //  There are no more Widget instances using this delegated
33579                //  event listener, so detach it.
33580
33581                if (Y.Object.isEmpty(info.instances)) {
33582                    info.handle.detach();
33583
33584                    if (_uievts[key]) {
33585                        delete _uievts[key];
33586                    }
33587                }
33588            }
33589        });
33590    },
33591
33592    /**
33593     * Map of DOM events that should be fired as Custom Events by the
33594     * Widget instance.
33595     *
33596     * @property UI_EVENTS
33597     * @for Widget
33598     * @type Object
33599     */
33600    UI_EVENTS: Y.Node.DOM_EVENTS,
33601
33602    /**
33603     * Returns the node on which to bind delegate listeners.
33604     *
33605     * @method _getUIEventNode
33606     * @for Widget
33607     * @protected
33608     */
33609    _getUIEventNode: function () {
33610        return this.get(BOUNDING_BOX);
33611    },
33612
33613    /**
33614     * Binds a delegated DOM event listener of the specified type to the
33615     * Widget's outtermost DOM element to facilitate the firing of a Custom
33616     * Event of the same type for the Widget instance.
33617     *
33618     * @method _createUIEvent
33619     * @for Widget
33620     * @param type {String} String representing the name of the event
33621     * @private
33622     */
33623    _createUIEvent: function (type) {
33624
33625        var uiEvtNode = this._getUIEventNode(),
33626            key = (Y.stamp(uiEvtNode) + type),
33627            info = _uievts[key],
33628            handle;
33629
33630        //  For each Node instance: Ensure that there is only one delegated
33631        //  event listener used to fire Widget UI events.
33632
33633        if (!info) {
33634
33635            handle = uiEvtNode.delegate(type, function (evt) {
33636
33637                var widget = Widget.getByNode(this);
33638
33639                // Widget could be null if node instance belongs to
33640                // another Y instance.
33641
33642                if (widget) {
33643                    if (widget._filterUIEvent(evt)) {
33644                        widget.fire(evt.type, { domEvent: evt });
33645                    }
33646                }
33647
33648            }, "." + Y.Widget.getClassName());
33649
33650            _uievts[key] = info = { instances: {}, handle: handle };
33651        }
33652
33653        //  Register this Widget as using this Node as a delegation container.
33654        info.instances[Y.stamp(this)] = 1;
33655    },
33656
33657    /**
33658     * This method is used to determine if we should fire
33659     * the UI Event or not. The default implementation makes sure
33660     * that for nested delegates (nested unrelated widgets), we don't
33661     * fire the UI event listener more than once at each level.
33662     *
33663     * <p>For example, without the additional filter, if you have nested
33664     * widgets, each widget will have a delegate listener. If you
33665     * click on the inner widget, the inner delegate listener's
33666     * filter will match once, but the outer will match twice
33667     * (based on delegate's design) - once for the inner widget,
33668     * and once for the outer.</p>
33669     *
33670     * @method _filterUIEvent
33671     * @for Widget
33672     * @param {DOMEventFacade} evt
33673     * @return {boolean} true if it's OK to fire the custom UI event, false if not.
33674     * @private
33675     *
33676     */
33677    _filterUIEvent: function(evt) {
33678        // Either it's hitting this widget's delegate container (and not some other widget's),
33679        // or the container it's hitting is handling this widget's ui events.
33680        return (evt.currentTarget.compareTo(evt.container) || evt.container.compareTo(this._getUIEventNode()));
33681    },
33682
33683    /**
33684     * Determines if the specified event is a UI event.
33685     *
33686     * @private
33687     * @method _isUIEvent
33688     * @for Widget
33689     * @param type {String} String representing the name of the event
33690     * @return {String} Event Returns the name of the UI Event, otherwise
33691     * undefined.
33692     */
33693    _getUIEvent: function (type) {
33694
33695        if (L.isString(type)) {
33696            var sType = this.parseType(type)[1],
33697                iDelim,
33698                returnVal;
33699
33700            if (sType) {
33701                // TODO: Get delimiter from ET, or have ET support this.
33702                iDelim = sType.indexOf(EVENT_PREFIX_DELIMITER);
33703                if (iDelim > -1) {
33704                    sType = sType.substring(iDelim + EVENT_PREFIX_DELIMITER.length);
33705                }
33706
33707                if (this.UI_EVENTS[sType]) {
33708                    returnVal = sType;
33709                }
33710            }
33711
33712            return returnVal;
33713        }
33714    },
33715
33716    /**
33717     * Sets up infrastructure required to fire a UI event.
33718     *
33719     * @private
33720     * @method _initUIEvent
33721     * @for Widget
33722     * @param type {String} String representing the name of the event
33723     * @return {String}
33724     */
33725    _initUIEvent: function (type) {
33726        var sType = this._getUIEvent(type),
33727            queue = this._uiEvtsInitQueue || {};
33728
33729        if (sType && !queue[sType]) {
33730
33731            this._uiEvtsInitQueue = queue[sType] = 1;
33732
33733            this.after(RENDER, function() {
33734                this._createUIEvent(sType);
33735                delete this._uiEvtsInitQueue[sType];
33736            });
33737        }
33738    },
33739
33740    //  Override of "on" from Base to facilitate the firing of Widget events
33741    //  based on DOM events of the same name/type (e.g. "click", "mouseover").
33742    //  Temporary solution until we have the ability to listen to when
33743    //  someone adds an event listener (bug 2528230)
33744    on: function (type) {
33745        this._initUIEvent(type);
33746        return Widget.superclass.on.apply(this, arguments);
33747    },
33748
33749    //  Override of "publish" from Base to facilitate the firing of Widget events
33750    //  based on DOM events of the same name/type (e.g. "click", "mouseover").
33751    //  Temporary solution until we have the ability to listen to when
33752    //  someone publishes an event (bug 2528230)
33753    publish: function (type, config) {
33754        var sType = this._getUIEvent(type);
33755        if (sType && config && config.defaultFn) {
33756            this._initUIEvent(sType);
33757        }
33758        return Widget.superclass.publish.apply(this, arguments);
33759    }
33760
33761}, true); // overwrite existing EventTarget methods
33762
33763
33764}, '3.18.1', {"requires": ["node-event-delegate", "widget-base"]});
33765YUI.add('widget-stdmod', function (Y, NAME) {
33766
33767/**
33768 * Provides standard module support for Widgets through an extension.
33769 *
33770 * @module widget-stdmod
33771 */
33772    var L = Y.Lang,
33773        Node = Y.Node,
33774        UA = Y.UA,
33775        Widget = Y.Widget,
33776
33777        EMPTY = "",
33778        HD = "hd",
33779        BD = "bd",
33780        FT = "ft",
33781        HEADER = "header",
33782        BODY = "body",
33783        FOOTER = "footer",
33784        FILL_HEIGHT = "fillHeight",
33785        STDMOD = "stdmod",
33786
33787        NODE_SUFFIX = "Node",
33788        CONTENT_SUFFIX = "Content",
33789
33790        FIRST_CHILD = "firstChild",
33791        CHILD_NODES = "childNodes",
33792        OWNER_DOCUMENT = "ownerDocument",
33793
33794        CONTENT_BOX = "contentBox",
33795
33796        HEIGHT = "height",
33797        OFFSET_HEIGHT = "offsetHeight",
33798        AUTO = "auto",
33799
33800        HeaderChange = "headerContentChange",
33801        BodyChange = "bodyContentChange",
33802        FooterChange = "footerContentChange",
33803        FillHeightChange = "fillHeightChange",
33804        HeightChange = "heightChange",
33805        ContentUpdate = "contentUpdate",
33806
33807        RENDERUI = "renderUI",
33808        BINDUI = "bindUI",
33809        SYNCUI = "syncUI",
33810
33811        APPLY_PARSED_CONFIG = "_applyParsedConfig",
33812
33813        UI = Y.Widget.UI_SRC;
33814
33815    /**
33816     * Widget extension, which can be used to add Standard Module support to the
33817     * base Widget class, through the <a href="Base.html#method_build">Base.build</a>
33818     * method.
33819     * <p>
33820     * The extension adds header, body and footer sections to the Widget's content box and
33821     * provides the corresponding methods and attributes to modify the contents of these sections.
33822     * </p>
33823     * @class WidgetStdMod
33824     * @param {Object} The user configuration object
33825     */
33826    function StdMod(config) {}
33827
33828    /**
33829     * Constant used to refer the the standard module header, in methods which expect a section specifier
33830     *
33831     * @property HEADER
33832     * @static
33833     * @type String
33834     */
33835    StdMod.HEADER = HEADER;
33836
33837    /**
33838     * Constant used to refer the the standard module body, in methods which expect a section specifier
33839     *
33840     * @property BODY
33841     * @static
33842     * @type String
33843     */
33844    StdMod.BODY = BODY;
33845
33846    /**
33847     * Constant used to refer the the standard module footer, in methods which expect a section specifier
33848     *
33849     * @property FOOTER
33850     * @static
33851     * @type String
33852     */
33853    StdMod.FOOTER = FOOTER;
33854
33855    /**
33856     * Constant used to specify insertion position, when adding content to sections of the standard module in
33857     * methods which expect a "where" argument.
33858     * <p>
33859     * Inserts new content <em>before</em> the sections existing content.
33860     * </p>
33861     * @property AFTER
33862     * @static
33863     * @type String
33864     */
33865    StdMod.AFTER = "after";
33866
33867    /**
33868     * Constant used to specify insertion position, when adding content to sections of the standard module in
33869     * methods which expect a "where" argument.
33870     * <p>
33871     * Inserts new content <em>before</em> the sections existing content.
33872     * </p>
33873     * @property BEFORE
33874     * @static
33875     * @type String
33876     */
33877    StdMod.BEFORE = "before";
33878    /**
33879     * Constant used to specify insertion position, when adding content to sections of the standard module in
33880     * methods which expect a "where" argument.
33881     * <p>
33882     * <em>Replaces</em> the sections existing content, with new content.
33883     * </p>
33884     * @property REPLACE
33885     * @static
33886     * @type String
33887     */
33888    StdMod.REPLACE = "replace";
33889
33890    var STD_HEADER = StdMod.HEADER,
33891        STD_BODY = StdMod.BODY,
33892        STD_FOOTER = StdMod.FOOTER,
33893
33894        HEADER_CONTENT = STD_HEADER + CONTENT_SUFFIX,
33895        FOOTER_CONTENT = STD_FOOTER + CONTENT_SUFFIX,
33896        BODY_CONTENT = STD_BODY + CONTENT_SUFFIX;
33897
33898    /**
33899     * Static property used to define the default attribute
33900     * configuration introduced by WidgetStdMod.
33901     *
33902     * @property ATTRS
33903     * @type Object
33904     * @static
33905     */
33906    StdMod.ATTRS = {
33907
33908        /**
33909         * @attribute headerContent
33910         * @type HTML
33911         * @default undefined
33912         * @description The content to be added to the header section. This will replace any existing content
33913         * in the header. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method.
33914         */
33915        headerContent: {
33916            value:null
33917        },
33918
33919        /**
33920         * @attribute footerContent
33921         * @type HTML
33922         * @default undefined
33923         * @description The content to be added to the footer section. This will replace any existing content
33924         * in the footer. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method.
33925         */
33926        footerContent: {
33927            value:null
33928        },
33929
33930        /**
33931         * @attribute bodyContent
33932         * @type HTML
33933         * @default undefined
33934         * @description The content to be added to the body section. This will replace any existing content
33935         * in the body. If you want to append, or insert new content, use the <a href="#method_setStdModContent">setStdModContent</a> method.
33936         */
33937        bodyContent: {
33938            value:null
33939        },
33940
33941        /**
33942         * @attribute fillHeight
33943         * @type {String}
33944         * @default WidgetStdMod.BODY
33945         * @description The section (WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER) which should be resized to fill the height of the standard module, when a
33946         * height is set on the Widget. If a height is not set on the widget, then all sections are sized based on
33947         * their content.
33948         */
33949        fillHeight: {
33950            value: StdMod.BODY,
33951            validator: function(val) {
33952                 return this._validateFillHeight(val);
33953            }
33954        }
33955    };
33956
33957    /**
33958     * The HTML parsing rules for the WidgetStdMod class.
33959     *
33960     * @property HTML_PARSER
33961     * @static
33962     * @type Object
33963     */
33964    StdMod.HTML_PARSER = {
33965        headerContent: function(contentBox) {
33966            return this._parseStdModHTML(STD_HEADER);
33967        },
33968
33969        bodyContent: function(contentBox) {
33970            return this._parseStdModHTML(STD_BODY);
33971        },
33972
33973        footerContent : function(contentBox) {
33974            return this._parseStdModHTML(STD_FOOTER);
33975        }
33976    };
33977
33978    /**
33979     * Static hash of default class names used for the header,
33980     * body and footer sections of the standard module, keyed by
33981     * the section identifier (WidgetStdMod.STD_HEADER, WidgetStdMod.STD_BODY, WidgetStdMod.STD_FOOTER)
33982     *
33983     * @property SECTION_CLASS_NAMES
33984     * @static
33985     * @type Object
33986     */
33987    StdMod.SECTION_CLASS_NAMES = {
33988        header: Widget.getClassName(HD),
33989        body: Widget.getClassName(BD),
33990        footer: Widget.getClassName(FT)
33991    };
33992
33993    /**
33994     * The template HTML strings for each of the standard module sections. Section entries are keyed by the section constants,
33995     * WidgetStdMod.HEADER, WidgetStdMod.BODY, WidgetStdMod.FOOTER, and contain the HTML to be added for each section.
33996     * e.g.
33997     * <pre>
33998     *    {
33999     *       header : '&lt;div class="yui-widget-hd"&gt;&lt;/div&gt;',
34000     *       body : '&lt;div class="yui-widget-bd"&gt;&lt;/div&gt;',
34001     *       footer : '&lt;div class="yui-widget-ft"&gt;&lt;/div&gt;'
34002     *    }
34003     * </pre>
34004     * @property TEMPLATES
34005     * @type Object
34006     * @static
34007     */
34008    StdMod.TEMPLATES = {
34009        header : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_HEADER] + '"></div>',
34010        body : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_BODY] + '"></div>',
34011        footer : '<div class="' + StdMod.SECTION_CLASS_NAMES[STD_FOOTER] + '"></div>'
34012    };
34013
34014    StdMod.prototype = {
34015
34016        initializer : function() {
34017            this._stdModNode = this.get(CONTENT_BOX);
34018
34019            Y.before(this._renderUIStdMod, this, RENDERUI);
34020            Y.before(this._bindUIStdMod, this, BINDUI);
34021            Y.before(this._syncUIStdMod, this, SYNCUI);
34022        },
34023
34024        /**
34025         * Synchronizes the UI to match the Widgets standard module state.
34026         * <p>
34027         * This method is invoked after syncUI is invoked for the Widget class
34028         * using YUI's aop infrastructure.
34029         * </p>
34030         * @method _syncUIStdMod
34031         * @protected
34032         */
34033        _syncUIStdMod : function() {
34034            var stdModParsed = this._stdModParsed;
34035
34036            if (!stdModParsed || !stdModParsed[HEADER_CONTENT]) {
34037                this._uiSetStdMod(STD_HEADER, this.get(HEADER_CONTENT));
34038            }
34039
34040            if (!stdModParsed || !stdModParsed[BODY_CONTENT]) {
34041                this._uiSetStdMod(STD_BODY, this.get(BODY_CONTENT));
34042            }
34043
34044            if (!stdModParsed || !stdModParsed[FOOTER_CONTENT]) {
34045                this._uiSetStdMod(STD_FOOTER, this.get(FOOTER_CONTENT));
34046            }
34047
34048            this._uiSetFillHeight(this.get(FILL_HEIGHT));
34049        },
34050
34051        /**
34052         * Creates/Initializes the DOM for standard module support.
34053         * <p>
34054         * This method is invoked after renderUI is invoked for the Widget class
34055         * using YUI's aop infrastructure.
34056         * </p>
34057         * @method _renderUIStdMod
34058         * @protected
34059         */
34060        _renderUIStdMod : function() {
34061            this._stdModNode.addClass(Widget.getClassName(STDMOD));
34062            this._renderStdModSections();
34063
34064            //This normally goes in bindUI but in order to allow setStdModContent() to work before renderUI
34065            //stage, these listeners should be set up at the earliest possible time.
34066            this.after(HeaderChange, this._afterHeaderChange);
34067            this.after(BodyChange, this._afterBodyChange);
34068            this.after(FooterChange, this._afterFooterChange);
34069        },
34070
34071        _renderStdModSections : function() {
34072            if (L.isValue(this.get(HEADER_CONTENT))) { this._renderStdMod(STD_HEADER); }
34073            if (L.isValue(this.get(BODY_CONTENT))) { this._renderStdMod(STD_BODY); }
34074            if (L.isValue(this.get(FOOTER_CONTENT))) { this._renderStdMod(STD_FOOTER); }
34075        },
34076
34077        /**
34078         * Binds event listeners responsible for updating the UI state in response to
34079         * Widget standard module related state changes.
34080         * <p>
34081         * This method is invoked after bindUI is invoked for the Widget class
34082         * using YUI's aop infrastructure.
34083         * </p>
34084         * @method _bindUIStdMod
34085         * @protected
34086         */
34087        _bindUIStdMod : function() {
34088            // this.after(HeaderChange, this._afterHeaderChange);
34089            // this.after(BodyChange, this._afterBodyChange);
34090            // this.after(FooterChange, this._afterFooterChange);
34091
34092            this.after(FillHeightChange, this._afterFillHeightChange);
34093            this.after(HeightChange, this._fillHeight);
34094            this.after(ContentUpdate, this._fillHeight);
34095        },
34096
34097        /**
34098         * Default attribute change listener for the headerContent attribute, responsible
34099         * for updating the UI, in response to attribute changes.
34100         *
34101         * @method _afterHeaderChange
34102         * @protected
34103         * @param {EventFacade} e The event facade for the attribute change
34104         */
34105        _afterHeaderChange : function(e) {
34106            if (e.src !== UI) {
34107                this._uiSetStdMod(STD_HEADER, e.newVal, e.stdModPosition);
34108            }
34109        },
34110
34111        /**
34112         * Default attribute change listener for the bodyContent attribute, responsible
34113         * for updating the UI, in response to attribute changes.
34114         *
34115         * @method _afterBodyChange
34116         * @protected
34117         * @param {EventFacade} e The event facade for the attribute change
34118         */
34119        _afterBodyChange : function(e) {
34120            if (e.src !== UI) {
34121                this._uiSetStdMod(STD_BODY, e.newVal, e.stdModPosition);
34122            }
34123        },
34124
34125        /**
34126         * Default attribute change listener for the footerContent attribute, responsible
34127         * for updating the UI, in response to attribute changes.
34128         *
34129         * @method _afterFooterChange
34130         * @protected
34131         * @param {EventFacade} e The event facade for the attribute change
34132         */
34133        _afterFooterChange : function(e) {
34134            if (e.src !== UI) {
34135                this._uiSetStdMod(STD_FOOTER, e.newVal, e.stdModPosition);
34136            }
34137        },
34138
34139        /**
34140         * Default attribute change listener for the fillHeight attribute, responsible
34141         * for updating the UI, in response to attribute changes.
34142         *
34143         * @method _afterFillHeightChange
34144         * @protected
34145         * @param {EventFacade} e The event facade for the attribute change
34146         */
34147        _afterFillHeightChange: function (e) {
34148            this._uiSetFillHeight(e.newVal);
34149        },
34150
34151        /**
34152         * Default validator for the fillHeight attribute. Verifies that the
34153         * value set is a valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER,
34154         * or a falsey value if fillHeight is to be disabled.
34155         *
34156         * @method _validateFillHeight
34157         * @protected
34158         * @param {String} val The section which should be setup to fill height, or false/null to disable fillHeight
34159         * @return true if valid, false if not
34160         */
34161        _validateFillHeight : function(val) {
34162            return !val || val == StdMod.BODY || val == StdMod.HEADER || val == StdMod.FOOTER;
34163        },
34164
34165        /**
34166         * Updates the rendered UI, to resize the provided section so that the standard module fills out
34167         * the specified widget height. Note: This method does not check whether or not a height is set
34168         * on the Widget.
34169         *
34170         * @method _uiSetFillHeight
34171         * @protected
34172         * @param {String} fillSection A valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER
34173         */
34174        _uiSetFillHeight : function(fillSection) {
34175            var fillNode = this.getStdModNode(fillSection);
34176            var currNode = this._currFillNode;
34177
34178            if (currNode && fillNode !== currNode){
34179                currNode.setStyle(HEIGHT, EMPTY);
34180            }
34181
34182            if (fillNode) {
34183                this._currFillNode = fillNode;
34184            }
34185
34186            this._fillHeight();
34187        },
34188
34189        /**
34190         * Updates the rendered UI, to resize the current section specified by the fillHeight attribute, so
34191         * that the standard module fills out the Widget height. If a height has not been set on Widget,
34192         * the section is not resized (height is set to "auto").
34193         *
34194         * @method _fillHeight
34195         * @private
34196         */
34197        _fillHeight : function() {
34198            if (this.get(FILL_HEIGHT)) {
34199                var height = this.get(HEIGHT);
34200                if (height != EMPTY && height != AUTO) {
34201                    this.fillHeight(this.getStdModNode(this.get(FILL_HEIGHT)));
34202                }
34203            }
34204        },
34205
34206        /**
34207         * Updates the rendered UI, adding the provided content (either an HTML string, or node reference),
34208         * to the specified section. The content is either added before, after or replaces existing content
34209         * in the section, based on the value of the <code>where</code> argument.
34210         *
34211         * @method _uiSetStdMod
34212         * @protected
34213         *
34214         * @param {String} section The section to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34215         * @param {String | Node} content The new content (either as an HTML string, or Node reference) to add to the section
34216         * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE.
34217         * If not provided, the content will replace existing content in the section.
34218         */
34219        _uiSetStdMod : function(section, content, where) {
34220            // Using isValue, so that "" is valid content
34221            if (L.isValue(content)) {
34222                var node = this.getStdModNode(section, true);
34223
34224                this._addStdModContent(node, content, where);
34225
34226                this.set(section + CONTENT_SUFFIX, this._getStdModContent(section), {src:UI});
34227            } else {
34228                this._eraseStdMod(section);
34229            }
34230            this.fire(ContentUpdate);
34231        },
34232
34233        /**
34234         * Creates the DOM node for the given section, and inserts it into the correct location in the contentBox.
34235         *
34236         * @method _renderStdMod
34237         * @protected
34238         * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34239         * @return {Node} A reference to the added section node
34240         */
34241        _renderStdMod : function(section) {
34242
34243            var contentBox = this.get(CONTENT_BOX),
34244                sectionNode = this._findStdModSection(section);
34245
34246            if (!sectionNode) {
34247                sectionNode = this._getStdModTemplate(section);
34248            }
34249
34250            this._insertStdModSection(contentBox, section, sectionNode);
34251
34252            this[section + NODE_SUFFIX] = sectionNode;
34253            return this[section + NODE_SUFFIX];
34254        },
34255
34256        /**
34257         * Removes the DOM node for the given section.
34258         *
34259         * @method _eraseStdMod
34260         * @protected
34261         * @param {String} section The section to remove. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34262         */
34263        _eraseStdMod : function(section) {
34264            var sectionNode = this.getStdModNode(section);
34265            if (sectionNode) {
34266                sectionNode.remove(true);
34267                delete this[section + NODE_SUFFIX];
34268            }
34269        },
34270
34271        /**
34272         * Helper method to insert the Node for the given section into the correct location in the contentBox.
34273         *
34274         * @method _insertStdModSection
34275         * @private
34276         * @param {Node} contentBox A reference to the Widgets content box.
34277         * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34278         * @param {Node} sectionNode The Node for the section.
34279         */
34280        _insertStdModSection : function(contentBox, section, sectionNode) {
34281            var fc = contentBox.get(FIRST_CHILD);
34282
34283            if (section === STD_FOOTER || !fc) {
34284                contentBox.appendChild(sectionNode);
34285            } else {
34286                if (section === STD_HEADER) {
34287                    contentBox.insertBefore(sectionNode, fc);
34288                } else {
34289                    var footer = this[STD_FOOTER + NODE_SUFFIX];
34290                    if (footer) {
34291                        contentBox.insertBefore(sectionNode, footer);
34292                    } else {
34293                        contentBox.appendChild(sectionNode);
34294                    }
34295                }
34296            }
34297        },
34298
34299        /**
34300         * Gets a new Node reference for the given standard module section, by cloning
34301         * the stored template node.
34302         *
34303         * @method _getStdModTemplate
34304         * @protected
34305         * @param {String} section The section to create a new node for. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34306         * @return {Node} The new Node instance for the section
34307         */
34308        _getStdModTemplate : function(section) {
34309            return Node.create(StdMod.TEMPLATES[section], this._stdModNode.get(OWNER_DOCUMENT));
34310        },
34311
34312        /**
34313         * Helper method to add content to a StdMod section node.
34314         * The content is added either before, after or replaces the existing node content
34315         * based on the value of the <code>where</code> argument.
34316         *
34317         * @method _addStdModContent
34318         * @private
34319         *
34320         * @param {Node} node The section Node to be updated.
34321         * @param {Node|NodeList|String} children The new content Node, NodeList or String to be added to section Node provided.
34322         * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE.
34323         * If not provided, the content will replace existing content in the Node.
34324         */
34325        _addStdModContent : function(node, children, where) {
34326
34327            // StdMod where to Node where
34328            switch (where) {
34329                case StdMod.BEFORE:  // 0 is before fistChild
34330                    where = 0;
34331                    break;
34332                case StdMod.AFTER:   // undefined is appendChild
34333                    where = undefined;
34334                    break;
34335                default:            // replace is replace, not specified is replace
34336                    where = StdMod.REPLACE;
34337            }
34338
34339            node.insert(children, where);
34340        },
34341
34342        /**
34343         * Helper method to obtain the precise height of the node provided, including padding and border.
34344         * The height could be a sub-pixel value for certain browsers, such as Firefox 3.
34345         *
34346         * @method _getPreciseHeight
34347         * @private
34348         * @param {Node} node The node for which the precise height is required.
34349         * @return {Number} The height of the Node including borders and padding, possibly a float.
34350         */
34351        _getPreciseHeight : function(node) {
34352            var height = (node) ? node.get(OFFSET_HEIGHT) : 0,
34353                getBCR = "getBoundingClientRect";
34354
34355            if (node && node.hasMethod(getBCR)) {
34356                var preciseRegion = node.invoke(getBCR);
34357                if (preciseRegion) {
34358                    height = preciseRegion.bottom - preciseRegion.top;
34359                }
34360            }
34361
34362            return height;
34363        },
34364
34365        /**
34366         * Helper method to to find the rendered node for the given section,
34367         * if it exists.
34368         *
34369         * @method _findStdModSection
34370         * @private
34371         * @param {String} section The section for which the render Node is to be found. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34372         * @return {Node} The rendered node for the given section, or null if not found.
34373         */
34374        _findStdModSection: function(section) {
34375            return this.get(CONTENT_BOX).one("> ." + StdMod.SECTION_CLASS_NAMES[section]);
34376        },
34377
34378        /**
34379         * Utility method, used by WidgetStdMods HTML_PARSER implementation
34380         * to extract data for each section from markup.
34381         *
34382         * @method _parseStdModHTML
34383         * @private
34384         * @param {String} section
34385         * @return {String}
34385 Inner HTML string with the contents of the section
34386         */
34387        _parseStdModHTML : function(section) {
34388
34389            var node = this._findStdModSection(section);
34390
34391            if (node) {
34392                if (!this._stdModParsed) {
34393                    this._stdModParsed = {};
34394                    Y.before(this._applyStdModParsedConfig, this, APPLY_PARSED_CONFIG);
34395                }
34396                this._stdModParsed[section + CONTENT_SUFFIX] = 1;
34397
34398                return node.get("innerHTML");
34399            }
34400
34401            return null;
34402        },
34403
34404        /**
34405         * This method is injected before the _applyParsedConfig step in
34406         * the application of HTML_PARSER, and sets up the state to
34407         * identify whether or not we should remove the current DOM content
34408         * or not, based on whether or not the current content attribute value
34409         * was extracted from the DOM, or provided by the user configuration
34410         *
34411         * @method _applyStdModParsedConfig
34412         * @private
34413         */
34414        _applyStdModParsedConfig : function(node, cfg, parsedCfg) {
34415            var parsed = this._stdModParsed;
34416            if (parsed) {
34417                parsed[HEADER_CONTENT] = !(HEADER_CONTENT in cfg) && (HEADER_CONTENT in parsed);
34418                parsed[BODY_CONTENT] = !(BODY_CONTENT in cfg) && (BODY_CONTENT in parsed);
34419                parsed[FOOTER_CONTENT] = !(FOOTER_CONTENT in cfg) && (FOOTER_CONTENT in parsed);
34420            }
34421        },
34422
34423        /**
34424         * Retrieves the child nodes (content) of a standard module section
34425         *
34426         * @method _getStdModContent
34427         * @private
34428         * @param {String} section The standard module section whose child nodes are to be retrieved. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34429         * @return {Node} The child node collection of the standard module section.
34430         */
34431        _getStdModContent : function(section) {
34432            return (this[section + NODE_SUFFIX]) ? this[section + NODE_SUFFIX].get(CHILD_NODES) : null;
34433        },
34434
34435        /**
34436         * Updates the body section of the standard module with the content provided (either an HTML string, or node reference).
34437         * <p>
34438         * This method can be used instead of the corresponding section content attribute if you'd like to retain the current content of the section,
34439         * and insert content before or after it, by specifying the <code>where</code> argument.
34440         * </p>
34441         * @method setStdModContent
34442         * @param {String} section The standard module section whose content is to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER.
34443         * @param {String | Node} content The content to be added, either an HTML string or a Node reference.
34444         * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE.
34445         * If not provided, the content will replace existing content in the section.
34446         */
34447        setStdModContent : function(section, content, where) {
34448            //var node = this.getStdModNode(section) || this._renderStdMod(section);
34449            this.set(section + CONTENT_SUFFIX, content, {stdModPosition:where});
34450            //this._addStdModContent(node, content, where);
34451        },
34452
34453        /**
34454        Returns the node reference for the specified `section`.
34455
34456        **Note:** The DOM is not queried for the node reference. The reference
34457        stored by the widget instance is returned if it was set. Passing a
34458        truthy for `forceCreate` will create the section node if it does not
34459        already exist.
34460
34461        @method getStdModNode
34462        @param {String} section The section whose node reference is required.
34463            Either `WidgetStdMod.HEADER`, `WidgetStdMod.BODY`, or
34464            `WidgetStdMod.FOOTER`.
34465        @param {Boolean} forceCreate Whether the section node should be created
34466            if it does not already exist.
34467        @return {Node} The node reference for the `section`, or null if not set.
34468        **/
34469        getStdModNode : function(section, forceCreate) {
34470            var node = this[section + NODE_SUFFIX] || null;
34471
34472            if (!node && forceCreate) {
34473                node = this._renderStdMod(section);
34474            }
34475
34476            return node;
34477        },
34478
34479        /**
34480         * Sets the height on the provided header, body or footer element to
34481         * fill out the height of the Widget. It determines the height of the
34482         * widgets bounding box, based on it's configured height value, and
34483         * sets the height of the provided section to fill out any
34484         * space remaining after the other standard module section heights
34485         * have been accounted for.
34486         *
34487         * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
34488         * height has not been set on the Widget, since for an "auto" height Widget,
34489         * the heights of the header/body/footer will drive the height of the Widget.</p>
34490         *
34491         * @method fillHeight
34492         * @param {Node} node The node which should be resized to fill out the height
34493         * of the Widget bounding box. Should be a standard module section node which belongs
34494         * to the widget.
34495         */
34496        fillHeight : function(node) {
34497            if (node) {
34498                var contentBox = this.get(CONTENT_BOX),
34499                    stdModNodes = [this.headerNode, this.bodyNode, this.footerNode],
34500                    stdModNode,
34501                    cbContentHeight,
34502                    filled = 0,
34503                    remaining = 0,
34504
34505                    validNode = false;
34506
34507                for (var i = 0, l = stdModNodes.length; i < l; i++) {
34508                    stdModNode = stdModNodes[i];
34509                    if (stdModNode) {
34510                        if (stdModNode !== node) {
34511                            filled += this._getPreciseHeight(stdModNode);
34512                        } else {
34513                            validNode = true;
34514                        }
34515                    }
34516                }
34517
34518                if (validNode) {
34519                    if (UA.ie || UA.opera) {
34520                        // Need to set height to 0, to allow height to be reduced
34521                        node.set(OFFSET_HEIGHT, 0);
34522                    }
34523
34524                    cbContentHeight = contentBox.get(OFFSET_HEIGHT) -
34525                            parseInt(contentBox.getComputedStyle("paddingTop"), 10) -
34526                            parseInt(contentBox.getComputedStyle("paddingBottom"), 10) -
34527                            parseInt(contentBox.getComputedStyle("borderBottomWidth"), 10) -
34528                            parseInt(contentBox.getComputedStyle("borderTopWidth"), 10);
34529
34530                    if (L.isNumber(cbContentHeight)) {
34531                        remaining = cbContentHeight - filled;
34532                        if (remaining >= 0) {
34533                            node.set(OFFSET_HEIGHT, remaining);
34534                        }
34535                    }
34536                }
34537            }
34538        }
34539    };
34540
34541    Y.WidgetStdMod = StdMod;
34542
34543
34544}, '3.18.1', {"requires": ["base-build", "widget"]});
34545YUI.add('widget-position', function (Y, NAME) {
34546
34547/**
34548 * Provides basic XY positioning support for Widgets, though an extension
34549 *
34550 * @module widget-position
34551 */
34552    var Lang = Y.Lang,
34553        Widget = Y.Widget,
34554
34555        XY_COORD = "xy",
34556
34557        POSITION = "position",
34558        POSITIONED = "positioned",
34559        BOUNDING_BOX = "boundingBox",
34560        RELATIVE = "relative",
34561
34562        RENDERUI = "renderUI",
34563        BINDUI = "bindUI",
34564        SYNCUI = "syncUI",
34565
34566        UI = Widget.UI_SRC,
34567
34568        XYChange = "xyChange";
34569
34570    /**
34571     * Widget extension, which can be used to add positioning support to the base Widget class,
34572     * through the <a href="Base.html#method_build">Base.build</a> method.
34573     *
34574     * @class WidgetPosition
34575     * @param {Object} config User configuration object
34576     */
34577    function Position(config) {
34578    }
34579
34580    /**
34581     * Static property used to define the default attribute
34582     * configuration introduced by WidgetPosition.
34583     *
34584     * @property ATTRS
34585     * @static
34586     * @type Object
34587     */
34588    Position.ATTRS = {
34589
34590        /**
34591         * @attribute x
34592         * @type number
34593         * @default 0
34594         *
34595         * @description Page X co-ordinate for the widget. This attribute acts as a facade for the
34596         * xy attribute. Changes in position can be monitored by listening for xyChange events.
34597         */
34598        x: {
34599            setter: function(val) {
34600                this._setX(val);
34601            },
34602            getter: function() {
34603                return this._getX();
34604            },
34605            lazyAdd:false
34606        },
34607
34608        /**
34609         * @attribute y
34610         * @type number
34611         * @default 0
34612         *
34613         * @description Page Y co-ordinate for the widget. This attribute acts as a facade for the
34614         * xy attribute. Changes in position can be monitored by listening for xyChange events.
34615         */
34616        y: {
34617            setter: function(val) {
34618                this._setY(val);
34619            },
34620            getter: function() {
34621                return this._getY();
34622            },
34623            lazyAdd: false
34624        },
34625
34626        /**
34627         * @attribute xy
34628         * @type Array
34629         * @default [0,0]
34630         *
34631         * @description Page XY co-ordinate pair for the widget.
34632         */
34633        xy: {
34634            value:[0,0],
34635            validator: function(val) {
34636                return this._validateXY(val);
34637            }
34638        }
34639    };
34640
34641    /**
34642     * Default class used to mark the boundingBox of a positioned widget.
34643     *
34644     * @property POSITIONED_CLASS_NAME
34645     * @type String
34646     * @default "yui-widget-positioned"
34647     * @static
34648     */
34649    Position.POSITIONED_CLASS_NAME = Widget.getClassName(POSITIONED);
34650
34651    Position.prototype = {
34652
34653        initializer : function() {
34654            this._posNode = this.get(BOUNDING_BOX);
34655
34656            // WIDGET METHOD OVERLAP
34657            Y.after(this._renderUIPosition, this, RENDERUI);
34658            Y.after(this._syncUIPosition, this, SYNCUI);
34659            Y.after(this._bindUIPosition, this, BINDUI);
34660        },
34661
34662        /**
34663         * Creates/Initializes the DOM to support xy page positioning.
34664         * <p>
34665         * This method in invoked after renderUI is invoked for the Widget class
34666         * using YUI's aop infrastructure.
34667         * </p>
34668         * @method _renderUIPosition
34669         * @protected
34670         */
34671        _renderUIPosition : function() {
34672            this._posNode.addClass(Position.POSITIONED_CLASS_NAME);
34673        },
34674
34675        /**
34676         * Synchronizes the UI to match the Widgets xy page position state.
34677         * <p>
34678         * This method in invoked after syncUI is invoked for the Widget class
34679         * using YUI's aop infrastructure.
34680         * </p>
34681         * @method _syncUIPosition
34682         * @protected
34683         */
34684        _syncUIPosition : function() {
34685            var posNode = this._posNode;
34686            if (posNode.getStyle(POSITION) === RELATIVE) {
34687                this.syncXY();
34688            }
34689            this._uiSetXY(this.get(XY_COORD));
34690        },
34691
34692        /**
34693         * Binds event listeners responsible for updating the UI state in response to
34694         * Widget position related state changes.
34695         * <p>
34696         * This method in invoked after bindUI is invoked for the Widget class
34697         * using YUI's aop infrastructure.
34698         * </p>
34699         * @method _bindUIPosition
34700         * @protected
34701         */
34702        _bindUIPosition :function() {
34703            this.after(XYChange, this._afterXYChange);
34704        },
34705
34706        /**
34707         * Moves the Widget to the specified page xy co-ordinate position.
34708         *
34709         * @method move
34710         *
34711         * @param {Number|Number[]} x The new x position or [x, y] values passed
34712         * as an array to support simple pass through of Node.getXY results
34713         * @param {Number} [y] The new y position
34714         */
34715        move: function () {
34716            var args = arguments,
34717                coord = (Lang.isArray(args[0])) ? args[0] : [args[0], args[1]];
34718                this.set(XY_COORD, coord);
34719        },
34720
34721        /**
34722         * Synchronizes the Panel's "xy", "x", and "y" properties with the
34723         * Widget's position in the DOM.
34724         *
34725         * @method syncXY
34726         */
34727        syncXY : function () {
34728            this.set(XY_COORD, this._posNode.getXY(), {src: UI});
34729        },
34730
34731        /**
34732         * Default validator for the XY attribute
34733         *
34734         * @method _validateXY
34735         * @protected
34736         * @param {Array} val The XY page co-ordinate value which is being set.
34737         * @return {boolean} true if valid, false if not.
34738         */
34739        _validateXY : function(val) {
34740            return (Lang.isArray(val) && Lang.isNumber(val[0]) && Lang.isNumber(val[1]));
34741        },
34742
34743        /**
34744         * Default setter for the X attribute. The setter passes the X value through
34745         * to the XY attribute, which is the sole store for the XY state.
34746         *
34747         * @method _setX
34748         * @protected
34749         * @param {Number} val The X page co-ordinate value
34750         */
34751        _setX : function(val) {
34752            this.set(XY_COORD, [val, this.get(XY_COORD)[1]]);
34753        },
34754
34755        /**
34756         * Default setter for the Y attribute. The setter passes the Y value through
34757         * to the XY attribute, which is the sole store for the XY state.
34758         *
34759         * @method _setY
34760         * @protected
34761         * @param {Number} val The Y page co-ordinate value
34762         */
34763        _setY : function(val) {
34764            this.set(XY_COORD, [this.get(XY_COORD)[0], val]);
34765        },
34766
34767        /**
34768         * Default getter for the X attribute. The value is retrieved from
34769         * the XY attribute, which is the sole store for the XY state.
34770         *
34771         * @method _getX
34772         * @protected
34773         * @return {Number} The X page co-ordinate value
34774         */
34775        _getX : function() {
34776            return this.get(XY_COORD)[0];
34777        },
34778
34779        /**
34780         * Default getter for the Y attribute. The value is retrieved from
34781         * the XY attribute, which is the sole store for the XY state.
34782         *
34783         * @method _getY
34784         * @protected
34785         * @return {Number} The Y page co-ordinate value
34786         */
34787        _getY : function() {
34788            return this.get(XY_COORD)[1];
34789        },
34790
34791        /**
34792         * Default attribute change listener for the xy attribute, responsible
34793         * for updating the UI, in response to attribute changes.
34794         *
34795         * @method _afterXYChange
34796         * @protected
34797         * @param {EventFacade} e The event facade for the attribute change
34798         */
34799        _afterXYChange : function(e) {
34800            if (e.src != UI) {
34801                this._uiSetXY(e.newVal);
34802            }
34803        },
34804
34805        /**
34806         * Updates the UI to reflect the XY page co-ordinates passed in.
34807         *
34808         * @method _uiSetXY
34809         * @protected
34810         * @param {String} val The XY page co-ordinates value to be reflected in the UI
34811         */
34812        _uiSetXY : function(val) {
34813            this._posNode.setXY(val);
34814        }
34815    };
34816
34817    Y.WidgetPosition = Position;
34818
34819
34820}, '3.18.1', {"requires": ["base-build", "node-screen", "widget"]});
34821YUI.add('widget-position-align', function (Y, NAME) {
34822
34823/**
34824Provides extended/advanced XY positioning support for Widgets, through an
34825extension.
34826
34827It builds on top of the `widget-position` module, to provide alignment and
34828centering support. Future releases aim to add constrained and fixed positioning
34829support.
34830
34831@module widget-position-align
34832**/
34833var Lang = Y.Lang,
34834
34835    ALIGN        = 'align',
34836    ALIGN_ON     = 'alignOn',
34837
34838    VISIBLE      = 'visible',
34839    BOUNDING_BOX = 'boundingBox',
34840
34841    OFFSET_WIDTH    = 'offsetWidth',
34842    OFFSET_HEIGHT   = 'offsetHeight',
34843    REGION          = 'region',
34844    VIEWPORT_REGION = 'viewportRegion';
34845
34846/**
34847Widget extension, which can be used to add extended XY positioning support to
34848the base Widget class, through the `Base.create` method.
34849
34850**Note:** This extension requires that the `WidgetPosition` extension be added
34851to the Widget (before `WidgetPositionAlign`, if part of the same extension list
34852passed to `Base.build`).
34853
34854@class WidgetPositionAlign
34855@param {Object} config User configuration object.
34856@constructor
34857**/
34858function PositionAlign (config) {}
34859
34860PositionAlign.ATTRS = {
34861
34862    /**
34863    The alignment configuration for this widget.
34864
34865    The `align` attribute is used to align a reference point on the widget, with
34866    the reference point on another `Node`, or the viewport. The object which
34867    `align` expects has the following properties:
34868
34869      * __`node`__: The `Node` to which the widget is to be aligned. If set to
34870        `null`, or not provided, the widget is aligned to the viewport.
34871
34872      * __`points`__: A two element Array, defining the two points on the widget
34873        and `Node`/viewport which are to be aligned. The first element is the
34874        point on the widget, and the second element is the point on the
34875        `Node`/viewport. Supported alignment points are defined as static
34876        properties on `WidgetPositionAlign`.
34877
34878    @example Aligns the top-right corner of the widget with the top-left corner
34879    of the viewport:
34880
34881        myWidget.set('align', {
34882            points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TL]
34883        });
34884
34885    @attribute align
34886    @type Object
34887    @default null
34888    **/
34889    align: {
34890        value: null
34891    },
34892
34893    /**
34894    A convenience Attribute, which can be used as a shortcut for the `align`
34895    Attribute.
34896
34897    If set to `true`, the widget is centered in the viewport. If set to a `Node`
34898    reference or valid selector String, the widget will be centered within the
34899    `Node`. If set to `false`, no center positioning is applied.
34900
34901    @attribute centered
34902    @type Boolean|Node
34903    @default false
34904    **/
34905    centered: {
34906        setter : '_setAlignCenter',
34907        lazyAdd:false,
34908        value  :false
34909    },
34910
34911    /**
34912    An Array of Objects corresponding to the `Node`s and events that will cause
34913    the alignment of this widget to be synced to the DOM.
34914
34915    The `alignOn` Attribute is expected to be an Array of Objects with the
34916    following properties:
34917
34918      * __`eventName`__: The String event name to listen for.
34919
34920      * __`node`__: The optional `Node` that will fire the event, it can be a
34921        `Node` reference or a selector String. This will default to the widget's
34922        `boundingBox`.
34923
34924    @example Sync this widget's alignment on window resize:
34925
34926        myWidget.set('alignOn', [
34927            {
34928                node     : Y.one('win'),
34929                eventName: 'resize'
34930            }
34931        ]);
34932
34933    @attribute alignOn
34934    @type Array
34935    @default []
34936    **/
34937    alignOn: {
34938        value    : [],
34939        validator: Y.Lang.isArray
34940    }
34941};
34942
34943/**
34944Constant used to specify the top-left corner for alignment
34945
34946@property TL
34947@type String
34948@value 'tl'
34949@static
34950**/
34951PositionAlign.TL = 'tl';
34952
34953/**
34954Constant used to specify the top-right corner for alignment
34955
34956@property TR
34957@type String
34958@value 'tr'
34959@static
34960**/
34961PositionAlign.TR = 'tr';
34962
34963/**
34964Constant used to specify the bottom-left corner for alignment
34965
34966@property BL
34967@type String
34968@value 'bl'
34969@static
34970**/
34971PositionAlign.BL = 'bl';
34972
34973/**
34974Constant used to specify the bottom-right corner for alignment
34975
34976@property BR
34977@type String
34978@value 'br'
34979@static
34980**/
34981PositionAlign.BR = 'br';
34982
34983/**
34984Constant used to specify the top edge-center point for alignment
34985
34986@property TC
34987@type String
34988@value 'tc'
34989@static
34990**/
34991PositionAlign.TC = 'tc';
34992
34993/**
34994Constant used to specify the right edge, center point for alignment
34995
34996@property RC
34997@type String
34998@value 'rc'
34999@static
35000**/
35001PositionAlign.RC = 'rc';
35002
35003/**
35004Constant used to specify the bottom edge, center point for alignment
35005
35006@property BC
35007@type String
35008@value 'bc'
35009@static
35010**/
35011PositionAlign.BC = 'bc';
35012
35013/**
35014Constant used to specify the left edge, center point for alignment
35015
35016@property LC
35017@type String
35018@value 'lc'
35019@static
35020**/
35021PositionAlign.LC = 'lc';
35022
35023/**
35024Constant used to specify the center of widget/node/viewport for alignment
35025
35026@property CC
35027@type String
35028@value 'cc'
35029@static
35030*/
35031PositionAlign.CC = 'cc';
35032
35033PositionAlign.prototype = {
35034    // -- Protected Properties -------------------------------------------------
35035
35036
35037    initializer : function() {
35038        if (!this._posNode) {
35039            Y.error('WidgetPosition needs to be added to the Widget, ' +
35040                'before WidgetPositionAlign is added');
35041        }
35042
35043        Y.after(this._bindUIPosAlign, this, 'bindUI');
35044        Y.after(this._syncUIPosAlign, this, 'syncUI');
35045    },
35046
35047    /**
35048    Holds the alignment-syncing event handles.
35049
35050    @property _posAlignUIHandles
35051    @type Array
35052    @default null
35053    @protected
35054    **/
35055    _posAlignUIHandles: null,
35056
35057    // -- Lifecycle Methods ----------------------------------------------------
35058
35059    destructor: function () {
35060        this._detachPosAlignUIHandles();
35061    },
35062
35063    /**
35064    Bind event listeners responsible for updating the UI state in response to
35065    the widget's position-align related state changes.
35066
35067    This method is invoked after `bindUI` has been invoked for the `Widget`
35068    class using the AOP infrastructure.
35069
35070    @method _bindUIPosAlign
35071    @protected
35072    **/
35073    _bindUIPosAlign: function () {
35074        this.after('alignChange', this._afterAlignChange);
35075        this.after('alignOnChange', this._afterAlignOnChange);
35076        this.after('visibleChange', this._syncUIPosAlign);
35077    },
35078
35079    /**
35080    Synchronizes the current `align` Attribute value to the DOM.
35081
35082    This method is invoked after `syncUI` has been invoked for the `Widget`
35083    class using the AOP infrastructure.
35084
35085    @method _syncUIPosAlign
35086    @protected
35087    **/
35088    _syncUIPosAlign: function () {
35089        var align = this.get(ALIGN);
35090
35091        this._uiSetVisiblePosAlign(this.get(VISIBLE));
35092
35093        if (align) {
35094            this._uiSetAlign(align.node, align.points);
35095        }
35096    },
35097
35098    // -- Public Methods -------------------------------------------------------
35099
35100    /**
35101    Aligns this widget to the provided `Node` (or viewport) using the provided
35102    points. This method can be invoked with no arguments which will cause the
35103    widget's current `align` Attribute value to be synced to the DOM.
35104
35105    @example Aligning to the top-left corner of the `<body>`:
35106
35107        myWidget.align('body',
35108            [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]);
35109
35110    @method align
35111    @param {Node|String|null} [node] A reference (or selector String) for the
35112      `Node` which with the widget is to be aligned. If null is passed in, the
35113      widget will be aligned with the viewport.
35114    @param {Array[2]} [points] A two item array specifying the points on the
35115      widget and `Node`/viewport which will to be aligned. The first entry is
35116      the point on the widget, and the second entry is the point on the
35117      `Node`/viewport. Valid point references are defined as static constants on
35118      the `WidgetPositionAlign` extension.
35119    @chainable
35120    **/
35121    align: function (node, points) {
35122        if (arguments.length) {
35123            // Set the `align` Attribute.
35124            this.set(ALIGN, {
35125                node  : node,
35126                points: points
35127            });
35128        } else {
35129            // Sync the current `align` Attribute value to the DOM.
35130            this._syncUIPosAlign();
35131        }
35132
35133        return this;
35134    },
35135
35136    /**
35137    Centers the widget in the viewport, or if a `Node` is passed in, it will
35138    be centered to that `Node`.
35139
35140    @method centered
35141    @param {Node|String} [node] A `Node` reference or selector String defining
35142      the `Node` which the widget should be centered. If a `Node` is not  passed
35143      in, then the widget will be centered to the viewport.
35144    @chainable
35145    **/
35146    centered: function (node) {
35147        return this.align(node, [PositionAlign.CC, PositionAlign.CC]);
35148    },
35149
35150    // -- Protected Methods ----------------------------------------------------
35151
35152    /**
35153    Default setter for `center` Attribute changes. Sets up the appropriate
35154    value, and passes it through the to the align attribute.
35155
35156    @method _setAlignCenter
35157    @param {Boolean|Node} val The Attribute value being set.
35158    @return {Boolean|Node} the value passed in.
35159    @protected
35160    **/
35161    _setAlignCenter: function (val) {
35162        if (val) {
35163            this.set(ALIGN, {
35164                node  : val === true ? null : val,
35165                points: [PositionAlign.CC, PositionAlign.CC]
35166            });
35167        }
35168
35169        return val;
35170    },
35171
35172    /**
35173    Updates the UI to reflect the `align` value passed in.
35174
35175    **Note:** See the `align` Attribute documentation, for the Object structure
35176    expected.
35177
35178    @method _uiSetAlign
35179    @param {Node|String|null} [node] The node to align to, or null to indicate
35180      the viewport.
35181    @param {Array} points The alignment points.
35182    @protected
35183    **/
35184    _uiSetAlign: function (node, points) {
35185        if ( ! Lang.isArray(points) || points.length !== 2) {
35186            Y.error('align: Invalid Points Arguments');
35187            return;
35188        }
35189
35190        var nodeRegion = this._getRegion(node),
35191            widgetPoint, nodePoint, xy;
35192
35193        if ( ! nodeRegion) {
35194            // No-op, nothing to align to.
35195            return;
35196        }
35197
35198        widgetPoint = points[0];
35199        nodePoint   = points[1];
35200
35201        // TODO: Optimize KWeight - Would lookup table help?
35202        switch (nodePoint) {
35203        case PositionAlign.TL:
35204            xy = [nodeRegion.left, nodeRegion.top];
35205            break;
35206
35207        case PositionAlign.TR:
35208            xy = [nodeRegion.right, nodeRegion.top];
35209            break;
35210
35211        case PositionAlign.BL:
35212            xy = [nodeRegion.left, nodeRegion.bottom];
35213            break;
35214
35215        case PositionAlign.BR:
35216            xy = [nodeRegion.right, nodeRegion.bottom];
35217            break;
35218
35219        case PositionAlign.TC:
35220            xy = [
35221                nodeRegion.left + Math.floor(nodeRegion.width / 2),
35222                nodeRegion.top
35223            ];
35224            break;
35225
35226        case PositionAlign.BC:
35227            xy = [
35228                nodeRegion.left + Math.floor(nodeRegion.width / 2),
35229                nodeRegion.bottom
35230            ];
35231            break;
35232
35233        case PositionAlign.LC:
35234            xy = [
35235                nodeRegion.left,
35236                nodeRegion.top + Math.floor(nodeRegion.height / 2)
35237            ];
35238            break;
35239
35240        case PositionAlign.RC:
35241            xy = [
35242                nodeRegion.right,
35243                nodeRegion.top + Math.floor(nodeRegion.height / 2)
35244            ];
35245            break;
35246
35247        case PositionAlign.CC:
35248            xy = [
35249                nodeRegion.left + Math.floor(nodeRegion.width / 2),
35250                nodeRegion.top + Math.floor(nodeRegion.height / 2)
35251            ];
35252            break;
35253
35254        default:
35255            break;
35256
35257        }
35258
35259        if (xy) {
35260            this._doAlign(widgetPoint, xy[0], xy[1]);
35261        }
35262    },
35263
35264    /**
35265    Attaches or detaches alignment-syncing event handlers based on the widget's
35266    `visible` Attribute state.
35267
35268    @method _uiSetVisiblePosAlign
35269    @param {Boolean} visible The current value of the widget's `visible`
35270      Attribute.
35271    @protected
35272    **/
35273    _uiSetVisiblePosAlign: function (visible) {
35274        if (visible) {
35275            this._attachPosAlignUIHandles();
35276        } else {
35277            this._detachPosAlignUIHandles();
35278        }
35279    },
35280
35281    /**
35282    Attaches the alignment-syncing event handlers.
35283
35284    @method _attachPosAlignUIHandles
35285    @protected
35286    **/
35287    _attachPosAlignUIHandles: function () {
35288        if (this._posAlignUIHandles) {
35289            // No-op if we have already setup the event handlers.
35290            return;
35291        }
35292
35293        var bb        = this.get(BOUNDING_BOX),
35294            syncAlign = Y.bind(this._syncUIPosAlign, this),
35295            handles   = [];
35296
35297        Y.Array.each(this.get(ALIGN_ON), function (o) {
35298            var event = o.eventName,
35299                node  = Y.one(o.node) || bb;
35300
35301            if (event) {
35302                handles.push(node.on(event, syncAlign));
35303            }
35304        });
35305
35306        this._posAlignUIHandles = handles;
35307    },
35308
35309    /**
35310    Detaches the alignment-syncing event handlers.
35311
35312    @method _detachPosAlignUIHandles
35313    @protected
35314    **/
35315    _detachPosAlignUIHandles: function () {
35316        var handles = this._posAlignUIHandles;
35317        if (handles) {
35318            new Y.EventHandle(handles).detach();
35319            this._posAlignUIHandles = null;
35320        }
35321    },
35322
35323    // -- Private Methods ------------------------------------------------------
35324
35325    /**
35326    Helper method, used to align the given point on the widget, with the XY page
35327    coordinates provided.
35328
35329    @method _doAlign
35330    @param {String} widgetPoint Supported point constant
35331      (e.g. WidgetPositionAlign.TL)
35332    @param {Number} x X page coordinate to align to.
35333    @param {Number} y Y page coordinate to align to.
35334    @private
35335    **/
35336    _doAlign: function (widgetPoint, x, y) {
35337        var widgetNode = this._posNode,
35338            xy;
35339
35340        switch (widgetPoint) {
35341        case PositionAlign.TL:
35342            xy = [x, y];
35343            break;
35344
35345        case PositionAlign.TR:
35346            xy = [
35347                x - widgetNode.get(OFFSET_WIDTH),
35348                y
35349            ];
35350            break;
35351
35352        case PositionAlign.BL:
35353            xy = [
35354                x,
35355                y - widgetNode.get(OFFSET_HEIGHT)
35356            ];
35357            break;
35358
35359        case PositionAlign.BR:
35360            xy = [
35361                x - widgetNode.get(OFFSET_WIDTH),
35362                y - widgetNode.get(OFFSET_HEIGHT)
35363            ];
35364            break;
35365
35366        case PositionAlign.TC:
35367            xy = [
35368                x - (widgetNode.get(OFFSET_WIDTH) / 2),
35369                y
35370            ];
35371            break;
35372
35373        case PositionAlign.BC:
35374            xy = [
35375                x - (widgetNode.get(OFFSET_WIDTH) / 2),
35376                y - widgetNode.get(OFFSET_HEIGHT)
35377            ];
35378            break;
35379
35380        case PositionAlign.LC:
35381            xy = [
35382                x,
35383                y - (widgetNode.get(OFFSET_HEIGHT) / 2)
35384            ];
35385            break;
35386
35387        case PositionAlign.RC:
35388            xy = [
35389                x - widgetNode.get(OFFSET_WIDTH),
35390                y - (widgetNode.get(OFFSET_HEIGHT) / 2)
35391            ];
35392            break;
35393
35394        case PositionAlign.CC:
35395            xy = [
35396                x - (widgetNode.get(OFFSET_WIDTH) / 2),
35397                y - (widgetNode.get(OFFSET_HEIGHT) / 2)
35398            ];
35399            break;
35400
35401        default:
35402            break;
35403
35404        }
35405
35406        if (xy) {
35407            this.move(xy);
35408        }
35409    },
35410
35411    /**
35412    Returns the region of the passed-in `Node`, or the viewport region if
35413    calling with passing in a `Node`.
35414
35415    @method _getRegion
35416    @param {Node} [node] The node to get the region of.
35417    @return {Object} The node's region.
35418    @private
35419    **/
35420    _getRegion: function (node) {
35421        var nodeRegion;
35422
35423        if ( ! node) {
35424            nodeRegion = this._posNode.get(VIEWPORT_REGION);
35425        } else {
35426            node = Y.Node.one(node);
35427            if (node) {
35428                nodeRegion = node.get(REGION);
35429            }
35430        }
35431
35432        return nodeRegion;
35433    },
35434
35435    // -- Protected Event Handlers ---------------------------------------------
35436
35437    /**
35438    Handles `alignChange` events by updating the UI in response to `align`
35439    Attribute changes.
35440
35441    @method _afterAlignChange
35442    @param {EventFacade} e
35443    @protected
35444    **/
35445    _afterAlignChange: function (e) {
35446        var align = e.newVal;
35447        if (align) {
35448            this._uiSetAlign(align.node, align.points);
35449        }
35450    },
35451
35452    /**
35453    Handles `alignOnChange` events by updating the alignment-syncing event
35454    handlers.
35455
35456    @method _afterAlignOnChange
35457    @param {EventFacade} e
35458    @protected
35459    **/
35460    _afterAlignOnChange: function(e) {
35461        this._detachPosAlignUIHandles();
35462
35463        if (this.get(VISIBLE)) {
35464            this._attachPosAlignUIHandles();
35465        }
35466    }
35467};
35468
35469Y.WidgetPositionAlign = PositionAlign;
35470
35471
35472}, '3.18.1', {"requires": ["widget-position"]});
35473YUI.add('widget-stack', function (Y, NAME) {
35474
35475/**
35476 * Provides stackable (z-index) support for Widgets through an extension.
35477 *
35478 * @module widget-stack
35479 */
35480    var L = Y.Lang,
35481        UA = Y.UA,
35482        Node = Y.Node,
35483        Widget = Y.Widget,
35484
35485        ZINDEX = "zIndex",
35486        SHIM = "shim",
35487        VISIBLE = "visible",
35488
35489        BOUNDING_BOX = "boundingBox",
35490
35491        RENDER_UI = "renderUI",
35492        BIND_UI = "bindUI",
35493        SYNC_UI = "syncUI",
35494
35495        OFFSET_WIDTH = "offsetWidth",
35496        OFFSET_HEIGHT = "offsetHeight",
35497        PARENT_NODE = "parentNode",
35498        FIRST_CHILD = "firstChild",
35499        OWNER_DOCUMENT = "ownerDocument",
35500
35501        WIDTH = "width",
35502        HEIGHT = "height",
35503        PX = "px",
35504
35505        // HANDLE KEYS
35506        SHIM_DEFERRED = "shimdeferred",
35507        SHIM_RESIZE = "shimresize",
35508
35509        // Events
35510        VisibleChange = "visibleChange",
35511        WidthChange = "widthChange",
35512        HeightChange = "heightChange",
35513        ShimChange = "shimChange",
35514        ZIndexChange = "zIndexChange",
35515        ContentUpdate = "contentUpdate",
35516
35517        // CSS
35518        STACKED = "stacked";
35519
35520    /**
35521     * Widget extension, which can be used to add stackable (z-index) support to the
35522     * base Widget class along with a shimming solution, through the
35523     * <a href="Base.html#method_build">Base.build</a> method.
35524     *
35525     * @class WidgetStack
35526     * @param {Object} User configuration object
35527     */
35528    function Stack(config) {}
35529
35530    // Static Properties
35531    /**
35532     * Static property used to define the default attribute
35533     * configuration introduced by WidgetStack.
35534     *
35535     * @property ATTRS
35536     * @type Object
35537     * @static
35538     */
35539    Stack.ATTRS = {
35540        /**
35541         * @attribute shim
35542         * @type boolean
35543         * @default false, for all browsers other than IE6, for which a shim is enabled by default.
35544         *
35545         * @description Boolean flag to indicate whether or not a shim should be added to the Widgets
35546         * boundingBox, to protect it from select box bleedthrough.
35547         */
35548        shim: {
35549            value: (UA.ie == 6)
35550        },
35551
35552        /**
35553         * @attribute zIndex
35554         * @type number
35555         * @default 0
35556         * @description The z-index to apply to the Widgets boundingBox. Non-numerical values for
35557         * zIndex will be converted to 0
35558         */
35559        zIndex: {
35560            value : 0,
35561            setter: '_setZIndex'
35562        }
35563    };
35564
35565    /**
35566     * The HTML parsing rules for the WidgetStack class.
35567     *
35568     * @property HTML_PARSER
35569     * @static
35570     * @type Object
35571     */
35572    Stack.HTML_PARSER = {
35573        zIndex: function (srcNode) {
35574            return this._parseZIndex(srcNode);
35575        }
35576    };
35577
35578    /**
35579     * Default class used to mark the shim element
35580     *
35581     * @property SHIM_CLASS_NAME
35582     * @type String
35583     * @static
35584     * @default "yui3-widget-shim"
35585     */
35586    Stack.SHIM_CLASS_NAME = Widget.getClassName(SHIM);
35587
35588    /**
35589     * Default class used to mark the boundingBox of a stacked widget.
35590     *
35591     * @property STACKED_CLASS_NAME
35592     * @type String
35593     * @static
35594     * @default "yui3-widget-stacked"
35595     */
35596    Stack.STACKED_CLASS_NAME = Widget.getClassName(STACKED);
35597
35598    /**
35599     * Default markup template used to generate the shim element.
35600     *
35601     * @property SHIM_TEMPLATE
35602     * @type String
35603     * @static
35604     */
35605    Stack.SHIM_TEMPLATE = '<iframe class="' + Stack.SHIM_CLASS_NAME + '" frameborder="0" title="Widget Stacking Shim" src="javascript:false" tabindex="-1" role="presentation"></iframe>';
35606
35607    Stack.prototype = {
35608
35609        initializer : function() {
35610            this._stackNode = this.get(BOUNDING_BOX);
35611            this._stackHandles = {};
35612
35613            // WIDGET METHOD OVERLAP
35614            Y.after(this._renderUIStack, this, RENDER_UI);
35615            Y.after(this._syncUIStack, this, SYNC_UI);
35616            Y.after(this._bindUIStack, this, BIND_UI);
35617        },
35618
35619        /**
35620         * Synchronizes the UI to match the Widgets stack state. This method in
35621         * invoked after syncUI is invoked for the Widget class using YUI's aop infrastructure.
35622         *
35623         * @method _syncUIStack
35624         * @protected
35625         */
35626        _syncUIStack: function() {
35627            this._uiSetShim(this.get(SHIM));
35628            this._uiSetZIndex(this.get(ZINDEX));
35629        },
35630
35631        /**
35632         * Binds event listeners responsible for updating the UI state in response to
35633         * Widget stack related state changes.
35634         * <p>
35635         * This method is invoked after bindUI is invoked for the Widget class
35636         * using YUI's aop infrastructure.
35637         * </p>
35638         * @method _bindUIStack
35639         * @protected
35640         */
35641        _bindUIStack: function() {
35642            this.after(ShimChange, this._afterShimChange);
35643            this.after(ZIndexChange, this._afterZIndexChange);
35644        },
35645
35646        /**
35647         * Creates/Initializes the DOM to support stackability.
35648         * <p>
35649         * This method in invoked after renderUI is invoked for the Widget class
35650         * using YUI's aop infrastructure.
35651         * </p>
35652         * @method _renderUIStack
35653         * @protected
35654         */
35655        _renderUIStack: function() {
35656            this._stackNode.addClass(Stack.STACKED_CLASS_NAME);
35657        },
35658
35659        /**
35660        Parses a `zIndex` attribute value from this widget's `srcNode`.
35661
35662        @method _parseZIndex
35663        @param {Node} srcNode The node to parse a `zIndex` value from.
35664        @return {Mixed} The parsed `zIndex` value.
35665        @protected
35666        **/
35667        _parseZIndex: function (srcNode) {
35668            var zIndex;
35669
35670            // Prefers how WebKit handles `z-index` which better matches the
35671            // spec:
35672            //
35673            // * http://www.w3.org/TR/CSS2/visuren.html#z-index
35674            // * https://bugs.webkit.org/show_bug.cgi?id=15562
35675            //
35676            // When a node isn't rendered in the document, and/or when a
35677            // node is not positioned, then it doesn't have a context to derive
35678            // a valid `z-index` value from.
35679            if (!srcNode.inDoc() || srcNode.getStyle('position') === 'static') {
35680                zIndex = 'auto';
35681            } else {
35682                // Uses `getComputedStyle()` because it has greater accuracy in
35683                // more browsers than `getStyle()` does for `z-index`.
35684                zIndex = srcNode.getComputedStyle('zIndex');
35685            }
35686
35687            // This extension adds a stacking context to widgets, therefore a
35688            // `srcNode` witout a stacking context (i.e. "auto") will return
35689            // `null` from this DOM parser. This way the widget's default or
35690            // user provided value for `zIndex` will be used.
35691            return zIndex === 'auto' ? null : zIndex;
35692        },
35693
35694        /**
35695         * Default setter for zIndex attribute changes. Normalizes zIndex values to
35696         * numbers, converting non-numerical values to 0.
35697         *
35698         * @method _setZIndex
35699         * @protected
35700         * @param {String | Number} zIndex
35701         * @return {Number} Normalized zIndex
35702         */
35703        _setZIndex: function(zIndex) {
35704            if (L.isString(zIndex)) {
35705                zIndex = parseInt(zIndex, 10);
35706            }
35707            if (!L.isNumber(zIndex)) {
35708                zIndex = 0;
35709            }
35710            return zIndex;
35711        },
35712
35713        /**
35714         * Default attribute change listener for the shim attribute, responsible
35715         * for updating the UI, in response to attribute changes.
35716         *
35717         * @method _afterShimChange
35718         * @protected
35719         * @param {EventFacade} e The event facade for the attribute change
35720         */
35721        _afterShimChange : function(e) {
35722            this._uiSetShim(e.newVal);
35723        },
35724
35725        /**
35726         * Default attribute change listener for the zIndex attribute, responsible
35727         * for updating the UI, in response to attribute changes.
35728         *
35729         * @method _afterZIndexChange
35730         * @protected
35731         * @param {EventFacade} e The event facade for the attribute change
35732         */
35733        _afterZIndexChange : function(e) {
35734            this._uiSetZIndex(e.newVal);
35735        },
35736
35737        /**
35738         * Updates the UI to reflect the zIndex value passed in.
35739         *
35740         * @method _uiSetZIndex
35741         * @protected
35742         * @param {number} zIndex The zindex to be reflected in the UI
35743         */
35744        _uiSetZIndex: function (zIndex) {
35745            this._stackNode.setStyle(ZINDEX, zIndex);
35746        },
35747
35748        /**
35749         * Updates the UI to enable/disable the shim. If the widget is not currently visible,
35750         * creation of the shim is deferred until it is made visible, for performance reasons.
35751         *
35752         * @method _uiSetShim
35753         * @protected
35754         * @param {boolean} enable If true, creates/renders the shim, if false, removes it.
35755         */
35756        _uiSetShim: function (enable) {
35757            if (enable) {
35758                // Lazy creation
35759                if (this.get(VISIBLE)) {
35760                    this._renderShim();
35761                } else {
35762                    this._renderShimDeferred();
35763                }
35764
35765                // Eagerly attach resize handlers
35766                //
35767                // Required because of Event stack behavior, commit ref: cd8dddc
35768                // Should be revisted after Ticket #2531067 is resolved.
35769                if (UA.ie == 6) {
35770                    this._addShimResizeHandlers();
35771                }
35772            } else {
35773                this._destroyShim();
35774            }
35775        },
35776
35777        /**
35778         * Sets up change handlers for the visible attribute, to defer shim creation/rendering
35779         * until the Widget is made visible.
35780         *
35781         * @method _renderShimDeferred
35782         * @private
35783         */
35784        _renderShimDeferred : function() {
35785
35786            this._stackHandles[SHIM_DEFERRED] = this._stackHandles[SHIM_DEFERRED] || [];
35787
35788            var handles = this._stackHandles[SHIM_DEFERRED],
35789                createBeforeVisible = function(e) {
35790                    if (e.newVal) {
35791                        this._renderShim();
35792                    }
35793                };
35794
35795            handles.push(this.on(VisibleChange, createBeforeVisible));
35796            // Depending how how Ticket #2531067 is resolved, a reversal of
35797            // commit ref: cd8dddc could lead to a more elagent solution, with
35798            // the addition of this line here:
35799            //
35800            // handles.push(this.after(VisibleChange, this.sizeShim));
35801        },
35802
35803        /**
35804         * Sets up event listeners to resize the shim when the size of the Widget changes.
35805         * <p>
35806         * NOTE: This method is only used for IE6 currently, since IE6 doesn't support a way to
35807         * resize the shim purely through CSS, when the Widget does not have an explicit width/height
35808         * set.
35809         * </p>
35810         * @method _addShimResizeHandlers
35811         * @private
35812         */
35813        _addShimResizeHandlers : function() {
35814
35815            this._stackHandles[SHIM_RESIZE] = this._stackHandles[SHIM_RESIZE] || [];
35816
35817            var sizeShim = this.sizeShim,
35818                handles = this._stackHandles[SHIM_RESIZE];
35819
35820            handles.push(this.after(VisibleChange, sizeShim));
35821            handles.push(this.after(WidthChange, sizeShim));
35822            handles.push(this.after(HeightChange, sizeShim));
35823            handles.push(this.after(ContentUpdate, sizeShim));
35824        },
35825
35826        /**
35827         * Detaches any handles stored for the provided key
35828         *
35829         * @method _detachStackHandles
35830         * @param String handleKey The key defining the group of handles which should be detached
35831         * @private
35832         */
35833        _detachStackHandles : function(handleKey) {
35834            var handles = this._stackHandles[handleKey],
35835                handle;
35836
35837            if (handles && handles.length > 0) {
35838                while((handle = handles.pop())) {
35839                    handle.detach();
35840                }
35841            }
35842        },
35843
35844        /**
35845         * Creates the shim element and adds it to the DOM
35846         *
35847         * @method _renderShim
35848         * @private
35849         */
35850        _renderShim : function() {
35851            var shimEl = this._shimNode,
35852                stackEl = this._stackNode;
35853
35854            if (!shimEl) {
35855                shimEl = this._shimNode = this._getShimTemplate();
35856                stackEl.insertBefore(shimEl, stackEl.get(FIRST_CHILD));
35857
35858                this._detachStackHandles(SHIM_DEFERRED);
35859                this.sizeShim();
35860            }
35861        },
35862
35863        /**
35864         * Removes the shim from the DOM, and detaches any related event
35865         * listeners.
35866         *
35867         * @method _destroyShim
35868         * @private
35869         */
35870        _destroyShim : function() {
35871            if (this._shimNode) {
35872                this._shimNode.get(PARENT_NODE).removeChild(this._shimNode);
35873                this._shimNode = null;
35874
35875                this._detachStackHandles(SHIM_DEFERRED);
35876                this._detachStackHandles(SHIM_RESIZE);
35877            }
35878        },
35879
35880        /**
35881         * For IE6, synchronizes the size and position of iframe shim to that of
35882         * Widget bounding box which it is protecting. For all other browsers,
35883         * this method does not do anything.
35884         *
35885         * @method sizeShim
35886         */
35887        sizeShim: function () {
35888            var shim = this._shimNode,
35889                node = this._stackNode;
35890
35891            if (shim && UA.ie === 6 && this.get(VISIBLE)) {
35892                shim.setStyle(WIDTH, node.get(OFFSET_WIDTH) + PX);
35893                shim.setStyle(HEIGHT, node.get(OFFSET_HEIGHT) + PX);
35894            }
35895        },
35896
35897        /**
35898         * Creates a cloned shim node, using the SHIM_TEMPLATE html template, for use on a new instance.
35899         *
35900         * @method _getShimTemplate
35901         * @private
35902         * @return {Node} node A new shim Node instance.
35903         */
35904        _getShimTemplate : function() {
35905            return Node.create(Stack.SHIM_TEMPLATE, this._stackNode.get(OWNER_DOCUMENT));
35906        }
35907    };
35908
35909    Y.WidgetStack = Stack;
35910
35911
35912}, '3.18.1', {"requires": ["base-build", "widget"], "skinnable": true});
35913YUI.add('widget-position-constrain', function (Y, NAME) {
35914
35915/**
35916 * Provides constrained xy positioning support for Widgets, through an extension.
35917 *
35918 * It builds on top of the widget-position module, to provide constrained positioning support.
35919 *
35920 * @module widget-position-constrain
35921 */
35922var CONSTRAIN = "constrain",
35923    CONSTRAIN_XYCHANGE = "constrain|xyChange",
35924    CONSTRAIN_CHANGE = "constrainChange",
35925
35926    PREVENT_OVERLAP = "preventOverlap",
35927    ALIGN = "align",
35928
35929    EMPTY_STR = "",
35930
35931    BINDUI = "bindUI",
35932
35933    XY = "xy",
35934    X_COORD = "x",
35935    Y_COORD = "y",
35936
35937    Node = Y.Node,
35938
35939    VIEWPORT_REGION = "viewportRegion",
35940    REGION = "region",
35941
35942    PREVENT_OVERLAP_MAP;
35943
35944/**
35945 * A widget extension, which can be used to add constrained xy positioning support to the base Widget class,
35946 * through the <a href="Base.html#method_build">Base.build</a> method. This extension requires that
35947 * the WidgetPosition extension be added to the Widget (before WidgetPositionConstrain, if part of the same
35948 * extension list passed to Base.build).
35949 *
35950 * @class WidgetPositionConstrain
35951 * @param {Object} User configuration object
35952 */
35953function PositionConstrain(config) {}
35954
35955/**
35956 * Static property used to define the default attribute
35957 * configuration introduced by WidgetPositionConstrain.
35958 *
35959 * @property ATTRS
35960 * @type Object
35961 * @static
35962 */
35963PositionConstrain.ATTRS = {
35964
35965    /**
35966     * @attribute constrain
35967     * @type boolean | Node
35968     * @default null
35969     * @description The node to constrain the widget's bounding box to, when setting xy. Can also be
35970     * set to true, to constrain to the viewport.
35971     */
35972    constrain : {
35973        value: null,
35974        setter: "_setConstrain"
35975    },
35976
35977    /**
35978     * @attribute preventOverlap
35979     * @type boolean
35980     * @description If set to true, and WidgetPositionAlign is also added to the Widget,
35981     * constrained positioning will attempt to prevent the widget's bounding box from overlapping
35982     * the element to which it has been aligned, by flipping the orientation of the alignment
35983     * for corner based alignments
35984     */
35985    preventOverlap : {
35986        value:false
35987    }
35988};
35989
35990/**
35991 * @property _PREVENT_OVERLAP
35992 * @static
35993 * @protected
35994 * @type Object
35995 * @description The set of positions for which to prevent
35996 * overlap.
35997 */
35998PREVENT_OVERLAP_MAP = PositionConstrain._PREVENT_OVERLAP = {
35999    x: {
36000        "tltr": 1,
36001        "blbr": 1,
36002        "brbl": 1,
36003        "trtl": 1
36004    },
36005    y : {
36006        "trbr": 1,
36007        "tlbl": 1,
36008        "bltl": 1,
36009        "brtr": 1
36010    }
36011};
36012
36013PositionConstrain.prototype = {
36014
36015    initializer : function() {
36016        if (!this._posNode) {
36017            Y.error("WidgetPosition needs to be added to the Widget, before WidgetPositionConstrain is added");
36018        }
36019        Y.after(this._bindUIPosConstrained, this, BINDUI);
36020    },
36021
36022    /**
36023     * Calculates the constrained positions for the XY positions provided, using
36024     * the provided node argument is passed in. If no node value is passed in, the value of
36025     * the "constrain" attribute is used.
36026     *
36027     * @method getConstrainedXY
36028     * @param {Array} xy The xy values to constrain
36029     * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport
36030     * @return {Array} The constrained xy values
36031     */
36032    getConstrainedXY : function(xy, node) {
36033        node = node || this.get(CONSTRAIN);
36034
36035        var constrainingRegion = this._getRegion((node === true) ? null : node),
36036            nodeRegion = this._posNode.get(REGION);
36037
36038        return [
36039            this._constrain(xy[0], X_COORD, nodeRegion, constrainingRegion),
36040            this._constrain(xy[1], Y_COORD, nodeRegion, constrainingRegion)
36041        ];
36042    },
36043
36044    /**
36045     * Constrains the widget's bounding box to a node (or the viewport). If xy or node are not
36046     * passed in, the current position and the value of "constrain" will be used respectively.
36047     *
36048     * The widget's position will be changed to the constrained position.
36049     *
36050     * @method constrain
36051     * @param {Array} xy Optional. The xy values to constrain
36052     * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport
36053     */
36054    constrain : function(xy, node) {
36055        var currentXY,
36056            constrainedXY,
36057            constraint = node || this.get(CONSTRAIN);
36058
36059        if (constraint) {
36060            currentXY = xy || this.get(XY);
36061            constrainedXY = this.getConstrainedXY(currentXY, constraint);
36062
36063            if (constrainedXY[0] !== currentXY[0] || constrainedXY[1] !== currentXY[1]) {
36064                this.set(XY, constrainedXY, { constrained:true });
36065            }
36066        }
36067    },
36068
36069    /**
36070     * The setter implementation for the "constrain" attribute.
36071     *
36072     * @method _setConstrain
36073     * @protected
36074     * @param {Node | boolean} val The attribute value
36075     */
36076    _setConstrain : function(val) {
36077        return (val === true) ? val : Node.one(val);
36078    },
36079
36080    /**
36081     * The method which performs the actual constrain calculations for a given axis ("x" or "y") based
36082     * on the regions provided.
36083     *
36084     * @method _constrain
36085     * @protected
36086     *
36087     * @param {Number} val The value to constrain
36088     * @param {String} axis The axis to use for constrainment
36089     * @param {Region} nodeRegion The region of the node to constrain
36090     * @param {Region} constrainingRegion The region of the node (or viewport) to constrain to
36091     *
36092     * @return {Number} The constrained value
36093     */
36094    _constrain: function(val, axis, nodeRegion, constrainingRegion) {
36095        if (constrainingRegion) {
36096
36097            if (this.get(PREVENT_OVERLAP)) {
36098                val = this._preventOverlap(val, axis, nodeRegion, constrainingRegion);
36099            }
36100
36101            var x = (axis == X_COORD),
36102
36103                regionSize    = (x) ? constrainingRegion.width : constrainingRegion.height,
36104                nodeSize      = (x) ? nodeRegion.width : nodeRegion.height,
36105                minConstraint = (x) ? constrainingRegion.left : constrainingRegion.top,
36106                maxConstraint = (x) ? constrainingRegion.right - nodeSize : constrainingRegion.bottom - nodeSize;
36107
36108            if (val < minConstraint || val > maxConstraint) {
36109                if (nodeSize < regionSize) {
36110                    if (val < minConstraint) {
36111                        val = minConstraint;
36112                    } else if (val > maxConstraint) {
36113                        val = maxConstraint;
36114                    }
36115                } else {
36116                    val = minConstraint;
36117                }
36118            }
36119        }
36120
36121        return val;
36122    },
36123
36124    /**
36125     * The method which performs the preventOverlap calculations for a given axis ("x" or "y") based
36126     * on the value and regions provided.
36127     *
36128     * @method _preventOverlap
36129     * @protected
36130     *
36131     * @param {Number} val The value being constrain
36132     * @param {String} axis The axis to being constrained
36133     * @param {Region} nodeRegion The region of the node being constrained
36134     * @param {Region} constrainingRegion The region of the node (or viewport) we need to constrain to
36135     *
36136     * @return {Number} The constrained value
36137     */
36138    _preventOverlap : function(val, axis, nodeRegion, constrainingRegion) {
36139
36140        var align = this.get(ALIGN),
36141            x = (axis === X_COORD),
36142            nodeSize,
36143            alignRegion,
36144            nearEdge,
36145            farEdge,
36146            spaceOnNearSide,
36147            spaceOnFarSide;
36148
36149        if (align && align.points && PREVENT_OVERLAP_MAP[axis][align.points.join(EMPTY_STR)]) {
36150
36151            alignRegion = this._getRegion(align.node);
36152
36153            if (alignRegion) {
36154                nodeSize        = (x) ? nodeRegion.width : nodeRegion.height;
36155                nearEdge        = (x) ? alignRegion.left : alignRegion.top;
36156                farEdge         = (x) ? alignRegion.right : alignRegion.bottom;
36157                spaceOnNearSide = (x) ? alignRegion.left - constrainingRegion.left : alignRegion.top - constrainingRegion.top;
36158                spaceOnFarSide  = (x) ? constrainingRegion.right - alignRegion.right : constrainingRegion.bottom - alignRegion.bottom;
36159            }
36160
36161            if (val > nearEdge) {
36162                if (spaceOnFarSide < nodeSize && spaceOnNearSide > nodeSize) {
36163                    val = nearEdge - nodeSize;
36164                }
36165            } else {
36166                if (spaceOnNearSide < nodeSize && spaceOnFarSide > nodeSize) {
36167                    val = farEdge;
36168                }
36169            }
36170        }
36171
36172        return val;
36173    },
36174
36175    /**
36176     * Binds event listeners responsible for updating the UI state in response to
36177     * Widget constrained positioning related state changes.
36178     * <p>
36179     * This method is invoked after bindUI is invoked for the Widget class
36180     * using YUI's aop infrastructure.
36181     * </p>
36182     *
36183     * @method _bindUIPosConstrained
36184     * @protected
36185     */
36186    _bindUIPosConstrained : function() {
36187        this.after(CONSTRAIN_CHANGE, this._afterConstrainChange);
36188        this._enableConstraints(this.get(CONSTRAIN));
36189    },
36190
36191    /**
36192     * After change listener for the "constrain" attribute, responsible
36193     * for updating the UI, in response to attribute changes.
36194     *
36195     * @method _afterConstrainChange
36196     * @protected
36197     * @param {EventFacade} e The event facade
36198     */
36199    _afterConstrainChange : function(e) {
36200        this._enableConstraints(e.newVal);
36201    },
36202
36203    /**
36204     * Updates the UI if enabling constraints, and sets up the xyChange event listeners
36205     * to constrain whenever the widget is moved. Disabling constraints removes the listeners.
36206     *
36207     * @method _enableConstraints
36208     * @private
36209     * @param {boolean} enable Enable or disable constraints
36210     */
36211    _enableConstraints : function(enable) {
36212        if (enable) {
36213            this.constrain();
36214            this._cxyHandle = this._cxyHandle || this.on(CONSTRAIN_XYCHANGE, this._constrainOnXYChange);
36215        } else if (this._cxyHandle) {
36216            this._cxyHandle.detach();
36217            this._cxyHandle = null;
36218        }
36219    },
36220
36221    /**
36222     * The on change listener for the "xy" attribute. Modifies the event facade'
36222s
36223     * newVal property with the constrained XY value.
36224     *
36225     * @method _constrainOnXYChange
36226     * @protected
36227     * @param {EventFacade} e The event facade for the attribute change
36228     */
36229    _constrainOnXYChange : function(e) {
36230        if (!e.constrained) {
36231            e.newVal = this.getConstrainedXY(e.newVal);
36232        }
36233    },
36234
36235    /**
36236     * Utility method to normalize region retrieval from a node instance,
36237     * or the viewport, if no node is provided.
36238     *
36239     * @method _getRegion
36240     * @private
36241     * @param {Node} node Optional.
36242     */
36243    _getRegion : function(node) {
36244        var region;
36245        if (!node) {
36246            region = this._posNode.get(VIEWPORT_REGION);
36247        } else {
36248            node = Node.one(node);
36249            if (node) {
36250                region = node.get(REGION);
36251            }
36252        }
36253        return region;
36254    }
36255};
36256
36257Y.WidgetPositionConstrain = PositionConstrain;
36258
36259
36260}, '3.18.1', {"requires": ["widget-position"]});
36261YUI.add('overlay', function (Y, NAME) {
36262
36263/**
36264 * Provides a basic Overlay widget, with Standard Module content support. The Overlay widget
36265 * provides Page XY positioning support, alignment and centering support along with basic
36266 * stackable support (z-index and shimming).
36267 *
36268 * @module overlay
36269 */
36270
36271/**
36272 * A basic Overlay Widget, which can be positioned based on Page XY co-ordinates and is stackable (z-index support).
36273 * It also provides alignment and centering support and uses a standard module format for it's content, with header,
36274 * body and footer section support.
36275 *
36276 * @class Overlay
36277 * @constructor
36278 * @extends Widget
36279 * @uses WidgetStdMod
36280 * @uses WidgetPosition
36281 * @uses WidgetStack
36282 * @uses WidgetPositionAlign
36283 * @uses WidgetPositionConstrain
36284 * @param {Object} object The user configuration for the instance.
36285 */
36286Y.Overlay = Y.Base.create("overlay", Y.Widget, [Y.WidgetStdMod, Y.WidgetPosition, Y.WidgetStack, Y.WidgetPositionAlign, Y.WidgetPositionConstrain]);
36287
36288
36289}, '3.18.1', {
36290    "requires": [
36291        "widget",
36292        "widget-stdmod",
36293        "widget-position",
36294        "widget-position-align",
36295        "widget-stack",
36296        "widget-position-constrain"
36297    ],
36298    "skinnable": true
36299});
36300YUI.add('widget-autohide', function (Y, NAME) {
36301
36302/**
36303 * A widget-level extension that provides ability to hide widget when
36304 * certain events occur.
36305 *
36306 * @module widget-autohide
36307 * @author eferraiuolo, tilomitra
36308 * @since 3.4.0
36309 */
36310
36311
36312var WIDGET_AUTOHIDE    = 'widgetAutohide',
36313    AUTOHIDE            = 'autohide',
36314    CLICK_OUTSIDE     = 'clickoutside',
36315    FOCUS_OUTSIDE     = 'focusoutside',
36316    DOCUMENT            = 'document',
36317    KEY                 = 'key',
36318    PRESS_ESCAPE         = 'esc',
36319    BIND_UI             = 'bindUI',
36320    SYNC_UI             = "syncUI",
36321    RENDERED            = "rendered",
36322    BOUNDING_BOX        = "boundingBox",
36323    VISIBLE             = "visible",
36324    CHANGE              = 'Change',
36325
36326    getCN               = Y.ClassNameManager.getClassName;
36327
36328/**
36329 * The WidgetAutohide class provides the hideOn attribute which can
36330 * be used to hide the widget when certain events occur.
36331 *
36332 * @class WidgetAutohide
36333 * @param {Object} config User configuration object
36334 */
36335function WidgetAutohide(config) {
36336    Y.after(this._bindUIAutohide, this, BIND_UI);
36337    Y.after(this._syncUIAutohide, this, SYNC_UI);
36338
36339
36340    if (this.get(RENDERED)) {
36341        this._bindUIAutohide();
36342        this._syncUIAutohide();
36343    }
36344
36345}
36346
36347/**
36348* Static property used to define the default attribute
36349* configuration introduced by WidgetAutohide.
36350*
36351* @property ATTRS
36352* @static
36353* @type Object
36354*/
36355WidgetAutohide.ATTRS = {
36356
36357
36358    /**
36359     * @attribute hideOn
36360     * @type array
36361     *
36362     * @description An array of objects corresponding to the nodes, events, and keycodes to hide the widget on.
36363     * The implementer can supply an array of objects, with each object having the following properties:
36364     * <p>eventName: (string, required): The eventName to listen to.</p>
36365     * <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p>
36366     * <p>keyCode: (string, optional): If listening for key events, specify the keyCode</p>
36367     * <p>By default, this attribute consists of one object which will cause the widget to hide if the
36368     * escape key is pressed.</p>
36369     */
36370    hideOn: {
36371        validator: Y.Lang.isArray,
36372        valueFn  : function() {
36373            return [
36374                {
36375                    node: Y.one(DOCUMENT),
36376                    eventName: KEY,
36377                    keyCode: PRESS_ESCAPE
36378                }
36379            ];
36380        }
36381    }
36382};
36383
36384WidgetAutohide.prototype = {
36385    // *** Instance Members *** //
36386
36387        _uiHandlesAutohide : null,
36388
36389        // *** Lifecycle Methods *** //
36390
36391        destructor : function () {
36392
36393            this._detachUIHandlesAutohide();
36394        },
36395
36396        /**
36397         * Binds event listeners to the widget.
36398         * <p>
36399         * This method in invoked after bindUI is invoked for the Widget class
36400         * using YUI's aop infrastructure.
36401         * </p>
36402         * @method _bindUIAutohide
36403         * @protected
36404         */
36405        _bindUIAutohide : function () {
36406
36407            this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeAutohide);
36408            this.after("hideOnChange", this._afterHideOnChange);
36409        },
36410
36411        /**
36412         * Syncs up the widget based on its current state. In particular, removes event listeners if
36413         * widget is not visible, and attaches them otherwise.
36414         * <p>
36415         * This method in invoked after syncUI is invoked for the Widget class
36416         * using YUI's aop infrastructure.
36417         * </p>
36418         * @method _syncUIAutohide
36419         * @protected
36420         */
36421        _syncUIAutohide : function () {
36422
36423            this._uiSetHostVisibleAutohide(this.get(VISIBLE));
36424        },
36425
36426        // *** Private Methods *** //
36427
36428        /**
36429         * Removes event listeners if widget is not visible, and attaches them otherwise.
36430         *
36431         * @method _uiSetHostVisibleAutohide
36432         * @protected
36433         */
36434        _uiSetHostVisibleAutohide : function (visible) {
36435
36436            if (visible) {
36437                //this._attachUIHandlesAutohide();
36438                Y.later(1, this, '_attachUIHandlesAutohide');
36439            } else {
36440                this._detachUIHandlesAutohide();
36441            }
36442        },
36443
36444        /**
36445         * Iterates through all objects in the hideOn attribute and creates event listeners.
36446         *
36447         * @method _attachUIHandlesAutohide
36448         * @protected
36449         */
36450        _attachUIHandlesAutohide : function () {
36451
36452            if (this._uiHandlesAutohide) { return; }
36453
36454            var bb = this.get(BOUNDING_BOX),
36455                hide = Y.bind(this.hide,this),
36456                uiHandles = [],
36457                self = this,
36458                hideOn = this.get('hideOn'),
36459                i = 0,
36460                o = {node: undefined, ev: undefined, keyCode: undefined};
36461
36462                //push all events on which the widget should be hidden
36463                for (; i < hideOn.length; i++) {
36464
36465                    o.node = hideOn[i].node;
36466                    o.ev = hideOn[i].eventName;
36467                    o.keyCode = hideOn[i].keyCode;
36468
36469                    //no keycode or node defined
36470                    if (!o.node && !o.keyCode && o.ev) {
36471                        uiHandles.push(bb.on(o.ev, hide));
36472                    }
36473
36474                    //node defined, no keycode (not a keypress)
36475                    else if (o.node && !o.keyCode && o.ev) {
36476                        uiHandles.push(o.node.on(o.ev, hide));
36477                    }
36478
36479                    //node defined, keycode defined, event defined (its a key press)
36480                    else if (o.node && o.keyCode && o.ev) {
36481                        uiHandles.push(o.node.on(o.ev, hide, o.keyCode));
36482                    }
36483
36484                    else {
36485                    }
36486
36487                }
36488
36489            this._uiHandlesAutohide = uiHandles;
36490        },
36491
36492        /**
36493         * Detaches all event listeners created by this extension
36494         *
36495         * @method _detachUIHandlesAutohide
36496         * @protected
36497         */
36498        _detachUIHandlesAutohide : function () {
36499
36500            Y.each(this._uiHandlesAutohide, function(h){
36501                h.detach();
36502            });
36503            this._uiHandlesAutohide = null;
36504        },
36505
36506        /**
36507         * Default function called when the visibility of the widget changes. Determines
36508         * whether to attach or detach event listeners based on the visibility of the widget.
36509         *
36510         * @method _afterHostVisibleChangeAutohide
36511         * @protected
36512         */
36513        _afterHostVisibleChangeAutohide : function (e) {
36514
36515            this._uiSetHostVisibleAutohide(e.newVal);
36516        },
36517
36518        /**
36519         * Default function called when hideOn Attribute is changed. Remove existing listeners and create new listeners.
36520         *
36521         * @method _afterHideOnChange
36522         * @protected
36523         */
36524        _afterHideOnChange : function(e) {
36525            this._detachUIHandlesAutohide();
36526
36527            if (this.get(VISIBLE)) {
36528                this._attachUIHandlesAutohide();
36529            }
36530        }
36531};
36532
36533Y.WidgetAutohide = WidgetAutohide;
36534
36535
36536}, '3.18.1', {"requires": ["base-build", "event-key", "event-outside", "widget"]});
36537YUI.add('button-core', function (Y, NAME) {
36538
36539/**
36540 * Provides an interface for working with button-like DOM nodes
36541 *
36542 * @module button-core
36543 * @since 3.5.0
36544 */
36545var getClassName = Y.ClassNameManager.getClassName,
36546    AttributeCore = Y.AttributeCore;
36547
36548/**
36549 * Creates a button
36550 *
36551 * @class ButtonCore
36552 * @uses AttributeCore
36553 * @param config {Object} Configuration object
36554 * @constructor
36555 */
36556function ButtonCore(config) {
36557    this.initializer(config);
36558}
36559
36560ButtonCore.prototype = {
36561
36562    /**
36563     *
36564     * @property TEMPLATE
36565     * @type {String}
36566     * @default <button/>
36567     */
36568    TEMPLATE: '<button/>',
36569
36570    /**
36571     *
36572     * @property constructor
36573     * @type {Object}
36574     * @default ButtonCore
36575     * @private
36576     */
36577    constructor: ButtonCore,
36578
36579    /**
36580     * @method initializer
36581     * @description Internal init() handler.
36582     * @param config {Object} Config object.
36583     * @private
36584     */
36585    initializer: function(config) {
36586        this._initNode(config);
36587        this._initAttributes(config);
36588        this._renderUI(config);
36589    },
36590
36591    /**
36592     * @method _initNode
36593     * @description Node initializer
36594     * @param config {Object} Config object.
36595     * @private
36596     */
36597    _initNode: function(config) {
36598        if (config.host) {
36599            this._host = Y.one(config.host);
36600        } else {
36601            this._host = Y.Node.create(this.TEMPLATE);
36602        }
36603    },
36604
36605    /**
36606     * @method _initAttributes
36607     * @description  Attribute initializer
36608     * @param config {Object} Config object.
36609     * @private
36610     */
36611    _initAttributes: function(config) {
36612        AttributeCore.call(this, ButtonCore.ATTRS, config);
36613    },
36614
36615    /**
36616     * @method renderUI
36617     * @description Renders any UI/DOM elements for Button instances
36618     * @param config {Object} Config object.
36619     * @private
36620     */
36621    _renderUI: function() {
36622        var node = this.getNode(),
36623            nodeName = node.get('nodeName').toLowerCase();
36624
36625        // Set some default node attributes
36626        node.addClass(ButtonCore.CLASS_NAMES.BUTTON);
36627
36628        if (nodeName !== 'button' && nodeName !== 'input') {
36629            node.set('role', 'button');
36630        }
36631    },
36632
36633    /**
36634     * @method enable
36635     * @description Sets the button's `disabled` DOM attribute to `false`
36636     * @public
36637     */
36638    enable: function() {
36639        this.set('disabled', false);
36640    },
36641
36642    /**
36643     * @method disable
36644     * @description Sets the button's `disabled` DOM attribute to `true`
36645     * @public
36646     */
36647    disable: function() {
36648        this.set('disabled', true);
36649    },
36650
36651    /**
36652     * @method getNode
36653     * @description Gets the button's host node
36654     * @return {Node} The host node instance
36655     * @public
36656     */
36657    getNode: function() {
36658        if (!this._host) {
36659            // If this._host doesn't exist, that means this._initNode
36660            // was never executed, meaning this is likely a Widget and
36661            // the host node should point to the boundingBox.
36662            this._host = this.get('boundingBox');
36663        }
36664
36665        return this._host;
36666    },
36667
36668    /**
36669     * @method _getLabel
36670     * @description Getter for a button's `label` ATTR
36671     * @return {String} The text label of the button
36672     * @private
36673     */
36674    _getLabel: function () {
36675        var node = this.getNode(),
36676            label = ButtonCore._getTextLabelFromNode(node);
36677
36678        return label;
36679    },
36680
36681    /**
36682     * @method _getLabelHTML
36683     * @description Getter for a button's `labelHTML` ATTR
36684     * @return {String} The HTML label of the button
36685     * @private
36686     */
36687    _getLabelHTML: function () {
36688        var node = this.getNode(),
36689            labelHTML = ButtonCore._getHTMLFromNode(node);
36690
36691        return labelHTML;
36692    },
36693
36694    /**
36695     * @method _setLabel
36696     * @description Setter for a button's `label` ATTR
36697     * @param value {String} The value to set for `label`
36698     * @param name {String} The name of this ATTR (`label`)
36699     * @param opts {Object} Additional options
36700     *    @param opts.src {String} A string identifying the callee.
36701     *        `internal` will not sync this value with the `labelHTML` ATTR
36702     * @return {String} The text label for the given node
36703     * @private
36704     */
36705    _setLabel: function (value, name, opts) {
36706        var label = Y.Escape.html(value);
36707
36708        if (!opts || opts.src !== 'internal') {
36709            this.set('labelHTML', label, {src: 'internal'});
36710        }
36711
36712        return label;
36713    },
36714
36715    /**
36716     * @method _setLabelHTML
36717     * @description Setter for a button's `labelHTML` ATTR
36718     * @param value {String} The value to set for `labelHTML`
36719     * @param name {String} The name of this ATTR (`labelHTML`)
36720     * @param opts {Object} Additional options
36721     *    @param opts.src {String} A string identifying the callee.
36722     *        `internal` will not sync this value with the `label` ATTR
36723     * @return {String} The HTML label for the given node
36724     * @private
36725     */
36726    _setLabelHTML: function (value, name, opts) {
36727        var node = this.getNode(),
36728            labelNode = ButtonCore._getLabelNodeFromParent(node),
36729            nodeName = node.get('nodeName').toLowerCase();
36730
36731        if (nodeName === 'input') {
36732            labelNode.set('value', value);
36733        }
36734        else {
36735            labelNode.setHTML(value);
36736        }
36737
36738        if (!opts || opts.src !== 'internal') {
36739            this.set('label', value, {src: 'internal'});
36740        }
36741
36742        return value;
36743    },
36744
36745    /**
36746     * @method _setDisabled
36747     * @description Setter for the `disabled` ATTR
36748     * @param value {boolean}
36749     * @private
36750     */
36751    _setDisabled: function(value) {
36752        var node = this.getNode();
36753
36754        node.getDOMNode().disabled = value; // avoid rerunning setter when this === node
36755        node.toggleClass(ButtonCore.CLASS_NAMES.DISABLED, value);
36756
36757        return value;
36758    }
36759};
36760
36761// ButtonCore inherits from AttributeCore
36762Y.mix(ButtonCore.prototype, AttributeCore.prototype);
36763
36764/**
36765 * Attribute configuration.
36766 *
36767 * @property ATTRS
36768 * @type {Object}
36769 * @protected
36770 * @static
36771 */
36772ButtonCore.ATTRS = {
36773
36774    /**
36775     * The text of the button's label
36776     *
36777     * @config label
36778     * @type String
36779     */
36780    label: {
36781        setter: '_setLabel',
36782        getter: '_getLabel',
36783        lazyAdd: false
36784    },
36785
36786    /**
36787     * The HTML of the button's label
36788     *
36789     * This attribute accepts HTML and inserts it into the DOM **without**
36790     * sanitization.  This attribute should only be used with HTML that has
36791     * either been escaped (using `Y.Escape.html`), or sanitized according to
36792     * the requirements of your application.
36793     *
36794     * If all you need is support for text labels, please use the `label`
36795     * attribute instead.
36796     *
36797     * @config labelHTML
36798     * @type HTML
36799     */
36800    labelHTML: {
36801        setter: '_setLabelHTML',
36802        getter: '_getLabelHTML',
36803        lazyAdd: false
36804    },
36805
36806    /**
36807     * The button's enabled/disabled state
36808     *
36809     * @config disabled
36810     * @type Boolean
36811     */
36812    disabled: {
36813        value: false,
36814        setter: '_setDisabled',
36815        lazyAdd: false
36816    }
36817};
36818
36819/**
36820 * Name of this component.
36821 *
36822 * @property NAME
36823 * @type String
36824 * @static
36825 */
36826ButtonCore.NAME = "button";
36827
36828/**
36829 * Array of static constants used to identify the classnames applied to DOM nodes
36830 *
36831 * @property CLASS_NAMES
36832 * @type {Object}
36833 * @public
36834 * @static
36835 */
36836ButtonCore.CLASS_NAMES = {
36837    BUTTON  : getClassName('button'),
36838    DISABLED: getClassName('button', 'disabled'),
36839    SELECTED: getClassName('button', 'selected'),
36840    LABEL   : getClassName('button', 'label')
36841};
36842
36843/**
36844 * Array of static constants used to for applying ARIA states
36845 *
36846 * @property ARIA_STATES
36847 * @type {Object}
36848 * @private
36849 * @static
36850 */
36851ButtonCore.ARIA_STATES = {
36852    PRESSED : 'aria-pressed',
36853    CHECKED : 'aria-checked'
36854};
36855
36856/**
36857 * Array of static constants used to for applying ARIA roles
36858 *
36859 * @property ARIA_ROLES
36860 * @type {Object}
36861 * @private
36862 * @static
36863 */
36864ButtonCore.ARIA_ROLES = {
36865    BUTTON  : 'button',
36866    CHECKBOX: 'checkbox',
36867    TOGGLE  : 'toggle'
36868};
36869
36870/**
36871 * Finds the label node within a button
36872 *
36873 * @method _getLabelNodeFromParent
36874 * @param node {Node} The parent node
36875 * @return {Node} The label node
36876 * @private
36877 * @static
36878 */
36879ButtonCore._getLabelNodeFromParent = function (node) {
36880    var labelNode = (node.one('.' + ButtonCore.CLASS_NAMES.LABEL) || node);
36881
36882    return labelNode;
36883};
36884
36885/**
36886 * Gets a text label from a node
36887 *
36888 * @method _getTextLabelFromNode
36889 * @param node {Node} The parent node
36890 * @return {String} The text label for a given node
36891 * @private
36892 * @static
36893 */
36894ButtonCore._getTextLabelFromNode = function (node) {
36895    var labelNode = ButtonCore._getLabelNodeFromParent(node),
36896        nodeName = labelNode.get('nodeName').toLowerCase(),
36897        label = labelNode.get(nodeName === 'input' ? 'value' : 'text');
36898
36899    return label;
36900};
36901
36902/**
36903 * A utility method that gets an HTML label from a given node
36904 *
36905 * @method _getHTMLFromNode
36906 * @param node {Node} The parent node
36907 * @return {String} The HTML label for a given node
36908 * @private
36909 * @static
36910 */
36911ButtonCore._getHTMLFromNode = function (node) {
36912    var labelNode = ButtonCore._getLabelNodeFromParent(node),
36913        label = labelNode.getHTML();
36914
36915    return label;
36916};
36917
36918/**
36919 * Gets the disabled attribute from a node
36920 *
36921 * @method _getDisabledFromNode
36922 * @param node {Node} The parent node
36923 * @return {boolean} The disabled state for a given node
36924 * @private
36925 * @static
36926 */
36927ButtonCore._getDisabledFromNode = function (node) {
36928    return node.get('disabled');
36929};
36930
36931// Export ButtonCore
36932Y.ButtonCore = ButtonCore;
36933
36934
36935}, '3.18.1', {"requires": ["attribute-core", "classnamemanager", "node-base", "escape"]});
36936YUI.add('button-plugin', function (Y, NAME) {
36937
36938/**
36939* A Button Plugin
36940*
36941* @module button-plugin
36942* @since 3.5.0
36943*/
36944
36945/**
36946* @class Button
36947* @param config {Object} Configuration object
36948* @extends ButtonCore
36949* @constructor
36950* @namespace Plugin
36951*/
36952function ButtonPlugin() {
36953    ButtonPlugin.superclass.constructor.apply(this, arguments);
36954}
36955
36956Y.extend(ButtonPlugin, Y.ButtonCore, {
36957
36958    /**
36959    * @method _afterNodeGet
36960    * @param name {string}
36961    * @private
36962    */
36963    _afterNodeGet: function (name) {
36964        // TODO: point to method (_uiSetLabel, etc) instead of getter/setter
36965        var ATTRS = this.constructor.ATTRS,
36966            fn = ATTRS[name] && ATTRS[name].getter && this[ATTRS[name].getter];
36967
36968        if (fn) {
36969            return new Y.Do.AlterReturn('get ' + name, fn.call(this));
36970        }
36971    },
36972
36973    /**
36974    * @method _afterNodeSet
36975    * @param name {String}
36976    * @param val {String}
36977    * @private
36978    */
36979    _afterNodeSet: function (name, val) {
36980        var ATTRS = this.constructor.ATTRS,
36981            fn = ATTRS[name] && ATTRS[name].setter && this[ATTRS[name].setter];
36982
36983        if (fn) {
36984            fn.call(this, val);
36985        }
36986    },
36987
36988    /**
36989    * @method _initNode
36990    * @param config {Object}
36991    * @private
36992    */
36993    _initNode: function(config) {
36994        var node = config.host;
36995        this._host = node;
36996
36997        Y.Do.after(this._afterNodeGet, node, 'get', this);
36998        Y.Do.after(this._afterNodeSet, node, 'set', this);
36999    },
37000
37001    /**
37002    * @method destroy
37003    * @private
37004    */
37005    destroy: function(){
37006        // Nothing to do, but things are happier with it here
37007    }
37008
37009}, {
37010
37011    /**
37012    * Attribute configuration.
37013    *
37014    * @property ATTRS
37015    * @type {Object}
37016    * @private
37017    * @static
37018    */
37019    ATTRS: Y.merge(Y.ButtonCore.ATTRS),
37020
37021    /**
37022    * Name of this component.
37023    *
37024    * @property NAME
37025    * @type String
37026    * @static
37027    */
37028    NAME: 'buttonPlugin',
37029
37030    /**
37031    * Namespace of this component.
37032    *
37033    * @property NS
37034    * @type String
37035    * @static
37036    */
37037    NS: 'button'
37038
37039});
37040
37041/**
37042* @method createNode
37043* @description A factory that plugs a Y.Node instance with Y.Plugin.Button
37044* @param node {Object}
37045* @param config {Object}
37046* @return {Object} A plugged Y.Node instance
37047* @public
37048*/
37049ButtonPlugin.createNode = function(node, config) {
37050    var template;
37051
37052    if (node && !config) {
37053        if (! (node.nodeType || node.getDOMNode || typeof node === 'string')) {
37054            config = node;
37055            node = config.srcNode;
37056        }
37057    }
37058
37059    config   = config || {};
37060    template = config.template || Y.Plugin.Button.prototype.TEMPLATE;
37061    node     = node || config.srcNode || Y.DOM.create(template);
37062
37063    return Y.one(node).plug(Y.Plugin.Button, config);
37064};
37065
37066Y.namespace('Plugin').Button = ButtonPlugin;
37067
37068
37069}, '3.18.1', {"requires": ["button-core", "cssbutton", "node-pluginhost"]});
37070YUI.add('widget-buttons', function (Y, NAME) {
37071
37072/**
37073Provides header/body/footer button support for Widgets that use the
37074`WidgetStdMod` extension.
37075
37076@module widget-buttons
37077@since 3.4.0
37078**/
37079
37080var YArray  = Y.Array,
37081    YLang   = Y.Lang,
37082    YObject = Y.Object,
37083
37084    ButtonPlugin = Y.Plugin.Button,
37085    Widget       = Y.Widget,
37086    WidgetStdMod = Y.WidgetStdMod,
37087
37088    getClassName = Y.ClassNameManager.getClassName,
37089    isArray      = YLang.isArray,
37090    isNumber     = YLang.isNumber,
37091    isString     = YLang.isString,
37092    isValue      = YLang.isValue;
37093
37094// Utility to determine if an object is a Y.Node instance, even if it was
37095// created in a different YUI sandbox.
37096function isNode(node) {
37097    return !!node.getDOMNode;
37098}
37099
37100/**
37101Provides header/body/footer button support for Widgets that use the
37102`WidgetStdMod` extension.
37103
37104This Widget extension makes it easy to declaratively configure a widget's
37105buttons. It adds a `buttons` attribute along with button- accessor and mutator
37106methods. All button nodes have the `Y.Plugin.Button` plugin applied.
37107
37108This extension also includes `HTML_PARSER` support to seed a widget's `buttons`
37109from those which already exist in its DOM.
37110
37111@class WidgetButtons
37112@extensionfor Widget
37113@since 3.4.0
37114**/
37115function WidgetButtons() {
37116    // Has to be setup before the `initializer()`.
37117    this._buttonsHandles = {};
37118}
37119
37120WidgetButtons.ATTRS = {
37121    /**
37122    Collection containing a widget's buttons.
37123
37124    The collection is an Object which contains an Array of `Y.Node`s for every
37125    `WidgetStdMod` section (header, body, footer) which has one or more buttons.
37126    All button nodes have the `Y.Plugin.Button` plugin applied.
37127
37128    This attribute is very flexible in the values it will accept. `buttons` can
37129    be specified as a single Array, or an Object of Arrays keyed to a particular
37130    section.
37131
37132    All specified values will be normalized to this type of structure:
37133
37134        {
37135            header: [...],
37136            footer: [...]
37137        }
37138
37139    A button can be specified as a `Y.Node`, config Object, or String name for a
37140    predefined button on the `BUTTONS` prototype property. When a config Object
37141    is provided, it will be merged with any defaults provided by a button with
37142    the same `name` defined on the `BUTTONS` property.
37143
37144    See `addButton()` for the detailed list of configuration properties.
37145
37146    For convenience, a widget's buttons will always persist and remain rendered
37147    after header/body/footer content updates. Buttons should be removed by
37148    updating this attribute or using the `removeButton()` method.
37149
37150    @example
37151        {
37152            // Uses predefined "close" button by string name.
37153            header: ['close'],
37154
37155            footer: [
37156                {
37157                    name  : 'cancel',
37158                    label : 'Cancel',
37159                    action: 'hide'
37160                },
37161
37162                {
37163                    name     : 'okay',
37164                    label    : 'Okay',
37165                    isDefault: true,
37166
37167                    events: {
37168                        click: function (e) {
37169                            this.hide();
37170                        }
37171                    }
37172                }
37173            ]
37174        }
37175
37176    @attribute buttons
37177    @type Object
37178    @default {}
37179    @since 3.4.0
37180    **/
37181    buttons: {
37182        getter: '_getButtons',
37183        setter: '_setButtons',
37184        value : {}
37185    },
37186
37187    /**
37188    The current default button as configured through this widget's `buttons`.
37189
37190    A button can be configured as the default button in the following ways:
37191
37192      * As a config Object with an `isDefault` property:
37193        `{label: 'Okay', isDefault: true}`.
37194
37195      * As a Node with a `data-default` attribute:
37196        `<button data-default="true">Okay</button>`.
37197
37198    This attribute is **read-only**; anytime there are changes to this widget's
37199    `buttons`, the `defaultButton` will be updated if needed.
37200
37201    **Note:** If two or more buttons are configured to be the default button,
37202    the last one wins.
37203
37204    @attribute defaultButton
37205    @type Node
37206    @default null
37207    @readOnly
37208    @since 3.5.0
37209    **/
37210    defaultButton: {
37211        readOnly: true,
37212        value   : null
37213    }
37214};
37215
37216/**
37217CSS classes used by `WidgetButtons`.
37218
37219@property CLASS_NAMES
37220@type Object
37221@static
37222@since 3.5.0
37223**/
37224WidgetButtons.CLASS_NAMES = {
37225    button : getClassName('button'),
37226    buttons: Widget.getClassName('buttons'),
37227    primary: getClassName('button', 'primary')
37228};
37229
37230WidgetButtons.HTML_PARSER = {
37231    buttons: function (srcNode) {
37232        return this._parseButtons(srcNode);
37233    }
37234};
37235
37236/**
37237The list of button configuration properties which are specific to
37238`WidgetButtons` and should not be passed to `Y.Plugin.Button.createNode()`.
37239
37240@property NON_BUTTON_NODE_CFG
37241@type Array
37242@static
37243@since 3.5.0
37244**/
37245WidgetButtons.NON_BUTTON_NODE_CFG = [
37246    'action', 'classNames', 'context', 'events', 'isDefault', 'section'
37247];
37248
37249WidgetButtons.prototype = {
37250    // -- Public Properties ----------------------------------------------------
37251
37252    /**
37253    Collection of predefined buttons mapped by name -> config.
37254
37255    These button configurations will serve as defaults for any button added to a
37256    widget's buttons which have the same `name`.
37257
37258    See `addButton()` for a list of possible configuration values.
37259
37260    @property BUTTONS
37261    @type Object
37262    @default {}
37263    @see addButton()
37264    @since 3.5.0
37265    **/
37266    BUTTONS: {},
37267
37268    /**
37269    The HTML template to use when creating the node which wraps all buttons of a
37270    section. By default it will have the CSS class: "yui3-widget-buttons".
37271
37272    @property BUTTONS_TEMPLATE
37273    @type String
37274    @default "<span />"
37275    @since 3.5.0
37276    **/
37277    BUTTONS_TEMPLATE: '<span />',
37278
37279    /**
37280    The default section to render buttons in when no section is specified.
37281
37282    @property DEFAULT_BUTTONS_SECTION
37283    @type String
37284    @default Y.WidgetStdMod.FOOTER
37285    @since 3.5.0
37286    **/
37287    DEFAULT_BUTTONS_SECTION: WidgetStdMod.FOOTER,
37288
37289    // -- Protected Properties -------------------------------------------------
37290
37291    /**
37292    A map of button node `_yuid` -> event-handle for all button nodes which were
37293    created by this widget.
37294
37295    @property _buttonsHandles
37296    @type Object
37297    @protected
37298    @since 3.5.0
37299    **/
37300
37301    /**
37302    A map of this widget's `buttons`, both name -> button and
37303    section:name -> button.
37304
37305    @property _buttonsMap
37306    @type Object
37307    @protected
37308    @since 3.5.0
37309    **/
37310
37311    /**
37312    Internal reference to this widget's default button.
37313
37314    @property _defaultButton
37315    @type Node
37316    @protected
37317    @since 3.5.0
37318    **/
37319
37320    // -- Lifecycle Methods ----------------------------------------------------
37321
37322    initializer: function () {
37323        // Require `Y.WidgetStdMod`.
37324        if (!this._stdModNode) {
37325            Y.error('WidgetStdMod must be added to a Widget before WidgetButtons.');
37326        }
37327
37328        // Creates button mappings and sets the `defaultButton`.
37329        this._mapButtons(this.get('buttons'));
37330        this._updateDefaultButton();
37331
37332        // Bound with `Y.bind()` to make more extensible.
37333        this.after({
37334            buttonsChange      : Y.bind('_afterButtonsChange', this),
37335            defaultButtonChange: Y.bind('_afterDefaultButtonChange', this)
37336        });
37337
37338        Y.after(this._bindUIButtons, this, 'bindUI');
37339        Y.after(this._syncUIButtons, this, 'syncUI');
37340    },
37341
37342    destructor: function () {
37343        // Detach all event subscriptions this widget added to its `buttons`.
37344        YObject.each(this._buttonsHandles, function (handle) {
37345            handle.detach();
37346        });
37347
37348        delete this._buttonsHandles;
37349        delete this._buttonsMap;
37350        delete this._defaultButton;
37351    },
37352
37353    // -- Public Methods -------------------------------------------------------
37354
37355    /**
37356    Adds a button to this widget.
37357
37358    The new button node will have the `Y.Plugin.Button` plugin applied, be added
37359    to this widget's `buttons`, and rendered in the specified `section` at the
37360    specified `index` (or end of the section when no `index` is provided). If
37361    the section does not exist, it will be created.
37362
37363    This fires the `buttonsChange` event and adds the following properties to
37364    the event facade:
37365
37366      * `button`: The button node or config object to add.
37367
37368      * `section`: The `WidgetStdMod` section (header/body/footer) where the
37369        button will be added.
37370
37371      * `index`: The index at which the button will be in the section.
37372
37373      * `src`: "add"
37374
37375    **Note:** The `index` argument will be passed to the Array `splice()`
37376    method, therefore a negative value will insert the `button` that many items
37377    from the end. The `index` property on the `buttonsChange` event facade is
37378    the index at which the `button` was added.
37379
37380    @method addButton
37381    @param {Node|Object|String} button The button to add. This can be a `Y.Node`
37382        instance, config Object, or String name for a predefined button on the
37383        `BUTTONS` prototype property. When a config Object is provided, it will
37384        be merged with any defaults provided by any `srcNode` and/or a button
37385        with the same `name` defined on the `BUTTONS` property. The following
37386        are the possible configuration properties beyond what Node plugins
37387        accept by default:
37388      @param {Function|String} [button.action] The default handler that should
37389        be called when the button is clicked. A String name of a Function that
37390        exists on the `context` object can also be provided. **Note:**
37391        Specifying a set of `events` will override this setting.
37392      @param {String|String[]} [button.classNames] Additional CSS classes to add
37393        to the button node.
37394      @param {Object} [button.context=this] Context which any `events` or
37395        `action` should be called with. Defaults to `this`, the widget.
37396        **Note:** `e.target` will access the button node in the event handlers.
37397      @param {Boolean} [button.disabled=false] Whether the button should be
37398        disabled.
37399      @param {String|Object} [button.events="click"] Event name, or set of
37400        events and handlers to bind to the button node. **See:** `Y.Node.on()`,
37401        this value is passed as the first argument to `on()`.
37402      @param {Boolean} [button.isDefault=false] Whether the button is the
37403        default button.
37404      @param {String} [button.label] The visible text/value displayed in the
37405        button.
37406      @param {String} [button.name] A name which can later be used to reference
37407        this button. If a button is defined on the `BUTTONS` property with this
37408        same name, its configuration properties will be merged in as defaults.
37409      @param {String} [button.section] The `WidgetStdMod` section (header, body,
37410        footer) where the button should be added.
37411      @param {Node} [button.srcNode] An existing Node to use for the button,
37412        default values will be seeded from this node, but are overriden by any
37413        values specified in the config object. By default a new &lt;button&gt;
37414        node will be created.
37415      @param {String} [button.template] A specific template to use when creating
37416        a new button node (e.g. "&lt;a /&gt;"). **Note:** Specifying a `srcNode`
37417        will overide this.
37418    @param {String} [section="footer"] The `WidgetStdMod` section
37419        (header/body/footer) where the button should be added. This takes
37420        precedence over the `button.section` configuration property.
37421    @param {Number} [index] The index at which the button should be inserted. If
37422        not specified, the button will be added to the end of the section. This
37423        value is passed to the Array `splice()` method, therefore a negative
37424        value will insert the `button` that many items from the end.
37425    @chainable
37426    @see Plugin.Button.createNode()
37427    @since 3.4.0
37428    **/
37429    addButton: function (button, section, index) {
37430        var buttons = this.get('buttons'),
37431            sectionButtons, atIndex;
37432
37433        // Makes sure we have the full config object.
37434        if (!isNode(button)) {
37435            button = this._mergeButtonConfig(button);
37436            section || (section = button.section);
37437        }
37438
37439        section || (section = this.DEFAULT_BUTTONS_SECTION);
37440        sectionButtons = buttons[section] || (buttons[section] = []);
37441        isNumber(index) || (index = sectionButtons.length);
37442
37443        // Insert new button at the correct position.
37444        sectionButtons.splice(index, 0, button);
37445
37446        // Determine the index at which the `button` now exists in the array.
37447        atIndex = YArray.indexOf(sectionButtons, button);
37448
37449        this.set('buttons', buttons, {
37450            button : button,
37451            section: section,
37452            index  : atIndex,
37453            src    : 'add'
37454        });
37455
37456        return this;
37457    },
37458
37459    /**
37460    Returns a button node from this widget's `buttons`.
37461
37462    @method getButton
37463    @param {Number|String} name The string name or index of the button.
37464    @param {String} [section="footer"] The `WidgetStdMod` section
37465        (header/body/footer) where the button exists. Only applicable when
37466        looking for a button by numerical index, or by name but scoped to a
37467        particular section.
37468    @return {Node} The button node.
37469    @since 3.5.0
37470    **/
37471    getButton: function (name, section) {
37472        if (!isValue(name)) { return; }
37473
37474        var map = this._buttonsMap,
37475            buttons;
37476
37477        section || (section = this.DEFAULT_BUTTONS_SECTION);
37478
37479        // Supports `getButton(1, 'header')` signature.
37480        if (isNumber(name)) {
37481            buttons = this.get('buttons');
37482            return buttons[section] && buttons[section][name];
37483        }
37484
37485        // Looks up button by name or section:name.
37486        return arguments.length > 1 ? map[section + ':' + name] : map[name];
37487    },
37488
37489    /**
37490    Removes a button from this widget.
37491
37492    The button will be removed from this widget's `buttons` and its DOM. Any
37493    event subscriptions on the button which were created by this widget will be
37494    detached. If the content section becomes empty after removing the button
37495    node, then the section will also be removed.
37496
37497    This fires the `buttonsChange` event and adds the following properties to
37498    the event facade:
37499
37500      * `button`: The button node to remove.
37501
37502      * `section`: The `WidgetStdMod` section (header/body/footer) where the
37503        button should be removed from.
37504
37505      * `index`: The index at which the button exists in the section.
37506
37507      * `src`: "remove"
37508
37509    @method removeButton
37510    @param {Node|Number|String} button The button to remove. This can be a
37511        `Y.Node` instance, index, or String name of a button.
37512    @param {String} [section="footer"] The `WidgetStdMod` section
37513        (header/body/footer) where the button exists. Only applicable when
37514        removing a button by numerical index, or by name but scoped to a
37515        particular section.
37516    @chainable
37517    @since 3.5.0
37518    **/
37519    removeButton: function (button, section) {
37520        if (!isValue(button)) { return this; }
37521
37522        var buttons = this.get('buttons'),
37523            index;
37524
37525        // Shortcut if `button` is already an index which is needed for slicing.
37526        if (isNumber(button)) {
37527            section || (section = this.DEFAULT_BUTTONS_SECTION);
37528            index  = button;
37529            button = buttons[section][index];
37530        } else {
37531            // Supports `button` being the string name.
37532            if (isString(button)) {
37533                // `getButton()` is called this way because its behavior is
37534                // different based on the number of arguments.
37535                button = this.getButton.apply(this, arguments);
37536            }
37537
37538            // Determines the `section` and `index` at which the button exists.
37539            YObject.some(buttons, function (sectionButtons, currentSection) {
37540                index = YArray.indexOf(sectionButtons, button);
37541
37542                if (index > -1) {
37543                    section = currentSection;
37544                    return true;
37545                }
37546            });
37547        }
37548
37549        // Button was found at an appropriate index.
37550        if (button && index > -1) {
37551            // Remove button from `section` array.
37552            buttons[section].splice(index, 1);
37553
37554            this.set('buttons', buttons, {
37555                button : button,
37556                section: section,
37557                index  : index,
37558                src    : 'remove'
37559            });
37560        }
37561
37562        return this;
37563    },
37564
37565    // -- Protected Methods ----------------------------------------------------
37566
37567    /**
37568    Binds UI event listeners. This method is inserted via AOP, and will execute
37569    after `bindUI()`.
37570
37571    @method _bindUIButtons
37572    @protected
37573    @since 3.4.0
37574    **/
37575    _bindUIButtons: function () {
37576        // Event handlers are bound with `bind()` to make them more extensible.
37577        var afterContentChange = Y.bind('_afterContentChangeButtons', this);
37578
37579        this.after({
37580            visibleChange      : Y.bind('_afterVisibleChangeButtons', this),
37581            headerContentChange: afterContentChange,
37582            bodyContentChange  : afterContentChange,
37583            footerContentChange: afterContentChange
37584        });
37585    },
37586
37587    /**
37588    Returns a button node based on the specified `button` node or configuration.
37589
37590    The button node will either be created via `Y.Plugin.Button.createNode()`,
37591    or when `button` is specified as a node already, it will by `plug()`ed with
37592    `Y.Plugin.Button`.
37593
37594    @method _createButton
37595    @param {Node|Object} button Button node or configuration object.
37596    @return {Node} The button node.
37597    @protected
37598    @since 3.5.0
37599    **/
37600    _createButton: function (button) {
37601        var config, buttonConfig, nonButtonNodeCfg,
37602            i, len, action, context, handle;
37603
37604        // Makes sure the exiting `Y.Node` instance is from this YUI sandbox and
37605        // is plugged with `Y.Plugin.Button`.
37606        if (isNode(button)) {
37607            return Y.one(button.getDOMNode()).plug(ButtonPlugin);
37608        }
37609
37610        // Merge `button` config with defaults and back-compat.
37611        config = Y.merge({
37612            context: this,
37613            events : 'click',
37614            label  : button.value
37615        }, button);
37616
37617        buttonConfig     = Y.merge(config);
37618        nonButtonNodeCfg = WidgetButtons.NON_BUTTON_NODE_CFG;
37619
37620        // Remove all non-button Node config props.
37621        for (i = 0, len = nonButtonNodeCfg.length; i < len; i += 1) {
37622            delete buttonConfig[nonButtonNodeCfg[i]];
37623        }
37624
37625        // Create the button node using the button Node-only config.
37626        button = ButtonPlugin.createNode(buttonConfig);
37627
37628        context = config.context;
37629        action  = config.action;
37630
37631        // Supports `action` as a String name of a Function on the `context`
37632        // object.
37633        if (isString(action)) {
37634            action = Y.bind(action, context);
37635        }
37636
37637        // Supports all types of crazy configs for event subscriptions and
37638        // stores a reference to the returned `EventHandle`.
37639        handle = button.on(config.events, action, context);
37640        this._buttonsHandles[Y.stamp(button, true)] = handle;
37641
37642        // Tags the button with the configured `name` and `isDefault` settings.
37643        button.setData('name', this._getButtonName(config));
37644        button.setData('default', this._getButtonDefault(config));
37645
37646        // Add any CSS classnames to the button node.
37647        YArray.each(YArray(config.classNames), button.addClass, button);
37648
37649        return button;
37650    },
37651
37652    /**
37653    Returns the buttons container for the specified `section`, passing a truthy
37654    value for `create` will create the node if it does not already exist.
37655
37656    **Note:** It is up to the caller to properly insert the returned container
37657    node into the content section.
37658
37659    @method _getButtonContainer
37660    @param {String} section The `WidgetStdMod` section (header/body/footer).
37661    @param {Boolean} create Whether the buttons container should be created if
37662        it does not already exist.
37663    @return {Node} The buttons container node for the specified `section`.
37664    @protected
37665    @see BUTTONS_TEMPLATE
37666    @since 3.5.0
37667    **/
37668    _getButtonContainer: function (section, create) {
37669        var sectionClassName = WidgetStdMod.SECTION_CLASS_NAMES[section],
37670            buttonsClassName = WidgetButtons.CLASS_NAMES.buttons,
37671            contentBox       = this.get('contentBox'),
37672            containerSelector, container;
37673
37674        // Search for an existing buttons container within the section.
37675        containerSelector = '.' + sectionClassName + ' .' + buttonsClassName;
37676        container         = contentBox.one(containerSelector);
37677
37678        // Create the `container` if it doesn't already exist.
37679        if (!container && create) {
37680            container = Y.Node.create(this.BUTTONS_TEMPLATE);
37681            container.addClass(buttonsClassName);
37682        }
37683
37684        return container;
37685    },
37686
37687    /**
37688    Returns whether or not the specified `button` is configured to be the
37689    default button.
37690
37691    When a button node is specified, the button's `getData()` method will be
37692    used to determine if the button is configured to be the default. When a
37693    button config object is specified, the `isDefault` prop will determine
37694    whether the button is the default.
37695
37696    **Note:** `<button data-default="true"></button>` is supported via the
37697    `button.getData('default')` API call.
37698
37699    @method _getButtonDefault
37700    @param {Node|Object} button The button node or configuration object.
37701    @return {Boolean} Whether the button is configured to be the default button.
37702    @protected
37703    @since 3.5.0
37704    **/
37705    _getButtonDefault: function (button) {
37706        var isDefault = isNode(button) ?
37707                button.getData('default') : button.isDefault;
37708
37709        if (isString(isDefault)) {
37710            return isDefault.toLowerCase() === 'true';
37711        }
37712
37713        return !!isDefault;
37714    },
37715
37716    /**
37717    Returns the name of the specified `button`.
37718
37719    When a button node is specified, the button's `getData('name')` method is
37720    preferred, but will fallback to `get('name')`, and the result will determine
37721    the button's name. When a button config object is specified, the `name` prop
37722    will determine the button's name.
37723
37724    **Note:** `<button data-name="foo"></button>` is supported via the
37725    `button.getData('name')` API call.
37726
37727    @method _getButtonName
37728    @param {Node|Object} button The button node or configuration object.
37729    @return {String} The name of the button.
37730    @protected
37731    @since 3.5.0
37732    **/
37733    _getButtonName: function (button) {
37734        var name;
37735
37736        if (isNode(button)) {
37737            name = button.getData('name') || button.get('name');
37738        } else {
37739            name = button && (button.name || button.type);
37740        }
37741
37742        return name;
37743    },
37744
37745    /**
37746    Getter for the `buttons` attribute. A copy of the `buttons` object is
37747    returned so the stored state cannot be modified by the callers of
37748    `get('buttons')`.
37749
37750    This will recreate a copy of the `buttons` object, and each section array
37751    (the button nodes are *not* copied/cloned.)
37752
37753    @method _getButtons
37754    @param {Object} buttons The widget's current `buttons` state.
37755    @return {Object} A copy of the widget's current `buttons` state.
37756    @protected
37757    @since 3.5.0
37758    **/
37759    _getButtons: function (buttons) {
37760        var buttonsCopy = {};
37761
37762        // Creates a new copy of the `buttons` object.
37763        YObject.each(buttons, function (sectionButtons, section) {
37764            // Creates of copy of the array of button nodes.
37765            buttonsCopy[section] = sectionButtons.concat();
37766        });
37767
37768        return buttonsCopy;
37769    },
37770
37771    /**
37772    Adds the specified `button` to the buttons map (both name -> button and
37773    section:name -> button), and sets the button as the default if it is
37774    configured as the default button.
37775
37776    **Note:** If two or more buttons are configured with the same `name` and/or
37777    configured to be the default button, the last one wins.
37778
37779    @method _mapButton
37780    @param {Node} button The button node to map.
37781    @param {String} section The `WidgetStdMod` section (header/body/footer).
37782    @protected
37783    @since 3.5.0
37784    **/
37785    _mapButton: function (button, section) {
37786        var map       = this._buttonsMap,
37787            name      = this._getButtonName(button),
37788            isDefault = this._getButtonDefault(button);
37789
37790        if (name) {
37791            // name -> button
37792            map[name] = button;
37793
37794            // section:name -> button
37795            map[section + ':' + name] = button;
37796        }
37797
37798        isDefault && (this._defaultButton = button);
37799    },
37800
37801    /**
37802    Adds the specified `buttons` to the buttons map (both name -> button and
37803    section:name -> button), and set the a button as the default if one is
37804    configured as the default button.
37805
37806    **Note:** This will clear all previous button mappings and null-out any
37807    previous default button! If two or more buttons are configured with the same
37808    `name` and/or configured to be the default button, the last one wins.
37809
37810    @method _mapButtons
37811    @param {Node[]} buttons The button nodes to map.
37812    @protected
37813    @since 3.5.0
37814    **/
37815    _mapButtons: function (buttons) {
37816        this._buttonsMap    = {};
37817        this._defaultButton = null;
37818
37819        YObject.each(buttons, function (sectionButtons, section) {
37820            var i, len;
37821
37822            for (i = 0, len = sectionButtons.length; i < len; i += 1) {
37823                this._mapButton(sectionButtons[i], section);
37824            }
37825        }, this);
37826    },
37827
37828    /**
37829    Returns a copy of the specified `config` object merged with any defaults
37830    provided by a `srcNode` and/or a predefined configuration for a button
37831    with the same `name` on the `BUTTONS` property.
37832
37833    @method _mergeButtonConfig
37834    @param {Object|String} config Button configuration object, or string name.
37835    @return {Object} A copy of the button configuration object merged with any
37836        defaults.
37837    @protected
37838    @since 3.5.0
37839    **/
37840    _mergeButtonConfig: function (config) {
37841        var buttonConfig, defConfig, name, button, tagName, label;
37842
37843        // Makes sure `config` is an Object and a copy of the specified value.
37844        config = isString(config) ? {name: config} : Y.merge(config);
37845
37846        // Seeds default values from the button node, if there is one.
37847        if (config.srcNode) {
37848            button  = config.srcNode;
37849            tagName = button.get('tagName').toLowerCase();
37850            label   = button.get(tagName === 'input' ? 'value' : 'text');
37851
37852            // Makes sure the button's current values override any defaults.
37853            buttonConfig = {
37854                disabled : !!button.get('disabled'),
37855                isDefault: this._getButtonDefault(button),
37856                name     : this._getButtonName(button)
37857            };
37858
37859            // Label should only be considered when not an empty string.
37860            label && (buttonConfig.label = label);
37861
37862            // Merge `config` with `buttonConfig` values.
37863            Y.mix(config, buttonConfig, false, null, 0, true);
37864        }
37865
37866        name      = this._getButtonName(config);
37867        defConfig = this.BUTTONS && this.BUTTONS[name];
37868
37869        // Merge `config` with predefined default values.
37870        if (defConfig) {
37871            Y.mix(config, defConfig, false, null, 0, true);
37872        }
37873
37874        return config;
37875    },
37876
37877    /**
37878    `HTML_PARSER` implementation for the `buttons` attribute.
37879
37880    **Note:** To determine a button node's name its `data-name` and `name`
37881    attributes are examined. Whether the button should be the default is
37882    determined by its `data-default` attribute.
37883
37884    @method _parseButtons
37885    @param {Node} srcNode This widget's srcNode to search for buttons.
37886    @return {null|Object} `buttons` Config object parsed from this widget's DOM.
37887    @protected
37888    @since 3.5.0
37889    **/
37890    _parseButtons: function (srcNode) {
37891        var buttonSelector = '.' + WidgetButtons.CLASS_NAMES.button,
37892            sections       = ['header', 'body', 'footer'],
37893            buttonsConfig  = null;
37894
37895        YArray.each(sections, function (section) {
37896            var container = this._getButtonContainer(section),
37897                buttons   = container && container.all(buttonSelector),
37898                sectionButtons;
37899
37900            if (!buttons || buttons.isEmpty()) { return; }
37901
37902            sectionButtons = [];
37903
37904            // Creates a button config object for every button node found and
37905            // adds it to the section. This way each button configuration can be
37906            // merged with any defaults provided by predefined `BUTTONS`.
37907            buttons.each(function (button) {
37908                sectionButtons.push({srcNode: button});
37909            });
37910
37911            buttonsConfig || (buttonsConfig = {});
37912            buttonsConfig[section] = sectionButtons;
37913        }, this);
37914
37915        return buttonsConfig;
37916    },
37917
37918    /**
37919    Setter for the `buttons` attribute. This processes the specified `config`
37920    and returns a new `buttons` object which is stored as the new state; leaving
37921    the original, specified `config` unmodified.
37922
37923    The button nodes will either be created via `Y.Plugin.Button.createNode()`,
37924    or when a button is already a Node already, it will by `plug()`ed with
37925    `Y.Plugin.Button`.
37926
37927    @method _setButtons
37928    @param {Array|Object} config The `buttons` configuration to process.
37929    @return {Object} The processed `buttons` object which represents the new
37930        state.
37931    @protected
37932    @since 3.5.0
37933    **/
37934    _setButtons: function (config) {
37935        var defSection = this.DEFAULT_BUTTONS_SECTION,
37936            buttons    = {};
37937
37938        function processButtons(buttonConfigs, currentSection) {
37939            if (!isArray(buttonConfigs)) { return; }
37940
37941            var i, len, button, section;
37942
37943            for (i = 0, len = buttonConfigs.length; i < len; i += 1) {
37944                button  = buttonConfigs[i];
37945                section = currentSection;
37946
37947                if (!isNode(button)) {
37948                    button = this._mergeButtonConfig(button);
37949                    section || (section = button.section);
37950                }
37951
37952                // Always passes through `_createButton()` to make sure the node
37953                // is decorated as a button.
37954                button = this._createButton(button);
37955
37956                // Use provided `section` or fallback to the default section.
37957                section || (section = defSection);
37958
37959                // Add button to the array of buttons for the specified section.
37960                (buttons[section] || (buttons[section] = [])).push(button);
37961            }
37962        }
37963
37964        // Handle `config` being either an Array or Object of Arrays.
37965        if (isArray(config)) {
37966            processButtons.call(this, config);
37967        } else {
37968            YObject.each(config, processButtons, this);
37969        }
37970
37971        return buttons;
37972    },
37973
37974    /**
37975    Syncs this widget's current button-related state to its DOM. This method is
37976    inserted via AOP, and will execute after `syncUI()`.
37977
37978    @method _syncUIButtons
37979    @protected
37980    @since 3.4.0
37981    **/
37982    _syncUIButtons: function () {
37983        this._uiSetButtons(this.get('buttons'));
37984        this._uiSetDefaultButton(this.get('defaultButton'));
37985        this._uiSetVisibleButtons(this.get('visible'));
37986    },
37987
37988    /**
37989    Inserts the specified `button` node into this widget's DOM at the specified
37990    `section` and `index` and updates the section content.
37991
37992    The section and button container nodes will be created if they do not
37993    already exist.
37994
37995    @method _uiInsertButton
37996    @param {Node} button The button node to insert into this widget's DOM.
37997    @param {String} section The `WidgetStdMod` section (header/body/footer).
37998    @param {Number} index Index at which the `button` should be positioned.
37999    @protected
38000    @since 3.5.0
38001    **/
38002    _uiInsertButton: function (button, section, index) {
38003        var buttonsClassName = WidgetButtons.CLASS_NAMES.button,
38004            buttonContainer  = this._getButtonContainer(section, true),
38005            sectionButtons   = buttonContainer.all('.' + buttonsClassName);
38006
38007        // Inserts the button node at the correct index.
38008        buttonContainer.insertBefore(button, sectionButtons.item(index));
38009
38010        // Adds the button container to the section content.
38011        this.setStdModContent(section, buttonContainer, 'after');
38012    },
38013
38014    /**
38015    Removes the button node from this widget's DOM and detaches any event
38016    subscriptions on the button that were created by this widget. The section
38017    content will be updated unless `{preserveContent: true}` is passed in the
38018    `options`.
38019
38020    By default the button container node will be removed when this removes the
38021    last button of the specified `section`; and if no other content remains in
38022    the section node, it will also be removed.
38023
38024    @method _uiRemoveButton
38025    @param {Node} button The button to remove and destroy.
38026    @param {String} section The `WidgetStdMod` section (header/body/footer).
38027    @param {Object} [options] Additional options.
38028      @param {Boolean} [options.preserveContent=false] Whether the section
38029        content should be updated.
38030    @protected
38031    @since 3.5.0
38032    **/
38033    _uiRemoveButton: function (button, section, options) {
38034        var yuid    = Y.stamp(button, this),
38035            handles = this._buttonsHandles,
38036            handle  = handles[yuid],
38037            buttonContainer, buttonClassName;
38038
38039        if (handle) {
38040            handle.detach();
38041        }
38042
38043        delete handles[yuid];
38044
38045        button.remove();
38046
38047        options || (options = {});
38048
38049        // Remove the button container and section nodes if needed.
38050        if (!options.preserveContent) {
38051            buttonContainer = this._getButtonContainer(section);
38052            buttonClassName = WidgetButtons.CLASS_NAMES.button;
38053
38054            // Only matters if we have a button container which is empty.
38055            if (buttonContainer &&
38056                    buttonContainer.all('.' + buttonClassName).isEmpty()) {
38057
38058                buttonContainer.remove();
38059                this._updateContentButtons(section);
38060            }
38061        }
38062    },
38063
38064    /**
38065    Sets the current `buttons` state to this widget's DOM by rendering the
38066    specified collection of `buttons` and updates the contents of each section
38067    as needed.
38068
38069    Button nodes which already exist in the DOM will remain intact, or will be
38070    moved if they should be in a new position. Old button nodes which are no
38071    longer represented in the specified `buttons` collection will be removed,
38072    and any event subscriptions on the button which were created by this widget
38073    will be detached.
38074
38075    If the button nodes in this widget's DOM actually change, then each content
38076    section will be updated (or removed) appropriately.
38077
38078    @method _uiSetButtons
38079    @param {Object} buttons The current `buttons` state to visually represent.
38080    @protected
38081    @since 3.5.0
38082    **/
38083    _uiSetButtons: function (buttons) {
38084        var buttonClassName = WidgetButtons.CLASS_NAMES.button,
38085            sections        = ['header', 'body', 'footer'];
38086
38087        YArray.each(sections, function (section) {
38088            var sectionButtons  = buttons[section] || [],
38089                numButtons      = sectionButtons.length,
38090                buttonContainer = this._getButtonContainer(section, numButtons),
38091                buttonsUpdated  = false,
38092                oldNodes, i, button, buttonIndex;
38093
38094            // When there's no button container, there are no new buttons or old
38095            // buttons that we have to deal with for this section.
38096            if (!buttonContainer) { return; }
38097
38098            oldNodes = buttonContainer.all('.' + buttonClassName);
38099
38100            for (i = 0; i < numButtons; i += 1) {
38101                button      = sectionButtons[i];
38102                buttonIndex = oldNodes.indexOf(button);
38103
38104                // Buttons already rendered in the Widget should remain there or
38105                // moved to their new index. New buttons will be added to the
38106                // current `buttonContainer`.
38107                if (buttonIndex > -1) {
38108                    // Remove button from existing buttons nodeList since its in
38109                    // the DOM already.
38110                    oldNodes.splice(buttonIndex, 1);
38111
38112                    // Check that the button is at the right position, if not,
38113                    // move it to its new position.
38114                    if (buttonIndex !== i) {
38115                        // Using `i + 1` because the button should be at index
38116                        // `i`; it's inserted before the node which comes after.
38117                        buttonContainer.insertBefore(button, i + 1);
38118                        buttonsUpdated = true;
38119                    }
38120                } else {
38121                    buttonContainer.appendChild(button);
38122                    buttonsUpdated = true;
38123                }
38124            }
38125
38126            // Safely removes the old button nodes which are no longer part of
38127            // this widget's `buttons`.
38128            oldNodes.each(function (button) {
38129                this._uiRemoveButton(button, section, {preserveContent: true});
38130                buttonsUpdated = true;
38131            }, this);
38132
38133            // Remove leftover empty button containers and updated the StdMod
38134            // content area.
38135            if (numButtons === 0) {
38136                buttonContainer.remove();
38137                this._updateContentButtons(section);
38138                return;
38139            }
38140
38141            // Adds the button container to the section content.
38142            if (buttonsUpdated) {
38143                this.setStdModContent(section, buttonContainer, 'after');
38144            }
38145        }, this);
38146    },
38147
38148    /**
38149    Adds the "yui3-button-primary" CSS class to the new `defaultButton` and
38150    removes it from the old default button.
38151
38152    @method _uiSetDefaultButton
38153    @param {Node} newButton The new `defaultButton`.
38154    @param {Node} oldButton The old `defaultButton`.
38155    @protected
38156    @since 3.5.0
38157    **/
38158    _uiSetDefaultButton: function (newButton, oldButton) {
38159        var primaryClassName = WidgetButtons.CLASS_NAMES.primary;
38160
38161        if (newButton) { newButton.addClass(primaryClassName); }
38162        if (oldButton) { oldButton.removeClass(primaryClassName); }
38163    },
38164
38165    /**
38166    Focuses this widget's `defaultButton` if there is one and this widget is
38167    visible.
38168
38169    @method _uiSetVisibleButtons
38170    @param {Boolean} visible Whether this widget is visible.
38171    @protected
38172    @since 3.5.0
38173    **/
38174    _uiSetVisibleButtons: function (visible) {
38175        if (!visible) { return; }
38176
38177        var defaultButton = this.get('defaultButton');
38178        if (defaultButton) {
38179            defaultButton.focus();
38180        }
38181    },
38182
38183    /**
38184    Removes the specified `button` from the buttons map (both name -> button and
38185    section:name -> button), and nulls-out the `defaultButton` if it is
38186    currently the default button.
38187
38188    @method _unMapButton
38189    @param {Node} button The button node to remove from the buttons map.
38190    @param {String} section The `WidgetStdMod` section (header/body/footer).
38191    @protected
38192    @since 3.5.0
38193    **/
38194    _unMapButton: function (button, section) {
38195        var map  = this._buttonsMap,
38196            name = this._getButtonName(button),
38197            sectionName;
38198
38199        // Only delete the map entry if the specified `button` is mapped to it.
38200        if (name) {
38201            // name -> button
38202            if (map[name] === button) {
38203                delete map[name];
38204            }
38205
38206            // section:name -> button
38207            sectionName = section + ':' + name;
38208            if (map[sectionName] === button) {
38209                delete map[sectionName];
38210            }
38211        }
38212
38213        // Clear the default button if its the specified `button`.
38214        if (this._defaultButton === button) {
38215            this._defaultButton = null;
38216        }
38217    },
38218
38219    /**
38220    Updates the `defaultButton` attribute if it needs to be updated by comparing
38221    its current value with the protected `_defaultButton` property.
38222
38223    @method _updateDefaultButton
38224    @protected
38225    @since 3.5.0
38226    **/
38227    _updateDefaultButton: function () {
38228        var defaultButton = this._defaultButton;
38229
38230        if (this.get('defaultButton') !== defaultButton) {
38231            this._set('defaultButton', defaultButton);
38232        }
38233    },
38234
38235    /**
38236    Updates the content attribute which corresponds to the specified `section`.
38237
38238    The method updates the section's content to its current `childNodes`
38239    (text and/or HTMLElement), or will null-out its contents if the section is
38240    empty. It also specifies a `src` of `buttons` on the change event facade.
38241
38242    @method _updateContentButtons
38243    @param {String} section The `WidgetStdMod` section (header/body/footer) to
38244        update.
38245    @protected
38246    @since 3.5.0
38247    **/
38248    _updateContentButtons: function (section) {
38249        // `childNodes` return text nodes and HTMLElements.
38250        var sectionContent = this.getStdModNode(section).get('childNodes');
38251
38252        // Updates the section to its current contents, or null if it is empty.
38253        this.set(section + 'Content', sectionContent.isEmpty() ? null :
38254            sectionContent, {src: 'buttons'});
38255    },
38256
38257    // -- Protected Event Handlers ---------------------------------------------
38258
38259    /**
38260    Handles this widget's `buttonsChange` event which fires anytime the
38261    `buttons` attribute is modified.
38262
38263    **Note:** This method special-cases the `buttons` modifications caused by
38264    `addButton()` and `removeButton()`, both of which set the `src` property on
38265    the event facade to "add" and "remove" respectively.
38266
38267    @method _afterButtonsChange
38268    @param {EventFacade} e
38269    @protected
38270    @since 3.4.0
38271    **/
38272    _afterButtonsChange: function (e) {
38273        var buttons = e.newVal,
38274            section = e.section,
38275            index   = e.index,
38276            src     = e.src,
38277            button;
38278
38279        // Special cases `addButton()` to only set and insert the new button.
38280        if (src === 'add') {
38281            // Make sure we have the button node.
38282            button = buttons[section][index];
38283
38284            this._mapButton(button, section);
38285            this._updateDefaultButton();
38286            this._uiInsertButton(button, section, index);
38287
38288            return;
38289        }
38290
38291        // Special cases `removeButton()` to only remove the specified button.
38292        if (src === 'remove') {
38293            // Button node already exists on the event facade.
38294            button = e.button;
38295
38296            this._unMapButton(button, section);
38297            this._updateDefaultButton();
38298            this._uiRemoveButton(button, section);
38299
38300            return;
38301        }
38302
38303        this._mapButtons(buttons);
38304        this._updateDefaultButton();
38305        this._uiSetButtons(buttons);
38306    },
38307
38308    /**
38309    Handles this widget's `headerContentChange`, `bodyContentChange`,
38310    `footerContentChange` events by making sure the `buttons` remain rendered
38311    after changes to the content areas.
38312
38313    These events are very chatty, so extra caution is taken to avoid doing extra
38314    work or getting into an infinite loop.
38315
38316    @method _afterContentChangeButtons
38317    @param {EventFacade} e
38318    @protected
38319    @since 3.5.0
38320    **/
38321    _afterContentChangeButtons: function (e) {
38322        var src     = e.src,
38323            pos     = e.stdModPosition,
38324            replace = !pos || pos === WidgetStdMod.REPLACE;
38325
38326        // Only do work when absolutely necessary.
38327        if (replace && src !== 'buttons' && src !== Widget.UI_SRC) {
38328            this._uiSetButtons(this.get('buttons'));
38329        }
38330    },
38331
38332    /**
38333    Handles this widget's `defaultButtonChange` event by adding the
38334    "yui3-button-primary" CSS class to the new `defaultButton` and removing it
38335    from the old default button.
38336
38337    @method _afterDefaultButtonChange
38338    @param {EventFacade} e
38339    @protected
38340    @since 3.5.0
38341    **/
38342    _afterDefaultButtonChange: function (e) {
38343        this._uiSetDefaultButton(e.newVal, e.prevVal);
38344    },
38345
38346    /**
38347    Handles this widget's `visibleChange` event by focusing the `defaultButton`
38348    if there is one.
38349
38350    @method _afterVisibleChangeButtons
38351    @param {EventFacade} e
38352    @protected
38353    @since 3.5.0
38354    **/
38355    _afterVisibleChangeButtons: function (e) {
38356        this._uiSetVisibleButtons(e.newVal);
38357    }
38358};
38359
38360Y.WidgetButtons = WidgetButtons;
38361
38362
38363}, '3.18.1', {"requires": ["button-plugin", "cssbutton", "widget-stdmod"]});
38364YUI.add('widget-modality', function (Y, NAME) {
38365
38366/**
38367 * Provides modality support for Widgets, though an extension
38368 *
38369 * @module widget-modality
38370 */
38371
38372var WIDGET       = 'widget',
38373    RENDER_UI    = 'renderUI',
38374    BIND_UI      = 'bindUI',
38375    SYNC_UI      = 'syncUI',
38376    BOUNDING_BOX = 'boundingBox',
38377    VISIBLE      = 'visible',
38378    Z_INDEX      = 'zIndex',
38379    CHANGE       = 'Change',
38380    isBoolean    = Y.Lang.isBoolean,
38381    getCN        = Y.ClassNameManager.getClassName,
38382    MaskShow     = "maskShow",
38383    MaskHide     = "maskHide",
38384    ClickOutside = "clickoutside",
38385    FocusOutside = "focusoutside",
38386
38387    supportsPosFixed = (function(){
38388
38389        /*! IS_POSITION_FIXED_SUPPORTED - Juriy Zaytsev (kangax) - http://yura.thinkweb2.com/cft/ */
38390
38391        var doc         = Y.config.doc,
38392            isSupported = null,
38393            el, root;
38394
38395        if (doc.createElement) {
38396            el = doc.createElement('div');
38397            if (el && el.style) {
38398                el.style.position = 'fixed';
38399                el.style.top = '10px';
38400                root = doc.body;
38401                if (root && root.appendChild && root.removeChild) {
38402                    root.appendChild(el);
38403                    isSupported = (el.offsetTop === 10);
38404                    root.removeChild(el);
38405                }
38406            }
38407        }
38408
38409        return isSupported;
38410    }());
38411
38412    /**
38413     * Widget extension, which can be used to add modality support to the base Widget class,
38414     * through the Base.create method.
38415     *
38416     * @class WidgetModality
38417     * @param {Object} config User configuration object
38418     */
38419    function WidgetModal(config) {}
38420
38421    var MODAL           = 'modal',
38422        MASK            = 'mask',
38423        MODAL_CLASSES   = {
38424            modal   : getCN(WIDGET, MODAL),
38425            mask    : getCN(WIDGET, MASK)
38426        };
38427
38428    /**
38429    * Static property used to define the default attribute
38430    * configuration introduced by WidgetModality.
38431    *
38432    * @property ATTRS
38433    * @static
38434    * @type Object
38435    */
38436    WidgetModal.ATTRS = {
38437            /**
38438             * @attribute maskNode
38439             * @type Y.Node
38440             *
38441             * @description Returns a Y.Node instance of the node being used as the mask.
38442             */
38443            maskNode : {
38444                getter      : '_getMaskNode',
38445                readOnly    : true
38446            },
38447
38448
38449            /**
38450             * @attribute modal
38451             * @type boolean
38452             *
38453             * @description Whether the widget should be modal or not.
38454             */
38455            modal: {
38456                value:false,
38457                validator: isBoolean
38458            },
38459
38460            /**
38461             * @attribute focusOn
38462             * @type array
38463             *
38464             * @description An array of objects corresponding to the nodes and events that will trigger a re-focus back on the widget.
38465             * The implementer can supply an array of objects, with each object having the following properties:
38466             * <p>eventName: (string, required): The eventName to listen to.</p>
38467             * <p>node: (Y.Node, optional): The Y.Node that will fire the event (defaults to the boundingBox of the widget)</p>
38468             * <p>By default, this attribute consists of two objects which will cause the widget to re-focus if anything
38469             * outside the widget is clicked on or focussed upon.</p>
38470             */
38471            focusOn: {
38472                valueFn: function() {
38473                    return [
38474                        {
38475                            // node: this.get(BOUNDING_BOX),
38476                            eventName: ClickOutside
38477                        },
38478                        {
38479                            //node: this.get(BOUNDING_BOX),
38480                            eventName: FocusOutside
38481                        }
38482                    ];
38483                },
38484
38485                validator: Y.Lang.isArray
38486            }
38487
38488    };
38489
38490
38491    WidgetModal.CLASSES = MODAL_CLASSES;
38492
38493
38494    WidgetModal._MASK = null;
38495    /**
38496     * Returns the mask if it exists on the page - otherwise creates a mask. There's only
38497     * one mask on a page at a given time.
38498     * <p>
38499     * This method in invoked internally by the getter of the maskNode ATTR.
38500     * </p>
38501     * @method _GET_MASK
38502     * @static
38503     */
38504    WidgetModal._GET_MASK = function() {
38505
38506        var mask = WidgetModal._MASK,
38507            win  = Y.one('win');
38508
38509        if (mask && (mask.getDOMNode() !== null) && mask.inDoc()) {
38510            return mask;
38511        }
38512
38513        mask = Y.Node.create('<div></div>').addClass(MODAL_CLASSES.mask);
38514        WidgetModal._MASK = mask;
38515
38516        if (supportsPosFixed) {
38517            mask.setStyles({
38518                position: 'fixed',
38519                width   : '100%',
38520                height  : '100%',
38521                top     : '0',
38522                left    : '0',
38523                display : 'block'
38524            });
38525        } else {
38526            mask.setStyles({
38527                position: 'absolute',
38528                width   : win.get('winWidth') +'px',
38529                height  : win.get('winHeight') + 'px',
38530                top     : '0',
38531                left    : '0',
38532                display : 'block'
38533            });
38534        }
38535
38536        return mask;
38537    };
38538
38539    /**
38540     * A stack of Y.Widget objects representing the current hierarchy of modal widgets presently displayed on the screen
38541     * @property STACK
38542     */
38543    WidgetModal.STACK = [];
38544
38545
38546    WidgetModal.prototype = {
38547
38548        initializer: function () {
38549            Y.after(this._renderUIModal, this, RENDER_UI);
38550            Y.after(this._syncUIModal, this, SYNC_UI);
38551            Y.after(this._bindUIModal, this, BIND_UI);
38552        },
38553
38554        destructor: function () {
38555            // Hack to remove this thing from the STACK.
38556            this._uiSetHostVisibleModal(false);
38557        },
38558
38559        // *** Instance Members *** //
38560
38561        _uiHandlesModal: null,
38562
38563
38564        /**
38565         * Adds modal class to the bounding box of the widget
38566         * <p>
38567         * This method in invoked after renderUI is invoked for the Widget class
38568         * using YUI's aop infrastructure.
38569         * </p>
38570         * @method _renderUIModal
38571         * @protected
38572         */
38573        _renderUIModal : function () {
38574
38575            var bb = this.get(BOUNDING_BOX);
38576                //cb = this.get(CONTENT_BOX);
38577
38578            //this makes the content box content appear over the mask
38579            // cb.setStyles({
38580            //     position: ""
38581            // });
38582
38583            this._repositionMask(this);
38584            bb.addClass(MODAL_CLASSES.modal);
38585
38586        },
38587
38588
38589        /**
38590         * Hooks up methods to be executed when the widget's visibility or z-index changes
38591         * <p>
38592         * This method in invoked after bindUI is invoked for the Widget class
38593         * using YUI's aop infrastructure.
38594         * </p>
38595         * @method _bindUIModal
38596         * @protected
38597         */
38598        _bindUIModal : function () {
38599
38600            this.after(VISIBLE+CHANGE, this._afterHostVisibleChangeModal);
38601            this.after(Z_INDEX+CHANGE, this._afterHostZIndexChangeModal);
38602            this.after("focusOnChange", this._afterFocusOnChange);
38603
38604            // Re-align the mask in the viewport if `position: fixed;` is not
38605            // supported. iOS < 5 and Android < 3 don't actually support it even
38606            // though they both pass the feature test; the UA sniff is here to
38607            // account for that. Ideally this should be replaced with a better
38608            // feature test.
38609            if (!supportsPosFixed ||
38610                    (Y.UA.ios && Y.UA.ios < 5) ||
38611                    (Y.UA.android && Y.UA.android < 3)) {
38612
38613                Y.one('win').on('scroll', this._resyncMask, this);
38614            }
38615        },
38616
38617        /**
38618         * Syncs the mask with the widget's current state, namely the visibility and z-index of the widget
38619         * <p>
38620         * This method in invoked after syncUI is invoked for the Widget class
38621         * using YUI's aop infrastructure.
38622         * </p>
38623         * @method _syncUIModal
38624         * @protected
38625         */
38626        _syncUIModal : function () {
38627
38628            //var host = this.get(HOST);
38629
38630            this._uiSetHostVisibleModal(this.get(VISIBLE));
38631
38632        },
38633
38634        /**
38635         * Provides mouse and tab focus to the widget's bounding box.
38636         *
38637         * @method _focus
38638         */
38639        _focus : function () {
38640
38641            var bb = this.get(BOUNDING_BOX),
38642            oldTI = bb.get('tabIndex');
38643
38644            bb.set('tabIndex', oldTI >= 0 ? oldTI : 0);
38645            this.focus();
38646        },
38647        /**
38648         * Blurs the widget.
38649         *
38650         * @method _blur
38651         */
38652        _blur : function () {
38653
38654            this.blur();
38655        },
38656
38657        /**
38658         * Returns the Y.Node instance of the maskNode
38659         *
38660         * @method _getMaskNode
38661         * @return {Node} The Y.Node instance of the mask, as returned from WidgetModal._GET_MASK
38662         */
38663        _getMaskNode : function () {
38664
38665            return WidgetModal._GET_MASK();
38666        },
38667
38668        /**
38669         * Performs events attaching/detaching, stack shifting and mask repositioning based on the visibility of the widget
38670         *
38671         * @method _uiSetHostVisibleModal
38672         * @param {boolean} Whether the widget is visible or not
38673         */
38674        _uiSetHostVisibleModal : function (visible) {
38675            var stack    = WidgetModal.STACK,
38676                maskNode = this.get('maskNode'),
38677                isModal  = this.get('modal'),
38678                topModal, index;
38679
38680            if (visible) {
38681
38682                Y.Array.each(stack, function(modal){
38683                    modal._detachUIHandlesModal();
38684                    modal._blur();
38685                });
38686
38687                // push on top of stack
38688                stack.unshift(this);
38689
38690                this._repositionMask(this);
38691                this._uiSetHostZIndexModal(this.get(Z_INDEX));
38692
38693                if (isModal) {
38694                    maskNode.show();
38695                    Y.later(1, this, '_attachUIHandlesModal');
38696                    this._focus();
38697                }
38698
38699
38700            } else {
38701
38702                index = Y.Array.indexOf(stack, this);
38703                if (index >= 0) {
38704                    // Remove modal widget from global stack.
38705                    stack.splice(index, 1);
38706                }
38707
38708                this._detachUIHandlesModal();
38709                this._blur();
38710
38711                if (stack.length) {
38712                    topModal = stack[0];
38713                    this._repositionMask(topModal);
38714                    //topModal._attachUIHandlesModal();
38715                    topModal._uiSetHostZIndexModal(topModal.get(Z_INDEX));
38716
38717                    if (topModal.get('modal')) {
38718                        //topModal._attachUIHandlesModal();
38719                        Y.later(1, topModal, '_attachUIHandlesModal');
38720                        topModal._focus();
38721                    }
38722
38723                } else {
38724
38725                    if (maskNode.getStyle('display') === 'block') {
38726                        maskNode.hide();
38727                    }
38728
38729                }
38730
38731            }
38732        },
38733
38734        /**
38735         * Sets the z-index of the mask node.
38736         *
38737         * @method _uiSetHostZIndexModal
38738         * @param {Number} Z-Index of the widget
38739         */
38740        _uiSetHostZIndexModal : function (zIndex) {
38741
38742            if (this.get('modal')) {
38743                this.get('maskNode').setStyle(Z_INDEX, zIndex || 0);
38744            }
38745
38746        },
38747
38748        /**
38749         * Attaches UI Listeners for "clickoutside" and "focusoutside" on the
38750         * widget. When these events occur, and the widget is modal, focus is
38751         * shifted back onto the widget.
38752         *
38753         * @method _attachUIHandlesModal
38754         */
38755        _attachUIHandlesModal : function () {
38756
38757            if (this._uiHandlesModal || WidgetModal.STACK[0] !== this) {
38758                // Quit early if we have ui handles, or if we not at the top
38759                // of the global stack.
38760                return;
38761            }
38762
38763            var bb          = this.get(BOUNDING_BOX),
38764                maskNode    = this.get('maskNode'),
38765                focusOn     = this.get('focusOn'),
38766                focus       = Y.bind(this._focus, this),
38767                uiHandles   = [],
38768                i, len, o;
38769
38770            for (i = 0, len = focusOn.length; i < len; i++) {
38771
38772                o = {};
38773                o.node = focusOn[i].node;
38774                o.ev = focusOn[i].eventName;
38775                o.keyCode = focusOn[i].keyCode;
38776
38777                //no keycode or node defined
38778                if (!o.node && !o.keyCode && o.ev) {
38779                    uiHandles.push(bb.on(o.ev, focus));
38780                }
38781
38782                //node defined, no keycode (not a keypress)
38783                else if (o.node && !o.keyCode && o.ev) {
38784                    uiHandles.push(o.node.on(o.ev, focus));
38785                }
38786
38787                //node defined, keycode defined, event defined (its a key press)
38788                else if (o.node && o.keyCode && o.ev) {
38789                    uiHandles.push(o.node.on(o.ev, focus, o.keyCode));
38790                }
38791
38792                else {
38793                }
38794
38795            }
38796
38797            if ( ! supportsPosFixed) {
38798                uiHandles.push(Y.one('win').on('scroll', Y.bind(function(){
38799                    maskNode.setStyle('top', maskNode.get('docScrollY'));
38800                }, this)));
38801            }
38802
38803            this._uiHandlesModal = uiHandles;
38804        },
38805
38806        /**
38807         * Detaches all UI Listeners that were set in _attachUIHandlesModal from the widget.
38808         *
38809         * @method _detachUIHandlesModal
38810         */
38811        _detachUIHandlesModal : function () {
38812            Y.each(this._uiHandlesModal, function(h){
38813                h.detach();
38814            });
38815            this._uiHandlesModal = null;
38816        },
38817
38818        /**
38819         * Default function that is called when visibility is changed on the widget.
38820         *
38821         * @method _afterHostVisibleChangeModal
38822         * @param {EventFacade} e The event facade of the change
38823         */
38824        _afterHostVisibleChangeModal : function (e) {
38825
38826            this._uiSetHostVisibleModal(e.newVal);
38827        },
38828
38829        /**
38830         * Default function that is called when z-index is changed on the widget.
38831         *
38832         * @method _afterHostZIndexChangeModal
38833         * @param {EventFacade} e The event facade of the change
38834         */
38835        _afterHostZIndexChangeModal : function (e) {
38836
38837            this._uiSetHostZIndexModal(e.newVal);
38838        },
38839
38840        /**
38841         * Returns a boolean representing whether the current widget is in a "nested modality" state.
38842         * This is done by checking the number of widgets currently on the stack.
38843         *
38844         * @method isNested
38845         * @public
38846         */
38847        isNested: function() {
38848            var length = WidgetModal.STACK.length,
38849            retval = (length > 1) ? true : false;
38850            return retval;
38851        },
38852
38853        /**
38854         * Repositions the mask in the DOM for nested modality cases.
38855         *
38856         * @method _repositionMask
38857         * @param {Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
38858         */
38859        _repositionMask: function(nextElem) {
38860
38861            var currentModal = this.get('modal'),
38862                nextModal    = nextElem.get('modal'),
38863                maskNode     = this.get('maskNode'),
38864                bb, bbParent;
38865
38866            //if this is modal and host is not modal
38867            if (currentModal && !nextModal) {
38868                //leave the mask where it is, since the host is not modal.
38869                maskNode.remove();
38870                this.fire(MaskHide);
38871            }
38872
38873            //if the main widget is not modal but the host is modal, or both of them are modal
38874            else if ((!currentModal && nextModal) || (currentModal && nextModal)) {
38875
38876                //then remove the mask off DOM, reposition it, and reinsert it into the DOM
38877                maskNode.remove();
38878                this.fire(MaskHide);
38879                bb = nextElem.get(BOUNDING_BOX);
38880                bbParent = bb.get('parentNode') || Y.one('body');
38881                bbParent.insert(maskNode, bbParent.get('firstChild'));
38882                this.fire(MaskShow);
38883            }
38884
38885        },
38886
38887        /**
38888         * Resyncs the mask in the viewport for browsers that don't support fixed positioning
38889         *
38890         * @method _resyncMask
38891         * @param {Y.Widget} nextElem The Y.Widget instance that will be visible in the stack once the current widget is closed.
38892         * @private
38893         */
38894        _resyncMask: function (e) {
38895            var o       = e.currentTarget,
38896                offsetX = o.get('docScrollX'),
38897                offsetY = o.get('docScrollY'),
38898                w       = o.get('innerWidth') || o.get('winWidth'),
38899                h       = o.get('innerHeight') || o.get('winHeight'),
38900                mask    = this.get('maskNode');
38901
38902            mask.setStyles({
38903                "top": offsetY + "px",
38904                "left": offsetX + "px",
38905                "width": w + 'px',
38906                "height": h + 'px'
38907            });
38908        },
38909
38910        /**
38911         * Default function called when focusOn Attribute is changed. Remove existing listeners and create new listeners.
38912         *
38913         * @method _afterFocusOnChange
38914         */
38915        _afterFocusOnChange : function() {
38916            this._detachUIHandlesModal();
38917
38918            if (this.get(VISIBLE)) {
38919                this._attachUIHandlesModal();
38920            }
38921        }
38922    };
38923
38924    Y.WidgetModality = WidgetModal;
38925
38926
38927
38928}, '3.18.1', {"requires": ["base-build", "event-outside", "widget"], "skinnable": true});
38929YUI.add('panel', function (Y, NAME) {
38930
38931// TODO: Change this description!
38932/**
38933Provides a Panel widget, a widget that mimics the functionality of a regular OS
38934window. Comes with Standard Module support, XY Positioning, Alignment Support,
38935Stack (z-index) support, modality, auto-focus and auto-hide functionality, and
38936header/footer button support.
38937
38938@module panel
38939**/
38940
38941var getClassName = Y.ClassNameManager.getClassName;
38942
38943// TODO: Change this description!
38944/**
38945A basic Panel Widget, which can be positioned based on Page XY co-ordinates and
38946is stackable (z-index support). It also provides alignment and centering support
38947and uses a standard module format for it's content, with header, body and footer
38948section support. It can be made modal, and has functionality to hide and focus
38949on different events. The header and footer sections can be modified to allow for
38950button support.
38951
38952@class Panel
38953@constructor
38954@extends Widget
38955@uses WidgetAutohide
38956@uses WidgetButtons
38957@uses WidgetModality
38958@uses WidgetPosition
38959@uses WidgetPositionAlign
38960@uses WidgetPositionConstrain
38961@uses WidgetStack
38962@uses WidgetStdMod
38963@since 3.4.0
38964 */
38965Y.Panel = Y.Base.create('panel', Y.Widget, [
38966    // Other Widget extensions depend on these two.
38967    Y.WidgetPosition,
38968    Y.WidgetStdMod,
38969
38970    Y.WidgetAutohide,
38971    Y.WidgetButtons,
38972    Y.WidgetModality,
38973    Y.WidgetPositionAlign,
38974    Y.WidgetPositionConstrain,
38975    Y.WidgetStack
38976], {
38977    // -- Public Properties ----------------------------------------------------
38978
38979    /**
38980    Collection of predefined buttons mapped from name => config.
38981
38982    Panel includes a "close" button which can be use by name. When the close
38983    button is in the header (which is the default), it will look like: [x].
38984
38985    See `addButton()` for a list of possible configuration values.
38986
38987    @example
38988        // Panel with close button in header.
38989        var panel = new Y.Panel({
38990            buttons: ['close']
38991        });
38992
38993        // Panel with close button in footer.
38994        var otherPanel = new Y.Panel({
38995            buttons: {
38996                footer: ['close']
38997            }
38998        });
38999
39000    @property BUTTONS
39001    @type Object
39002    @default {close: {}}
39003    @since 3.5.0
39004    **/
39005    BUTTONS: {
39006        close: {
39007            label  : 'Close',
39008            action : 'hide',
39009            section: 'header',
39010
39011            // Uses `type="button"` so the button's default action can still
39012            // occur but it won't cause things like a form to submit.
39013            template  : '<button type="button" />',
39014            classNames: getClassName('button', 'close')
39015        }
39016    }
39017}, {
39018    ATTRS: {
39019        // TODO: API Docs.
39020        buttons: {
39021            value: ['close']
39022        }
39023    }
39024});
39025
39026
39027}, '3.18.1', {
39028    "requires": [
39029        "widget",
39030        "widget-autohide",
39031        "widget-buttons",
39032        "widget-modality",
39033        "widget-position",
39034        "widget-position-align",
39035        "widget-position-constrain",
39036        "widget-stack",
39037        "widget-stdmod"
39038    ],
39039    "skinnable": true
39040});
39041YUI.add('yui-throttle', function (Y, NAME) {
39042
39043/**
39044Throttles a call to a method based on the time between calls. This method is attached
39045to the `Y` object and is <a href="../classes/YUI.html#method_throttle">documented there</a>.
39046
39047    var fn = Y.throttle(function() {
39048        counter++;
39049    });
39050
39051    for (i; i< 35000; i++) {
39052        out++;
39053        fn();
39054    }
39055
39056
39057@module yui
39058@submodule yui-throttle
39059*/
39060
39061/*! Based on work by Simon Willison: http://gist.github.com/292562 */
39062/**
39063 * Throttles a call to a method based on the time between calls.
39064 * @method throttle
39065 * @for YUI
39066 * @param fn {function} The function call to throttle.
39067 * @param ms {Number} The number of milliseconds to throttle the method call.
39068 * Can set globally with Y.config.throttleTime or by call. Passing a -1 will
39069 * disable the throttle. Defaults to 150.
39070 * @return {function} Returns a wrapped function that calls fn throttled.
39071 * @since 3.1.0
39072 */
39073Y.throttle = function(fn, ms) {
39074    ms = (ms) ? ms : (Y.config.throttleTime || 150);
39075
39076    if (ms === -1) {
39077        return function() {
39078            fn.apply(this, arguments);
39079        };
39080    }
39081
39082    var last = Y.Lang.now();
39083
39084    return function() {
39085        var now = Y.Lang.now();
39086        if (now - last > ms) {
39087            last = now;
39088            fn.apply(this, arguments);
39089        }
39090    };
39091};
39092
39093
39094}, '3.18.1', {"requires": ["yui-base"]});
39095YUI.add('dd-ddm-base', function (Y, NAME) {
39096
39097
39098    /**
39099     * Provides the base Drag Drop Manager required for making a Node draggable.
39100     * @module dd
39101     * @submodule dd-ddm-base
39102     */
39103     /**
39104     * Provides the base Drag Drop Manager required for making a Node draggable.
39105     * @class DDM
39106     * @extends Base
39107     * @constructor
39108     * @namespace DD
39109     */
39110
39111    var DDMBase = function() {
39112        DDMBase.superclass.constructor.apply(this, arguments);
39113    };
39114
39115    DDMBase.NAME = 'ddm';
39116
39117    DDMBase.ATTRS = {
39118        /**
39119        * The cursor to apply when dragging, if shimmed the shim will get the cursor.
39120        * @attribute dragCursor
39121        * @type String
39122        */
39123        dragCursor: {
39124            value: 'move'
39125        },
39126        /**
39127        * The number of pixels to move to start a drag operation, default is 3.
39128        * @attribute clickPixelThresh
39129        * @type Number
39130        */
39131        clickPixelThresh: {
39132            value: 3
39133        },
39134        /**
39135        * The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
39136        * @attribute clickTimeThresh
39137        * @type Number
39138        */
39139        clickTimeThresh: {
39140            value: 1000
39141        },
39142        /**
39143        * The number of milliseconds to throttle the mousemove event. Default: 150
39144        * @attribute throttleTime
39145        * @type Number
39146        */
39147        throttleTime: {
39148            //value: 150
39149            value: -1
39150        },
39151        /**
39152        * This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances.
39153        * @attribute dragMode
39154        * @type String
39155        */
39156        dragMode: {
39157            value: 'point',
39158            setter: function(mode) {
39159                this._setDragMode(mode);
39160                return mode;
39161            }
39162        }
39163
39164    };
39165
39166    Y.extend(DDMBase, Y.Base, {
39167        _createPG: function() {},
39168        /**
39169        * flag set when we activate our first drag, so DDM can start listening for events.
39170        * @property _active
39171        * @type {Boolean}
39172        */
39173        _active: null,
39174        /**
39175        * Handler for dragMode attribute setter.
39176        * @private
39177        * @method _setDragMode
39178        * @param {String|Number} mode The Number value or the String for the DragMode to default all future drag instances to.
39179        * @return Number The Mode to be set
39180        */
39181        _setDragMode: function(mode) {
39182            if (mode === null) {
39183                mode = Y.DD.DDM.get('dragMode');
39184            }
39185            switch (mode) {
39186                case 1:
39187                case 'intersect':
39188                    return 1;
39189                case 2:
39190                case 'strict':
39191                    return 2;
39192                case 0:
39193                case 'point':
39194                    return 0;
39195            }
39196            return 0;
39197        },
39198        /**
39199        * The PREFIX to attach to all DD CSS class names
39200        * @property CSS_PREFIX
39201        * @type {String}
39202        */
39203        CSS_PREFIX: Y.ClassNameManager.getClassName('dd'),
39204        _activateTargets: function() {},
39205        /**
39206        * Holder for all registered drag elements.
39207        * @private
39208        * @property _drags
39209        * @type {Array}
39210        */
39211        _drags: [],
39212        /**
39213        * A reference to the currently active draggable object.
39214        * @property activeDrag
39215        * @type {Drag}
39216        */
39217        activeDrag: false,
39218        /**
39219        * Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag.
39220        * @private
39221        * @method _regDrag
39222        * @param {Drag} d The Drag object
39223        */
39224        _regDrag: function(d) {
39225            if (this.getDrag(d.get('node'))) {
39226                return false;
39227            }
39228
39229            if (!this._active) {
39230                this._setupListeners();
39231            }
39232            this._drags.push(d);
39233            return true;
39234        },
39235        /**
39236        * Remove this drag object from the DDM._drags array.
39237        * @private
39238        * @method _unregDrag
39239        * @param {Drag} d The drag object.
39240        */
39241        _unregDrag: function(d) {
39242            var tmp = [];
39243            Y.Array.each(this._drags, function(n) {
39244                if (n !== d) {
39245                    tmp[tmp.length] = n;
39246                }
39247            });
39248            this._drags = tmp;
39249        },
39250        /**
39251        * Add the document listeners.
39252        * @private
39253        * @method _setupListeners
39254        */
39255        _setupListeners: function() {
39256            this._createPG();
39257            this._active = true;
39258
39259            var doc = Y.one(Y.config.doc);
39260            doc.on('mousemove', Y.throttle(Y.bind(this._docMove, this), this.get('throttleTime')));
39261            doc.on('mouseup', Y.bind(this._end, this));
39262        },
39263        /**
39264        * Internal method used by Drag to signal the start of a drag operation
39265        * @private
39266        * @method _start
39267        */
39268        _start: function() {
39269            this.fire('ddm:start');
39270            this._startDrag();
39271        },
39272        /**
39273        * Factory method to be overwritten by other DDM's
39274        * @private
39275        * @method _startDrag
39276        * @param {Number} x The x position of the drag element
39277        * @param {Number} y The y position of the drag element
39278        * @param {Number} w The width of the drag element
39279        * @param {Number} h The height of the drag element
39280        */
39281        _startDrag: function() {},
39282        /**
39283        * Factory method to be overwritten by other DDM's
39284        * @private
39285        * @method _endDrag
39286        */
39287        _endDrag: function() {},
39288        _dropMove: function() {},
39289        /**
39290        * Internal method used by Drag to signal the end of a drag operation
39291        * @private
39292        * @method _end
39293        */
39294        _end: function() {
39295            if (this.activeDrag) {
39296                this._shimming = false;
39297                this._endDrag();
39298                this.fire('ddm:end');
39299                this.activeDrag.end.call(this.activeDrag);
39300                this.activeDrag = null;
39301            }
39302        },
39303        /**
39304        * Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
39305        * @method stopDrag
39306        * @chainable
39307        */
39308        stopDrag: function() {
39309            if (this.activeDrag) {
39310                this._end();
39311            }
39312            return this;
39313        },
39314        /**
39315        * Set to true when drag starts and useShim is true. Used in pairing with _docMove
39316        * @private
39317        * @property _shimming
39318        * @see _docMove
39319        * @type {Boolean}
39320        */
39321        _shimming: false,
39322        /**
39323        * Internal listener for the mousemove on Document. Checks if the shim is in place to only call _move once per mouse move
39324        * @private
39325        * @method _docMove
39326        * @param {EventFacade} ev The Dom mousemove Event
39327        */
39328        _docMove: function(ev) {
39329            if (!this._shimming) {
39330                this._move(ev);
39331            }
39332        },
39333        /**
39334        * Internal listener for the mousemove DOM event to pass to the Drag's move method.
39335        * @private
39336        * @method _move
39337        * @param {EventFacade} ev The Dom mousemove Event
39338        */
39339        _move: function(ev) {
39340            if (this.activeDrag) {
39341                this.activeDrag._move.call(this.activeDrag, ev);
39342                this._dropMove();
39343            }
39344        },
39345        /**
39346        * //TODO Private, rename??...
39347        * Helper method to use to set the gutter from the attribute setter.
39348        * CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
39349        * @private
39350        * @method cssSizestoObject
39351        * @param {String} gutter CSS style string for gutter
39352        * @return {Object} The gutter Object Literal.
39353        */
39354        cssSizestoObject: function(gutter) {
39355            var x = gutter.split(' ');
39356
39357            switch (x.length) {
39358                case 1: x[1] = x[2] = x[3] = x[0]; break;
39359                case 2: x[2] = x[0]; x[3] = x[1]; break;
39360                case 3: x[3] = x[1]; break;
39361            }
39362
39363            return {
39364                top   : parseInt(x[0],10),
39365                right : parseInt(x[1],10),
39366                bottom: parseInt(x[2],10),
39367                left  : parseInt(x[3],10)
39368            };
39369        },
39370        /**
39371        * Get a valid Drag instance back from a Node or a selector string, false otherwise
39372        * @method getDrag
39373        * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object
39374        * @return {Object}
39375        */
39376        getDrag: function(node) {
39377            var drag = false,
39378                n = Y.one(node);
39379            if (n instanceof Y.Node) {
39380                Y.Array.each(this._drags, function(v) {
39381                    if (n.compareTo(v.get('node'))) {
39382                        drag = v;
39383                    }
39384                });
39385            }
39386            return drag;
39387        },
39388        /**
39389        * Swap the position of 2 nodes based on their CSS positioning.
39390        * @method swapPosition
39391        * @param {Node} n1 The first node to swap
39392        * @param {Node} n2 The first node to swap
39393        * @return {Node}
39394        */
39395        swapPosition: function(n1, n2) {
39396            n1 = Y.DD.DDM.getNode(n1);
39397            n2 = Y.DD.DDM.getNode(n2);
39398            var xy1 = n1.getXY(),
39399                xy2 = n2.getXY();
39400
39401            n1.setXY(xy2);
39402            n2.setXY(xy1);
39403            return n1;
39404        },
39405        /**
39406        * Return a node instance from the given node, selector string or Y.Base extended object.
39407        * @method getNode
39408        * @param {Node/Object/String} n The node to resolve.
39409        * @return {Node}
39410        */
39411        getNode: function(n) {
39412            if (n instanceof Y.Node) {
39413                return n;
39414            }
39415            if (n && n.get) {
39416                if (Y.Widget && (n instanceof Y.Widget)) {
39417                    n = n.get('boundingBox');
39418                } else {
39419                    n = n.get('node');
39420                }
39421            } else {
39422                n = Y.one(n);
39423            }
39424            return n;
39425        },
39426        /**
39427        * Swap the position of 2 nodes based on their DOM location.
39428        * @method swapNode
39429        * @param {Node} n1 The first node to swap
39430        * @param {Node} n2 The first node to swap
39431        * @return {Node}
39432        */
39433        swapNode: function(n1, n2) {
39434            n1 = Y.DD.DDM.getNode(n1);
39435            n2 = Y.DD.DDM.getNode(n2);
39436            var p = n2.get('parentNode'),
39437                s = n2.get('nextSibling');
39438
39439            if (s === n1) {
39440                p.insertBefore(n1, n2);
39441            } else if (n2 === n1.get('nextSibling')) {
39442                p.insertBefore(n2, n1);
39443            } else {
39444                n1.get('parentNode').replaceChild(n2, n1);
39445                p.insertBefore(n1, s);
39446            }
39447            return n1;
39448        }
39449    });
39450
39451    Y.namespace('DD');
39452    Y.DD.DDM = new DDMBase();
39453
39454    /**
39455    * Fires from the DDM before all drag events fire.
39456    * @event ddm:start
39457    * @type {CustomEvent}
39458    */
39459    /**
39460    * Fires from the DDM after the DDM finishes, before the drag end events.
39461    * @event ddm:end
39462    * @type {CustomEvent}
39463    */
39464
39465
39466
39467
39468}, '3.18.1', {"requires": ["node", "base", "yui-throttle", "classnamemanager"]});
39469YUI.add('dd-drag', function (Y, NAME) {
39470
39471
39472    /**
39473     * Provides the ability to drag a Node.
39474     * @module dd
39475     * @submodule dd-drag
39476     */
39477    /**
39478     * Provides the ability to drag a Node.
39479     * @class Drag
39480     * @extends Base
39481     * @constructor
39482     * @namespace DD
39483     */
39484
39485    var DDM = Y.DD.DDM,
39486        NODE = 'node',
39487        DRAGGING = 'dragging',
39488        DRAG_NODE = 'dragNode',
39489        OFFSET_HEIGHT = 'offsetHeight',
39490        OFFSET_WIDTH = 'offsetWidth',
39491        /**
39492        * Handles the mouseup DOM event, does nothing internally just fires.
39493        * @event drag:mouseup
39494        * @bubbles DDM
39495        * @type {CustomEvent}
39496        */
39497        /**
39498        * Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
39499        * @event drag:mouseDown
39500        * @preventable _defMouseDownFn
39501        * @param {EventFacade} event An Event Facade object with the following specific property added:
39502        * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
39503        * @bubbles DDM
39504        * @type {CustomEvent}
39505        */
39506        EV_MOUSE_DOWN = 'drag:mouseDown',
39507        /**
39508        * Fires after the mousedown event has been cleared.
39509        * @event drag:afterMouseDown
39510        * @param {EventFacade} event An Event Facade object with the following specific property added:
39511        * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
39512        * @bubbles DDM
39513        * @type {CustomEvent}
39514        */
39515        EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
39516        /**
39517        * Fires after a handle is removed.
39518        * @event drag:removeHandle
39519        * @param {EventFacade} event An Event Facade object with the following specific property added:
39520        * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
39521        * @bubbles DDM
39522        * @type {CustomEvent}
39523        */
39524        EV_REMOVE_HANDLE = 'drag:removeHandle',
39525        /**
39526        * Fires after a handle is added.
39527        * @event drag:addHandle
39528        * @param {EventFacade} event An Event Facade object with the following specific property added:
39529        * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
39530        * @bubbles DDM
39531        * @type {CustomEvent}
39532        */
39533        EV_ADD_HANDLE = 'drag:addHandle',
39534        /**
39535        * Fires after an invalid selector is removed.
39536        * @event drag:removeInvalid
39537        * @param {EventFacade} event An Event Facade object with the following specific property added:
39538        * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
39539        * @bubbles DDM
39540        * @type {CustomEvent}
39541        */
39542        EV_REMOVE_INVALID = 'drag:removeInvalid',
39543        /**
39544        * Fires after an invalid selector is added.
39545        * @event drag:addInvalid
39546        * @param {EventFacade} event An Event Facade object with the following specific property added:
39547        * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
39548        * @bubbles DDM
39549        * @type {CustomEvent}
39550        */
39551        EV_ADD_INVALID = 'drag:addInvalid',
39552        /**
39553        * Fires at the start of a drag operation.
39554        * @event drag:start
39555        * @param {EventFacade} event An Event Facade object with the following specific property added:
39556        * <dl>
39557        * <dt>pageX</dt><dd>The original node position X.</dd>
39558        * <dt>pageY</dt><dd>The original node position Y.</dd>
39559        * <dt>startTime</dt><dd>The startTime of the event. getTime on the current Date object.</dd>
39560        * </dl>
39561        * @bubbles DDM
39562        * @type {CustomEvent}
39563        */
39564        EV_START = 'drag:start',
39565        /**
39566        * Fires at the end of a drag operation.
39567        * @event drag:end
39568        * @param {EventFacade} event An Event Facade object with the following specific property added:
39569        * <dl>
39570        * <dt>pageX</dt><dd>The current node position X.</dd>
39571        * <dt>pageY</dt><dd>The current node position Y.</dd>
39572        * <dt>startTime</dt><dd>The startTime of the event, from the start event.</dd>
39573        * <dt>endTime</dt><dd>The endTime of the event. getTime on the current Date object.</dd>
39574        * </dl>
39575        * @bubbles DDM
39576        * @type {CustomEvent}
39577        */
39578        EV_END = 'drag:end',
39579        /**
39580        * Fires every mousemove during a drag operation.
39581        * @event drag:drag
39582        * @param {EventFacade} event An Event Facade object with the following specific property added:
39583        * <dl>
39584        * <dt>pageX</dt><dd>The current node position X.</dd>
39585        * <dt>pageY</dt><dd>The current node position Y.</dd>
39586        * <dt>scroll</dt><dd>Should a scroll action occur.</dd>
39587        * <dt>info</dt><dd>Object hash containing calculated XY arrays: start, xy, delta, offset</dd>
39588        * </dl>
39589        * @bubbles DDM
39590        * @type {CustomEvent}
39591        */
39592        EV_DRAG = 'drag:drag',
39593        /**
39594        * Fires when this node is aligned.
39595        * @event drag:align
39596        * @preventable _defAlignFn
39597        * @param {EventFacade} event An Event Facade object with the following specific property added:
39598        * <dl>
39599        * <dt>pageX</dt><dd>The current node position X.</dd>
39600        * <dt>pageY</dt><dd>The current node position Y.</dd>
39601        * </dl>
39602        * @bubbles DDM
39603        * @type {CustomEvent}
39604        */
39605        EV_ALIGN = 'drag:align',
39606        /**
39607        * Fires when this node is over a Drop Target. (Fired from dd-drop)
39608        * @event drag:over
39609        * @param {EventFacade} event An Event Facade object with the following specific property added:
39610        * <dl>
39611        * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
39612        * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
39613        * </dl>
39614        * @bubbles DDM
39615        * @type {CustomEvent}
39616        */
39617        /**
39618        * Fires when this node enters a Drop Target. (Fired from dd-drop)
39619        * @event drag:enter
39620        * @param {EventFacade} event An Event Facade object with the following specific property added:
39621        * <dl>
39622        * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
39623        * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
39624        * </dl>
39625        * @bubbles DDM
39626        * @type {CustomEvent}
39627        */
39628        /**
39629        * Fires when this node exits a Drop Target. (Fired from dd-drop)
39630        * @event drag:exit
39631        * @param {EventFacade} event An Event Facade object with the following specific property added:
39632        * <dl>
39633        * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
39634        * </dl>
39635        * @bubbles DDM
39636        * @type {CustomEvent}
39637        */
39638        /**
39639        * Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
39640        * @event drag:drophit
39641        * @param {EventFacade} event An Event Facade object with the following specific property added:
39642        * <dl>
39643        * <dt>drop</dt><dd>The best guess on what was dropped on.</dd>
39644        * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
39645        * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd>
39646        * </dl>
39647        * @bubbles DDM
39648        * @type {CustomEvent}
39649        */
39650        /**
39651        * Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
39652        * @event drag:dropmiss
39653        * @param {EventFacade} event An Event Facade object with the following specific property added:
39654        * <dl>
39655        * <dt>pageX</dt><dd>The current node position X.</dd>
39656        * <dt>pageY</dt><dd>The current node position Y.</dd>
39657        * </dl>
39658        * @bubbles DDM
39659        * @type {CustomEvent}
39660        */
39661
39662    Drag = function(o) {
39663        this._lazyAddAttrs = false;
39664        Drag.superclass.constructor.apply(this, arguments);
39665
39666        var valid = DDM._regDrag(this);
39667        if (!valid) {
39668            Y.error('Failed to register node, already in use: ' + o.node);
39669        }
39670    };
39671
39672    Drag.NAME = 'drag';
39673
39674    /**
39675    * This property defaults to "mousedown", but when drag-gestures is loaded, it is changed to "gesturemovestart"
39676    * @static
39677    * @property START_EVENT
39678    */
39679    Drag.START_EVENT = 'mousedown';
39680
39681    Drag.ATTRS = {
39682        /**
39683        * Y.Node instance to use as the element to initiate a drag operation
39684        * @attribute node
39685        * @type Node
39686        */
39687        node: {
39688            setter: function(node) {
39689                if (this._canDrag(node)) {
39690                    return node;
39691                }
39692                var n = Y.one(node);
39693                if (!n) {
39694                    Y.error('DD.Drag: Invalid Node Given: ' + node);
39695                }
39696                return n;
39697            }
39698        },
39699        /**
39700        * Y.Node instance to use as the draggable element, defaults to node
39701        * @attribute dragNode
39702        * @type Node
39703        */
39704        dragNode: {
39705            setter: function(node) {
39706                if (this._canDrag(node)) {
39707                    return node;
39708                }
39709                var n = Y.one(node);
39710                if (!n) {
39711                    Y.error('DD.Drag: Invalid dragNode Given: ' + node);
39712                }
39713                return n;
39714            }
39715        },
39716        /**
39717        * Offset the drag element by the difference in cursor position: default true
39718        * @attribute offsetNode
39719        * @type Boolean
39720        */
39721        offsetNode: {
39722            value: true
39723        },
39724        /**
39725        * Center the dragNode to the mouse position on drag:start: default false
39726        * @attribute startCentered
39727        * @type Boolean
39728        */
39729        startCentered: {
39730            value: false
39731        },
39732        /**
39733        * The number of pixels to move to start a drag operation, default is 3.
39734        * @attribute clickPixelThresh
39735        * @type Number
39736        */
39737        clickPixelThresh: {
39738            value: DDM.get('clickPixelThresh')
39739        },
39740        /**
39741        * The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
39742        * @attribute clickTimeThresh
39743        * @type Number
39744        */
39745        clickTimeThresh: {
39746            value: DDM.get('clickTimeThresh')
39747        },
39748        /**
39749        * Set to lock this drag element so that it can't be dragged: default false.
39750        * @attribute lock
39751        * @type Boolean
39752        */
39753        lock: {
39754            value: false,
39755            setter: function(lock) {
39756                if (lock) {
39757                    this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
39758                } else {
39759                    this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
39760                }
39761                return lock;
39762            }
39763        },
39764        /**
39765        * A payload holder to store arbitrary data about this drag object, can be used to store any value.
39766        * @attribute data
39767        * @type Mixed
39768        */
39769        data: {
39770            value: false
39771        },
39772        /**
39773        * If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
39774        * @attribute move
39775        * @type Boolean
39776        */
39777        move: {
39778            value: true
39779        },
39780        /**
39781        * Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
39782        * @attribute useShim
39783        * @type Boolean
39784        */
39785        useShim: {
39786            value: true
39787        },
39788        /**
39789        * Config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
39790        * @attribute activeHandle
39791        * @type Node
39792        */
39793        activeHandle: {
39794            value: false
39795        },
39796        /**
39797        * By default a drag operation will only begin if the mousedown occurred with the primary mouse button.
39798        * Setting this to false will allow for all mousedown events to trigger a drag.
39799        * @attribute primaryButtonOnly
39800        * @type Boolean
39801        */
39802        primaryButtonOnly: {
39803            value: true
39804        },
39805        /**
39806        * This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
39807        * @attribute dragging
39808        * @type Boolean
39809        */
39810        dragging: {
39811            value: false
39812        },
39813        parent: {
39814            value: false
39815        },
39816        /**
39817        * This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
39818        * @attribute target
39819        * @type Boolean
39820        */
39821        target: {
39822            value: false,
39823            setter: function(config) {
39824                this._handleTarget(config);
39825                return config;
39826            }
39827        },
39828        /**
39829        * This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
39830        * @attribute dragMode
39831        * @type String
39832        */
39833        dragMode: {
39834            value: null,
39835            setter: function(mode) {
39836                return DDM._setDragMode(mode);
39837            }
39838        },
39839        /**
39840        * Array of groups to add this drag into.
39841        * @attribute groups
39842        * @type Array
39843        */
39844        groups: {
39845            value: ['default'],
39846            getter: function() {
39847                if (!this._groups) {
39848                    this._groups = {};
39849                    return [];
39850                }
39851
39852                return Y.Object.keys(this._groups);
39853            },
39854            setter: function(g) {
39855                this._groups = Y.Array.hash(g);
39856                return g;
39857            }
39858        },
39859        /**
39860        * Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
39861        * @attribute handles
39862        * @type Array
39863        */
39864        handles: {
39865            value: null,
39866            setter: function(g) {
39867                if (g) {
39868                    this._handles = {};
39869                    Y.Array.each(g, function(v) {
39870                        var key = v;
39871                        if (v instanceof Y.Node || v instanceof Y.NodeList) {
39872                            key = v._yuid;
39873                        }
39874                        this._handles[key] = v;
39875                    }, this);
39876                } else {
39877                    this._handles = null;
39878                }
39879                return g;
39880            }
39881        },
39882        /**
39883        * Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config
39884        * @deprecated
39885        * @attribute bubbles
39886        * @type Object
39887        */
39888        bubbles: {
39889            setter: function(t) {
39890                this.addTarget(t);
39891                return t;
39892            }
39893        },
39894        /**
39895        * Should the mousedown event be halted. Default: true
39896        * @attribute haltDown
39897        * @type Boolean
39898        */
39899        haltDown: {
39900            value: true
39901        }
39902    };
39903
39904    Y.extend(Drag, Y.Base, {
39905        /**
39906        * Checks the object for the methods needed to drag the object around.
39907        * Normally this would be a node instance, but in the case of Graphics, it
39908        * may be an SVG node or something similar.
39909        * @method _canDrag
39910        * @private
39911        * @param {Object} n The object to check
39912        * @return {Boolean} True or false if the Object contains the methods needed to Drag
39913        */
39914        _canDrag: function(n) {
39915            if (n && n.setXY && n.getXY && n.test && n.contains) {
39916                return true;
39917            }
39918            return false;
39919        },
39920        /**
39921        * The default bubbleTarget for this object. Default: Y.DD.DDM
39922        * @private
39923        * @property _bubbleTargets
39924        */
39925        _bubbleTargets: Y.DD.DDM,
39926        /**
39927        * Add this Drag instance to a group, this should be used for on-the-fly group additions.
39928        * @method addToGroup
39929        * @param {String} g The group to add this Drag Instance to.
39930        * @chainable
39931        */
39932        addToGroup: function(g) {
39933            this._groups[g] = true;
39934            DDM._activateTargets();
39935            return this;
39936        },
39937        /**
39938        * Remove this Drag instance from a group, this should be used for on-the-fly group removals.
39939        * @method removeFromGroup
39940        * @param {String} g The group to remove this Drag Instance from.
39941        * @chainable
39942        */
39943        removeFromGroup: function(g) {
39944            delete this._groups[g];
39945            DDM._activateTargets();
39946            return this;
39947        },
39948        /**
39949        * This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
39950        * @property target
39951        * @type {Object}
39952        */
39953        target: null,
39954        /**
39955        * Attribute handler for the target config attribute.
39956        * @private
39957        * @method _handleTarget
39958        * @param {Boolean/Object} config The Config
39959        */
39960        _handleTarget: function(config) {
39961            if (Y.DD.Drop) {
39962                if (config === false) {
39963                    if (this.target) {
39964                        DDM._unregTarget(this.target);
39965                        this.target = null;
39966                    }
39967                } else {
39968                    if (!Y.Lang.isObject(config)) {
39969                        config = {};
39970                    }
39971                    config.bubbleTargets = config.bubbleTargets || this.getTargets();
39972                    config.node = this.get(NODE);
39973                    config.groups = config.groups || this.get('groups');
39974                    this.target = new Y.DD.Drop(config);
39975                }
39976            }
39977        },
39978        /**
39979        * Storage Array for the groups this drag belongs to.
39980        * @private
39981        * @property _groups
39982        * @type {Array}
39983        */
39984        _groups: null,
39985        /**
39986        * This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
39987        * @private
39988        * @method _createEvents
39989        */
39990        _createEvents: function() {
39991
39992            this.publish(EV_MOUSE_DOWN, {
39993                defaultFn: this._defMouseDownFn,
39994                queuable: false,
39995                emitFacade: true,
39996                bubbles: true,
39997                prefix: 'drag'
39998            });
39999
40000            this.publish(EV_ALIGN, {
40001                defaultFn: this._defAlignFn,
40002                queuable: false,
40003                emitFacade: true,
40004                bubbles: true,
40005                prefix: 'drag'
40006            });
40007
40008            this.publish(EV_DRAG, {
40009                defaultFn: this._defDragFn,
40010                queuable: false,
40011                emitFacade: true,
40012                bubbles: true,
40013                prefix: 'drag'
40014            });
40015
40016            this.publish(EV_END, {
40017                defaultFn: this._defEndFn,
40018                preventedFn: this._prevEndFn,
40019                queuable: false,
40020                emitFacade: true,
40021                bubbles: true,
40022                prefix: 'drag'
40023            });
40024
40025            var ev = [
40026                EV_AFTER_MOUSE_DOWN,
40027                EV_REMOVE_HANDLE,
40028                EV_ADD_HANDLE,
40029                EV_REMOVE_INVALID,
40030                EV_ADD_INVALID,
40031                EV_START,
40032                'drag:drophit',
40033                'drag:dropmiss',
40034                'drag:over',
40035                'drag:enter',
40036                'drag:exit'
40037            ];
40038
40039            Y.Array.each(ev, function(v) {
40040                this.publish(v, {
40041                    type: v,
40042                    emitFacade: true,
40043                    bubbles: true,
40044                    preventable: false,
40045                    queuable: false,
40046                    prefix: 'drag'
40047                });
40048            }, this);
40049        },
40050        /**
40051        * A private reference to the mousedown DOM event
40052        * @private
40053        * @property _ev_md
40054        * @type {EventFacade}
40055        */
40056        _ev_md: null,
40057        /**
40058        * The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
40059        * @private
40060        * @property _startTime
40061        * @type Date
40062        */
40063        _startTime: null,
40064        /**
40065        * The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
40066        * @private
40067        * @property _endTime
40068        * @type Date
40069        */
40070        _endTime: null,
40071        /**
40072        * A private hash of the valid drag handles
40073        * @private
40074        * @property _handles
40075        * @type {Object}
40076        */
40077        _handles: null,
40078        /**
40079        * A private hash of the invalid selector strings
40080        * @private
40081        * @property _invalids
40082        * @type {Object}
40083        */
40084        _invalids: null,
40085        /**
40086        * A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
40087        * @private
40088        * @property _invalidsDefault
40089        * @type {Object}
40090        */
40091        _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
40092        /**
40093        * Private flag to see if the drag threshhold was met
40094        * @private
40095        * @property _dragThreshMet
40096        * @type {Boolean}
40097        */
40098        _dragThreshMet: null,
40099        /**
40100        * Flag to determine if the drag operation came from a timeout
40101        * @private
40102        * @property _fromTimeout
40103        * @type {Boolean}
40104        */
40105        _fromTimeout: null,
40106        /**
40107        * Holder for the setTimeout call
40108        * @private
40109        * @property _clickTimeout
40110        * @type {Boolean}
40111        */
40112        _clickTimeout: null,
40113        /**
40114        * The offset of the mouse position to the element's position
40115        * @property deltaXY
40116        * @type {Array}
40117        */
40118        deltaXY: null,
40119        /**
40120        * The initial mouse position
40121        * @property startXY
40122        * @type {Array}
40123        */
40124        startXY: null,
40125        /**
40126        * The initial element position
40127        * @property nodeXY
40128        * @type {Array}
40129        */
40130        nodeXY: null,
40131        /**
40132        * The position of the element as it's moving (for offset calculations)
40133        * @property lastXY
40134        * @type {Array}
40135        */
40136        lastXY: null,
40137        /**
40138        * The xy that the node will be set to. Changing this will alter the position as it's dragged.
40139        * @property actXY
40140        * @type {Array}
40141        */
40142        actXY: null,
40143        /**
40144        * The real xy position of the node.
40145        * @property realXY
40146        * @type {Array}
40147        */
40148        realXY: null,
40149        /**
40150        * The XY coords of the mousemove
40151        * @property mouseXY
40152        * @type {Array}
40153        */
40154        mouseXY: null,
40155        /**
40156        * A region object associated with this drag, used for checking regions while dragging.
40157        * @property region
40158        * @type Object
40159        */
40160        region: null,
40161        /**
40162        * Handler for the mouseup DOM event
40163        * @private
40164        * @method _handleMouseUp
40165        * @param {EventFacade} ev The Event
40166        */
40167        _handleMouseUp: function() {
40168            this.fire('drag:mouseup');
40169            this._fixIEMouseUp();
40170            if (DDM.activeDrag) {
40171                DDM._end();
40172            }
40173        },
40174        /**
40175        * The function we use as the ondragstart handler when we start a drag
40176        * in Internet Explorer. This keeps IE from blowing up on images as drag handles.
40177        * @private
40178        * @method _fixDragStart
40179        * @param {Event} e The Event
40180        */
40181        _fixDragStart: function(e) {
40182            if (this.validClick(e)) {
40183                e.preventDefault();
40184            }
40185        },
40186        /**
40187        * The function we use as the onselectstart handler when we start a drag in Internet Explorer
40188        * @private
40189        * @method _ieSelectFix
40190        */
40191        _ieSelectFix: function() {
40192            return false;
40193        },
40194        /**
40195        * We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
40196        * @private
40197        * @property _ieSelectBack
40198        */
40199        _ieSelectBack: null,
40200        /**
40201        * This method copies the onselectstart listner on the document to the _ieSelectFix property
40202        * @private
40203        * @method _fixIEMouseDown
40204        */
40205        _fixIEMouseDown: function() {
40206            if (Y.UA.ie) {
40207                this._ieSelectBack = Y.config.doc.body.onselectstart;
40208                Y.config.doc.body.onselectstart = this._ieSelectFix;
40209            }
40210        },
40211        /**
40212        * This method copies the _ieSelectFix property back to the onselectstart listner on the document.
40213        * @private
40214        * @method _fixIEMouseUp
40215        */
40216        _fixIEMouseUp: function() {
40217            if (Y.UA.ie) {
40218                Y.config.doc.body.onselectstart = this._ieSelectBack;
40219            }
40220        },
40221        /**
40222        * Handler for the mousedown DOM event
40223        * @private
40224        * @method _handleMouseDownEvent
40225        * @param {EventFacade} ev  The Event
40226        */
40227        _handleMouseDownEvent: function(ev) {
40228            if (this.validClick(ev)) {
40229                ev.preventDefault();
40230            }
40231            this.fire(EV_MOUSE_DOWN, { ev: ev });
40232        },
40233        /**
40234        * Handler for the mousedown DOM event
40235        * @private
40236        * @method _defMouseDownFn
40237        * @param {EventFacade} e  The Event
40238        */
40239        _defMouseDownFn: function(e) {
40240            var ev = e.ev;
40241
40242            this._dragThreshMet = false;
40243            this._ev_md = ev;
40244
40245            if (this.get('primaryButtonOnly') && ev.button > 1) {
40246                return false;
40247            }
40248            if (this.validClick(ev)) {
40249                this._fixIEMouseDown(ev);
40250                if (Drag.START_EVENT.indexOf('gesture') !== 0) {
40251                    //Only do these if it's not a gesture
40252                    if (this.get('haltDown')) {
40253                        ev.halt();
40254                    } else {
40255                        ev.preventDefault();
40256                    }
40257                }
40258
40259                this._setStartPosition([ev.pageX, ev.pageY]);
40260
40261                DDM.activeDrag = this;
40262
40263                this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
40264            }
40265            this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
40266        },
40267        /**
40268        * Method first checks to see if we have handles, if so it validates the click
40269        * against the handle. Then if it finds a valid handle, it checks it against
40270        * the invalid handles list. Returns true if a good handle was used, false otherwise.
40271        * @method validClick
40272        * @param {EventFacade} ev  The Event
40273        * @return {Boolean}
40274        */
40275        validClick: function(ev) {
40276            var r = false, n = false,
40277            tar = ev.target,
40278            hTest = null,
40279            els = null,
40280            nlist = null,
40281            set = false;
40282            if (this._handles) {
40283                Y.Object.each(this._handles, function(i, n) {
40284                    if (i instanceof Y.Node || i instanceof Y.NodeList) {
40285                        if (!r) {
40286                            nlist = i;
40287                            if (nlist instanceof Y.Node) {
40288                                nlist = new Y.NodeList(i._node);
40289                            }
40290                            nlist.each(function(nl) {
40291                                if (nl.contains(tar)) {
40292                                    r = true;
40293                                }
40294                            });
40295                        }
40296                    } else if (Y.Lang.isString(n)) {
40297                        //Am I this or am I inside this
40298                        if (tar.test(n + ', ' + n + ' *') && !hTest) {
40299                            hTest = n;
40300                            r = true;
40301                        }
40302                    }
40303                });
40304            } else {
40305                n = this.get(NODE);
40306                if (n.contains(tar) || n.compareTo(tar)) {
40307                    r = true;
40308                }
40309            }
40310            if (r) {
40311                if (this._invalids) {
40312                    Y.Object.each(this._invalids, function(i, n) {
40313                        if (Y.Lang.isString(n)) {
40314                            //Am I this or am I inside this
40315                            if (tar.test(n + ', ' + n + ' *')) {
40316                                r = false;
40317                            }
40318                        }
40319                    });
40320                }
40321            }
40322            if (r) {
40323                if (hTest) {
40324                    els = ev.currentTarget.all(hTest);
40325                    set = false;
40326                    els.each(function(n) {
40327                        if ((n.contains(tar) || n.compareTo(tar)) && !set) {
40328                            set = true;
40329                            this.set('activeHandle', n);
40330                        }
40331                    }, this);
40332                } else {
40333                    this.set('activeHandle', this.get(NODE));
40334                }
40335            }
40336            return r;
40337        },
40338        /**
40339        * Sets the current position of the Element and calculates the offset
40340        * @private
40341        * @method _setStartPosition
40342        * @param {Array} xy The XY coords to set the position to.
40343        */
40344        _setStartPosition: function(xy) {
40345            this.startXY = xy;
40346
40347            this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
40348
40349            if (this.get('offsetNode')) {
40350                this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
40351            } else {
40352                this.deltaXY = [0, 0];
40353            }
40354        },
40355        /**
40356        * The method passed to setTimeout to determine if the clickTimeThreshold was met.
40357        * @private
40358        * @method _timeoutCheck
40359        */
40360        _timeoutCheck: function() {
40361            if (!this.get('lock') && !this._dragThreshMet && this._ev_md) {
40362                this._fromTimeout = this._dragThreshMet = true;
40363                this.start();
40364                this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
40365            }
40366        },
40367        /**
40368        * Remove a Selector added by addHandle
40369        * @method removeHandle
40370        * @param {String} str The selector for the handle to be removed.
40371        * @chainable
40372        */
40373        removeHandle: function(str) {
40374            var key = str;
40375            if (str instanceof Y.Node || str instanceof Y.NodeList) {
40376                key = str._yuid;
40377            }
40378            if (this._handles[key]) {
40379                delete this._handles[key];
40380                this.fire(EV_REMOVE_HANDLE, { handle: str });
40381            }
40382            return this;
40383        },
40384        /**
40385        * Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
40386        * @method addHandle
40387        * @param {String} str The selector to test for a valid handle. Must be a child of the element.
40388        * @chainable
40389        */
40390        addHandle: function(str) {
40391            if (!this._handles) {
40392                this._handles = {};
40393            }
40394            var key = str;
40395            if (str instanceof Y.Node || str instanceof Y.NodeList) {
40396                key = str._yuid;
40397            }
40398            this._handles[key] = str;
40399            this.fire(EV_ADD_HANDLE, { handle: str });
40400            return this;
40401        },
40402        /**
40403        * Remove an invalid handle added by addInvalid
40404        * @method removeInvalid
40405        * @param {String} str The invalid handle to remove from the internal list.
40406        * @chainable
40407        */
40408        removeInvalid: function(str) {
40409            if (this._invalids[str]) {
40410                this._invalids[str] = null;
40411                delete this._invalids[str];
40412                this.fire(EV_REMOVE_INVALID, { handle: str });
40413            }
40414            return this;
40415        },
40416        /**
40417        * Add a selector string to test the handle against. If the test passes the drag operation will not continue.
40418        * @method addInvalid
40419        * @param {String} str The selector to test against to determine if this is an invalid drag handle.
40420        * @chainable
40421        */
40422        addInvalid: function(str) {
40423            if (Y.Lang.isString(str)) {
40424                this._invalids[str] = true;
40425                this.fire(EV_ADD_INVALID, { handle: str });
40426            }
40427            return this;
40428        },
40429        /**
40430        * Internal init handler
40431        * @private
40432        * @method initializer
40433        */
40434        initializer: function() {
40435
40436            this.get(NODE).dd = this;
40437
40438            if (!this.get(NODE).get('id')) {
40439                var id = Y.stamp(this.get(NODE));
40440                this.get(NODE).set('id', id);
40441            }
40442
40443            this.actXY = [];
40444
40445            this._invalids = Y.clone(this._invalidsDefault, true);
40446
40447            this._createEvents();
40448
40449            if (!this.get(DRAG_NODE)) {
40450                this.set(DRAG_NODE, this.get(NODE));
40451            }
40452
40453            //Fix for #2528096
40454            //Don't prep the DD instance until all plugins are loaded.
40455            this.on('initializedChange', Y.bind(this._prep, this));
40456
40457            //Shouldn't have to do this..
40458            this.set('groups', this.get('groups'));
40459        },
40460        /**
40461        * Attach event listners and add classname
40462        * @private
40463        * @method _prep
40464        */
40465        _prep: function() {
40466            this._dragThreshMet = false;
40467            var node = this.get(NODE);
40468            node.addClass(DDM.CSS_PREFIX + '-draggable');
40469            node.on(Drag.START_EVENT, Y.bind(this._handleMouseDownEvent, this));
40470            node.on('mouseup', Y.bind(this._handleMouseUp, this));
40471            node.on('dragstart', Y.bind(this._fixDragStart, this));
40472        },
40473        /**
40474        * Detach event listeners and remove classname
40475        * @private
40476        * @method _unprep
40477        */
40478        _unprep: function() {
40479            var node = this.get(NODE);
40480            node.removeClass(DDM.CSS_PREFIX + '-draggable');
40481            node.detachAll('mouseup');
40482            node.detachAll('dragstart');
40483            node.detachAll(Drag.START_EVENT);
40484            this.mouseXY = [];
40485            this.deltaXY = [0,0];
40486            this.startXY = [];
40487            this.nodeXY = [];
40488            this.lastXY = [];
40489            this.actXY = [];
40490            this.realXY = [];
40491        },
40492        /**
40493        * Starts the drag operation
40494        * @method start
40495        * @chainable
40496        */
40497        start: function() {
40498            if (!this.get('lock') && !this.get(DRAGGING)) {
40499                var node = this.get(NODE), ow, oh, xy;
40500                this._startTime = (new Date()).getTime();
40501
40502                DDM._start();
40503                node.addClass(DDM.CSS_PREFIX + '-dragging');
40504                this.fire(EV_START, {
40505                    pageX: this.nodeXY[0],
40506                    pageY: this.nodeXY[1],
40507                    startTime: this._startTime
40508                });
40509                node = this.get(DRAG_NODE);
40510                xy = this.nodeXY;
40511
40512                ow = node.get(OFFSET_WIDTH);
40513                oh = node.get(OFFSET_HEIGHT);
40514
40515                if (this.get('startCentered')) {
40516                    this._setStartPosition([xy[0] + (ow / 2), xy[1] + (oh / 2)]);
40517                }
40518
40519
40520                this.region = {
40521                    '0': xy[0],
40522                    '1': xy[1],
40523                    area: 0,
40524                    top: xy[1],
40525                    right: xy[0] + ow,
40526                    bottom: xy[1] + oh,
40527                    left: xy[0]
40528                };
40529                this.set(DRAGGING, true);
40530            }
40531            return this;
40532        },
40533        /**
40534        * Ends the drag operation
40535        * @method end
40536        * @chainable
40537        */
40538        end: function() {
40539            this._endTime = (new Date()).getTime();
40540            if (this._clickTimeout) {
40541                this._clickTimeout.cancel();
40542            }
40543            this._dragThreshMet = this._fromTimeout = false;
40544
40545            if (!this.get('lock') && this.get(DRAGGING)) {
40546                this.fire(EV_END, {
40547                    pageX: this.lastXY[0],
40548                    pageY: this.lastXY[1],
40549                    startTime: this._startTime,
40550                    endTime: this._endTime
40551                });
40552            }
40553            this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
40554            this.set(DRAGGING, false);
40555            this.deltaXY = [0, 0];
40556
40557            return this;
40558        },
40559        /**
40560        * Handler for fixing the selection in IE
40561        * @private
40562        * @method _defEndFn
40563        */
40564        _defEndFn: function() {
40565            this._fixIEMouseUp();
40566            this._ev_md = null;
40567        },
40568        /**
40569        * Handler for preventing the drag:end event. It will reset the node back to it's start position
40570        * @private
40571        * @method _prevEndFn
40572        */
40573        _prevEndFn: function() {
40574            this._fixIEMouseUp();
40575            //Bug #1852577
40576            this.get(DRAG_NODE).setXY(this.nodeXY);
40577            this._ev_md = null;
40578            this.region = null;
40579        },
40580        /**
40581        * Calculates the offsets and set's the XY that the element will move to.
40582        * @private
40583        * @method _align
40584        * @param {Array} xy The xy coords to align with.
40585        */
40586        _align: function(xy) {
40587            this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
40588        },
40589        /**
40590        * Calculates the offsets and set's the XY that the element will move to.
40591        * @private
40592        * @method _defAlignFn
40593        * @param {EventFacade} e The drag:align event.
40594        */
40595        _defAlignFn: function(e) {
40596            this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
40597        },
40598        /**
40599        * This method performs the alignment before the element move.
40600        * @private
40601        * @method _alignNode
40602        * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
40603        */
40604        _alignNode: function(eXY, scroll) {
40605            this._align(eXY);
40606            if (!scroll) {
40607                this._moveNode();
40608            }
40609        },
40610        /**
40611        * This method performs the actual element move.
40612        * @private
40613        * @method _moveNode
40614        */
40615        _moveNode: function(scroll) {
40616            //if (!this.get(DRAGGING)) {
40617            //    return;
40618            //}
40619            var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
40620
40621            diffXY[0] = (xy[0] - this.lastXY[0]);
40622            diffXY[1] = (xy[1] - this.lastXY[1]);
40623
40624            diffXY2[0] = (xy[0] - this.nodeXY[0]);
40625            diffXY2[1] = (xy[1] - this.nodeXY[1]);
40626
40627
40628            this.region = {
40629                '0': xy[0],
40630                '1': xy[1],
40631                area: 0,
40632                top: xy[1],
40633                right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
40634                bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
40635                left: xy[0]
40636            };
40637
40638            this.fire(EV_DRAG, {
40639                pageX: xy[0],
40640                pageY: xy[1],
40641                scroll: scroll,
40642                info: {
40643                    start: startXY,
40644                    xy: xy,
40645                    delta: diffXY,
40646                    offset: diffXY2
40647                }
40648            });
40649
40650            this.lastXY = xy;
40651        },
40652        /**
40653        * Default function for drag:drag. Fired from _moveNode.
40654        * @private
40655        * @method _defDragFn
40656        * @param {EventFacade} ev The drag:drag event
40657        */
40658        _defDragFn: function(e) {
40659            if (this.get('move')) {
40660                if (e.scroll && e.scroll.node) {
40661                    var domNode = e.scroll.node.getDOMNode();
40662                    //If it's the window
40663                    if (domNode === Y.config.win) {
40664                        domNode.scrollTo(e.scroll.left, e.scroll.top);
40665                    } else {
40666                        e.scroll.node.set('scrollTop', e.scroll.top);
40667                        e.scroll.node.set('scrollLeft', e.scroll.left);
40668                    }
40669                }
40670                this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
40671                this.realXY = [e.pageX, e.pageY];
40672            }
40673        },
40674        /**
40675        * Fired from DragDropMgr (DDM) on mousemove.
40676        * @private
40677        * @method _move
40678        * @param {EventFacade} ev The mousemove DOM event
40679        */
40680        _move: function(ev) {
40681            if (this.get('lock')) {
40682                return false;
40683            }
40684
40685            this.mouseXY = [ev.pageX, ev.pageY];
40686            if (!this._dragThreshMet) {
40687                var diffX = Math.abs(this.startXY[0] - ev.pageX),
40688                diffY = Math.abs(this.startXY[1] - ev.pageY);
40689                if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
40690                    this._dragThreshMet = true;
40691                    this.start();
40692                    //This only happens on gestures to stop the page from scrolling
40693                    if (ev && ev.preventDefault) {
40694                        ev.preventDefault();
40695                    }
40696                    this._alignNode([ev.pageX, ev.pageY]);
40697                }
40698            } else {
40699                if (this._clickTimeout) {
40700                    this._clickTimeout.cancel();
40701                }
40702                this._alignNode([ev.pageX, ev.pageY]);
40703            }
40704        },
40705        /**
40706        * Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
40707        * @method stopDrag
40708        * @chainable
40709        */
40710        stopDrag: function() {
40711            if (this.get(DRAGGING)) {
40712                DDM._end();
40713            }
40714            return this;
40715        },
40716        /**
40717        * Lifecycle destructor, unreg the drag from the DDM and remove listeners
40718        * @private
40719        * @method destructor
40720        */
40721        destructor: function() {
40722            this._unprep();
40723            if (this.target) {
40724                this.target.destroy();
40725            }
40726            DDM._unregDrag(this);
40727        }
40728    });
40729    Y.namespace('DD');
40730    Y.DD.Drag = Drag;
40731
40732
40733
40734
40735}, '3.18.1', {"requires": ["dd-ddm-base", "selector-css2"]});
40736YUI.add('dd-plugin', function (Y, NAME) {
40737
40738
40739
40740       /**
40741        * Simple Drag plugin that can be attached to a Node or Widget via the plug method.
40742        * @module dd
40743        * @submodule dd-plugin
40744        */
40745       /**
40746        * Simple Drag plugin that can be attached to a Node or Widget via the plug method.
40747        * @class Drag
40748        * @extends DD.Drag
40749        * @constructor
40750        * @namespace Plugin
40751        */
40752        var Drag = function(config) {
40753                if (Y.Widget && config.host instanceof Y.Widget) {
40754                        config.node = config.host.get('boundingBox');
40755                        config.widget = config.host;
40756                } else {
40757                        config.node = config.host;
40758                        config.widget = false;
40759                }
40760                Drag.superclass.constructor.call(this, config);
40761        },
40762
40763        EV_START = 'drag:start',
40764        EV_DRAG = 'drag:drag',
40765        EV_DRAG_END = 'drag:end';
40766
40767        /**
40768        * dd-plugin
40769        * @property NAME
40770        * @type {String}
40771        */
40772        Drag.NAME = "dd-plugin";
40773
40774        /**
40775        * The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd;
40776        * @property NS
40777        * @type {String}
40778        */
40779        Drag.NS = "dd";
40780
40781        Y.extend(Drag, Y.DD.Drag, {
40782
40783                _widgetHandles: null,
40784
40785                /**
40786                * refers to a Y.Widget if its the host, otherwise = false.
40787                *
40788                * @attribute _widget
40789                * @private
40790                */
40791                _widget: undefined,
40792
40793
40794                /**
40795                * refers to the [x,y] coordinate where the drag was stopped last
40796                *
40797                * @attribute _stoppedPosition
40798                * @private
40799                */
40800                _stoppedPosition: undefined,
40801
40802
40803                /**
40804                * Returns true if widget uses widgetPosition, otherwise returns false
40805                *
40806                * @method _usesWidgetPosition
40807                * @private
40808                */
40809                _usesWidgetPosition: function(widget) {
40810                        var r = false;
40811                        if (widget) {
40812                                r = (widget.hasImpl && widget.hasImpl(Y.WidgetPosition)) ? true : false;
40813                        }
40814                        return r;
40815                },
40816                /**
40817                * Attached to the `drag:start` event, it checks if this plugin needs
40818                * to attach or detach listeners for widgets. If `dd-proxy` is plugged
40819                * the default widget positioning should be ignored.
40820                * @method _checkEvents
40821                * @private
40822                */
40823                _checkEvents: function() {
40824                    if (this._widget) {
40825                        //It's a widget
40826                        if (this.proxy) {
40827                            //It's a proxy
40828                            if (this._widgetHandles.length > 0) {
40829                                //Remove Listeners
40830                                this._removeWidgetListeners();
40831                            }
40832                        } else {
40833                            if (this._widgetHandles.length === 0) {
40834                                this._attachWidgetListeners();
40835                            }
40836                        }
40837                    }
40838                },
40839                /**
40840                * Remove the attached widget listeners
40841                * @method _removeWidgetListeners
40842                * @private
40843                */
40844                _removeWidgetListeners: function() {
40845                    Y.Array.each(this._widgetHandles, function(handle) {
40846                        handle.detach();
40847                    });
40848                    this._widgetHandles = [];
40849                },
40850                /**
40851                * If this is a Widget, then attach the positioning listeners
40852                * @method _attachWidgetListeners
40853                * @private
40854                */
40855                _attachWidgetListeners: function() {
40856                        //if this thing is a widget, and it uses widgetposition...
40857                        if (this._usesWidgetPosition(this._widget)) {
40858
40859                               //set the x,y on the widget's ATTRS
40860                               this._widgetHandles.push(this.on(EV_DRAG, this._setWidgetCoords));
40861
40862                               //store the new position that the widget ends up on
40863                               this._widgetHandles.push(this.on(EV_DRAG_END, this._updateStopPosition));
40864                        }
40865                },
40866                /**
40867                * Sets up event listeners on drag events if interacting with a widget
40868                *
40869                * @method initializer
40870                * @protected
40871                */
40872                initializer: function(config) {
40873
40874                        this._widgetHandles = [];
40875
40876                        this._widget = config.widget;
40877
40878                        this.on(EV_START, this._checkEvents); //Always run, don't check
40879
40880                        this._attachWidgetListeners();
40881
40882                },
40883
40884                /**
40885                * Updates x,y or xy attributes on widget based on where the widget is dragged
40886                *
40887                * @method initializer
40888                * @param {EventFacade} e Event Facade
40889                * @private
40890                */
40891                _setWidgetCoords: function(e) {
40892
40893                        //get the last position where the widget was, or get the starting point
40894                        var nodeXY = this._stoppedPosition || e.target.nodeXY,
40895                         realXY = e.target.realXY,
40896
40897                         //amount moved = [(x2 - x1) , (y2 - y1)]
40898                         movedXY = [realXY[0] - nodeXY[0], realXY[1] - nodeXY[1]];
40899
40900                         //if both have changed..
40901                         if (movedXY[0] !== 0 && movedXY[1] !== 0) {
40902                                 this._widget.set('xy', realXY);
40903                         }
40904
40905                         //if only x is 0, set the Y
40906                         else if (movedXY[0] === 0) {
40907                                 this._widget.set('y',realXY[1]);
40908                         }
40909
40910                         //otherwise, y is 0, so set X
40911                         else if (movedXY[1] === 0){
40912                                 this._widget.set('x', realXY[0]);
40913                         }
40914                },
40915
40916                /**
40917                * Updates the last position where the widget was stopped.
40918                *
40919                * @method _updateStopPosition
40920                * @param {EventFacade} e Event Facade
40921                * @private
40922                */
40923                _updateStopPosition: function(e) {
40924                        this._stoppedPosition = e.target.realXY;
40925                }
40926        });
40927
40928        Y.namespace('Plugin');
40929        Y.Plugin.Drag = Drag;
40930
40931
40932
40933
40934
40935}, '3.18.1', {"optional": ["dd-constrain", "dd-proxy"], "requires": ["dd-drag"]});
40936var Y = YUI().use('*');

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.