diff -r 322d0feea350 -r 89ef5ed3c48b src/cm/media/js/lib/yui/yui_3.10.3/build/simpleyui/simpleyui-debug.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.10.3/build/simpleyui/simpleyui-debug.js Tue Jul 16 14:29:46 2013 +0200 @@ -0,0 +1,21632 @@ +/* +YUI 3.10.3 (build 2fb5187) +Copyright 2013 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +/** +The YUI module contains the components required for building the YUI seed file. +This includes the script loading mechanism, a simple queue, and the core +utilities for the library. + +@module yui +@main yui +@submodule yui-base +**/ + +/*jshint eqeqeq: false*/ +if (typeof YUI != 'undefined') { + YUI._YUI = YUI; +} + +/** +The YUI global namespace object. This is the constructor for all YUI instances. + +This is a self-instantiable factory function, meaning you don't need to precede +it with the `new` operator. You can invoke it directly like this: + + YUI().use('*', function (Y) { + // Y is a new YUI instance. + }); + +But it also works like this: + + var Y = YUI(); + +The `YUI` constructor accepts an optional config object, like this: + + YUI({ + debug: true, + combine: false + }).use('node', function (Y) { + // Y.Node is ready to use. + }); + +See the API docs for the Config class for the complete +list of supported configuration properties accepted by the YUI constuctor. + +If a global `YUI` object is already defined, the existing YUI object will not be +overwritten, to ensure that defined namespaces are preserved. + +Each YUI instance has full custom event support, but only if the event system is +available. + +@class YUI +@uses EventTarget +@constructor +@global +@param {Object} [config]* Zero or more optional configuration objects. Config + values are stored in the `Y.config` property. See the + Config docs for the list of supported properties. +**/ + + /*global YUI*/ + /*global YUI_config*/ + var YUI = function() { + var i = 0, + Y = this, + args = arguments, + l = args.length, + instanceOf = function(o, type) { + return (o && o.hasOwnProperty && (o instanceof type)); + }, + gconf = (typeof YUI_config !== 'undefined') && YUI_config; + + if (!(instanceOf(Y, YUI))) { + Y = new YUI(); + } else { + // set up the core environment + Y._init(); + + /** + Master configuration that might span multiple contexts in a non- + browser environment. It is applied first to all instances in all + contexts. + + @example + + YUI.GlobalConfig = { + filter: 'debug' + }; + + YUI().use('node', function (Y) { + // debug files used here + }); + + YUI({ + filter: 'min' + }).use('node', function (Y) { + // min files used here + }); + + @property {Object} GlobalConfig + @global + @static + **/ + if (YUI.GlobalConfig) { + Y.applyConfig(YUI.GlobalConfig); + } + + /** + Page-level config applied to all YUI instances created on the + current page. This is applied after `YUI.GlobalConfig` and before + any instance-level configuration. + + @example + + // Single global var to include before YUI seed file + YUI_config = { + filter: 'debug' + }; + + YUI().use('node', function (Y) { + // debug files used here + }); + + YUI({ + filter: 'min' + }).use('node', function (Y) { + // min files used here + }); + + @property {Object} YUI_config + @global + **/ + if (gconf) { + Y.applyConfig(gconf); + } + + // bind the specified additional modules for this instance + if (!l) { + Y._setup(); + } + } + + if (l) { + // Each instance can accept one or more configuration objects. + // These are applied after YUI.GlobalConfig and YUI_Config, + // overriding values set in those config files if there is a + // matching property. + for (; i < l; i++) { + Y.applyConfig(args[i]); + } + + Y._setup(); + } + + Y.instanceOf = instanceOf; + + return Y; + }; + +(function() { + + var proto, prop, + VERSION = '@VERSION@', + PERIOD = '.', + BASE = 'http://yui.yahooapis.com/', + /* + These CSS class names can't be generated by + getClassName since it is not available at the + time they are being used. + */ + DOC_LABEL = 'yui3-js-enabled', + CSS_STAMP_EL = 'yui3-css-stamp', + NOOP = function() {}, + SLICE = Array.prototype.slice, + APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo + 'io.xdrResponse': 1, // can call. this should + 'SWF.eventHandler': 1 }, // be done at build time + hasWin = (typeof window != 'undefined'), + win = (hasWin) ? window : null, + doc = (hasWin) ? win.document : null, + docEl = doc && doc.documentElement, + docClass = docEl && docEl.className, + instances = {}, + time = new Date().getTime(), + add = function(el, type, fn, capture) { + if (el && el.addEventListener) { + el.addEventListener(type, fn, capture); + } else if (el && el.attachEvent) { + el.attachEvent('on' + type, fn); + } + }, + remove = function(el, type, fn, capture) { + if (el && el.removeEventListener) { + // this can throw an uncaught exception in FF + try { + el.removeEventListener(type, fn, capture); + } catch (ex) {} + } else if (el && el.detachEvent) { + el.detachEvent('on' + type, fn); + } + }, + handleLoad = function() { + YUI.Env.windowLoaded = true; + YUI.Env.DOMReady = true; + if (hasWin) { + remove(window, 'load', handleLoad); + } + }, + getLoader = function(Y, o) { + var loader = Y.Env._loader, + lCore = [ 'loader-base' ], + G_ENV = YUI.Env, + mods = G_ENV.mods; + + if (loader) { + //loader._config(Y.config); + loader.ignoreRegistered = false; + loader.onEnd = null; + loader.data = null; + loader.required = []; + loader.loadType = null; + } else { + loader = new Y.Loader(Y.config); + Y.Env._loader = loader; + } + if (mods && mods.loader) { + lCore = [].concat(lCore, YUI.Env.loaderExtras); + } + YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore)); + + return loader; + }, + + clobber = function(r, s) { + for (var i in s) { + if (s.hasOwnProperty(i)) { + r[i] = s[i]; + } + } + }, + + ALREADY_DONE = { success: true }; + +// Stamp the documentElement (HTML) with a class of "yui-loaded" to +// enable styles that need to key off of JS being enabled. +if (docEl && docClass.indexOf(DOC_LABEL) == -1) { + if (docClass) { + docClass += ' '; + } + docClass += DOC_LABEL; + docEl.className = docClass; +} + +if (VERSION.indexOf('@') > -1) { + VERSION = '3.5.0'; // dev time hack for cdn test +} + +proto = { + /** + Applies a new configuration object to the config of this YUI instance. This + will merge new group/module definitions, and will also update the loader + cache if necessary. Updating `Y.config` directly will not update the cache. + + @method applyConfig + @param {Object} o the configuration object. + @since 3.2.0 + **/ + applyConfig: function(o) { + + o = o || NOOP; + + var attr, + name, + // detail, + config = this.config, + mods = config.modules, + groups = config.groups, + aliases = config.aliases, + loader = this.Env._loader; + + for (name in o) { + if (o.hasOwnProperty(name)) { + attr = o[name]; + if (mods && name == 'modules') { + clobber(mods, attr); + } else if (aliases && name == 'aliases') { + clobber(aliases, attr); + } else if (groups && name == 'groups') { + clobber(groups, attr); + } else if (name == 'win') { + config[name] = (attr && attr.contentWindow) || attr; + config.doc = config[name] ? config[name].document : null; + } else if (name == '_yuid') { + // preserve the guid + } else { + config[name] = attr; + } + } + } + + if (loader) { + loader._config(o); + } + + }, + + /** + Old way to apply a config to this instance (calls `applyConfig` under the + hood). + + @private + @method _config + @param {Object} o The config to apply + **/ + _config: function(o) { + this.applyConfig(o); + }, + + /** + Initializes this YUI instance. + + @private + @method _init + **/ + _init: function() { + var filter, el, + Y = this, + G_ENV = YUI.Env, + Env = Y.Env, + prop; + + /** + The version number of this YUI instance. + + This value is typically updated by a script when a YUI release is built, + so it may not reflect the correct version number when YUI is run from + the development source tree. + + @property {String} version + **/ + Y.version = VERSION; + + if (!Env) { + Y.Env = { + core: ['get', 'features', 'intl-base', 'yui-log', 'yui-later'], + loaderExtras: ['loader-rollup', 'loader-yui3'], + mods: {}, // flat module map + versions: {}, // version module map + base: BASE, + cdn: BASE + VERSION + '/build/', + // bootstrapped: false, + _idx: 0, + _used: {}, + _attached: {}, + _missed: [], + _yidx: 0, + _uidx: 0, + _guidp: 'y', + _loaded: {}, + // serviced: {}, + // Regex in English: + // I'll start at the \b(simpleyui). + // 1. Look in the test string for "simpleyui" or "yui" or + // "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break. That is, it + // can't match "foyui" or "i_heart_simpleyui". This can be anywhere in the string. + // 2. After #1 must come a forward slash followed by the string matched in #1, so + // "yui-base/yui-base" or "simpleyui/simpleyui" or "yui-pants/yui-pants". + // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min", + // so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt". + // 4. This is followed by ".js", so "yui/yui.js", "simpleyui/simpleyui-min.js" + // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string, + // then capture the junk between the LAST "&" and the string in 1-4. So + // "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js" + // will capture "3.3.0/build/" + // + // Regex Exploded: + // (?:\? Find a ? + // (?:[^&]*&) followed by 0..n characters followed by an & + // * in fact, find as many sets of characters followed by a & as you can + // ([^&]*) capture the stuff after the last & in \1 + // )? but it's ok if all this ?junk&more_junk stuff isn't even there + // \b(simpleyui| after a word break find either the string "simpleyui" or + // yui(?:-\w+)? the string "yui" optionally followed by a -, then more characters + // ) and store the simpleyui or yui-* string in \2 + // \/\2 then comes a / followed by the simpleyui or yui-* string in \2 + // (?:-(min|debug))? optionally followed by "-min" or "-debug" + // .js and ending in ".js" + _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(simpleyui|yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/, + parseBasePath: function(src, pattern) { + var match = src.match(pattern), + path, filter; + + if (match) { + path = RegExp.leftContext || src.slice(0, src.indexOf(match[0])); + + // this is to set up the path to the loader. The file + // filter for loader should match the yui include. + filter = match[3]; + + // extract correct path for mixed combo urls + // http://yuilibrary.com/projects/yui3/ticket/2528423 + if (match[1]) { + path += '?' + match[1]; + } + path = { + filter: filter, + path: path + }; + } + return path; + }, + getBase: G_ENV && G_ENV.getBase || + function(pattern) { + var nodes = (doc && doc.getElementsByTagName('script')) || [], + path = Env.cdn, parsed, + i, len, src; + + for (i = 0, len = nodes.length; i < len; ++i) { + src = nodes[i].src; + if (src) { + parsed = Y.Env.parseBasePath(src, pattern); + if (parsed) { + filter = parsed.filter; + path = parsed.path; + break; + } + } + } + + // use CDN default + return path; + } + + }; + + Env = Y.Env; + + Env._loaded[VERSION] = {}; + + if (G_ENV && Y !== YUI) { + Env._yidx = ++G_ENV._yidx; + Env._guidp = ('yui_' + VERSION + '_' + + Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_'); + } else if (YUI._YUI) { + + G_ENV = YUI._YUI.Env; + Env._yidx += G_ENV._yidx; + Env._uidx += G_ENV._uidx; + + for (prop in G_ENV) { + if (!(prop in Env)) { + Env[prop] = G_ENV[prop]; + } + } + + delete YUI._YUI; + } + + Y.id = Y.stamp(Y); + instances[Y.id] = Y; + + } + + Y.constructor = YUI; + + // configuration defaults + Y.config = Y.config || { + bootstrap: true, + cacheUse: true, + debug: true, + doc: doc, + fetchCSS: true, + throwFail: true, + useBrowserConsole: true, + useNativeES5: true, + win: win, + global: Function('return this')() + }; + + //Register the CSS stamp element + if (doc && !doc.getElementById(CSS_STAMP_EL)) { + el = doc.createElement('div'); + el.innerHTML = '
'; + YUI.Env.cssStampEl = el.firstChild; + if (doc.body) { + doc.body.appendChild(YUI.Env.cssStampEl); + } else { + docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild); + } + } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) { + YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL); + } + + Y.config.lang = Y.config.lang || 'en-US'; + + Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE); + + if (!filter || (!('mindebug').indexOf(filter))) { + filter = 'min'; + } + filter = (filter) ? '-' + filter : filter; + Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js'; + + }, + + /** + Finishes the instance setup. Attaches whatever YUI modules were defined + at the time that this instance was created. + + @method _setup + @private + **/ + _setup: function() { + var i, Y = this, + core = [], + mods = YUI.Env.mods, + extras = Y.config.core || [].concat(YUI.Env.core); //Clone it.. + + for (i = 0; i < extras.length; i++) { + if (mods[extras[i]]) { + core.push(extras[i]); + } + } + + Y._attach(['yui-base']); + Y._attach(core); + + if (Y.Loader) { + getLoader(Y); + } + + // Y.log(Y.id + ' initialized', 'info', 'yui'); + }, + + /** + Executes the named method on the specified YUI instance if that method is + whitelisted. + + @method applyTo + @param {String} id YUI instance id. + @param {String} method Name of the method to execute. For example: + 'Object.keys'. + @param {Array} args Arguments to apply to the method. + @return {Mixed} Return value from the applied method, or `null` if the + specified instance was not found or the method was not whitelisted. + **/ + applyTo: function(id, method, args) { + if (!(method in APPLY_TO_AUTH)) { + this.log(method + ': applyTo not allowed', 'warn', 'yui'); + return null; + } + + var instance = instances[id], nest, m, i; + if (instance) { + nest = method.split('.'); + m = instance; + for (i = 0; i < nest.length; i = i + 1) { + m = m[nest[i]]; + if (!m) { + this.log('applyTo not found: ' + method, 'warn', 'yui'); + } + } + return m && m.apply(instance, args); + } + + return null; + }, + +/** +Registers a YUI module and makes it available for use in a `YUI().use()` call or +as a dependency for other modules. + +The easiest way to create a first-class YUI module is to use +Shifter, the YUI component build +tool. + +Shifter will automatically wrap your module code in a `YUI.add()` call along +with any configuration info required for the module. + +@example + + YUI.add('davglass', function (Y) { + Y.davglass = function () { + Y.log('Dav was here!'); + }; + }, '3.4.0', { + requires: ['harley-davidson', 'mt-dew'] + }); + +@method add +@param {String} name Module name. +@param {Function} fn Function containing module code. This function will be + executed whenever the module is attached to a specific YUI instance. + + @param {YUI} fn.Y The YUI instance to which this module is attached. + @param {String} fn.name Name of the module + +@param {String} version Module version number. This is currently used only for + informational purposes, and is not used internally by YUI. + +@param {Object} [config] Module config. + @param {Array} [config.requires] Array of other module names that must be + attached before this module can be attached. + @param {Array} [config.optional] Array of optional module names that should + be attached before this module is attached if they've already been + loaded. If the `loadOptional` YUI option is `true`, optional modules + that have not yet been loaded will be loaded just as if they were hard + requirements. + @param {Array} [config.use] Array of module names that are included within + or otherwise provided by this module, and which should be attached + automatically when this module is attached. This makes it possible to + create "virtual rollup" modules that simply attach a collection of other + modules or submodules. + +@return {YUI} This YUI instance. +**/ + add: function(name, fn, version, details) { + details = details || {}; + var env = YUI.Env, + mod = { + name: name, + fn: fn, + version: version, + details: details + }, + //Instance hash so we don't apply it to the same instance twice + applied = {}, + loader, inst, + i, versions = env.versions; + + env.mods[name] = mod; + versions[version] = versions[version] || {}; + versions[version][name] = mod; + + for (i in instances) { + if (instances.hasOwnProperty(i)) { + inst = instances[i]; + if (!applied[inst.id]) { + applied[inst.id] = true; + loader = inst.Env._loader; + if (loader) { + if (!loader.moduleInfo[name] || loader.moduleInfo[name].temp) { + loader.addModule(details, name); + } + } + } + } + } + + return this; + }, + + /** + Executes the callback function associated with each required module, + attaching the module to this YUI instance. + + @method _attach + @param {Array} r The array of modules to attach + @param {Boolean} [moot=false] If `true`, don't throw a warning if the module + is not attached. + @private + **/ + _attach: function(r, moot) { + var i, name, mod, details, req, use, after, + mods = YUI.Env.mods, + aliases = YUI.Env.aliases, + Y = this, j, + cache = YUI.Env._renderedMods, + loader = Y.Env._loader, + done = Y.Env._attached, + len = r.length, loader, def, go, + c = []; + + //Check for conditional modules (in a second+ instance) and add their requirements + //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass + for (i = 0; i < len; i++) { + name = r[i]; + mod = mods[name]; + c.push(name); + if (loader && loader.conditions[name]) { + for (j in loader.conditions[name]) { + if (loader.conditions[name].hasOwnProperty(j)) { + def = loader.conditions[name][j]; + go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y))); + if (go) { + c.push(def.name); + } + } + } + } + } + r = c; + len = r.length; + + for (i = 0; i < len; i++) { + if (!done[r[i]]) { + name = r[i]; + mod = mods[name]; + + if (aliases && aliases[name] && !mod) { + Y._attach(aliases[name]); + continue; + } + if (!mod) { + if (loader && loader.moduleInfo[name]) { + mod = loader.moduleInfo[name]; + moot = true; + } + + // Y.log('no js def for: ' + name, 'info', 'yui'); + + //if (!loader || !loader.moduleInfo[name]) { + //if ((!loader || !loader.moduleInfo[name]) && !moot) { + if (!moot && name) { + if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) { + Y.Env._missed.push(name); + Y.Env._missed = Y.Array.dedupe(Y.Env._missed); + Y.message('NOT loaded: ' + name, 'warn', 'yui'); + } + } + } else { + done[name] = true; + //Don't like this, but in case a mod was asked for once, then we fetch it + //We need to remove it from the missed list ^davglass + for (j = 0; j < Y.Env._missed.length; j++) { + if (Y.Env._missed[j] === name) { + Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui'); + Y.Env._missed.splice(j, 1); + } + } + /* + If it's a temp module, we need to redo it's requirements if it's already loaded + since it may have been loaded by another instance and it's dependencies might + have been redefined inside the fetched file. + */ + if (loader && cache && cache[name] && cache[name].temp) { + loader.getRequires(cache[name]); + req = []; + for (j in loader.moduleInfo[name].expanded_map) { + if (loader.moduleInfo[name].expanded_map.hasOwnProperty(j)) { + req.push(j); + } + } + Y._attach(req); + } + + details = mod.details; + req = details.requires; + use = details.use; + after = details.after; + //Force Intl load if there is a language (Loader logic) @todo fix this shit + if (details.lang) { + req = req || []; + req.unshift('intl'); + } + + if (req) { + for (j = 0; j < req.length; j++) { + if (!done[req[j]]) { + if (!Y._attach(req)) { + return false; + } + break; + } + } + } + + if (after) { + for (j = 0; j < after.length; j++) { + if (!done[after[j]]) { + if (!Y._attach(after, true)) { + return false; + } + break; + } + } + } + + if (mod.fn) { + if (Y.config.throwFail) { + mod.fn(Y, name); + } else { + try { + mod.fn(Y, name); + } catch (e) { + Y.error('Attach error: ' + name, e, name); + return false; + } + } + } + + if (use) { + for (j = 0; j < use.length; j++) { + if (!done[use[j]]) { + if (!Y._attach(use)) { + return false; + } + break; + } + } + } + + + + } + } + } + + return true; + }, + + /** + Delays the `use` callback until another event has taken place such as + `window.onload`, `domready`, `contentready`, or `available`. + + @private + @method _delayCallback + @param {Function} cb The original `use` callback. + @param {String|Object} until Either an event name ('load', 'domready', etc.) + or an object containing event/args keys for contentready/available. + @return {Function} + **/ + _delayCallback: function(cb, until) { + + var Y = this, + mod = ['event-base']; + + until = (Y.Lang.isObject(until) ? until : { event: until }); + + if (until.event === 'load') { + mod.push('event-synthetic'); + } + + Y.log('Delaying use callback until: ' + until.event, 'info', 'yui'); + return function() { + Y.log('Use callback fired, waiting on delay', 'info', 'yui'); + var args = arguments; + Y._use(mod, function() { + Y.log('Delayed use wrapper callback after dependencies', 'info', 'yui'); + Y.on(until.event, function() { + args[1].delayUntil = until.event; + Y.log('Delayed use callback done after ' + until.event, 'info', 'yui'); + cb.apply(Y, args); + }, until.args); + }); + }; + }, + + /** + Attaches one or more modules to this YUI instance. When this is executed, + the requirements of the desired modules are analyzed, and one of several + things can happen: + + + * All required modules have already been loaded, and just need to be + attached to this YUI instance. In this case, the `use()` callback will + be executed synchronously after the modules are attached. + + * One or more modules have not yet been loaded, or the Get utility is not + available, or the `bootstrap` config option is `false`. In this case, + a warning is issued indicating that modules are missing, but all + available modules will still be attached and the `use()` callback will + be executed synchronously. + + * One or more modules are missing and the Loader is not available but the + Get utility is, and `bootstrap` is not `false`. In this case, the Get + utility will be used to load the Loader, and we will then proceed to + the following state: + + * One or more modules are missing and the Loader is available. In this + case, the Loader will be used to resolve the dependency tree for the + missing modules and load them and their dependencies. When the Loader is + finished loading modules, the `use()` callback will be executed + asynchronously. + + @example + + // Loads and attaches dd and its dependencies. + YUI().use('dd', function (Y) { + // ... + }); + + // Loads and attaches dd and node as well as all of their dependencies. + YUI().use(['dd', 'node'], function (Y) { + // ... + }); + + // Attaches all modules that have already been loaded. + YUI().use('*', function (Y) { + // ... + }); + + // Attaches a gallery module. + YUI().use('gallery-yql', function (Y) { + // ... + }); + + // Attaches a YUI 2in3 module. + YUI().use('yui2-datatable', function (Y) { + // ... + }); + + @method use + @param {String|Array} modules* One or more module names to attach. + @param {Function} [callback] Callback function to be executed once all + specified modules and their dependencies have been attached. + @param {YUI} callback.Y The YUI instance created for this sandbox. + @param {Object} callback.status Object containing `success`, `msg` and + `data` properties. + @chainable + **/ + use: function() { + var args = SLICE.call(arguments, 0), + callback = args[args.length - 1], + Y = this, + i = 0, + name, + Env = Y.Env, + provisioned = true; + + // The last argument supplied to use can be a load complete callback + if (Y.Lang.isFunction(callback)) { + args.pop(); + if (Y.config.delayUntil) { + callback = Y._delayCallback(callback, Y.config.delayUntil); + } + } else { + callback = null; + } + if (Y.Lang.isArray(args[0])) { + args = args[0]; + } + + if (Y.config.cacheUse) { + while ((name = args[i++])) { + if (!Env._attached[name]) { + provisioned = false; + break; + } + } + + if (provisioned) { + if (args.length) { + Y.log('already provisioned: ' + args, 'info', 'yui'); + } + Y._notify(callback, ALREADY_DONE, args); + return Y; + } + } + + if (Y._loading) { + Y._useQueue = Y._useQueue || new Y.Queue(); + Y._useQueue.add([args, callback]); + } else { + Y._use(args, function(Y, response) { + Y._notify(callback, response, args); + }); + } + + return Y; + }, + + /** + Handles Loader notifications about attachment/load errors. + + @method _notify + @param {Function} callback Callback to pass to `Y.config.loadErrorFn`. + @param {Object} response Response returned from Loader. + @param {Array} args Arguments passed from Loader. + @private + **/ + _notify: function(callback, response, args) { + if (!response.success && this.config.loadErrorFn) { + this.config.loadErrorFn.call(this, this, callback, response, args); + } else if (callback) { + if (this.Env._missed && this.Env._missed.length) { + response.msg = 'Missing modules: ' + this.Env._missed.join(); + response.success = false; + } + if (this.config.throwFail) { + callback(this, response); + } else { + try { + callback(this, response); + } catch (e) { + this.error('use callback error', e, args); + } + } + } + }, + + /** + Called from the `use` method queue to ensure that only one set of loading + logic is performed at a time. + + @method _use + @param {String} args* One or more modules to attach. + @param {Function} [callback] Function to call once all required modules have + been attached. + @private + **/ + _use: function(args, callback) { + + if (!this.Array) { + this._attach(['yui-base']); + } + + var len, loader, handleBoot, + Y = this, + G_ENV = YUI.Env, + mods = G_ENV.mods, + Env = Y.Env, + used = Env._used, + aliases = G_ENV.aliases, + queue = G_ENV._loaderQueue, + firstArg = args[0], + YArray = Y.Array, + config = Y.config, + boot = config.bootstrap, + missing = [], + i, + r = [], + ret = true, + fetchCSS = config.fetchCSS, + process = function(names, skip) { + + var i = 0, a = [], name, len, m, req, use; + + if (!names.length) { + return; + } + + if (aliases) { + len = names.length; + for (i = 0; i < len; i++) { + if (aliases[names[i]] && !mods[names[i]]) { + a = [].concat(a, aliases[names[i]]); + } else { + a.push(names[i]); + } + } + names = a; + } + + len = names.length; + + for (i = 0; i < len; i++) { + name = names[i]; + if (!skip) { + r.push(name); + } + + // only attach a module once + if (used[name]) { + continue; + } + + m = mods[name]; + req = null; + use = null; + + if (m) { + used[name] = true; + req = m.details.requires; + use = m.details.use; + } else { + // CSS files don't register themselves, see if it has + // been loaded + if (!G_ENV._loaded[VERSION][name]) { + missing.push(name); + } else { + used[name] = true; // probably css + } + } + + // make sure requirements are attached + if (req && req.length) { + process(req); + } + + // make sure we grab the submodule dependencies too + if (use && use.length) { + process(use, 1); + } + } + + }, + + handleLoader = function(fromLoader) { + var response = fromLoader || { + success: true, + msg: 'not dynamic' + }, + redo, origMissing, + ret = true, + data = response.data; + + Y._loading = false; + + if (data) { + origMissing = missing; + missing = []; + r = []; + process(data); + redo = missing.length; + if (redo) { + if ([].concat(missing).sort().join() == + origMissing.sort().join()) { + redo = false; + } + } + } + + if (redo && data) { + Y._loading = true; + Y._use(missing, function() { + Y.log('Nested use callback: ' + data, 'info', 'yui'); + if (Y._attach(data)) { + Y._notify(callback, response, data); + } + }); + } else { + if (data) { + // Y.log('attaching from loader: ' + data, 'info', 'yui'); + ret = Y._attach(data); + } + if (ret) { + Y._notify(callback, response, args); + } + } + + if (Y._useQueue && Y._useQueue.size() && !Y._loading) { + Y._use.apply(Y, Y._useQueue.next()); + } + + }; + +// Y.log(Y.id + ': use called: ' + a + ' :: ' + callback, 'info', 'yui'); + + // YUI().use('*'); // bind everything available + if (firstArg === '*') { + args = []; + for (i in mods) { + if (mods.hasOwnProperty(i)) { + args.push(i); + } + } + ret = Y._attach(args); + if (ret) { + handleLoader(); + } + return Y; + } + + if ((mods.loader || mods['loader-base']) && !Y.Loader) { + Y.log('Loader was found in meta, but it is not attached. Attaching..', 'info', 'yui'); + Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]); + } + + // Y.log('before loader requirements: ' + args, 'info', 'yui'); + + // use loader to expand dependencies and sort the + // requirements if it is available. + if (boot && Y.Loader && args.length) { + Y.log('Using loader to expand dependencies', 'info', 'yui'); + loader = getLoader(Y); + loader.require(args); + loader.ignoreRegistered = true; + loader._boot = true; + loader.calculate(null, (fetchCSS) ? null : 'js'); + args = loader.sorted; + loader._boot = false; + } + + process(args); + + len = missing.length; + + + if (len) { + missing = YArray.dedupe(missing); + len = missing.length; +Y.log('Modules missing: ' + missing + ', ' + missing.length, 'info', 'yui'); + } + + + // dynamic load + if (boot && len && Y.Loader) { +// Y.log('Using loader to fetch missing deps: ' + missing, 'info', 'yui'); + Y.log('Using Loader', 'info', 'yui'); + Y._loading = true; + loader = getLoader(Y); + loader.onEnd = handleLoader; + loader.context = Y; + loader.data = args; + loader.ignoreRegistered = false; + loader.require(missing); + loader.insert(null, (fetchCSS) ? null : 'js'); + + } else if (boot && len && Y.Get && !Env.bootstrapped) { + + Y._loading = true; + + handleBoot = function() { + Y._loading = false; + queue.running = false; + Env.bootstrapped = true; + G_ENV._bootstrapping = false; + if (Y._attach(['loader'])) { + Y._use(args, callback); + } + }; + + if (G_ENV._bootstrapping) { +Y.log('Waiting for loader', 'info', 'yui'); + queue.add(handleBoot); + } else { + G_ENV._bootstrapping = true; +Y.log('Fetching loader: ' + config.base + config.loaderPath, 'info', 'yui'); + Y.Get.script(config.base + config.loaderPath, { + onEnd: handleBoot + }); + } + + } else { + Y.log('Attaching available dependencies: ' + args, 'info', 'yui'); + ret = Y._attach(args); + if (ret) { + handleLoader(); + } + } + + return Y; + }, + + + /** + Utility method for safely creating namespaces if they don't already exist. + May be called statically on the YUI global object or as a method on a YUI + instance. + + When called statically, a namespace will be created on the YUI global + object: + + // Create `YUI.your.namespace.here` as nested objects, preserving any + // objects that already exist instead of overwriting them. + YUI.namespace('your.namespace.here'); + + When called as a method on a YUI instance, a namespace will be created on + that instance: + + // Creates `Y.property.package`. + Y.namespace('property.package'); + + Dots in the input string cause `namespace` to create nested objects for each + token. If any part of the requested namespace already exists, the current + object will be left in place and will not be overwritten. This allows + multiple calls to `namespace` to preserve existing namespaced properties. + + If the first token in the namespace string is "YAHOO", that token is + discarded. This is legacy behavior for backwards compatibility with YUI 2. + + Be careful with namespace tokens. Reserved words may work in some browsers + and not others. For instance, the following will fail in some browsers + because the supported version of JavaScript reserves the word "long": + + Y.namespace('really.long.nested.namespace'); + + Note: If you pass multiple arguments to create multiple namespaces, only the + last one created is returned from this function. + + @method namespace + @param {String} namespace* One or more namespaces to create. + @return {Object} Reference to the last namespace object created. + **/ + namespace: function() { + var a = arguments, o, i = 0, j, d, arg; + + for (; i < a.length; i++) { + o = this; //Reset base object per argument or it will get reused from the last + arg = a[i]; + if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present + d = arg.split(PERIOD); + for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) { + o[d[j]] = o[d[j]] || {}; + o = o[d[j]]; + } + } else { + o[arg] = o[arg] || {}; + o = o[arg]; //Reset base object to the new object so it's returned + } + } + return o; + }, + + // this is replaced if the log module is included + log: NOOP, + message: NOOP, + // this is replaced if the dump module is included + dump: function (o) { return ''+o; }, + + /** + Reports an error. + + The reporting mechanism is controlled by the `throwFail` configuration + attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is + truthy, a JS exception is thrown. + + If an `errorFn` is specified in the config it must return `true` to indicate + that the exception was handled and keep it from being thrown. + + @method error + @param {String} msg Error message. + @param {Error|String} [e] JavaScript error object or an error string. + @param {String} [src] Source of the error (such as the name of the module in + which the error occurred). + @chainable + **/ + error: function(msg, e, src) { + //TODO Add check for window.onerror here + + var Y = this, ret; + + if (Y.config.errorFn) { + ret = Y.config.errorFn.apply(Y, arguments); + } + + if (!ret) { + throw (e || new Error(msg)); + } else { + Y.message(msg, 'error', ''+src); // don't scrub this one + } + + return Y; + }, + + /** + Generates an id string that is unique among all YUI instances in this + execution context. + + @method guid + @param {String} [pre] Prefix. + @return {String} Unique id. + **/ + guid: function(pre) { + var id = this.Env._guidp + '_' + (++this.Env._uidx); + return (pre) ? (pre + id) : id; + }, + + /** + Returns a unique id associated with the given object and (if *readOnly* is + falsy) stamps the object with that id so it can be identified in the future. + + Stamping an object involves adding a `_yuid` property to it that contains + the object's id. One exception to this is that in Internet Explorer, DOM + nodes have a `uniqueID` property that contains a browser-generated unique + id, which will be used instead of a YUI-generated id when available. + + @method stamp + @param {Object} o Object to stamp. + @param {Boolean} readOnly If truthy and the given object has not already + been stamped, the object will not be modified and `null` will be + returned. + @return {String} Object's unique id, or `null` if *readOnly* was truthy and + the given object was not already stamped. + **/ + stamp: function(o, readOnly) { + var uid; + if (!o) { + return o; + } + + // IE generates its own unique ID for dom nodes + // The uniqueID property of a document node returns a new ID + if (o.uniqueID && o.nodeType && o.nodeType !== 9) { + uid = o.uniqueID; + } else { + uid = (typeof o === 'string') ? o : o._yuid; + } + + if (!uid) { + uid = this.guid(); + if (!readOnly) { + try { + o._yuid = uid; + } catch (e) { + uid = null; + } + } + } + return uid; + }, + + /** + Destroys this YUI instance. + + @method destroy + @since 3.3.0 + **/ + destroy: function() { + var Y = this; + if (Y.Event) { + Y.Event._unload(); + } + delete instances[Y.id]; + delete Y.Env; + delete Y.config; + } + + /** + Safe `instanceof` wrapper that works around a memory leak in IE when the + object being tested is `window` or `document`. + + Unless you are testing objects that may be `window` or `document`, you + should use the native `instanceof` operator instead of this method. + + @method instanceOf + @param {Object} o Object to check. + @param {Object} type Class to check against. + @since 3.3.0 + **/ +}; + + YUI.prototype = proto; + + // inheritance utilities are not available yet + for (prop in proto) { + if (proto.hasOwnProperty(prop)) { + YUI[prop] = proto[prop]; + } + } + + /** + Applies a configuration to all YUI instances in this execution context. + + The main use case for this method is in "mashups" where several third-party + scripts need to write to a global YUI config, but cannot share a single + centrally-managed config object. This way they can all call + `YUI.applyConfig({})` instead of overwriting the single global config. + + @example + + YUI.applyConfig({ + modules: { + davglass: { + fullpath: './davglass.js' + } + } + }); + + YUI.applyConfig({ + modules: { + foo: { + fullpath: './foo.js' + } + } + }); + + YUI().use('davglass', function (Y) { + // Module davglass will be available here. + }); + + @method applyConfig + @param {Object} o Configuration object to apply. + @static + @since 3.5.0 + **/ + YUI.applyConfig = function(o) { + if (!o) { + return; + } + //If there is a GlobalConfig, apply it first to set the defaults + if (YUI.GlobalConfig) { + this.prototype.applyConfig.call(this, YUI.GlobalConfig); + } + //Apply this config to it + this.prototype.applyConfig.call(this, o); + //Reset GlobalConfig to the combined config + YUI.GlobalConfig = this.config; + }; + + // set up the environment + YUI._init(); + + if (hasWin) { + // add a window load event at load time so we can capture + // the case where it fires before dynamic loading is + // complete. + add(window, 'load', handleLoad); + } else { + handleLoad(); + } + + YUI.Env.add = add; + YUI.Env.remove = remove; + + /*global exports*/ + // Support the CommonJS method for exporting our single global + if (typeof exports == 'object') { + exports.YUI = YUI; + /** + * Set a method to be called when `Get.script` is called in Node.js + * `Get` will open the file, then pass it's content and it's path + * to this method before attaching it. Commonly used for code coverage + * instrumentation. Calling this multiple times will only + * attach the last hook method. This method is only + * available in Node.js. + * @method setLoadHook + * @static + * @param {Function} fn The function to set + * @param {String} fn.data The content of the file + * @param {String} fn.path The file path of the file + */ + YUI.setLoadHook = function(fn) { + YUI._getLoadHook = fn; + }; + /** + * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook` + * @method _getLoadHook + * @private + * @param {String} data The content of the file + * @param {String} path The file path of the file + */ + YUI._getLoadHook = null; + } + +}()); + + +/** +Config object that contains all of the configuration options for +this `YUI` instance. + +This object is supplied by the implementer when instantiating YUI. Some +properties have default values if they are not supplied by the implementer. + +This object should not be updated directly because some values are cached. Use +`applyConfig()` to update the config object on a YUI instance that has already +been configured. + +@class config +@static +**/ + +/** +If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata +if they're needed to load additional dependencies and aren't already available. + +Setting this to `false` will prevent YUI from automatically loading the Loader +and module metadata, so you will need to manually ensure that they're available +or handle dependency resolution yourself. + +@property {Boolean} bootstrap +@default true +**/ + +/** +If `true`, `Y.log()` messages will be written to the browser's debug console +when available and when `useBrowserConsole` is also `true`. + +@property {Boolean} debug +@default true +**/ + +/** +Log messages to the browser console if `debug` is `true` and the browser has a +supported console. + +@property {Boolean} useBrowserConsole +@default true +**/ + +/** +A hash of log sources that should be logged. If specified, only messages from +these sources will be logged. Others will be discarded. + +@property {Object} logInclude +@type object +**/ + +/** +A hash of log sources that should be not be logged. If specified, all sources +will be logged *except* those on this list. + +@property {Object} logExclude +**/ + +/** +When the YUI seed file is dynamically loaded after the `window.onload` event has +fired, set this to `true` to tell YUI that it shouldn't wait for `window.onload` +to occur. + +This ensures that components that rely on `window.onload` and the `domready` +custom event will work as expected even when YUI is dynamically injected. + +@property {Boolean} injected +@default false +**/ + +/** +If `true`, `Y.error()` will generate or re-throw a JavaScript error. Otherwise, +errors are merely logged silently. + +@property {Boolean} throwFail +@default true +**/ + +/** +Reference to the global object for this execution context. + +In a browser, this is the current `window` object. In Node.js, this is the +Node.js `global` object. + +@property {Object} global +**/ + +/** +The browser window or frame that this YUI instance should operate in. + +When running in Node.js, this property is `undefined`, since there is no +`window` object. Use `global` to get a reference to the global object that will +work in both browsers and Node.js. + +@property {Window} win +**/ + +/** +The browser `document` object associated with this YUI instance's `win` object. + +When running in Node.js, this property is `undefined`, since there is no +`document` object. + +@property {Document} doc +**/ + +/** +A list of modules that defines the YUI core (overrides the default list). + +@property {Array} core +@type Array +@default ['get', 'features', 'intl-base', 'yui-log', 'yui-later', 'loader-base', 'loader-rollup', 'loader-yui3'] +**/ + +/** +A list of languages to use in order of preference. + +This list is matched against the list of available languages in modules that the +YUI instance uses to determine the best possible localization of language +sensitive modules. + +Languages are represented using BCP 47 language tags, such as "en-GB" for +English as used in the United Kingdom, or "zh-Hans-CN" for simplified Chinese as +used in China. The list may be provided as a comma-separated string or as an +array. + +@property {String|String[]} lang +**/ + +/** +Default date format. + +@property {String} dateFormat +@deprecated Use configuration in `DataType.Date.format()` instead. +**/ + +/** +Default locale. + +@property {String} locale +@deprecated Use `config.lang` instead. +**/ + +/** +Default generic polling interval in milliseconds. + +@property {Number} pollInterval +@default 20 +**/ + +/** +The number of dynamic `', 'script'); + } +}); + +if (!testFeature('innerhtml', 'table')) { + // TODO: thead/tfoot with nested tbody + // IE adds TBODY when creating TABLE elements (which may share this impl) + creators.tbody = function(html, doc) { + var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc), + tb = Y.DOM._children(frag, 'tbody')[0]; + + if (frag.children.length > 1 && tb && !re_tbody.test(html)) { + tb.parentNode.removeChild(tb); // strip extraneous tbody + } + return frag; + }; +} + +if (!testFeature('innerhtml-div', 'script')) { + creators.script = function(html, doc) { + var frag = doc.createElement('div'); + + frag.innerHTML = '-' + html; + frag.removeChild(frag.firstChild); + return frag; + }; + + creators.link = creators.style = creators.script; +} + +if (!testFeature('innerhtml-div', 'tr')) { + Y.mix(creators, { + option: function(html, doc) { + return Y_DOM.create('', doc); + }, + + tr: function(html, doc) { + return Y_DOM.create('' + html + '', doc); + }, + + td: function(html, doc) { + return Y_DOM.create('Execute the supplied method before the specified function. Wrapping + * function may optionally return an instance of the following classes to + * further alter runtime behavior:
+ *returnValue. No other wrapping functions will be
+ * executed.Execute the supplied method after the specified function. Wrapping + * function may optionally return an instance of the following classes to + * further alter runtime behavior:
+ *returnValue. No other wrapping functions will be
+ * executed.returnValue instead of the wrapped
+ * method's original return value. This can be further altered by
+ * other after phase wrappers.The static properties Y.Do.originalRetVal and
+ * Y.Do.currentRetVal will be populated for reference.
before and after.
+ *
+ * @method _inject
+ * @param when {string} before or after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @private
+ * @static
+ */
+ _inject: function(when, fn, obj, sFn) {
+ // object id
+ var id = Y.stamp(obj), o, sid;
+
+ if (!obj._yuiaop) {
+ // create a map entry for the obj if it doesn't exist, to hold overridden methods
+ obj._yuiaop = {};
+ }
+
+ o = obj._yuiaop;
+
+ if (!o[sFn]) {
+ // create a map entry for the method if it doesn't exist
+ o[sFn] = new Y.Do.Method(obj, sFn);
+
+ // re-route the method to our wrapper
+ obj[sFn] = function() {
+ return o[sFn].exec.apply(o[sFn], arguments);
+ };
+ }
+
+ // subscriber id
+ sid = id + Y.stamp(fn) + sFn;
+
+ // register the callback
+ o[sFn].register(sid, fn, when);
+
+ return new Y.EventHandle(o[sFn], sid);
+ },
+
+ /**
+ * Detach a before or after subscription.
+ *
+ * @method detach
+ * @param handle {string} the subscription handle
+ * @static
+ */
+ detach: function(handle) {
+ if (handle.detach) {
+ handle.detach();
+ }
+ }
+};
+
+Y.Do = DO;
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Contains the return value from the wrapped method, accessible
+ * by 'after' event listeners.
+ *
+ * @property originalRetVal
+ * @static
+ * @since 3.2.0
+ */
+
+/**
+ * Contains the current state of the return value, consumable by
+ * 'after' event listeners, and updated if an after subscriber
+ * changes the return value generated by the wrapped function.
+ *
+ * @property currentRetVal
+ * @static
+ * @since 3.2.0
+ */
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Wrapper for a displaced method with aop enabled
+ * @class Do.Method
+ * @constructor
+ * @param obj The object to operate on
+ * @param sFn The name of the method to displace
+ */
+DO.Method = function(obj, sFn) {
+ this.obj = obj;
+ this.methodName = sFn;
+ this.method = obj[sFn];
+ this.before = {};
+ this.after = {};
+};
+
+/**
+ * Register a aop subscriber
+ * @method register
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+DO.Method.prototype.register = function (sid, fn, when) {
+ if (when) {
+ this.after[sid] = fn;
+ } else {
+ this.before[sid] = fn;
+ }
+};
+
+/**
+ * Unregister a aop subscriber
+ * @method delete
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+DO.Method.prototype._delete = function (sid) {
+ // Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
+ delete this.before[sid];
+ delete this.after[sid];
+};
+
+/**
+ * Execute the wrapped method. All arguments are passed into the wrapping
+ * functions. If any of the before wrappers return an instance of
+ * Y.Do.Halt or Y.Do.Prevent, neither the wrapped
+ * function nor any after phase subscribers will be executed.
The return value will be the return value of the wrapped function or one
+ * provided by a wrapper function via an instance of Y.Do.Halt or
+ * Y.Do.AlterReturn.
+ *
+ * @method exec
+ * @param arg* {any} Arguments are passed to the wrapping and wrapped functions
+ * @return {any} Return value of wrapped function unless overwritten (see above)
+ */
+DO.Method.prototype.exec = function () {
+
+ var args = Y.Array(arguments, 0, true),
+ i, ret, newRet,
+ bf = this.before,
+ af = this.after,
+ prevented = false;
+
+ // execute before
+ for (i in bf) {
+ if (bf.hasOwnProperty(i)) {
+ ret = bf[i].apply(this.obj, args);
+ if (ret) {
+ switch (ret.constructor) {
+ case DO.Halt:
+ return ret.retVal;
+ case DO.AlterArgs:
+ args = ret.newArgs;
+ break;
+ case DO.Prevent:
+ prevented = true;
+ break;
+ default:
+ }
+ }
+ }
+ }
+
+ // execute method
+ if (!prevented) {
+ ret = this.method.apply(this.obj, args);
+ }
+
+ DO.originalRetVal = ret;
+ DO.currentRetVal = ret;
+
+ // execute after methods.
+ for (i in af) {
+ if (af.hasOwnProperty(i)) {
+ newRet = af[i].apply(this.obj, args);
+ // Stop processing if a Halt object is returned
+ if (newRet && newRet.constructor === DO.Halt) {
+ return newRet.retVal;
+ // Check for a new return value
+ } else if (newRet && newRet.constructor === DO.AlterReturn) {
+ ret = newRet.newRetVal;
+ // Update the static retval state
+ DO.currentRetVal = ret;
+ }
+ }
+ }
+
+ return ret;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Return an AlterArgs object when you want to change the arguments that
+ * were passed into the function. Useful for Do.before subscribers. An
+ * example would be a service that scrubs out illegal characters prior to
+ * executing the core business logic.
+ * @class Do.AlterArgs
+ * @constructor
+ * @param msg {String} (optional) Explanation of the altered return value
+ * @param newArgs {Array} Call parameters to be used for the original method
+ * instead of the arguments originally passed in.
+ */
+DO.AlterArgs = function(msg, newArgs) {
+ this.msg = msg;
+ this.newArgs = newArgs;
+};
+
+/**
+ * Return an AlterReturn object when you want to change the result returned
+ * from the core method to the caller. Useful for Do.after subscribers.
+ * @class Do.AlterReturn
+ * @constructor
+ * @param msg {String} (optional) Explanation of the altered return value
+ * @param newRetVal {any} Return value passed to code that invoked the wrapped
+ * function.
+ */
+DO.AlterReturn = function(msg, newRetVal) {
+ this.msg = msg;
+ this.newRetVal = newRetVal;
+};
+
+/**
+ * Return a Halt object when you want to terminate the execution
+ * of all subsequent subscribers as well as the wrapped method
+ * if it has not exectued yet. Useful for Do.before subscribers.
+ * @class Do.Halt
+ * @constructor
+ * @param msg {String} (optional) Explanation of why the termination was done
+ * @param retVal {any} Return value passed to code that invoked the wrapped
+ * function.
+ */
+DO.Halt = function(msg, retVal) {
+ this.msg = msg;
+ this.retVal = retVal;
+};
+
+/**
+ * Return a Prevent object when you want to prevent the wrapped function
+ * from executing, but want the remaining listeners to execute. Useful
+ * for Do.before subscribers.
+ * @class Do.Prevent
+ * @constructor
+ * @param msg {String} (optional) Explanation of why the termination was done
+ */
+DO.Prevent = function(msg) {
+ this.msg = msg;
+};
+
+/**
+ * Return an Error object when you want to terminate the execution
+ * of all subsequent method calls.
+ * @class Do.Error
+ * @constructor
+ * @param msg {String} (optional) Explanation of the altered return value
+ * @param retVal {any} Return value passed to code that invoked the wrapped
+ * function.
+ * @deprecated use Y.Do.Halt or Y.Do.Prevent
+ */
+DO.Error = DO.Halt;
+
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+
+
+// var onsubscribeType = "_event:onsub",
+var YArray = Y.Array,
+
+ AFTER = 'after',
+ CONFIGS = [
+ 'broadcast',
+ 'monitored',
+ 'bubbles',
+ 'context',
+ 'contextFn',
+ 'currentTarget',
+ 'defaultFn',
+ 'defaultTargetOnly',
+ 'details',
+ 'emitFacade',
+ 'fireOnce',
+ 'async',
+ 'host',
+ 'preventable',
+ 'preventedFn',
+ 'queuable',
+ 'silent',
+ 'stoppedFn',
+ 'target',
+ 'type'
+ ],
+
+ CONFIGS_HASH = YArray.hash(CONFIGS),
+
+ nativeSlice = Array.prototype.slice,
+
+ YUI3_SIGNATURE = 9,
+ YUI_LOG = 'yui:log',
+
+ mixConfigs = function(r, s, ov) {
+ var p;
+
+ for (p in s) {
+ if (CONFIGS_HASH[p] && (ov || !(p in r))) {
+ r[p] = s[p];
+ }
+ }
+
+ return r;
+ };
+
+/**
+ * The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ *
+ * @param {String} type The type of event, which is passed to the callback
+ * when the event fires.
+ * @param {object} defaults configuration object.
+ * @class CustomEvent
+ * @constructor
+ */
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+
+/**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+
+Y.CustomEvent = function(type, defaults) {
+
+ this._kds = Y.CustomEvent.keepDeprecatedSubs;
+
+ this.id = Y.guid();
+
+ this.type = type;
+ this.silent = this.logSystem = (type === YUI_LOG);
+
+ if (this._kds) {
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber {}
+ * @deprecated
+ */
+
+ /**
+ * 'After' subscribers
+ * @property afters
+ * @type Subscriber {}
+ * @deprecated
+ */
+ this.subscribers = {};
+ this.afters = {};
+ }
+
+ if (defaults) {
+ mixConfigs(this, defaults, true);
+ }
+};
+
+/**
+ * Static flag to enable population of the `subscribers`
+ * and `afters` properties held on a `CustomEvent` instance.
+ *
+ * These properties were changed to private properties (`_subscribers` and `_afters`), and
+ * converted from objects to arrays for performance reasons.
+ *
+ * Setting this property to true will populate the deprecated `subscribers` and `afters`
+ * properties for people who may be using them (which is expected to be rare). There will
+ * be a performance hit, compared to the new array based implementation.
+ *
+ * If you are using these deprecated properties for a use case which the public API
+ * does not support, please file an enhancement request, and we can provide an alternate
+ * public implementation which doesn't have the performance cost required to maintiain the
+ * properties as objects.
+ *
+ * @property keepDeprecatedSubs
+ * @static
+ * @for CustomEvent
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+Y.CustomEvent.keepDeprecatedSubs = false;
+
+Y.CustomEvent.mixConfigs = mixConfigs;
+
+Y.CustomEvent.prototype = {
+
+ constructor: Y.CustomEvent,
+
+ /**
+ * Monitor when an event is attached or detached.
+ *
+ * @property monitored
+ * @type boolean
+ */
+
+ /**
+ * If 0, this event does not broadcast. If 1, the YUI instance is notified
+ * every time this event fires. If 2, the YUI instance and the YUI global
+ * (if event is enabled on the global) are notified every time this event
+ * fires.
+ * @property broadcast
+ * @type int
+ */
+
+ /**
+ * Specifies whether this event should be queued when the host is actively
+ * processing an event. This will effect exectution order of the callbacks
+ * for the various events.
+ * @property queuable
+ * @type boolean
+ * @default false
+ */
+
+ /**
+ * This event has fired if true
+ *
+ * @property fired
+ * @type boolean
+ * @default false;
+ */
+
+ /**
+ * An array containing the arguments the custom event
+ * was last fired with.
+ * @property firedWith
+ * @type Array
+ */
+
+ /**
+ * This event should only fire one time if true, and if
+ * it has fired, any new subscribers should be notified
+ * immediately.
+ *
+ * @property fireOnce
+ * @type boolean
+ * @default false;
+ */
+
+ /**
+ * fireOnce listeners will fire syncronously unless async
+ * is set to true
+ * @property async
+ * @type boolean
+ * @default false
+ */
+
+ /**
+ * Flag for stopPropagation that is modified during fire()
+ * 1 means to stop propagation to bubble targets. 2 means
+ * to also stop additional subscribers on this target.
+ * @property stopped
+ * @type int
+ */
+
+ /**
+ * Flag for preventDefault that is modified during fire().
+ * if it is not 0, the default behavior for this event
+ * @property prevented
+ * @type int
+ */
+
+ /**
+ * Specifies the host for this custom event. This is used
+ * to enable event bubbling
+ * @property host
+ * @type EventTarget
+ */
+
+ /**
+ * The default function to execute after event listeners
+ * have fire, but only if the default action was not
+ * prevented.
+ * @property defaultFn
+ * @type Function
+ */
+
+ /**
+ * The function to execute if a subscriber calls
+ * stopPropagation or stopImmediatePropagation
+ * @property stoppedFn
+ * @type Function
+ */
+
+ /**
+ * The function to execute if a subscriber calls
+ * preventDefault
+ * @property preventedFn
+ * @type Function
+ */
+
+ /**
+ * The subscribers to this event
+ * @property _subscribers
+ * @type Subscriber []
+ * @private
+ */
+
+ /**
+ * 'After' subscribers
+ * @property _afters
+ * @type Subscriber []
+ * @private
+ */
+
+ /**
+ * If set to true, the custom event will deliver an EventFacade object
+ * that is similar to a DOM event object.
+ * @property emitFacade
+ * @type boolean
+ * @default false
+ */
+
+ /**
+ * Supports multiple options for listener signatures in order to
+ * port YUI 2 apps.
+ * @property signature
+ * @type int
+ * @default 9
+ */
+ signature : YUI3_SIGNATURE,
+
+ /**
+ * The context the the event will fire from by default. Defaults to the YUI
+ * instance.
+ * @property context
+ * @type object
+ */
+ context : Y,
+
+ /**
+ * Specifies whether or not this event's default function
+ * can be cancelled by a subscriber by executing preventDefault()
+ * on the event facade
+ * @property preventable
+ * @type boolean
+ * @default true
+ */
+ preventable : true,
+
+ /**
+ * Specifies whether or not a subscriber can stop the event propagation
+ * via stopPropagation(), stopImmediatePropagation(), or halt()
+ *
+ * Events can only bubble if emitFacade is true.
+ *
+ * @property bubbles
+ * @type boolean
+ * @default true
+ */
+ bubbles : true,
+
+ /**
+ * Returns the number of subscribers for this event as the sum of the on()
+ * subscribers and after() subscribers.
+ *
+ * @method hasSubs
+ * @return Number
+ */
+ hasSubs: function(when) {
+ var s = 0,
+ a = 0,
+ subs = this._subscribers,
+ afters = this._afters,
+ sib = this.sibling;
+
+ if (subs) {
+ s = subs.length;
+ }
+
+ if (afters) {
+ a = afters.length;
+ }
+
+ if (sib) {
+ subs = sib._subscribers;
+ afters = sib._afters;
+
+ if (subs) {
+ s += subs.length;
+ }
+
+ if (afters) {
+ a += afters.length;
+ }
+ }
+
+ if (when) {
+ return (when === 'after') ? a : s;
+ }
+
+ return (s + a);
+ },
+
+ /**
+ * Monitor the event state for the subscribed event. The first parameter
+ * is what should be monitored, the rest are the normal parameters when
+ * subscribing to an event.
+ * @method monitor
+ * @param what {string} what to monitor ('detach', 'attach', 'publish').
+ * @return {EventHandle} return value from the monitor event subscription.
+ */
+ monitor: function(what) {
+ this.monitored = true;
+ var type = this.id + '|' + this.type + '_' + what,
+ args = nativeSlice.call(arguments, 0);
+ args[0] = type;
+ return this.host.on.apply(this.host, args);
+ },
+
+ /**
+ * Get all of the subscribers to this event and any sibling event
+ * @method getSubs
+ * @return {Array} first item is the on subscribers, second the after.
+ */
+ getSubs: function() {
+
+ var sibling = this.sibling,
+ subs = this._subscribers,
+ afters = this._afters,
+ siblingSubs,
+ siblingAfters;
+
+ if (sibling) {
+ siblingSubs = sibling._subscribers;
+ siblingAfters = sibling._afters;
+ }
+
+ if (siblingSubs) {
+ if (subs) {
+ subs = subs.concat(siblingSubs);
+ } else {
+ subs = siblingSubs.concat();
+ }
+ } else {
+ if (subs) {
+ subs = subs.concat();
+ } else {
+ subs = [];
+ }
+ }
+
+ if (siblingAfters) {
+ if (afters) {
+ afters = afters.concat(siblingAfters);
+ } else {
+ afters = siblingAfters.concat();
+ }
+ } else {
+ if (afters) {
+ afters = afters.concat();
+ } else {
+ afters = [];
+ }
+ }
+
+ return [subs, afters];
+ },
+
+ /**
+ * Apply configuration properties. Only applies the CONFIG whitelist
+ * @method applyConfig
+ * @param o hash of properties to apply.
+ * @param force {boolean} if true, properties that exist on the event
+ * will be overwritten.
+ */
+ applyConfig: function(o, force) {
+ mixConfigs(this, o, force);
+ },
+
+ /**
+ * Create the Subscription for subscribing function, context, and bound
+ * arguments. If this is a fireOnce event, the subscriber is immediately
+ * notified.
+ *
+ * @method _on
+ * @param fn {Function} Subscription callback
+ * @param [context] {Object} Override `this` in the callback
+ * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire()
+ * @param [when] {String} "after" to slot into after subscribers
+ * @return {EventHandle}
+ * @protected
+ */
+ _on: function(fn, context, args, when) {
+
+ if (!fn) { this.log('Invalid callback for CE: ' + this.type); }
+
+ var s = new Y.Subscriber(fn, context, args, when);
+
+ if (this.fireOnce && this.fired) {
+ if (this.async) {
+ setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
+ } else {
+ this._notify(s, this.firedWith);
+ }
+ }
+
+ if (when === AFTER) {
+ if (!this._afters) {
+ this._afters = [];
+ this._hasAfters = true;
+ }
+ this._afters.push(s);
+ } else {
+ if (!this._subscribers) {
+ this._subscribers = [];
+ this._hasSubs = true;
+ }
+ this._subscribers.push(s);
+ }
+
+ if (this._kds) {
+ if (when === AFTER) {
+ this.afters[s.id] = s;
+ } else {
+ this.subscribers[s.id] = s;
+ }
+ }
+
+ return new Y.EventHandle(this, s);
+ },
+
+ /**
+ * Listen for this event
+ * @method subscribe
+ * @param {Function} fn The function to execute.
+ * @return {EventHandle} Unsubscribe handle.
+ * @deprecated use on.
+ */
+ subscribe: function(fn, context) {
+ Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
+ var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event
+ * @method on
+ * @param {Function} fn The function to execute.
+ * @param {object} context optional execution context.
+ * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
+ * when the event fires.
+ * @return {EventHandle} An object with a detach method to detch the handler(s).
+ */
+ on: function(fn, context) {
+ var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
+
+ if (this.monitored && this.host) {
+ this.host._monitor('attach', this, {
+ args: arguments
+ });
+ }
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event after the normal subscribers have been notified and
+ * the default behavior has been applied. If a normal subscriber prevents the
+ * default behavior, it also prevents after listeners from firing.
+ * @method after
+ * @param {Function} fn The function to execute.
+ * @param {object} context optional execution context.
+ * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
+ * when the event fires.
+ * @return {EventHandle} handle Unsubscribe handle.
+ */
+ after: function(fn, context) {
+ var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
+ return this._on(fn, context, a, AFTER);
+ },
+
+ /**
+ * Detach listeners.
+ * @method detach
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed.
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int} returns the number of subscribers unsubscribed.
+ */
+ detach: function(fn, context) {
+ // unsubscribe handle
+ if (fn && fn.detach) {
+ return fn.detach();
+ }
+
+ var i, s,
+ found = 0,
+ subs = this._subscribers,
+ afters = this._afters;
+
+ if (subs) {
+ for (i = subs.length; i >= 0; i--) {
+ s = subs[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s, subs, i);
+ found++;
+ }
+ }
+ }
+
+ if (afters) {
+ for (i = afters.length; i >= 0; i--) {
+ s = afters[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s, afters, i);
+ found++;
+ }
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Detach listeners.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed.
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int|undefined} returns the number of subscribers unsubscribed.
+ * @deprecated use detach.
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Notify a single subscriber
+ * @method _notify
+ * @param {Subscriber} s the subscriber.
+ * @param {Array} args the arguments array to apply to the listener.
+ * @protected
+ */
+ _notify: function(s, args, ef) {
+
+ this.log(this.type + '->' + 'sub: ' + s.id);
+
+ var ret;
+
+ ret = s.notify(args, this);
+
+ if (false === ret || this.stopped > 1) {
+ this.log(this.type + ' cancelled by subscriber');
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Logger abstraction to centralize the application of the silent flag
+ * @method log
+ * @param {string} msg message to log.
+ * @param {string} cat log category.
+ */
+ log: function(msg, cat) {
+ if (!this.silent) { Y.log(this.id + ': ' + msg, cat || 'info', 'event'); }
+ },
+
+ /**
+ * Notifies the subscribers. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters:
+ *
on except the
+ * listener is immediatelly detached when it is executed.
+ * @method once
+ * @param {String} type The name of the event
+ * @param {Function} fn The callback to execute in response to the event
+ * @param {Object} [context] Override `this` object in callback
+ * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
+ * @return {EventHandle} A subscription handle capable of detaching the
+ * subscription
+ */
+ once: function() {
+ var handle = this.on.apply(this, arguments);
+ handle.batch(function(hand) {
+ if (hand.sub) {
+ hand.sub.once = true;
+ }
+ });
+ return handle;
+ },
+
+ /**
+ * Listen to a custom event hosted by this object one time.
+ * This is the equivalent to after except the
+ * listener is immediatelly detached when it is executed.
+ * @method onceAfter
+ * @param {String} type The name of the event
+ * @param {Function} fn The callback to execute in response to the event
+ * @param {Object} [context] Override `this` object in callback
+ * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
+ * @return {EventHandle} A subscription handle capable of detaching that
+ * subscription
+ */
+ onceAfter: function() {
+ var handle = this.after.apply(this, arguments);
+ handle.batch(function(hand) {
+ if (hand.sub) {
+ hand.sub.once = true;
+ }
+ });
+ return handle;
+ },
+
+ /**
+ * Takes the type parameter passed to 'on' and parses out the
+ * various pieces that could be included in the type. If the
+ * event type is passed without a prefix, it will be expanded
+ * to include the prefix one is supplied or the event target
+ * is configured with a default prefix.
+ * @method parseType
+ * @param {String} type the type
+ * @param {String} [pre=this._yuievt.config.prefix] the prefix
+ * @since 3.3.0
+ * @return {Array} an array containing:
+ * * the detach category, if supplied,
+ * * the prefixed event type,
+ * * whether or not this is an after listener,
+ * * the supplied event type
+ */
+ parseType: function(type, pre) {
+ return _parseType(type, pre || this._yuievt.config.prefix);
+ },
+
+ /**
+ * Subscribe a callback function to a custom event fired by this object or
+ * from an object that bubbles its events to this object.
+ *
+ * Callback functions for events published with `emitFacade = true` will
+ * receive an `EventFacade` as the first argument (typically named "e").
+ * These callbacks can then call `e.preventDefault()` to disable the
+ * behavior published to that event's `defaultFn`. See the `EventFacade`
+ * API for all available properties and methods. Subscribers to
+ * non-`emitFacade` events will receive the arguments passed to `fire()`
+ * after the event name.
+ *
+ * To subscribe to multiple events at once, pass an object as the first
+ * argument, where the key:value pairs correspond to the eventName:callback,
+ * or pass an array of event names as the first argument to subscribe to
+ * all listed events with the same callback.
+ *
+ * Returning `false` from a callback is supported as an alternative to
+ * calling `e.preventDefault(); e.stopPropagation();`. However, it is
+ * recommended to use the event methods whenever possible.
+ *
+ * @method on
+ * @param {String} type The name of the event
+ * @param {Function} fn The callback to execute in response to the event
+ * @param {Object} [context] Override `this` object in callback
+ * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
+ * @return {EventHandle} A subscription handle capable of detaching that
+ * subscription
+ */
+ on: function(type, fn, context) {
+
+ var yuievt = this._yuievt,
+ parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce,
+ detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
+ Node = Y.Node, n, domevent, isArr;
+
+ // full name, args, detachcategory, after
+ this._monitor('attach', parts[1], {
+ args: arguments,
+ category: parts[0],
+ after: parts[2]
+ });
+
+ if (L.isObject(type)) {
+
+ if (L.isFunction(type)) {
+ return Y.Do.before.apply(Y.Do, arguments);
+ }
+
+ f = fn;
+ c = context;
+ args = nativeSlice.call(arguments, 0);
+ ret = [];
+
+ if (L.isArray(type)) {
+ isArr = true;
+ }
+
+ after = type._after;
+ delete type._after;
+
+ Y.each(type, function(v, k) {
+
+ if (L.isObject(v)) {
+ f = v.fn || ((L.isFunction(v)) ? v : f);
+ c = v.context || c;
+ }
+
+ var nv = (after) ? AFTER_PREFIX : '';
+
+ args[0] = nv + ((isArr) ? v : k);
+ args[1] = f;
+ args[2] = c;
+
+ ret.push(this.on.apply(this, args));
+
+ }, this);
+
+ return (yuievt.chain) ? this : new Y.EventHandle(ret);
+ }
+
+ detachcategory = parts[0];
+ after = parts[2];
+ shorttype = parts[3];
+
+ // extra redirection so we catch adaptor events too. take a look at this.
+ if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
+ args = nativeSlice.call(arguments, 0);
+ args.splice(2, 0, Node.getDOMNode(this));
+ // Y.log("Node detected, redirecting with these args: " + args);
+ return Y.on.apply(Y, args);
+ }
+
+ type = parts[1];
+
+ if (Y.instanceOf(this, YUI)) {
+
+ adapt = Y.Env.evt.plugins[type];
+ args = nativeSlice.call(arguments, 0);
+ args[0] = shorttype;
+
+ if (Node) {
+ n = args[2];
+
+ if (Y.instanceOf(n, Y.NodeList)) {
+ n = Y.NodeList.getDOMNodes(n);
+ } else if (Y.instanceOf(n, Node)) {
+ n = Node.getDOMNode(n);
+ }
+
+ domevent = (shorttype in Node.DOM_EVENTS);
+
+ // Captures both DOM events and event plugins.
+ if (domevent) {
+ args[2] = n;
+ }
+ }
+
+ // check for the existance of an event adaptor
+ if (adapt) {
+ Y.log('Using adaptor for ' + shorttype + ', ' + n, 'info', 'event');
+ handle = adapt.on.apply(Y, args);
+ } else if ((!type) || domevent) {
+ handle = Y.Event._attach(args);
+ }
+
+ }
+
+ if (!handle) {
+ ce = yuievt.events[type] || this.publish(type);
+ handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true);
+
+ // TODO: More robust regex, accounting for category
+ if (type.indexOf("*:") !== -1) {
+ this._hasSiblings = true;
+ }
+ }
+
+ if (detachcategory) {
+ store[detachcategory] = store[detachcategory] || {};
+ store[detachcategory][type] = store[detachcategory][type] || [];
+ store[detachcategory][type].push(handle);
+ }
+
+ return (yuievt.chain) ? this : handle;
+
+ },
+
+ /**
+ * subscribe to an event
+ * @method subscribe
+ * @deprecated use on
+ */
+ subscribe: function() {
+ Y.log('EventTarget subscribe() is deprecated, use on()', 'warn', 'deprecated');
+ return this.on.apply(this, arguments);
+ },
+
+ /**
+ * Detach one or more listeners the from the specified event
+ * @method detach
+ * @param type {string|Object} Either the handle to the subscriber or the
+ * type of event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param context {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {EventTarget} the host
+ */
+ detach: function(type, fn, context) {
+
+ var evts = this._yuievt.events,
+ i,
+ Node = Y.Node,
+ isNode = Node && (Y.instanceOf(this, Node));
+
+ // detachAll disabled on the Y instance.
+ if (!type && (this !== Y)) {
+ for (i in evts) {
+ if (evts.hasOwnProperty(i)) {
+ evts[i].detach(fn, context);
+ }
+ }
+ if (isNode) {
+ Y.Event.purgeElement(Node.getDOMNode(this));
+ }
+
+ return this;
+ }
+
+ var parts = _parseType(type, this._yuievt.config.prefix),
+ detachcategory = L.isArray(parts) ? parts[0] : null,
+ shorttype = (parts) ? parts[3] : null,
+ adapt, store = Y.Env.evt.handles, detachhost, cat, args,
+ ce,
+
+ keyDetacher = function(lcat, ltype, host) {
+ var handles = lcat[ltype], ce, i;
+ if (handles) {
+ for (i = handles.length - 1; i >= 0; --i) {
+ ce = handles[i].evt;
+ if (ce.host === host || ce.el === host) {
+ handles[i].detach();
+ }
+ }
+ }
+ };
+
+ if (detachcategory) {
+
+ cat = store[detachcategory];
+ type = parts[1];
+ detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
+
+ if (cat) {
+ if (type) {
+ keyDetacher(cat, type, detachhost);
+ } else {
+ for (i in cat) {
+ if (cat.hasOwnProperty(i)) {
+ keyDetacher(cat, i, detachhost);
+ }
+ }
+ }
+
+ return this;
+ }
+
+ // If this is an event handle, use it to detach
+ } else if (L.isObject(type) && type.detach) {
+ type.detach();
+ return this;
+ // extra redirection so we catch adaptor events too. take a look at this.
+ } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
+ args = nativeSlice.call(arguments, 0);
+ args[2] = Node.getDOMNode(this);
+ Y.detach.apply(Y, args);
+ return this;
+ }
+
+ adapt = Y.Env.evt.plugins[shorttype];
+
+ // The YUI instance handles DOM events and adaptors
+ if (Y.instanceOf(this, YUI)) {
+ args = nativeSlice.call(arguments, 0);
+ // use the adaptor specific detach code if
+ if (adapt && adapt.detach) {
+ adapt.detach.apply(Y, args);
+ return this;
+ // DOM event fork
+ } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
+ args[0] = type;
+ Y.Event.detach.apply(Y.Event, args);
+ return this;
+ }
+ }
+
+ // ce = evts[type];
+ ce = evts[parts[1]];
+ if (ce) {
+ ce.detach(fn, context);
+ }
+
+ return this;
+ },
+
+ /**
+ * detach a listener
+ * @method unsubscribe
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+Y.log('EventTarget unsubscribe() is deprecated, use detach()', 'warn', 'deprecated');
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method detachAll
+ * @param type {String} The type, or name of the event
+ */
+ detachAll: function(type) {
+ return this.detach(type);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param type {String} The type, or name of the event
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+Y.log('EventTarget unsubscribeAll() is deprecated, use detachAll()', 'warn', 'deprecated');
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method publish
+ *
+ * @param type {String} the type, or name of the event
+ * @param opts {object} optional config params. Valid properties are:
+ *
+ * set and get methods.
+ *
+ * @class Node
+ * @constructor
+ * @param {DOMNode} node the DOM node to be mapped to the Node instance.
+ * @uses EventTarget
+ */
+
+// "globals"
+var DOT = '.',
+ NODE_NAME = 'nodeName',
+ NODE_TYPE = 'nodeType',
+ OWNER_DOCUMENT = 'ownerDocument',
+ TAG_NAME = 'tagName',
+ UID = '_yuid',
+ EMPTY_OBJ = {},
+
+ _slice = Array.prototype.slice,
+
+ Y_DOM = Y.DOM,
+
+ Y_Node = function(node) {
+ if (!this.getDOMNode) { // support optional "new"
+ return new Y_Node(node);
+ }
+
+ if (typeof node == 'string') {
+ node = Y_Node._fromString(node);
+ if (!node) {
+ return null; // NOTE: return
+ }
+ }
+
+ var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
+
+ if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
+ node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
+ }
+
+ uid = uid || Y.stamp(node);
+ if (!uid) { // stamp failed; likely IE non-HTMLElement
+ uid = Y.guid();
+ }
+
+ this[UID] = uid;
+
+ /**
+ * The underlying DOM node bound to the Y.Node instance
+ * @property _node
+ * @type DOMNode
+ * @private
+ */
+ this._node = node;
+
+ this._stateProxy = node; // when augmented with Attribute
+
+ if (this._initPlugins) { // when augmented with Plugin.Host
+ this._initPlugins();
+ }
+ },
+
+ // used with previous/next/ancestor tests
+ _wrapFn = function(fn) {
+ var ret = null;
+ if (fn) {
+ ret = (typeof fn == 'string') ?
+ function(n) {
+ return Y.Selector.test(n, fn);
+ } :
+ function(n) {
+ return fn(Y.one(n));
+ };
+ }
+
+ return ret;
+ };
+// end "globals"
+
+Y_Node.ATTRS = {};
+Y_Node.DOM_EVENTS = {};
+
+Y_Node._fromString = function(node) {
+ if (node) {
+ if (node.indexOf('doc') === 0) { // doc OR document
+ node = Y.config.doc;
+ } else if (node.indexOf('win') === 0) { // win OR window
+ node = Y.config.win;
+ } else {
+ node = Y.Selector.query(node, null, true);
+ }
+ }
+
+ return node || null;
+};
+
+/**
+ * The name of the component
+ * @static
+ * @type String
+ * @property NAME
+ */
+Y_Node.NAME = 'node';
+
+/*
+ * The pattern used to identify ARIA attributes
+ */
+Y_Node.re_aria = /^(?:role$|aria-)/;
+
+Y_Node.SHOW_TRANSITION = 'fadeIn';
+Y_Node.HIDE_TRANSITION = 'fadeOut';
+
+/**
+ * A list of Node instances that have been created
+ * @private
+ * @type Object
+ * @property _instances
+ * @static
+ *
+ */
+Y_Node._instances = {};
+
+/**
+ * Retrieves the DOM node bound to a Node instance
+ * @method getDOMNode
+ * @static
+ *
+ * @param {Node | HTMLNode} node The Node instance or an HTMLNode
+ * @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed
+ * as the node argument, it is simply returned.
+ */
+Y_Node.getDOMNode = function(node) {
+ if (node) {
+ return (node.nodeType) ? node : node._node || null;
+ }
+ return null;
+};
+
+/**
+ * Checks Node return values and wraps DOM Nodes as Y.Node instances
+ * and DOM Collections / Arrays as Y.NodeList instances.
+ * Other return values just pass thru. If undefined is returned (e.g. no return)
+ * then the Node instance is returned for chainability.
+ * @method scrubVal
+ * @static
+ *
+ * @param {any} node The Node instance or an HTMLNode
+ * @return {Node | NodeList | Any} Depends on what is returned from the DOM node.
+ */
+Y_Node.scrubVal = function(val, node) {
+ if (val) { // only truthy values are risky
+ if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
+ if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
+ val = Y.one(val);
+ } else if ((val.item && !val._nodes) || // dom collection or Node instance
+ (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
+ val = Y.all(val);
+ }
+ }
+ } else if (typeof val === 'undefined') {
+ val = node; // for chaining
+ } else if (val === null) {
+ val = null; // IE: DOM null not the same as null
+ }
+
+ return val;
+};
+
+/**
+ * Adds methods to the Y.Node prototype, routing through scrubVal.
+ * @method addMethod
+ * @static
+ *
+ * @param {String} name The name of the method to add
+ * @param {Function} fn The function that becomes the method
+ * @param {Object} context An optional context to call the method with
+ * (defaults to the Node instance)
+ * @return {any} Depends on what is returned from the DOM node.
+ */
+Y_Node.addMethod = function(name, fn, context) {
+ if (name && fn && typeof fn == 'function') {
+ Y_Node.prototype[name] = function() {
+ var args = _slice.call(arguments),
+ node = this,
+ ret;
+
+ if (args[0] && args[0]._node) {
+ args[0] = args[0]._node;
+ }
+
+ if (args[1] && args[1]._node) {
+ args[1] = args[1]._node;
+ }
+ args.unshift(node._node);
+
+ ret = fn.apply(node, args);
+
+ if (ret) { // scrub truthy
+ ret = Y_Node.scrubVal(ret, node);
+ }
+
+ (typeof ret != 'undefined') || (ret = node);
+ return ret;
+ };
+ } else {
+ Y.log('unable to add method: ' + name, 'warn', 'Node');
+ }
+};
+
+/**
+ * Imports utility methods to be added as Y.Node methods.
+ * @method importMethod
+ * @static
+ *
+ * @param {Object} host The object that contains the method to import.
+ * @param {String} name The name of the method to import
+ * @param {String} altName An optional name to use in place of the host name
+ * @param {Object} context An optional context to call the method with
+ */
+Y_Node.importMethod = function(host, name, altName) {
+ if (typeof name == 'string') {
+ altName = altName || name;
+ Y_Node.addMethod(altName, host[name], host);
+ } else {
+ Y.Array.each(name, function(n) {
+ Y_Node.importMethod(host, n);
+ });
+ }
+};
+
+/**
+ * Retrieves a NodeList based on the given CSS selector.
+ * @method all
+ *
+ * @param {string} selector The CSS selector to test against.
+ * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
+ * @for YUI
+ */
+
+/**
+ * Returns a single Node instance bound to the node or the
+ * first element matching the given selector. Returns null if no match found.
+ * Note: For chaining purposes you may want to
+ * use Y.all, which returns a NodeList when no match is found.
+ * @method one
+ * @param {String | HTMLElement} node a node or Selector
+ * @return {Node | null} a Node instance or null if no match found.
+ * @for YUI
+ */
+
+/**
+ * Returns a single Node instance bound to the node or the
+ * first element matching the given selector. Returns null if no match found.
+ * Note: For chaining purposes you may want to
+ * use Y.all, which returns a NodeList when no match is found.
+ * @method one
+ * @static
+ * @param {String | HTMLElement} node a node or Selector
+ * @return {Node | null} a Node instance or null if no match found.
+ * @for Node
+ */
+Y_Node.one = function(node) {
+ var instance = null,
+ cachedNode,
+ uid;
+
+ if (node) {
+ if (typeof node == 'string') {
+ node = Y_Node._fromString(node);
+ if (!node) {
+ return null; // NOTE: return
+ }
+ } else if (node.getDOMNode) {
+ return node; // NOTE: return
+ }
+
+ if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
+ uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
+ instance = Y_Node._instances[uid]; // reuse exising instances
+ cachedNode = instance ? instance._node : null;
+ if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
+ instance = new Y_Node(node);
+ if (node.nodeType != 11) { // dont cache document fragment
+ Y_Node._instances[instance[UID]] = instance; // cache node
+ }
+ }
+ }
+ }
+
+ return instance;
+};
+
+/**
+ * The default setter for DOM properties
+ * Called with instance context (this === the Node instance)
+ * @method DEFAULT_SETTER
+ * @static
+ * @param {String} name The attribute/property being set
+ * @param {any} val The value to be set
+ * @return {any} The value
+ */
+Y_Node.DEFAULT_SETTER = function(name, val) {
+ var node = this._stateProxy,
+ strPath;
+
+ if (name.indexOf(DOT) > -1) {
+ strPath = name;
+ name = name.split(DOT);
+ // only allow when defined on node
+ Y.Object.setValue(node, name, val);
+ } else if (typeof node[name] != 'undefined') { // pass thru DOM properties
+ node[name] = val;
+ }
+
+ return val;
+};
+
+/**
+ * The default getter for DOM properties
+ * Called with instance context (this === the Node instance)
+ * @method DEFAULT_GETTER
+ * @static
+ * @param {String} name The attribute/property to look up
+ * @return {any} The current value
+ */
+Y_Node.DEFAULT_GETTER = function(name) {
+ var node = this._stateProxy,
+ val;
+
+ if (name.indexOf && name.indexOf(DOT) > -1) {
+ val = Y.Object.getValue(node, name.split(DOT));
+ } else if (typeof node[name] != 'undefined') { // pass thru from DOM
+ val = node[name];
+ }
+
+ return val;
+};
+
+Y.mix(Y_Node.prototype, {
+ DATA_PREFIX: 'data-',
+
+ /**
+ * The method called when outputting Node instances as strings
+ * @method toString
+ * @return {String} A string representation of the Node instance
+ */
+ toString: function() {
+ var str = this[UID] + ': not bound to a node',
+ node = this._node,
+ attrs, id, className;
+
+ if (node) {
+ attrs = node.attributes;
+ id = (attrs && attrs.id) ? node.getAttribute('id') : null;
+ className = (attrs && attrs.className) ? node.getAttribute('className') : null;
+ str = node[NODE_NAME];
+
+ if (id) {
+ str += '#' + id;
+ }
+
+ if (className) {
+ str += '.' + className.replace(' ', '.');
+ }
+
+ // TODO: add yuid?
+ str += ' ' + this[UID];
+ }
+ return str;
+ },
+
+ /**
+ * Returns an attribute value on the Node instance.
+ * Unless pre-configured (via `Node.ATTRS`), get hands
+ * off to the underlying DOM node. Only valid
+ * attributes/properties for the node will be queried.
+ * @method get
+ * @param {String} attr The attribute
+ * @return {any} The current value of the attribute
+ */
+ get: function(attr) {
+ var val;
+
+ if (this._getAttr) { // use Attribute imple
+ val = this._getAttr(attr);
+ } else {
+ val = this._get(attr);
+ }
+
+ if (val) {
+ val = Y_Node.scrubVal(val, this);
+ } else if (val === null) {
+ val = null; // IE: DOM null is not true null (even though they ===)
+ }
+ return val;
+ },
+
+ /**
+ * Helper method for get.
+ * @method _get
+ * @private
+ * @param {String} attr The attribute
+ * @return {any} The current value of the attribute
+ */
+ _get: function(attr) {
+ var attrConfig = Y_Node.ATTRS[attr],
+ val;
+
+ if (attrConfig && attrConfig.getter) {
+ val = attrConfig.getter.call(this);
+ } else if (Y_Node.re_aria.test(attr)) {
+ val = this._node.getAttribute(attr, 2);
+ } else {
+ val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
+ }
+
+ return val;
+ },
+
+ /**
+ * Sets an attribute on the Node instance.
+ * Unless pre-configured (via Node.ATTRS), set hands
+ * off to the underlying DOM node. Only valid
+ * attributes/properties for the node will be set.
+ * To set custom attributes use setAttribute.
+ * @method set
+ * @param {String} attr The attribute to be set.
+ * @param {any} val The value to set the attribute to.
+ * @chainable
+ */
+ set: function(attr, val) {
+ var attrConfig = Y_Node.ATTRS[attr];
+
+ if (this._setAttr) { // use Attribute imple
+ this._setAttr.apply(this, arguments);
+ } else { // use setters inline
+ if (attrConfig && attrConfig.setter) {
+ attrConfig.setter.call(this, val, attr);
+ } else if (Y_Node.re_aria.test(attr)) { // special case Aria
+ this._node.setAttribute(attr, val);
+ } else {
+ Y_Node.DEFAULT_SETTER.apply(this, arguments);
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Sets multiple attributes.
+ * @method setAttrs
+ * @param {Object} attrMap an object of name/value pairs to set
+ * @chainable
+ */
+ setAttrs: function(attrMap) {
+ if (this._setAttrs) { // use Attribute imple
+ this._setAttrs(attrMap);
+ } else { // use setters inline
+ Y.Object.each(attrMap, function(v, n) {
+ this.set(n, v);
+ }, this);
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns an object containing the values for the requested attributes.
+ * @method getAttrs
+ * @param {Array} attrs an array of attributes to get values
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ getAttrs: function(attrs) {
+ var ret = {};
+ if (this._getAttrs) { // use Attribute imple
+ this._getAttrs(attrs);
+ } else { // use setters inline
+ Y.Array.each(attrs, function(v, n) {
+ ret[v] = this.get(v);
+ }, this);
+ }
+
+ return ret;
+ },
+
+ /**
+ * Compares nodes to determine if they match.
+ * Node instances can be compared to each other and/or HTMLElements.
+ * @method compareTo
+ * @param {HTMLElement | Node} refNode The reference node to compare to the node.
+ * @return {Boolean} True if the nodes match, false if they do not.
+ */
+ compareTo: function(refNode) {
+ var node = this._node;
+
+ if (refNode && refNode._node) {
+ refNode = refNode._node;
+ }
+ return node === refNode;
+ },
+
+ /**
+ * Determines whether the node is appended to the document.
+ * @method inDoc
+ * @param {Node|HTMLElement} doc optional An optional document to check against.
+ * Defaults to current document.
+ * @return {Boolean} Whether or not this node is appended to the document.
+ */
+ inDoc: function(doc) {
+ var node = this._node;
+ doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
+ if (doc.documentElement) {
+ return Y_DOM.contains(doc.documentElement, node);
+ }
+ },
+
+ getById: function(id) {
+ var node = this._node,
+ ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
+ if (ret && Y_DOM.contains(node, ret)) {
+ ret = Y.one(ret);
+ } else {
+ ret = null;
+ }
+ return ret;
+ },
+
+ /**
+ * Returns the nearest ancestor that passes the test applied by supplied boolean method.
+ * @method ancestor
+ * @param {String | Function} fn A selector string or boolean method for testing elements.
+ * If a function is used, it receives the current node being tested as the only argument.
+ * If fn is not passed as an argument, the parent node will be returned.
+ * @param {Boolean} testSelf optional Whether or not to include the element in the scan
+ * @param {String | Function} stopFn optional A selector string or boolean
+ * method to indicate when the search should stop. The search bails when the function
+ * returns true or the selector matches.
+ * If a function is used, it receives the current node being tested as the only argument.
+ * @return {Node} The matching Node instance or null if not found
+ */
+ ancestor: function(fn, testSelf, stopFn) {
+ // testSelf is optional, check for stopFn as 2nd arg
+ if (arguments.length === 2 &&
+ (typeof testSelf == 'string' || typeof testSelf == 'function')) {
+ stopFn = testSelf;
+ }
+
+ return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
+ },
+
+ /**
+ * Returns the ancestors that pass the test applied by supplied boolean method.
+ * @method ancestors
+ * @param {String | Function} fn A selector string or boolean method for testing elements.
+ * @param {Boolean} testSelf optional Whether or not to include the element in the scan
+ * If a function is used, it receives the current node being tested as the only argument.
+ * @return {NodeList} A NodeList instance containing the matching elements
+ */
+ ancestors: function(fn, testSelf, stopFn) {
+ if (arguments.length === 2 &&
+ (typeof testSelf == 'string' || typeof testSelf == 'function')) {
+ stopFn = testSelf;
+ }
+ return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
+ },
+
+ /**
+ * Returns the previous matching sibling.
+ * Returns the nearest element node sibling if no method provided.
+ * @method previous
+ * @param {String | Function} fn A selector or boolean method for testing elements.
+ * If a function is used, it receives the current node being tested as the only argument.
+ * @return {Node} Node instance or null if not found
+ */
+ previous: function(fn, all) {
+ return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
+ },
+
+ /**
+ * Returns the next matching sibling.
+ * Returns the nearest element node sibling if no method provided.
+ * @method next
+ * @param {String | Function} fn A selector or boolean method for testing elements.
+ * If a function is used, it receives the current node being tested as the only argument.
+ * @return {Node} Node instance or null if not found
+ */
+ next: function(fn, all) {
+ return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
+ },
+
+ /**
+ * Returns all matching siblings.
+ * Returns all siblings if no method provided.
+ * @method siblings
+ * @param {String | Function} fn A selector or boolean method for testing elements.
+ * If a function is used, it receives the current node being tested as the only argument.
+ * @return {NodeList} NodeList instance bound to found siblings
+ */
+ siblings: function(fn) {
+ return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
+ },
+
+ /**
+ * Retrieves a single Node instance, the first element matching the given
+ * CSS selector.
+ * Returns null if no match found.
+ * @method one
+ *
+ * @param {string} selector The CSS selector to test against.
+ * @return {Node | null} A Node instance for the matching HTMLElement or null
+ * if no match found.
+ */
+ one: function(selector) {
+ return Y.one(Y.Selector.query(selector, this._node, true));
+ },
+
+ /**
+ * Retrieves a NodeList based on the given CSS selector.
+ * @method all
+ *
+ * @param {string} selector The CSS selector to test against.
+ * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
+ */
+ all: function(selector) {
+ var nodelist;
+
+ if (this._node) {
+ nodelist = Y.all(Y.Selector.query(selector, this._node));
+ nodelist._query = selector;
+ nodelist._queryRoot = this._node;
+ }
+
+ return nodelist || Y.all([]);
+ },
+
+ // TODO: allow fn test
+ /**
+ * Test if the supplied node matches the supplied selector.
+ * @method test
+ *
+ * @param {string} selector The CSS selector to test against.
+ * @return {boolean} Whether or not the node matches the selector.
+ */
+ test: function(selector) {
+ return Y.Selector.test(this._node, selector);
+ },
+
+ /**
+ * Removes the node from its parent.
+ * Shortcut for myNode.get('parentNode').removeChild(myNode);
+ * @method remove
+ * @param {Boolean} destroy whether or not to call destroy() on the node
+ * after removal.
+ * @chainable
+ *
+ */
+ remove: function(destroy) {
+ var node = this._node;
+
+ if (node && node.parentNode) {
+ node.parentNode.removeChild(node);
+ }
+
+ if (destroy) {
+ this.destroy();
+ }
+
+ return this;
+ },
+
+ /**
+ * Replace the node with the other node. This is a DOM update only
+ * and does not change the node bound to the Node instance.
+ * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
+ * @method replace
+ * @param {Node | HTMLNode} newNode Node to be inserted
+ * @chainable
+ *
+ */
+ replace: function(newNode) {
+ var node = this._node;
+ if (typeof newNode == 'string') {
+ newNode = Y_Node.create(newNode);
+ }
+ node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
+ return this;
+ },
+
+ /**
+ * @method replaceChild
+ * @for Node
+ * @param {String | HTMLElement | Node} node Node to be inserted
+ * @param {HTMLElement | Node} refNode Node to be replaced
+ * @return {Node} The replaced node
+ */
+ replaceChild: function(node, refNode) {
+ if (typeof node == 'string') {
+ node = Y_DOM.create(node);
+ }
+
+ return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
+ },
+
+ /**
+ * Nulls internal node references, removes any plugins and event listeners.
+ * Note that destroy() will not remove the node from its parent or from the DOM. For that
+ * functionality, call remove(true).
+ * @method destroy
+ * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
+ * node's subtree (default is false)
+ *
+ */
+ destroy: function(recursive) {
+ var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid',
+ instance;
+
+ this.purge(); // TODO: only remove events add via this Node
+
+ if (this.unplug) { // may not be a PluginHost
+ this.unplug();
+ }
+
+ this.clearData();
+
+ if (recursive) {
+ Y.NodeList.each(this.all('*'), function(node) {
+ instance = Y_Node._instances[node[UID]];
+ if (instance) {
+ instance.destroy();
+ } else { // purge in case added by other means
+ Y.Event.purgeElement(node);
+ }
+ });
+ }
+
+ this._node = null;
+ this._stateProxy = null;
+
+ delete Y_Node._instances[this._yuid];
+ },
+
+ /**
+ * Invokes a method on the Node instance
+ * @method invoke
+ * @param {String} method The name of the method to invoke
+ * @param {Any} a, b, c, etc. Arguments to invoke the method with.
+ * @return Whatever the underly method returns.
+ * DOM Nodes and Collections return values
+ * are converted to Node/NodeList instances.
+ *
+ */
+ invoke: function(method, a, b, c, d, e) {
+ var node = this._node,
+ ret;
+
+ if (a && a._node) {
+ a = a._node;
+ }
+
+ if (b && b._node) {
+ b = b._node;
+ }
+
+ ret = node[method](a, b, c, d, e);
+ return Y_Node.scrubVal(ret, this);
+ },
+
+ /**
+ * @method swap
+ * @description Swap DOM locations with the given node.
+ * This does not change which DOM node each Node instance refers to.
+ * @param {Node} otherNode The node to swap with
+ * @chainable
+ */
+ swap: Y.config.doc.documentElement.swapNode ?
+ function(otherNode) {
+ this._node.swapNode(Y_Node.getDOMNode(otherNode));
+ } :
+ function(otherNode) {
+ otherNode = Y_Node.getDOMNode(otherNode);
+ var node = this._node,
+ parent = otherNode.parentNode,
+ nextSibling = otherNode.nextSibling;
+
+ if (nextSibling === node) {
+ parent.insertBefore(node, otherNode);
+ } else if (otherNode === node.nextSibling) {
+ parent.insertBefore(otherNode, node);
+ } else {
+ node.parentNode.replaceChild(otherNode, node);
+ Y_DOM.addHTML(parent, node, nextSibling);
+ }
+ return this;
+ },
+
+
+ hasMethod: function(method) {
+ var node = this._node;
+ return !!(node && method in node &&
+ typeof node[method] != 'unknown' &&
+ (typeof node[method] == 'function' ||
+ String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
+ },
+
+ isFragment: function() {
+ return (this.get('nodeType') === 11);
+ },
+
+ /**
+ * Removes and destroys all of the nodes within the node.
+ * @method empty
+ * @chainable
+ */
+ empty: function() {
+ this.get('childNodes').remove().destroy(true);
+ return this;
+ },
+
+ /**
+ * Returns the DOM node bound to the Node instance
+ * @method getDOMNode
+ * @return {DOMNode}
+ */
+ getDOMNode: function() {
+ return this._node;
+ }
+}, true);
+
+Y.Node = Y_Node;
+Y.one = Y_Node.one;
+/**
+ * The NodeList module provides support for managing collections of Nodes.
+ * @module node
+ * @submodule node-core
+ */
+
+/**
+ * The NodeList class provides a wrapper for manipulating DOM NodeLists.
+ * NodeList properties can be accessed via the set/get methods.
+ * Use Y.all() to retrieve NodeList instances.
+ *
+ * @class NodeList
+ * @constructor
+ * @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.
+ */
+
+var NodeList = function(nodes) {
+ var tmp = [];
+
+ if (nodes) {
+ if (typeof nodes === 'string') { // selector query
+ this._query = nodes;
+ nodes = Y.Selector.query(nodes);
+ } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
+ nodes = [nodes];
+ } else if (nodes._node) { // Y.Node
+ nodes = [nodes._node];
+ } else if (nodes[0] && nodes[0]._node) { // allow array of Y.Nodes
+ Y.Array.each(nodes, function(node) {
+ if (node._node) {
+ tmp.push(node._node);
+ }
+ });
+ nodes = tmp;
+ } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
+ nodes = Y.Array(nodes, 0, true);
+ }
+ }
+
+ /**
+ * The underlying array of DOM nodes bound to the Y.NodeList instance
+ * @property _nodes
+ * @private
+ */
+ this._nodes = nodes || [];
+};
+
+NodeList.NAME = 'NodeList';
+
+/**
+ * Retrieves the DOM nodes bound to a NodeList instance
+ * @method getDOMNodes
+ * @static
+ *
+ * @param {NodeList} nodelist The NodeList instance
+ * @return {Array} The array of DOM nodes bound to the NodeList
+ */
+NodeList.getDOMNodes = function(nodelist) {
+ return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
+};
+
+NodeList.each = function(instance, fn, context) {
+ var nodes = instance._nodes;
+ if (nodes && nodes.length) {
+ Y.Array.each(nodes, fn, context || instance);
+ } else {
+ Y.log('no nodes bound to ' + this, 'warn', 'NodeList');
+ }
+};
+
+NodeList.addMethod = function(name, fn, context) {
+ if (name && fn) {
+ NodeList.prototype[name] = function() {
+ var ret = [],
+ args = arguments;
+
+ Y.Array.each(this._nodes, function(node) {
+ var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
+ instance = Y.Node._instances[node[UID]],
+ ctx,
+ result;
+
+ if (!instance) {
+ instance = NodeList._getTempNode(node);
+ }
+ ctx = context || instance;
+ result = fn.apply(ctx, args);
+ if (result !== undefined && result !== instance) {
+ ret[ret.length] = result;
+ }
+ });
+
+ // TODO: remove tmp pointer
+ return ret.length ? ret : this;
+ };
+ } else {
+ Y.log('unable to add method: ' + name + ' to NodeList', 'warn', 'node');
+ }
+};
+
+NodeList.importMethod = function(host, name, altName) {
+ if (typeof name === 'string') {
+ altName = altName || name;
+ NodeList.addMethod(name, host[name]);
+ } else {
+ Y.Array.each(name, function(n) {
+ NodeList.importMethod(host, n);
+ });
+ }
+};
+
+NodeList._getTempNode = function(node) {
+ var tmp = NodeList._tempNode;
+ if (!tmp) {
+ tmp = Y.Node.create('');
+ NodeList._tempNode = tmp;
+ }
+
+ tmp._node = node;
+ tmp._stateProxy = node;
+ return tmp;
+};
+
+Y.mix(NodeList.prototype, {
+ _invoke: function(method, args, getter) {
+ var ret = (getter) ? [] : this;
+
+ this.each(function(node) {
+ var val = node[method].apply(node, args);
+ if (getter) {
+ ret.push(val);
+ }
+ });
+
+ return ret;
+ },
+
+ /**
+ * Retrieves the Node instance at the given index.
+ * @method item
+ *
+ * @param {Number} index The index of the target Node.
+ * @return {Node} The Node instance at the given index.
+ */
+ item: function(index) {
+ return Y.one((this._nodes || [])[index]);
+ },
+
+ /**
+ * Applies the given function to each Node in the NodeList.
+ * @method each
+ * @param {Function} fn The function to apply. It receives 3 arguments:
+ * the current node instance, the node's index, and the NodeList instance
+ * @param {Object} context optional An optional context to apply the function with
+ * Default context is the current Node instance
+ * @chainable
+ */
+ each: function(fn, context) {
+ var instance = this;
+ Y.Array.each(this._nodes, function(node, index) {
+ node = Y.one(node);
+ return fn.call(context || node, node, index, instance);
+ });
+ return instance;
+ },
+
+ batch: function(fn, context) {
+ var nodelist = this;
+
+ Y.Array.each(this._nodes, function(node, index) {
+ var instance = Y.Node._instances[node[UID]];
+ if (!instance) {
+ instance = NodeList._getTempNode(node);
+ }
+
+ return fn.call(context || instance, instance, index, nodelist);
+ });
+ return nodelist;
+ },
+
+ /**
+ * Executes the function once for each node until a true value is returned.
+ * @method some
+ * @param {Function} fn The function to apply. It receives 3 arguments:
+ * the current node instance, the node's index, and the NodeList instance
+ * @param {Object} context optional An optional context to execute the function from.
+ * Default context is the current Node instance
+ * @return {Boolean} Whether or not the function returned true for any node.
+ */
+ some: function(fn, context) {
+ var instance = this;
+ return Y.Array.some(this._nodes, function(node, index) {
+ node = Y.one(node);
+ context = context || node;
+ return fn.call(context, node, index, instance);
+ });
+ },
+
+ /**
+ * Creates a documenFragment from the nodes bound to the NodeList instance
+ * @method toFrag
+ * @return {Node} a Node instance bound to the documentFragment
+ */
+ toFrag: function() {
+ return Y.one(Y.DOM._nl2frag(this._nodes));
+ },
+
+ /**
+ * Returns the index of the node in the NodeList instance
+ * or -1 if the node isn't found.
+ * @method indexOf
+ * @param {Node | DOMNode} node the node to search for
+ * @return {Int} the index of the node value or -1 if not found
+ */
+ indexOf: function(node) {
+ return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
+ },
+
+ /**
+ * Filters the NodeList instance down to only nodes matching the given selector.
+ * @method filter
+ * @param {String} selector The selector to filter against
+ * @return {NodeList} NodeList containing the updated collection
+ * @see Selector
+ */
+ filter: function(selector) {
+ return Y.all(Y.Selector.filter(this._nodes, selector));
+ },
+
+
+ /**
+ * Creates a new NodeList containing all nodes at every n indices, where
+ * remainder n % index equals r.
+ * (zero-based index).
+ * @method modulus
+ * @param {Int} n The offset to use (return every nth node)
+ * @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
+ * @return {NodeList} NodeList containing the updated collection
+ */
+ modulus: function(n, r) {
+ r = r || 0;
+ var nodes = [];
+ NodeList.each(this, function(node, i) {
+ if (i % n === r) {
+ nodes.push(node);
+ }
+ });
+
+ return Y.all(nodes);
+ },
+
+ /**
+ * Creates a new NodeList containing all nodes at odd indices
+ * (zero-based index).
+ * @method odd
+ * @return {NodeList} NodeList containing the updated collection
+ */
+ odd: function() {
+ return this.modulus(2, 1);
+ },
+
+ /**
+ * Creates a new NodeList containing all nodes at even indices
+ * (zero-based index), including zero.
+ * @method even
+ * @return {NodeList} NodeList containing the updated collection
+ */
+ even: function() {
+ return this.modulus(2);
+ },
+
+ destructor: function() {
+ },
+
+ /**
+ * Reruns the initial query, when created using a selector query
+ * @method refresh
+ * @chainable
+ */
+ refresh: function() {
+ var doc,
+ nodes = this._nodes,
+ query = this._query,
+ root = this._queryRoot;
+
+ if (query) {
+ if (!root) {
+ if (nodes && nodes[0] && nodes[0].ownerDocument) {
+ root = nodes[0].ownerDocument;
+ }
+ }
+
+ this._nodes = Y.Selector.query(query, root);
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns the current number of items in the NodeList.
+ * @method size
+ * @return {Int} The number of items in the NodeList.
+ */
+ size: function() {
+ return this._nodes.length;
+ },
+
+ /**
+ * Determines if the instance is bound to any nodes
+ * @method isEmpty
+ * @return {Boolean} Whether or not the NodeList is bound to any nodes
+ */
+ isEmpty: function() {
+ return this._nodes.length < 1;
+ },
+
+ toString: function() {
+ var str = '',
+ errorMsg = this[UID] + ': not bound to any nodes',
+ nodes = this._nodes,
+ node;
+
+ if (nodes && nodes[0]) {
+ node = nodes[0];
+ str += node[NODE_NAME];
+ if (node.id) {
+ str += '#' + node.id;
+ }
+
+ if (node.className) {
+ str += '.' + node.className.replace(' ', '.');
+ }
+
+ if (nodes.length > 1) {
+ str += '...[' + nodes.length + ' items]';
+ }
+ }
+ return str || errorMsg;
+ },
+
+ /**
+ * Returns the DOM node bound to the Node instance
+ * @method getDOMNodes
+ * @return {Array}
+ */
+ getDOMNodes: function() {
+ return this._nodes;
+ }
+}, true);
+
+NodeList.importMethod(Y.Node.prototype, [
+ /**
+ * Called on each Node instance. Nulls internal node references,
+ * removes any plugins and event listeners
+ * @method destroy
+ * @param {Boolean} recursivePurge (optional) Whether or not to
+ * remove listeners from the node's subtree (default is false)
+ * @see Node.destroy
+ */
+ 'destroy',
+
+ /**
+ * Called on each Node instance. Removes and destroys all of the nodes
+ * within the node
+ * @method empty
+ * @chainable
+ * @see Node.empty
+ */
+ 'empty',
+
+ /**
+ * Called on each Node instance. Removes the node from its parent.
+ * Shortcut for myNode.get('parentNode').removeChild(myNode);
+ * @method remove
+ * @param {Boolean} destroy whether or not to call destroy() on the node
+ * after removal.
+ * @chainable
+ * @see Node.remove
+ */
+ 'remove',
+
+ /**
+ * Called on each Node instance. Sets an attribute on the Node instance.
+ * Unless pre-configured (via Node.ATTRS), set hands
+ * off to the underlying DOM node. Only valid
+ * attributes/properties for the node will be set.
+ * To set custom attributes use setAttribute.
+ * @method set
+ * @param {String} attr The attribute to be set.
+ * @param {any} val The value to set the attribute to.
+ * @chainable
+ * @see Node.set
+ */
+ 'set'
+]);
+
+// one-off implementation to convert array of Nodes to NodeList
+// e.g. Y.all('input').get('parentNode');
+
+/** Called on each Node instance
+ * @method get
+ * @see Node
+ */
+NodeList.prototype.get = function(attr) {
+ var ret = [],
+ nodes = this._nodes,
+ isNodeList = false,
+ getTemp = NodeList._getTempNode,
+ instance,
+ val;
+
+ if (nodes[0]) {
+ instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
+ val = instance._get(attr);
+ if (val && val.nodeType) {
+ isNodeList = true;
+ }
+ }
+
+ Y.Array.each(nodes, function(node) {
+ instance = Y.Node._instances[node._yuid];
+
+ if (!instance) {
+ instance = getTemp(node);
+ }
+
+ val = instance._get(attr);
+ if (!isNodeList) { // convert array of Nodes to NodeList
+ val = Y.Node.scrubVal(val, instance);
+ }
+
+ ret.push(val);
+ });
+
+ return (isNodeList) ? Y.all(ret) : ret;
+};
+
+Y.NodeList = NodeList;
+
+Y.all = function(nodes) {
+ return new NodeList(nodes);
+};
+
+Y.Node.all = Y.all;
+/**
+ * @module node
+ * @submodule node-core
+ */
+
+var Y_NodeList = Y.NodeList,
+ ArrayProto = Array.prototype,
+ ArrayMethods = {
+ /** Returns a new NodeList combining the given NodeList(s)
+ * @for NodeList
+ * @method concat
+ * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
+ * concatenate to the resulting NodeList
+ * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
+ */
+ 'concat': 1,
+ /** Removes the last from the NodeList and returns it.
+ * @for NodeList
+ * @method pop
+ * @return {Node | null} The last item in the NodeList, or null if the list is empty.
+ */
+ 'pop': 0,
+ /** Adds the given Node(s) to the end of the NodeList.
+ * @for NodeList
+ * @method push
+ * @param {Node | DOMNode} nodes One or more nodes to add to the end of the NodeList.
+ */
+ 'push': 0,
+ /** Removes the first item from the NodeList and returns it.
+ * @for NodeList
+ * @method shift
+ * @return {Node | null} The first item in the NodeList, or null if the NodeList is empty.
+ */
+ 'shift': 0,
+ /** Returns a new NodeList comprising the Nodes in the given range.
+ * @for NodeList
+ * @method slice
+ * @param {Number} begin Zero-based index at which to begin extraction.
+ 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.
+ * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
+ slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
+ 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.
+ If end is omitted, slice extracts to the end of the sequence.
+ * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
+ */
+ 'slice': 1,
+ /** Changes the content of the NodeList, adding new elements while removing old elements.
+ * @for NodeList
+ * @method splice
+ * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
+ * @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.
+ * {Node | DOMNode| element1, ..., elementN
+ The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
+ * @return {NodeList} The element(s) removed.
+ */
+ 'splice': 1,
+ /** Adds the given Node(s) to the beginning of the NodeList.
+ * @for NodeList
+ * @method unshift
+ * @param {Node | DOMNode} nodes One or more nodes to add to the NodeList.
+ */
+ 'unshift': 0
+ };
+
+
+Y.Object.each(ArrayMethods, function(returnNodeList, name) {
+ Y_NodeList.prototype[name] = function() {
+ var args = [],
+ i = 0,
+ arg,
+ ret;
+
+ while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists
+ args.push(arg._node || arg._nodes || arg);
+ }
+
+ ret = ArrayProto[name].apply(this._nodes, args);
+
+ if (returnNodeList) {
+ ret = Y.all(ret);
+ } else {
+ ret = Y.Node.scrubVal(ret);
+ }
+
+ return ret;
+ };
+});
+/**
+ * @module node
+ * @submodule node-core
+ */
+
+Y.Array.each([
+ /**
+ * Passes through to DOM method.
+ * @for Node
+ * @method removeChild
+ * @param {HTMLElement | Node} node Node to be removed
+ * @return {Node} The removed node
+ */
+ 'removeChild',
+
+ /**
+ * Passes through to DOM method.
+ * @method hasChildNodes
+ * @return {Boolean} Whether or not the node has any childNodes
+ */
+ 'hasChildNodes',
+
+ /**
+ * Passes through to DOM method.
+ * @method cloneNode
+ * @param {Boolean} deep Whether or not to perform a deep clone, which includes
+ * subtree and attributes
+ * @return {Node} The clone
+ */
+ 'cloneNode',
+
+ /**
+ * Passes through to DOM method.
+ * @method hasAttribute
+ * @param {String} attribute The attribute to test for
+ * @return {Boolean} Whether or not the attribute is present
+ */
+ 'hasAttribute',
+
+ /**
+ * Passes through to DOM method.
+ * @method scrollIntoView
+ * @chainable
+ */
+ 'scrollIntoView',
+
+ /**
+ * Passes through to DOM method.
+ * @method getElementsByTagName
+ * @param {String} tagName The tagName to collect
+ * @return {NodeList} A NodeList representing the HTMLCollection
+ */
+ 'getElementsByTagName',
+
+ /**
+ * Passes through to DOM method.
+ * @method focus
+ * @chainable
+ */
+ 'focus',
+
+ /**
+ * Passes through to DOM method.
+ * @method blur
+ * @chainable
+ */
+ 'blur',
+
+ /**
+ * Passes through to DOM method.
+ * Only valid on FORM elements
+ * @method submit
+ * @chainable
+ */
+ 'submit',
+
+ /**
+ * Passes through to DOM method.
+ * Only valid on FORM elements
+ * @method reset
+ * @chainable
+ */
+ 'reset',
+
+ /**
+ * Passes through to DOM method.
+ * @method select
+ * @chainable
+ */
+ 'select',
+
+ /**
+ * Passes through to DOM method.
+ * Only valid on TABLE elements
+ * @method createCaption
+ * @chainable
+ */
+ 'createCaption'
+
+], function(method) {
+ Y.log('adding: ' + method, 'info', 'node');
+ Y.Node.prototype[method] = function(arg1, arg2, arg3) {
+ var ret = this.invoke(method, arg1, arg2, arg3);
+ return ret;
+ };
+});
+
+/**
+ * Passes through to DOM method.
+ * @method removeAttribute
+ * @param {String} attribute The attribute to be removed
+ * @chainable
+ */
+ // one-off implementation due to IE returning boolean, breaking chaining
+Y.Node.prototype.removeAttribute = function(attr) {
+ var node = this._node;
+ if (node) {
+ node.removeAttribute(attr, 0); // comma zero for IE < 8 to force case-insensitive
+ }
+
+ return this;
+};
+
+Y.Node.importMethod(Y.DOM, [
+ /**
+ * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
+ * @method contains
+ * @param {Node | HTMLElement} needle The possible node or descendent
+ * @return {Boolean} Whether or not this node is the needle its ancestor
+ */
+ 'contains',
+ /**
+ * Allows setting attributes on DOM nodes, normalizing in some cases.
+ * This passes through to the DOM node, allowing for custom attributes.
+ * @method setAttribute
+ * @for Node
+ * @chainable
+ * @param {string} name The attribute name
+ * @param {string} value The value to set
+ */
+ 'setAttribute',
+ /**
+ * Allows getting attributes on DOM nodes, normalizing in some cases.
+ * This passes through to the DOM node, allowing for custom attributes.
+ * @method getAttribute
+ * @for Node
+ * @param {string} name The attribute name
+ * @return {string} The attribute value
+ */
+ 'getAttribute',
+
+ /**
+ * Wraps the given HTML around the node.
+ * @method wrap
+ * @param {String} html The markup to wrap around the node.
+ * @chainable
+ * @for Node
+ */
+ 'wrap',
+
+ /**
+ * Removes the node's parent node.
+ * @method unwrap
+ * @chainable
+ */
+ 'unwrap',
+
+ /**
+ * Applies a unique ID to the node if none exists
+ * @method generateID
+ * @return {String} The existing or generated ID
+ */
+ 'generateID'
+]);
+
+Y.NodeList.importMethod(Y.Node.prototype, [
+/**
+ * Allows getting attributes on DOM nodes, normalizing in some cases.
+ * This passes through to the DOM node, allowing for custom attributes.
+ * @method getAttribute
+ * @see Node
+ * @for NodeList
+ * @param {string} name The attribute name
+ * @return {string} The attribute value
+ */
+
+ 'getAttribute',
+/**
+ * Allows setting attributes on DOM nodes, normalizing in some cases.
+ * This passes through to the DOM node, allowing for custom attributes.
+ * @method setAttribute
+ * @see Node
+ * @for NodeList
+ * @chainable
+ * @param {string} name The attribute name
+ * @param {string} value The value to set
+ */
+ 'setAttribute',
+
+/**
+ * Allows for removing attributes on DOM nodes.
+ * This passes through to the DOM node, allowing for custom attributes.
+ * @method removeAttribute
+ * @see Node
+ * @for NodeList
+ * @param {string} name The attribute to remove
+ */
+ 'removeAttribute',
+/**
+ * Removes the parent node from node in the list.
+ * @method unwrap
+ * @chainable
+ */
+ 'unwrap',
+/**
+ * Wraps the given HTML around each node.
+ * @method wrap
+ * @param {String} html The markup to wrap around the node.
+ * @chainable
+ */
+ 'wrap',
+
+/**
+ * Applies a unique ID to each node if none exists
+ * @method generateID
+ * @return {String} The existing or generated ID
+ */
+ 'generateID'
+]);
+
+
+}, '@VERSION@', {"requires": ["dom-core", "selector"]});
+YUI.add('node-base', function (Y, NAME) {
+
+/**
+ * @module node
+ * @submodule node-base
+ */
+
+var methods = [
+/**
+ * Determines whether each node has the given className.
+ * @method hasClass
+ * @for Node
+ * @param {String} className the class name to search for
+ * @return {Boolean} Whether or not the element has the specified class
+ */
+ 'hasClass',
+
+/**
+ * Adds a class name to each node.
+ * @method addClass
+ * @param {String} className the class name to add to the node's class attribute
+ * @chainable
+ */
+ 'addClass',
+
+/**
+ * Removes a class name from each node.
+ * @method removeClass
+ * @param {String} className the class name to remove from the node's class attribute
+ * @chainable
+ */
+ 'removeClass',
+
+/**
+ * Replace a class with another class for each node.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ * @chainable
+ */
+ 'replaceClass',
+
+/**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @param {String} className the class name to be toggled
+ * @param {Boolean} force Option to force adding or removing the class.
+ * @chainable
+ */
+ 'toggleClass'
+];
+
+Y.Node.importMethod(Y.DOM, methods);
+/**
+ * Determines whether each node has the given className.
+ * @method hasClass
+ * @see Node.hasClass
+ * @for NodeList
+ * @param {String} className the class name to search for
+ * @return {Array} An array of booleans for each node bound to the NodeList.
+ */
+
+/**
+ * Adds a class name to each node.
+ * @method addClass
+ * @see Node.addClass
+ * @param {String} className the class name to add to the node's class attribute
+ * @chainable
+ */
+
+/**
+ * Removes a class name from each node.
+ * @method removeClass
+ * @see Node.removeClass
+ * @param {String} className the class name to remove from the node's class attribute
+ * @chainable
+ */
+
+/**
+ * Replace a class with another class for each node.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @see Node.replaceClass
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ * @chainable
+ */
+
+/**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @see Node.toggleClass
+ * @param {String} className the class name to be toggled
+ * @chainable
+ */
+Y.NodeList.importMethod(Y.Node.prototype, methods);
+/**
+ * @module node
+ * @submodule node-base
+ */
+
+var Y_Node = Y.Node,
+ Y_DOM = Y.DOM;
+
+/**
+ * Returns a new dom node using the provided markup string.
+ * @method create
+ * @static
+ * @param {String} html The markup used to create the element
+ * Use `Y.Escape.html()`
+ * to escape html content.
+ * @param {HTMLDocument} doc An optional document context
+ * @return {Node} A Node instance bound to a DOM node or fragment
+ * @for Node
+ */
+Y_Node.create = function(html, doc) {
+ if (doc && doc._node) {
+ doc = doc._node;
+ }
+ return Y.one(Y_DOM.create(html, doc));
+};
+
+Y.mix(Y_Node.prototype, {
+ /**
+ * Creates a new Node using the provided markup string.
+ * @method create
+ * @param {String} html The markup used to create the element.
+ * Use `Y.Escape.html()`
+ * to escape html content.
+ * @param {HTMLDocument} doc An optional document context
+ * @return {Node} A Node instance bound to a DOM node or fragment
+ */
+ create: Y_Node.create,
+
+ /**
+ * Inserts the content before the reference node.
+ * @method insert
+ * @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert
+ * Use `Y.Escape.html()`
+ * to escape html content.
+ * @param {Int | Node | HTMLElement | String} where The position to insert at.
+ * Possible "where" arguments
+ * The callback is executed with a single parameter: + * the custom object parameter, if provided.
+ * + * @method onAvailable + * + * @param {string||string[]} id the id of the element, or an array + * of ids to look for. + * @param {function} fn what to execute when the element is found. + * @param {object} p_obj an optional object to be passed back as + * a parameter to fn. + * @param {boolean|object} p_override If set to true, fn will execute + * in the context of p_obj, if set to an object it + * will execute in the context of that object + * @param checkContent {boolean} check child node readiness (onContentReady) + * @static + * @deprecated Use Y.on("available") + */ + // @TODO fix arguments + onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) { + + var a = Y.Array(id), i, availHandle; + + // Y.log('onAvailable registered for: ' + id); + + for (i=0; ilazyEventFacade is set to true.
+ *
+ * @method _define
+ * @param o {DOMObject} A DOM object to add the property to
+ * @param prop {String} The name of the new property
+ * @param valueFn {Function} The function that will return the initial, default
+ * value for the property.
+ * @static
+ * @private
+ */
+IELazyFacade._define = function (o, prop, valueFn) {
+ function val(v) {
+ var ret = (arguments.length) ? v : valueFn.call(this);
+
+ delete o[prop];
+ Object.defineProperty(o, prop, {
+ value: ret,
+ configurable: true,
+ writable: true
+ });
+ return ret;
+ }
+ Object.defineProperty(o, prop, {
+ get: val,
+ set: val,
+ configurable: true
+ });
+};
+
+if (imp && (!imp.hasFeature('Events', '2.0'))) {
+ if (useLazyFacade) {
+ // Make sure we can use the lazy facade logic
+ try {
+ Object.defineProperty(Y.config.doc.createEventObject(), 'z', {});
+ } catch (e) {
+ useLazyFacade = false;
+ }
+ }
+
+ Y.DOMEventFacade = (useLazyFacade) ? IELazyFacade : IEEventFacade;
+}
+
+
+}, '@VERSION@', {"requires": ["node-base"]});
+YUI.add('pluginhost-base', function (Y, NAME) {
+
+ /**
+ * Provides the augmentable PluginHost interface, which can be added to any class.
+ * @module pluginhost
+ */
+
+ /**
+ * Provides the augmentable PluginHost interface, which can be added to any class.
+ * @module pluginhost-base
+ */
+
+ /**
+ * + * An augmentable class, which provides the augmented class with the ability to host plugins. + * It adds plug and unplug methods to the augmented class, which can + * be used to add or remove plugins from instances of the class. + *
+ * + *Plugins can also be added through the constructor configuration object passed to the host class' constructor using + * the "plugins" property. Supported values for the "plugins" property are those defined by the plug method. + * + * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host): + *
+ * Plug.Host's protected _initPlugins and _destroyPlugins + * methods should be invoked by the host class at the appropriate point in the host's lifecyle. + *
+ * + * @class Plugin.Host + */ + + var L = Y.Lang; + + function PluginHost() { + this._plugins = {}; + } + + PluginHost.prototype = { + + /** + * Adds a plugin to the host object. This will instantiate the + * plugin and attach it to the configured namespace on the host object. + * + * @method plug + * @chainable + * @param P {Function | Object |Array} Accepts the plugin class, or an + * object with a "fn" property specifying the plugin class and + * a "cfg" property specifying the configuration for the Plugin. + *+ * Additionally an Array can also be passed in, with the above function or + * object values, allowing the user to add multiple plugins in a single call. + *
+ * @param config (Optional) If the first argument is the plugin class, the second argument + * can be the configuration for the plugin. + * @return {Base} A reference to the host object + */ + plug: function(Plugin, config) { + var i, ln, ns; + + if (L.isArray(Plugin)) { + for (i = 0, ln = Plugin.length; i < ln; i++) { + this.plug(Plugin[i]); + } + } else { + if (Plugin && !L.isFunction(Plugin)) { + config = Plugin.cfg; + Plugin = Plugin.fn; + } + + // Plugin should be fn by now + if (Plugin && Plugin.NS) { + ns = Plugin.NS; + + config = config || {}; + config.host = this; + + if (this.hasPlugin(ns)) { + // Update config + if (this[ns].setAttrs) { + this[ns].setAttrs(config); + } + else { Y.log("Attempt to replug an already attached plugin, and we can't setAttrs, because it's not Attribute based: " + ns); } + } else { + // Create new instance + this[ns] = new Plugin(config); + this._plugins[ns] = Plugin; + } + } + else { Y.log("Attempt to plug in an invalid plugin. Host:" + this + ", Plugin:" + Plugin); } + } + return this; + }, + + /** + * Removes a plugin from the host object. This will destroy the + * plugin instance and delete the namespace from the host object. + * + * @method unplug + * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, + * all registered plugins are unplugged. + * @return {Base} A reference to the host object + * @chainable + */ + unplug: function(plugin) { + var ns = plugin, + plugins = this._plugins; + + if (plugin) { + if (L.isFunction(plugin)) { + ns = plugin.NS; + if (ns && (!plugins[ns] || plugins[ns] !== plugin)) { + ns = null; + } + } + + if (ns) { + if (this[ns]) { + if (this[ns].destroy) { + this[ns].destroy(); + } + delete this[ns]; + } + if (plugins[ns]) { + delete plugins[ns]; + } + } + } else { + for (ns in this._plugins) { + if (this._plugins.hasOwnProperty(ns)) { + this.unplug(ns); + } + } + } + return this; + }, + + /** + * Determines if a plugin has plugged into this host. + * + * @method hasPlugin + * @param {String} ns The plugin's namespace + * @return {Plugin} Returns a truthy value (the plugin instance) if present, or undefined if not. + */ + hasPlugin : function(ns) { + return (this._plugins[ns] && this[ns]); + }, + + /** + * Initializes static plugins registered on the host (using the + * Base.plug static method) and any plugins passed to the + * instance through the "plugins" configuration property. + * + * @method _initPlugins + * @param {Config} config The configuration object with property name/value pairs. + * @private + */ + + _initPlugins: function(config) { + this._plugins = this._plugins || {}; + + if (this._initConfigPlugins) { + this._initConfigPlugins(config); + } + }, + + /** + * Unplugs and destroys all plugins on the host + * @method _destroyPlugins + * @private + */ + _destroyPlugins: function() { + this.unplug(); + } + }; + + Y.namespace("Plugin").Host = PluginHost; + + +}, '@VERSION@', {"requires": ["yui-base"]}); +YUI.add('pluginhost-config', function (Y, NAME) { + + /** + * Adds pluginhost constructor configuration and static configuration support + * @submodule pluginhost-config + */ + + var PluginHost = Y.Plugin.Host, + L = Y.Lang; + + /** + * A protected initialization method, used by the host class to initialize + * plugin configurations passed the constructor, through the config object. + * + * Host objects should invoke this method at the appropriate time in their + * construction lifecycle. + * + * @method _initConfigPlugins + * @param {Object} config The configuration object passed to the constructor + * @protected + * @for Plugin.Host + */ + PluginHost.prototype._initConfigPlugins = function(config) { + + // Class Configuration + var classes = (this._getClasses) ? this._getClasses() : [this.constructor], + plug = [], + unplug = {}, + constructor, i, classPlug, classUnplug, pluginClassName; + + // TODO: Room for optimization. Can we apply statically/unplug in same pass? + for (i = classes.length - 1; i >= 0; i--) { + constructor = classes[i]; + + classUnplug = constructor._UNPLUG; + if (classUnplug) { + // subclasses over-write + Y.mix(unplug, classUnplug, true); + } + + classPlug = constructor._PLUG; + if (classPlug) { + // subclasses over-write + Y.mix(plug, classPlug, true); + } + } + + for (pluginClassName in plug) { + if (plug.hasOwnProperty(pluginClassName)) { + if (!unplug[pluginClassName]) { + this.plug(plug[pluginClassName]); + } + } + } + + // User Configuration + if (config && config.plugins) { + this.plug(config.plugins); + } + }; + + /** + * Registers plugins to be instantiated at the class level (plugins + * which should be plugged into every instance of the class by default). + * + * @method plug + * @static + * + * @param {Function} hostClass The host class on which to register the plugins + * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined) + * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin + * @for Plugin.Host + */ + PluginHost.plug = function(hostClass, plugin, config) { + // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ] + var p, i, l, name; + + if (hostClass !== Y.Base) { + hostClass._PLUG = hostClass._PLUG || {}; + + if (!L.isArray(plugin)) { + if (config) { + plugin = {fn:plugin, cfg:config}; + } + plugin = [plugin]; + } + + for (i = 0, l = plugin.length; i < l;i++) { + p = plugin[i]; + name = p.NAME || p.fn.NAME; + hostClass._PLUG[name] = p; + } + } + }; + + /** + * Unregisters any class level plugins which have been registered by the host class, or any + * other class in the hierarchy. + * + * @method unplug + * @static + * + * @param {Function} hostClass The host class from which to unregister the plugins + * @param {Function | Array} plugin The plugin class, or an array of plugin classes + * @for Plugin.Host + */ + PluginHost.unplug = function(hostClass, plugin) { + var p, i, l, name; + + if (hostClass !== Y.Base) { + hostClass._UNPLUG = hostClass._UNPLUG || {}; + + if (!L.isArray(plugin)) { + plugin = [plugin]; + } + + for (i = 0, l = plugin.length; i < l; i++) { + p = plugin[i]; + name = p.NAME; + if (!hostClass._PLUG[name]) { + hostClass._UNPLUG[name] = p; + } else { + delete hostClass._PLUG[name]; + } + } + } + }; + + +}, '@VERSION@', {"requires": ["pluginhost-base"]}); +YUI.add('event-delegate', function (Y, NAME) { + +/** + * Adds event delegation support to the library. + * + * @module event + * @submodule event-delegate + */ + +var toArray = Y.Array, + YLang = Y.Lang, + isString = YLang.isString, + isObject = YLang.isObject, + isArray = YLang.isArray, + selectorTest = Y.Selector.test, + detachCategories = Y.Env.evt.handles; + +/** + *Sets up event delegation on a container element. The delegated event + * will use a supplied selector or filtering function to test if the event + * references at least one node that should trigger the subscription + * callback.
+ * + *Selector string filters will trigger the callback if the event originated + * from a node that matches it or is contained in a node that matches it. + * Function filters are called for each Node up the parent axis to the + * subscribing container node, and receive at each level the Node and the event + * object. The function should return true (or a truthy value) if that Node + * should trigger the subscription callback. Note, it is possible for filters + * to match multiple Nodes for a single event. In this case, the delegate + * callback will be executed for each matching Node.
+ * + *For each matching Node, the callback will be executed with its 'this'
+ * object set to the Node matched by the filter (unless a specific context was
+ * provided during subscription), and the provided event's
+ * Sets up a delegation listener for an event occurring inside the Node.
+ * The delegated event will be verified against a supplied selector or
+ * filtering function to test if the event references at least one node that
+ * should trigger the subscription callback. Selector string filters will trigger the callback if the event originated
+ * from a node that matches it or is contained in a node that matches it.
+ * Function filters are called for each Node up the parent axis to the
+ * subscribing container node, and receive at each level the Node and the event
+ * object. The function should return true (or a truthy value) if that Node
+ * should trigger the subscription callback. Note, it is possible for filters
+ * to match multiple Nodes for a single event. In this case, the delegate
+ * callback will be executed for each matching Node. For each matching Node, the callback will be executed with its 'this'
+ * object set to the Node matched by the filter (unless a specific context was
+ * provided during subscription), and the provided event's
+ *
+ * Additionally an Array can also be passed in, with the above function or
+ * object values, allowing the user to add multiple plugins in a single call.
+ * Provides Y.QueryString.stringify method for converting objects to Query Strings.
+ * This is a subset implementation of the full querystring-stringify. This module provides the bare minimum functionality (encoding a hash of simple values),
+ * without the additional support for nested data structures. Every key-value pair is
+ * encoded by encodeURIComponent. This module provides a minimalistic way for io to handle single-level objects
+ * as transaction data. Callback functions for `start` and `end` receive the id of the
+ * transaction as a first argument. For `complete`, `success`, and
+ * `failure`, callbacks receive the id and the response object
+ * (usually the XMLHttpRequest instance). If the `arguments`
+ * property was included in the configuration object passed to
+ * `Y.io()`, the configured data will be passed to all callbacks as
+ * the last argument. Callback functions for `start` and `end` receive the id of the
+ transaction as a first argument. For `complete`, `success`, and
+ `failure`, callbacks receive the id and the response object
+ (usually the XMLHttpRequest instance). If the `arguments`
+ property was included in the configuration object passed to
+ `Y.io()`, the configured data will be passed to all callbacks as
+ the last argument.currentTarget will also be set to the matching Node. The
+ * containing Node from which the subscription was originally made can be
+ * referenced as e.container.
+ *
+ * @method delegate
+ * @param type {String} the event type to delegate
+ * @param fn {Function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {String|node} the element that is the delegation container
+ * @param filter {string|Function} a selector that must match the target of the
+ * event or a function to test target and its parents for a match
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @static
+ * @for Event
+ */
+function delegate(type, fn, el, filter) {
+ var args = toArray(arguments, 0, true),
+ query = isString(el) ? el : null,
+ typeBits, synth, container, categories, cat, i, len, handles, handle;
+
+ // Support Y.delegate({ click: fnA, key: fnB }, el, filter, ...);
+ // and Y.delegate(['click', 'key'], fn, el, filter, ...);
+ if (isObject(type)) {
+ handles = [];
+
+ if (isArray(type)) {
+ for (i = 0, len = type.length; i < len; ++i) {
+ args[0] = type[i];
+ handles.push(Y.delegate.apply(Y, args));
+ }
+ } else {
+ // Y.delegate({'click', fn}, el, filter) =>
+ // Y.delegate('click', fn, el, filter)
+ args.unshift(null); // one arg becomes two; need to make space
+
+ for (i in type) {
+ if (type.hasOwnProperty(i)) {
+ args[0] = i;
+ args[1] = type[i];
+ handles.push(Y.delegate.apply(Y, args));
+ }
+ }
+ }
+
+ return new Y.EventHandle(handles);
+ }
+
+ typeBits = type.split(/\|/);
+
+ if (typeBits.length > 1) {
+ cat = typeBits.shift();
+ args[0] = type = typeBits.shift();
+ }
+
+ synth = Y.Node.DOM_EVENTS[type];
+
+ if (isObject(synth) && synth.delegate) {
+ handle = synth.delegate.apply(synth, arguments);
+ }
+
+ if (!handle) {
+ if (!type || !fn || !el || !filter) {
+ Y.log("delegate requires type, callback, parent, & filter", "warn");
+ return;
+ }
+
+ container = (query) ? Y.Selector.query(query, null, true) : el;
+
+ if (!container && isString(el)) {
+ handle = Y.on('available', function () {
+ Y.mix(handle, Y.delegate.apply(Y, args), true);
+ }, el);
+ }
+
+ if (!handle && container) {
+ args.splice(2, 2, container); // remove the filter
+
+ handle = Y.Event._attach(args, { facade: false });
+ handle.sub.filter = filter;
+ handle.sub._notify = delegate.notifySub;
+ }
+ }
+
+ if (handle && cat) {
+ categories = detachCategories[cat] || (detachCategories[cat] = {});
+ categories = categories[type] || (categories[type] = []);
+ categories.push(handle);
+ }
+
+ return handle;
+}
+
+/**
+Overrides the _notify method on the normal DOM subscription to
+inject the filtering logic and only proceed in the case of a match.
+
+This method is hosted as a private property of the `delegate` method
+(e.g. `Y.delegate.notifySub`)
+
+@method notifySub
+@param thisObj {Object} default 'this' object for the callback
+@param args {Array} arguments passed to the event's fire()
+@param ce {CustomEvent} the custom event managing the DOM subscriptions for
+ the subscribed event on the subscribing node.
+@return {Boolean} false if the event was stopped
+@private
+@static
+@since 3.2.0
+**/
+delegate.notifySub = function (thisObj, args, ce) {
+ // Preserve args for other subscribers
+ args = args.slice();
+ if (this.args) {
+ args.push.apply(args, this.args);
+ }
+
+ // Only notify subs if the event occurred on a targeted element
+ var currentTarget = delegate._applyFilter(this.filter, args, ce),
+ //container = e.currentTarget,
+ e, i, len, ret;
+
+ if (currentTarget) {
+ // Support multiple matches up the the container subtree
+ currentTarget = toArray(currentTarget);
+
+ // The second arg is the currentTarget, but we'll be reusing this
+ // facade, replacing the currentTarget for each use, so it doesn't
+ // matter what element we seed it with.
+ e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce);
+
+ e.container = Y.one(ce.el);
+
+ for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) {
+ e.currentTarget = Y.one(currentTarget[i]);
+
+ ret = this.fn.apply(this.context || e.currentTarget, args);
+
+ if (ret === false) { // stop further notifications
+ break;
+ }
+ }
+
+ return ret;
+ }
+};
+
+/**
+Compiles a selector string into a filter function to identify whether
+Nodes along the parent axis of an event's target should trigger event
+notification.
+
+This function is memoized, so previously compiled filter functions are
+returned if the same selector string is provided.
+
+This function may be useful when defining synthetic events for delegate
+handling.
+
+Hosted as a property of the `delegate` method (e.g. `Y.delegate.compileFilter`).
+
+@method compileFilter
+@param selector {String} the selector string to base the filtration on
+@return {Function}
+@since 3.2.0
+@static
+**/
+delegate.compileFilter = Y.cached(function (selector) {
+ return function (target, e) {
+ return selectorTest(target._node, selector,
+ (e.currentTarget === e.target) ? null : e.currentTarget._node);
+ };
+});
+
+/**
+Regex to test for disabled elements during filtering. This is only relevant to
+IE to normalize behavior with other browsers, which swallow events that occur
+to disabled elements. IE fires the event from the parent element instead of the
+original target, though it does preserve `event.srcElement` as the disabled
+element. IE also supports disabled on ``, but the event still bubbles, so it
+acts more like `e.preventDefault()` plus styling. That issue is not handled here
+because other browsers fire the event on the ``, so delegate is supported in
+both cases.
+
+@property _disabledRE
+@type {RegExp}
+@protected
+@since 3.8.1
+**/
+delegate._disabledRE = /^(?:button|input|select|textarea)$/i;
+
+/**
+Walks up the parent axis of an event's target, and tests each element
+against a supplied filter function. If any Nodes, including the container,
+satisfy the filter, the delegated callback will be triggered for each.
+
+Hosted as a protected property of the `delegate` method (e.g.
+`Y.delegate._applyFilter`).
+
+@method _applyFilter
+@param filter {Function} boolean function to test for inclusion in event
+ notification
+@param args {Array} the arguments that would be passed to subscribers
+@param ce {CustomEvent} the DOM event wrapper
+@return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter
+@protected
+**/
+delegate._applyFilter = function (filter, args, ce) {
+ var e = args[0],
+ container = ce.el, // facadeless events in IE, have no e.currentTarget
+ target = e.target || e.srcElement,
+ match = [],
+ isContainer = false;
+
+ // Resolve text nodes to their containing element
+ if (target.nodeType === 3) {
+ target = target.parentNode;
+ }
+
+ // For IE. IE propagates events from the parent element of disabled
+ // elements, where other browsers swallow the event entirely. To normalize
+ // this in IE, filtering for matching elements should abort if the target
+ // is a disabled form control.
+ if (target.disabled && delegate._disabledRE.test(target.nodeName)) {
+ return match;
+ }
+
+ // passing target as the first arg rather than leaving well enough alone
+ // making 'this' in the filter function refer to the target. This is to
+ // support bound filter functions.
+ args.unshift(target);
+
+ if (isString(filter)) {
+ while (target) {
+ isContainer = (target === container);
+ if (selectorTest(target, filter, (isContainer ? null: container))) {
+ match.push(target);
+ }
+
+ if (isContainer) {
+ break;
+ }
+
+ target = target.parentNode;
+ }
+ } else {
+ // filter functions are implementer code and should receive wrappers
+ args[0] = Y.one(target);
+ args[1] = new Y.DOMEventFacade(e, container, ce);
+
+ while (target) {
+ // filter(target, e, extra args...) - this === target
+ if (filter.apply(args[0], args)) {
+ match.push(target);
+ }
+
+ if (target === container) {
+ break;
+ }
+
+ target = target.parentNode;
+ args[0] = Y.one(target);
+ }
+ args[1] = e; // restore the raw DOM event
+ }
+
+ if (match.length <= 1) {
+ match = match[0]; // single match or undefined
+ }
+
+ // remove the target
+ args.shift();
+
+ return match;
+};
+
+/**
+ * Sets up event delegation on a container element. The delegated event
+ * will use a supplied filter to test if the callback should be executed.
+ * This filter can be either a selector string or a function that returns
+ * a Node to use as the currentTarget for the event.
+ *
+ * The event object for the delegated event is supplied to the callback
+ * function. It is modified slightly in order to support all properties
+ * that may be needed for event delegation. 'currentTarget' is set to
+ * the element that matched the selector string filter or the Node returned
+ * from the filter function. 'container' is set to the element that the
+ * listener is delegated from (this normally would be the 'currentTarget').
+ *
+ * Filter functions will be called with the arguments that would be passed to
+ * the callback function, including the event object as the first parameter.
+ * The function should return false (or a falsey value) if the success criteria
+ * aren't met, and the Node to use as the event's currentTarget and 'this'
+ * object if they are.
+ *
+ * @method delegate
+ * @param type {string} the event type to delegate
+ * @param fn {function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {string|node} the element that is the delegation container
+ * @param filter {string|function} a selector that must match the target of the
+ * event or a function that returns a Node or false.
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.delegate = Y.Event.delegate = delegate;
+
+
+}, '@VERSION@', {"requires": ["node-base"]});
+YUI.add('node-event-delegate', function (Y, NAME) {
+
+/**
+ * Functionality to make the node a delegated event container
+ * @module node
+ * @submodule node-event-delegate
+ */
+
+/**
+ * currentTarget will also be set to the matching Node. The
+ * containing Node from which the subscription was originally made can be
+ * referenced as e.container.
+ *
+ * @method delegate
+ * @param type {String} the event type to delegate
+ * @param fn {Function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param spec {String|Function} a selector that must match the target of the
+ * event or a function to test target and its parents for a match
+ * @param context {Object} optional argument that specifies what 'this' refers to.
+ * @param args* {any} 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for Node
+ */
+Y.Node.prototype.delegate = function(type) {
+
+ var args = Y.Array(arguments, 0, true),
+ index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2;
+
+ args.splice(index, 0, this._node);
+
+ return Y.delegate.apply(Y, args);
+};
+
+
+}, '@VERSION@', {"requires": ["node-base", "event-delegate"]});
+YUI.add('node-pluginhost', function (Y, NAME) {
+
+/**
+ * @module node
+ * @submodule node-pluginhost
+ */
+
+/**
+ * Registers plugins to be instantiated at the class level (plugins
+ * which should be plugged into every instance of Node by default).
+ *
+ * @method plug
+ * @static
+ * @for Node
+ * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
+ * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
+ */
+Y.Node.plug = function() {
+ var args = Y.Array(arguments);
+ args.unshift(Y.Node);
+ Y.Plugin.Host.plug.apply(Y.Base, args);
+ return Y.Node;
+};
+
+/**
+ * Unregisters any class level plugins which have been registered by the Node
+ *
+ * @method unplug
+ * @static
+ *
+ * @param {Function | Array} plugin The plugin class, or an array of plugin classes
+ */
+Y.Node.unplug = function() {
+ var args = Y.Array(arguments);
+ args.unshift(Y.Node);
+ Y.Plugin.Host.unplug.apply(Y.Base, args);
+ return Y.Node;
+};
+
+Y.mix(Y.Node, Y.Plugin.Host, false, null, 1);
+
+// allow batching of plug/unplug via NodeList
+// doesn't use NodeList.importMethod because we need real Nodes (not tmpNode)
+/**
+ * Adds a plugin to each node in the NodeList.
+ * This will instantiate the plugin and attach it to the configured namespace on each node
+ * @method plug
+ * @for NodeList
+ * @param P {Function | Object |Array} Accepts the plugin class, or an
+ * object with a "fn" property specifying the plugin class and
+ * a "cfg" property specifying the configuration for the Plugin.
+ *
+ *
+ *
+ * @method send
+ * @public
+ * @param {String} uri Qualified path to transaction resource.
+ * @param {Object} config Configuration object for the transaction.
+ * @param {Number} id Transaction id, if already set.
+ * @return {Object}
+ */
+ send: function(uri, config, id) {
+ var transaction, method, i, len, sync, data,
+ io = this,
+ u = uri,
+ response = {};
+
+ config = config ? Y.Object(config) : {};
+ transaction = io._create(config, id);
+ method = config.method ? config.method.toUpperCase() : 'GET';
+ sync = config.sync;
+ data = config.data;
+
+ // Serialize a map object into a key-value string using
+ // querystring-stringify-simple.
+ if ((Y.Lang.isObject(data) && !data.nodeType) && !transaction.upload) {
+ if (Y.QueryString && Y.QueryString.stringify) {
+ Y.log('Stringifying config.data for request', 'info', 'io');
+ config.data = data = Y.QueryString.stringify(data);
+ } else {
+ Y.log('Failed to stringify config.data object, likely because `querystring-stringify-simple` is missing.', 'warn', 'io');
+ }
+ }
+
+ if (config.form) {
+ if (config.form.upload) {
+ // This is a file upload transaction, calling
+ // upload() in io-upload-iframe.
+ return io.upload(transaction, uri, config);
+ } else {
+ // Serialize HTML form data into a key-value string.
+ data = io._serialize(config.form, data);
+ }
+ }
+
+ // Convert falsy values to an empty string. This way IE can't be
+ // rediculous and translate `undefined` to "undefined".
+ data || (data = '');
+
+ if (data) {
+ switch (method) {
+ case 'GET':
+ case 'HEAD':
+ case 'DELETE':
+ u = io._concat(u, data);
+ data = '';
+ Y.log('HTTP' + method + ' with data. The querystring is: ' + u, 'info', 'io');
+ break;
+ case 'POST':
+ case 'PUT':
+ // If Content-Type is defined in the configuration object, or
+ // or as a default header, it will be used instead of
+ // 'application/x-www-form-urlencoded; charset=UTF-8'
+ config.headers = Y.merge({
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+ }, config.headers);
+ break;
+ }
+ }
+
+ if (transaction.xdr) {
+ // Route data to io-xdr module for flash and XDomainRequest.
+ return io.xdr(u, transaction, config);
+ }
+ else if (transaction.notify) {
+ // Route data to custom transport
+ return transaction.c.send(transaction, uri, config);
+ }
+
+ if (!sync && !transaction.upload) {
+ transaction.c.onreadystatechange = function() {
+ io._rS(transaction, config);
+ };
+ }
+
+ try {
+ // Determine if request is to be set as
+ // synchronous or asynchronous.
+ transaction.c.open(method, u, !sync, config.username || null, config.password || null);
+ io._setHeaders(transaction.c, config.headers || {});
+ io.start(transaction, config);
+
+ // Will work only in browsers that implement the
+ // Cross-Origin Resource Sharing draft.
+ if (config.xdr && config.xdr.credentials && SUPPORTS_CORS) {
+ transaction.c.withCredentials = true;
+ }
+
+ // Using "null" with HTTP POST will result in a request
+ // with no Content-Length header defined.
+ transaction.c.send(data);
+
+ if (sync) {
+ // Create a response object for synchronous transactions,
+ // mixing id and arguments properties with the xhr
+ // properties whitelist.
+ for (i = 0, len = XHR_PROPS.length; i < len; ++i) {
+ response[XHR_PROPS[i]] = transaction.c[XHR_PROPS[i]];
+ }
+
+ response.getAllResponseHeaders = function() {
+ return transaction.c.getAllResponseHeaders();
+ };
+
+ response.getResponseHeader = function(name) {
+ return transaction.c.getResponseHeader(name);
+ };
+
+ io.complete(transaction, config);
+ io._result(transaction, config);
+
+ return response;
+ }
+ } catch(e) {
+ if (transaction.xdr) {
+ // This exception is usually thrown by browsers
+ // that do not support XMLHttpRequest Level 2.
+ // Retry the request with the XDR transport set
+ // to 'flash'. If the Flash transport is not
+ // initialized or available, the transaction
+ // will resolve to a transport error.
+ return io._retry(transaction, uri, config);
+ } else {
+ io.complete(transaction, config);
+ io._result(transaction, config);
+ }
+ }
+
+ // If config.timeout is defined, and the request is standard XHR,
+ // initialize timeout polling.
+ if (config.timeout) {
+ io._startTimeout(transaction, config.timeout);
+ Y.log('Configuration timeout set to: ' + config.timeout, 'info', 'io');
+ }
+
+ return {
+ id: transaction.id,
+ abort: function() {
+ return transaction.c ? io._abort(transaction, 'abort') : false;
+ },
+ isInProgress: function() {
+ return transaction.c ? (transaction.c.readyState % 4) : false;
+ },
+ io: io
+ };
+ }
+};
+
+/**
+Method for initiating an ajax call. The first argument is the url end
+point for the call. The second argument is an object to configure the
+transaction and attach event subscriptions. The configuration object
+supports the following properties:
+
+
+ *
+ *
+ *
+ *
+ *
+
+
+@method io
+@static
+@param {String} url qualified path to transaction resource.
+@param {Object} config configuration object for the transaction.
+@return {Object}
+@for YUI
+**/
+Y.io = function(url, config) {
+ // Calling IO through the static interface will use and reuse
+ // an instance of IO.
+ var transaction = Y.io._map['io:0'] || new IO();
+ return transaction.send.apply(transaction, [url, config]);
+};
+
+/**
+Method for setting and deleting IO HTTP headers to be sent with every
+request.
+
+Hosted as a property on the `io` function (e.g. `Y.io.header`).
+
+@method header
+@param {String} name HTTP header
+@param {String} value HTTP header value
+@static
+**/
+Y.io.header = function(name, value) {
+ // Calling IO through the static interface will use and reuse
+ // an instance of IO.
+ var transaction = Y.io._map['io:0'] || new IO();
+ transaction.setHeader(name, value);
+};
+
+Y.IO = IO;
+// Map of all IO instances created.
+Y.io._map = {};
+var XHR = win && win.XMLHttpRequest,
+ XDR = win && win.XDomainRequest,
+ AX = win && win.ActiveXObject,
+
+ // Checks for the presence of the `withCredentials` in an XHR instance
+ // object, which will be present if the environment supports CORS.
+ SUPPORTS_CORS = XHR && 'withCredentials' in (new XMLHttpRequest());
+
+
+Y.mix(Y.IO, {
+ /**
+ * The ID of the default IO transport, defaults to `xhr`
+ * @property _default
+ * @type {String}
+ * @static
+ */
+ _default: 'xhr',
+ /**
+ *
+ * @method defaultTransport
+ * @static
+ * @param {String} [id] The transport to set as the default, if empty a new transport is created.
+ * @return {Object} The transport object with a `send` method
+ */
+ defaultTransport: function(id) {
+ if (id) {
+ Y.log('Setting default IO to: ' + id, 'info', 'io');
+ Y.IO._default = id;
+ } else {
+ var o = {
+ c: Y.IO.transports[Y.IO._default](),
+ notify: Y.IO._default === 'xhr' ? false : true
+ };
+ Y.log('Creating default transport: ' + Y.IO._default, 'info', 'io');
+ return o;
+ }
+ },
+ /**
+ * An object hash of custom transports available to IO
+ * @property transports
+ * @type {Object}
+ * @static
+ */
+ transports: {
+ xhr: function () {
+ return XHR ? new XMLHttpRequest() :
+ AX ? new ActiveXObject('Microsoft.XMLHTTP') : null;
+ },
+ xdr: function () {
+ return XDR ? new XDomainRequest() : null;
+ },
+ iframe: function () { return {}; },
+ flash: null,
+ nodejs: null
+ },
+ /**
+ * Create a custom transport of type and return it's object
+ * @method customTransport
+ * @param {String} id The id of the transport to create.
+ * @static
+ */
+ customTransport: function(id) {
+ var o = { c: Y.IO.transports[id]() };
+
+ o[(id === 'xdr' || id === 'flash') ? 'xdr' : 'notify'] = true;
+ return o;
+ }
+});
+
+Y.mix(Y.IO.prototype, {
+ /**
+ * Fired from the notify method of the transport which in turn fires
+ * the event on the IO object.
+ * @method notify
+ * @param {String} event The name of the event
+ * @param {Object} transaction The transaction object
+ * @param {Object} config The configuration object for this transaction
+ */
+ notify: function(event, transaction, config) {
+ var io = this;
+
+ switch (event) {
+ case 'timeout':
+ case 'abort':
+ case 'transport error':
+ transaction.c = { status: 0, statusText: event };
+ event = 'failure';
+ default:
+ io[event].apply(io, [transaction, config]);
+ }
+ }
+});
+
+
+
+
+}, '@VERSION@', {"requires": ["event-custom-base", "querystring-stringify-simple"]});
+YUI.add('json-parse', function (Y, NAME) {
+
+var _JSON = Y.config.global.JSON;
+
+Y.namespace('JSON').parse = function (obj, reviver, space) {
+ return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space);
+};
+
+
+}, '@VERSION@', {"requires": ["yui-base"]});
+YUI.add('transition', function (Y, NAME) {
+
+/**
+* Provides the transition method for Node.
+* Transition has no API of its own, but adds the transition method to Node.
+*
+* @module transition
+* @requires node-style
+*/
+
+var CAMEL_VENDOR_PREFIX = '',
+ VENDOR_PREFIX = '',
+ DOCUMENT = Y.config.doc,
+ DOCUMENT_ELEMENT = 'documentElement',
+ DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style,
+ TRANSITION_CAMEL = 'transition',
+ TRANSITION_PROPERTY_CAMEL = 'transitionProperty',
+ TRANSITION_PROPERTY,
+ TRANSITION_DURATION,
+ TRANSITION_TIMING_FUNCTION,
+ TRANSITION_DELAY,
+ TRANSITION_END,
+ ON_TRANSITION_END,
+
+ EMPTY_OBJ = {},
+
+ VENDORS = [
+ 'Webkit',
+ 'Moz'
+ ],
+
+ VENDOR_TRANSITION_END = {
+ Webkit: 'webkitTransitionEnd'
+ },
+
+/**
+ * A class for constructing transition instances.
+ * Adds the "transition" method to Node.
+ * @class Transition
+ * @constructor
+ */
+
+Transition = function() {
+ this.init.apply(this, arguments);
+};
+
+// One off handling of transform-prefixing.
+Transition._TRANSFORM = 'transform';
+
+Transition._toCamel = function(property) {
+ property = property.replace(/-([a-z])/gi, function(m0, m1) {
+ return m1.toUpperCase();
+ });
+
+ return property;
+};
+
+Transition._toHyphen = function(property) {
+ property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
+ var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2;
+
+ if (m3) {
+ str += '-' + m3.toLowerCase();
+ }
+
+ return str;
+ });
+
+ return property;
+};
+
+Transition.SHOW_TRANSITION = 'fadeIn';
+Transition.HIDE_TRANSITION = 'fadeOut';
+
+Transition.useNative = false;
+
+// Map transition properties to vendor-specific versions.
+if ('transition' in DOCUMENT_STYLE
+ && 'transitionProperty' in DOCUMENT_STYLE
+ && 'transitionDuration' in DOCUMENT_STYLE
+ && 'transitionTimingFunction' in DOCUMENT_STYLE
+ && 'transitionDelay' in DOCUMENT_STYLE) {
+ Transition.useNative = true;
+ Transition.supported = true; // TODO: remove
+} else {
+ Y.Array.each(VENDORS, function(val) { // then vendor specific
+ var property = val + 'Transition';
+ if (property in DOCUMENT[DOCUMENT_ELEMENT].style) {
+ CAMEL_VENDOR_PREFIX = val;
+ VENDOR_PREFIX = Transition._toHyphen(val) + '-';
+
+ Transition.useNative = true;
+ Transition.supported = true; // TODO: remove
+ Transition._VENDOR_PREFIX = val;
+ }
+ });
+}
+
+// Map transform property to vendor-specific versions.
+// One-off required for cssText injection.
+if (typeof DOCUMENT_STYLE.transform === 'undefined') {
+ Y.Array.each(VENDORS, function(val) { // then vendor specific
+ var property = val + 'Transform';
+ if (typeof DOCUMENT_STYLE[property] !== 'undefined') {
+ Transition._TRANSFORM = property;
+ }
+ });
+}
+
+if (CAMEL_VENDOR_PREFIX) {
+ TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + 'Transition';
+ TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty';
+}
+
+TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property';
+TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration';
+TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function';
+TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay';
+
+TRANSITION_END = 'transitionend';
+ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend';
+TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END;
+
+Transition.fx = {};
+Transition.toggles = {};
+
+Transition._hasEnd = {};
+
+Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
+
+Y.Node.DOM_EVENTS[TRANSITION_END] = 1;
+
+Transition.NAME = 'transition';
+
+Transition.DEFAULT_EASING = 'ease';
+Transition.DEFAULT_DURATION = 0.5;
+Transition.DEFAULT_DELAY = 0;
+
+Transition._nodeAttrs = {};
+
+Transition.prototype = {
+ constructor: Transition,
+ init: function(node, config) {
+ var anim = this;
+ anim._node = node;
+ if (!anim._running && config) {
+ anim._config = config;
+ node._transition = anim; // cache for reuse
+
+ anim._duration = ('duration' in config) ?
+ config.duration: anim.constructor.DEFAULT_DURATION;
+
+ anim._delay = ('delay' in config) ?
+ config.delay: anim.constructor.DEFAULT_DELAY;
+
+ anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
+ anim._count = 0; // track number of animated properties
+ anim._running = false;
+
+ }
+
+ return anim;
+ },
+
+ addProperty: function(prop, config) {
+ var anim = this,
+ node = this._node,
+ uid = Y.stamp(node),
+ nodeInstance = Y.one(node),
+ attrs = Transition._nodeAttrs[uid],
+ computed,
+ compareVal,
+ dur,
+ attr,
+ val;
+
+ if (!attrs) {
+ attrs = Transition._nodeAttrs[uid] = {};
+ }
+
+ attr = attrs[prop];
+
+ // might just be a value
+ if (config && config.value !== undefined) {
+ val = config.value;
+ } else if (config !== undefined) {
+ val = config;
+ config = EMPTY_OBJ;
+ }
+
+ if (typeof val === 'function') {
+ val = val.call(nodeInstance, nodeInstance);
+ }
+
+ if (attr && attr.transition) {
+ // take control if another transition owns this property
+ if (attr.transition !== anim) {
+ attr.transition._count--; // remapping attr to this transition
+ }
+ }
+
+ anim._count++; // properties per transition
+
+ // make 0 async and fire events
+ dur = ((typeof config.duration !== 'undefined') ? config.duration :
+ anim._duration) || 0.0001;
+
+ attrs[prop] = {
+ value: val,
+ duration: dur,
+ delay: (typeof config.delay !== 'undefined') ? config.delay :
+ anim._delay,
+
+ easing: config.easing || anim._easing,
+
+ transition: anim
+ };
+
+ // native end event doesnt fire when setting to same value
+ // supplementing with timer
+ // val may be a string or number (height: 0, etc), but computedStyle is always string
+ computed = Y.DOM.getComputedStyle(node, prop);
+ compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
+
+ if (Transition.useNative && compareVal === val) {
+ setTimeout(function() {
+ anim._onNativeEnd.call(node, {
+ propertyName: prop,
+ elapsedTime: dur
+ });
+ }, dur * 1000);
+ }
+ },
+
+ removeProperty: function(prop) {
+ var anim = this,
+ attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
+
+ if (attrs && attrs[prop]) {
+ delete attrs[prop];
+ anim._count--;
+ }
+
+ },
+
+ initAttrs: function(config) {
+ var attr,
+ node = this._node;
+
+ if (config.transform && !config[Transition._TRANSFORM]) {
+ config[Transition._TRANSFORM] = config.transform;
+ delete config.transform; // TODO: copy
+ }
+
+ for (attr in config) {
+ if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
+ this.addProperty(attr, config[attr]);
+
+ // when size is auto or % webkit starts from zero instead of computed
+ // (https://bugs.webkit.org/show_bug.cgi?id=16020)
+ // TODO: selective set
+ if (node.style[attr] === '') {
+ Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
+ }
+ }
+ }
+ },
+
+ /**
+ * Starts or an animation.
+ * @method run
+ * @chainable
+ * @private
+ */
+ run: function(callback) {
+ var anim = this,
+ node = anim._node,
+ config = anim._config,
+ data = {
+ type: 'transition:start',
+ config: config
+ };
+
+
+ if (!anim._running) {
+ anim._running = true;
+
+ if (config.on && config.on.start) {
+ config.on.start.call(Y.one(node), data);
+ }
+
+ anim.initAttrs(anim._config);
+
+ anim._callback = callback;
+ anim._start();
+ }
+
+
+ return anim;
+ },
+
+ _start: function() {
+ this._runNative();
+ },
+
+ _prepDur: function(dur) {
+ dur = parseFloat(dur) * 1000;
+
+ return dur + 'ms';
+ },
+
+ _runNative: function() {
+ var anim = this,
+ node = anim._node,
+ uid = Y.stamp(node),
+ style = node.style,
+ computed = node.ownerDocument.defaultView.getComputedStyle(node),
+ attrs = Transition._nodeAttrs[uid],
+ cssText = '',
+ cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)],
+
+ transitionText = TRANSITION_PROPERTY + ': ',
+ duration = TRANSITION_DURATION + ': ',
+ easing = TRANSITION_TIMING_FUNCTION + ': ',
+ delay = TRANSITION_DELAY + ': ',
+ hyphy,
+ attr,
+ name;
+
+ // preserve existing transitions
+ if (cssTransition !== 'all') {
+ transitionText += cssTransition + ',';
+ duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ',';
+ easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ',';
+ delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ',';
+
+ }
+
+ // run transitions mapped to this instance
+ for (name in attrs) {
+ hyphy = Transition._toHyphen(name);
+ attr = attrs[name];
+ if ((attr = attrs[name]) && attr.transition === anim) {
+ if (name in node.style) { // only native styles allowed
+ duration += anim._prepDur(attr.duration) + ',';
+ delay += anim._prepDur(attr.delay) + ',';
+ easing += (attr.easing) + ',';
+
+ transitionText += hyphy + ',';
+ cssText += hyphy + ': ' + attr.value + '; ';
+ } else {
+ this.removeProperty(name);
+ }
+ }
+ }
+
+ transitionText = transitionText.replace(/,$/, ';');
+ duration = duration.replace(/,$/, ';');
+ easing = easing.replace(/,$/, ';');
+ delay = delay.replace(/,$/, ';');
+
+ // only one native end event per node
+ if (!Transition._hasEnd[uid]) {
+ node.addEventListener(TRANSITION_END, anim._onNativeEnd, '');
+ Transition._hasEnd[uid] = true;
+
+ }
+
+ style.cssText += transitionText + duration + easing + delay + cssText;
+
+ },
+
+ _end: function(elapsed) {
+ var anim = this,
+ node = anim._node,
+ callback = anim._callback,
+ config = anim._config,
+ data = {
+ type: 'transition:end',
+ config: config,
+ elapsedTime: elapsed
+ },
+
+ nodeInstance = Y.one(node);
+
+ anim._running = false;
+ anim._callback = null;
+
+ if (node) {
+ if (config.on && config.on.end) {
+ setTimeout(function() { // IE: allow previous update to finish
+ config.on.end.call(nodeInstance, data);
+
+ // nested to ensure proper fire order
+ if (callback) {
+ callback.call(nodeInstance, data);
+ }
+
+ }, 1);
+ } else if (callback) {
+ setTimeout(function() { // IE: allow previous update to finish
+ callback.call(nodeInstance, data);
+ }, 1);
+ }
+ }
+
+ },
+
+ _endNative: function(name) {
+ var node = this._node,
+ value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)];
+
+ name = Transition._toHyphen(name);
+ if (typeof value === 'string') {
+ value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
+ value = value.replace(/^,|,$/, '');
+ node.style[TRANSITION_CAMEL] = value;
+ }
+ },
+
+ _onNativeEnd: function(e) {
+ var node = this,
+ uid = Y.stamp(node),
+ event = e,//e._event,
+ name = Transition._toCamel(event.propertyName),
+ elapsed = event.elapsedTime,
+ attrs = Transition._nodeAttrs[uid],
+ attr = attrs[name],
+ anim = (attr) ? attr.transition : null,
+ data,
+ config;
+
+ if (anim) {
+ anim.removeProperty(name);
+ anim._endNative(name);
+ config = anim._config[name];
+
+ data = {
+ type: 'propertyEnd',
+ propertyName: name,
+ elapsedTime: elapsed,
+ config: config
+ };
+
+ if (config && config.on && config.on.end) {
+ config.on.end.call(Y.one(node), data);
+ }
+
+ if (anim._count <= 0) { // after propertyEnd fires
+ anim._end(elapsed);
+ node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style
+ }
+ }
+ },
+
+ destroy: function() {
+ var anim = this,
+ node = anim._node;
+
+ if (node) {
+ node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
+ anim._node = null;
+ }
+ }
+};
+
+Y.Transition = Transition;
+Y.TransitionNative = Transition; // TODO: remove
+
+/**
+ * Animate one or more css properties to a given value. Requires the "transition" module.
+ *
+
+
+
+
+ example usage:
+ * Y.one('#demo').transition({
+ * duration: 1, // in seconds, default is 0.5
+ * easing: 'ease-out', // default is 'ease'
+ * delay: '1', // delay start for 1 second, default is 0
+ *
+ * height: '10px',
+ * width: '10px',
+ *
+ * opacity: { // per property
+ * value: 0,
+ * duration: 2,
+ * delay: 2,
+ * easing: 'ease-in'
+ * }
+ * });
+ *
+ * @for Node
+ * @method transition
+ * @param {Object} config An object containing one or more style properties, a duration and an easing.
+ * @param {Function} callback A function to run after the transition has completed.
+ * @chainable
+*/
+Y.Node.prototype.transition = function(name, config, callback) {
+ var
+ transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
+ anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
+ fxConfig,
+ prop;
+
+ if (typeof name === 'string') { // named effect, pull config from registry
+ if (typeof config === 'function') {
+ callback = config;
+ config = null;
+ }
+
+ fxConfig = Transition.fx[name];
+
+ if (config && typeof config !== 'boolean') {
+ config = Y.clone(config);
+
+ for (prop in fxConfig) {
+ if (fxConfig.hasOwnProperty(prop)) {
+ if (! (prop in config)) {
+ config[prop] = fxConfig[prop];
+ }
+ }
+ }
+ } else {
+ config = fxConfig;
+ }
+
+ } else { // name is a config, config is a callback or undefined
+ callback = config;
+ config = name;
+ }
+
+ if (anim && !anim._running) {
+ anim.init(this, config);
+ } else {
+ anim = new Transition(this._node, config);
+ }
+
+ anim.run(callback);
+ return this;
+};
+
+Y.Node.prototype.show = function(name, config, callback) {
+ this._show(); // show prior to transition
+ if (name && Y.Transition) {
+ if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
+ if (typeof config === 'function') {
+ callback = config;
+ config = name;
+ }
+ name = Transition.SHOW_TRANSITION;
+ }
+ this.transition(name, config, callback);
+ }
+ else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); }
+ return this;
+};
+
+Y.NodeList.prototype.show = function(name, config, callback) {
+ var nodes = this._nodes,
+ i = 0,
+ node;
+
+ while ((node = nodes[i++])) {
+ Y.one(node).show(name, config, callback);
+ }
+
+ return this;
+};
+
+
+
+var _wrapCallBack = function(anim, fn, callback) {
+ return function() {
+ if (fn) {
+ fn.call(anim);
+ }
+ if (callback && typeof callback === 'function') {
+ callback.apply(anim._node, arguments);
+ }
+ };
+};
+
+Y.Node.prototype.hide = function(name, config, callback) {
+ if (name && Y.Transition) {
+ if (typeof config === 'function') {
+ callback = config;
+ config = null;
+ }
+
+ callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
+ if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
+ if (typeof config === 'function') {
+ callback = config;
+ config = name;
+ }
+ name = Transition.HIDE_TRANSITION;
+ }
+ this.transition(name, config, callback);
+ } else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node');
+ } else {
+ this._hide();
+ }
+ return this;
+};
+
+Y.NodeList.prototype.hide = function(name, config, callback) {
+ var nodes = this._nodes,
+ i = 0,
+ node;
+
+ while ((node = nodes[i++])) {
+ Y.one(node).hide(name, config, callback);
+ }
+
+ return this;
+};
+
+/**
+ * Animate one or more css properties to a given value. Requires the "transition" module.
+ * example usage:
+ * Y.all('.demo').transition({
+ * duration: 1, // in seconds, default is 0.5
+ * easing: 'ease-out', // default is 'ease'
+ * delay: '1', // delay start for 1 second, default is 0
+ *
+ * height: '10px',
+ * width: '10px',
+ *
+ * opacity: { // per property
+ * value: 0,
+ * duration: 2,
+ * delay: 2,
+ * easing: 'ease-in'
+ * }
+ * });
+ *
+ * @for NodeList
+ * @method transition
+ * @param {Object} config An object containing one or more style properties, a duration and an easing.
+ * @param {Function} callback A function to run after the transition has completed. The callback fires
+ * once per item in the NodeList.
+ * @chainable
+*/
+Y.NodeList.prototype.transition = function(config, callback) {
+ var nodes = this._nodes,
+ i = 0,
+ node;
+
+ while ((node = nodes[i++])) {
+ Y.one(node).transition(config, callback);
+ }
+
+ return this;
+};
+
+Y.Node.prototype.toggleView = function(name, on, callback) {
+ this._toggles = this._toggles || [];
+ callback = arguments[arguments.length - 1];
+
+ if (typeof name !== 'string') { // no transition, just toggle
+ on = name;
+ this._toggleView(on, callback); // call original _toggleView in Y.Node
+ return;
+ }
+
+ if (typeof on === 'function') { // Ignore "on" if used for callback argument.
+ on = undefined;
+ }
+
+ if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle
+ on = ! this._toggles[name];
+ }
+
+ on = (on) ? 1 : 0;
+ if (on) {
+ this._show();
+ } else {
+ callback = _wrapCallBack(this, this._hide, callback);
+ }
+
+ this._toggles[name] = on;
+ this.transition(Y.Transition.toggles[name][on], callback);
+
+ return this;
+};
+
+Y.NodeList.prototype.toggleView = function(name, on, callback) {
+ var nodes = this._nodes,
+ i = 0,
+ node;
+
+ while ((node = nodes[i++])) {
+ node = Y.one(node);
+ node.toggleView.apply(node, arguments);
+ }
+
+ return this;
+};
+
+Y.mix(Transition.fx, {
+ fadeOut: {
+ opacity: 0,
+ duration: 0.5,
+ easing: 'ease-out'
+ },
+
+ fadeIn: {
+ opacity: 1,
+ duration: 0.5,
+ easing: 'ease-in'
+ },
+
+ sizeOut: {
+ height: 0,
+ width: 0,
+ duration: 0.75,
+ easing: 'ease-out'
+ },
+
+ sizeIn: {
+ height: function(node) {
+ return node.get('scrollHeight') + 'px';
+ },
+ width: function(node) {
+ return node.get('scrollWidth') + 'px';
+ },
+ duration: 0.5,
+ easing: 'ease-in',
+
+ on: {
+ start: function() {
+ var overflow = this.getStyle('overflow');
+ if (overflow !== 'hidden') { // enable scrollHeight/Width
+ this.setStyle('overflow', 'hidden');
+ this._transitionOverflow = overflow;
+ }
+ },
+
+ end: function() {
+ if (this._transitionOverflow) { // revert overridden value
+ this.setStyle('overflow', this._transitionOverflow);
+ delete this._transitionOverflow;
+ }
+ }
+ }
+ }
+});
+
+Y.mix(Transition.toggles, {
+ size: ['sizeOut', 'sizeIn'],
+ fade: ['fadeOut', 'fadeIn']
+});
+
+
+}, '@VERSION@', {"requires": ["node-style"]});
+YUI.add('selector-css2', function (Y, NAME) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/*
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,
+ SORT_RESULTS: true,
+
+ // TODO: better detection, document specific
+ _isXML: (function() {
+ var isXML = (Y.config.doc.createElement('div').tagName !== 'DIV');
+ return isXML;
+ }()),
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z0-9]+[-\\w\\uE000]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.DOM._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ child,
+ id,
+ className,
+ tagName;
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
+ // try ID first, unless no root.all && root not in document
+ // (root.all works off document, but not getElementById)
+ if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) {
+ nodes = Y.DOM.allById(id, root);
+ // try className
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else { // default to tagName
+ nodes = root.getElementsByTagName(tagName);
+ }
+
+ } else { // brute getElementsByTagName()
+ child = root.firstChild;
+ while (child) {
+ // only collect HTMLElements
+ // match tag to supplement missing getElementsByTagName
+ if (child.tagName && (tagName === '*' || child.tagName === tagName)) {
+ nodes.push(child);
+ }
+ child = child.nextSibling || child.firstChild;
+ }
+ }
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ value,
+ tests,
+ test;
+
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ if (test[0] === 'tagName' && !Selector._isXML) {
+ value = value.toUpperCase();
+ }
+ if (typeof value != 'string' && value !== undefined && value.toString) {
+ value = value.toString(); // coerce for comparison
+ } else if (value === undefined && tmpNode.getAttribute) {
+ // use getAttribute for non-standard attributes
+ value = tmpNode.getAttribute(test[0], 2); // 2 === force string for IE
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
+ operator.test && !operator.test(value)) || // regex test
+ (!operator.test && // protect against RegExp as function (webkit)
+ typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }
+ node = tmpNode = null;
+ return result;
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Selector.operators,
+ escVal = (match[3]) ? match[3].replace(/\\/g, '') : '',
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ Y.config.doc.documentElement.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+
+
+ match[3] = escVal;
+
+ // escape all but ID for prefilter, which may run through QSA (via Dom.allById)
+ token[match[1]] = (match[1] === 'id') ? match[3] : escVal;
+
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1');
+ test = new RegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1];
+
+ if (!Selector._isXML) {
+ tag = tag.toUpperCase();
+ }
+
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array and unescape special chars for tests
+ if (match[2]) {
+ match[2] = match[2].replace(/\\/g, '');
+ }
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /*
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._parseSelector(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser.name !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceMarkers: function(selector) {
+ selector = selector.replace(/\[/g, '\uE003');
+ selector = selector.replace(/\]/g, '\uE004');
+
+ selector = selector.replace(/\(/g, '\uE005');
+ selector = selector.replace(/\)/g, '\uE006');
+ return selector;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Y.Selector.shorthand,
+ re;
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ return selector;
+ },
+
+ _parseSelector: function(selector) {
+ var replaced = Y.Selector._replaceSelector(selector),
+ selector = replaced.selector;
+
+ // replace shorthand (".foo, #bar") after pseudos and attrs
+ // to avoid replacing unescaped chars
+ selector = Y.Selector._replaceShorthand(selector);
+
+ selector = Y.Selector._restore('attr', selector, replaced.attrs);
+ selector = Y.Selector._restore('pseudo', selector, replaced.pseudos);
+
+ // replace braces and parens before restoring escaped chars
+ // to avoid replacing ecaped markers
+ selector = Y.Selector._replaceMarkers(selector);
+ selector = Y.Selector._restore('esc', selector, replaced.esc);
+
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ },
+
+ id: function(node, attr) {
+ return Y.DOM.getId(node);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && Y.config.doc.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '@VERSION@', {"requires": ["selector-native"]});
+YUI.add('selector-css3', function (Y, NAME) {
+
+/**
+ * The selector css3 module provides support for css3 selectors.
+ * @module dom
+ * @submodule selector-css3
+ * @for Selector
+ */
+
+/*
+ an+b = get every _a_th node starting at the _b_th
+ 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
+ 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
+ an+0 = get every _a_th element, "0" may be omitted
+*/
+
+Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
+
+Y.Selector._getNth = function(node, expr, tag, reverse) {
+ Y.Selector._reNth.test(expr);
+ var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
+ n = RegExp.$2, // "n"
+ oddeven = RegExp.$3, // "odd" or "even"
+ b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
+ result = [],
+ siblings = Y.DOM._children(node.parentNode, tag),
+ op;
+
+ if (oddeven) {
+ a = 2; // always every other
+ op = '+';
+ n = 'n';
+ b = (oddeven === 'odd') ? 1 : 0;
+ } else if ( isNaN(a) ) {
+ a = (n) ? 1 : 0; // start from the first or no repeat
+ }
+
+ if (a === 0) { // just the first
+ if (reverse) {
+ b = siblings.length - b + 1;
+ }
+
+ if (siblings[b - 1] === node) {
+ return true;
+ } else {
+ return false;
+ }
+
+ } else if (a < 0) {
+ reverse = !!reverse;
+ a = Math.abs(a);
+ }
+
+ if (!reverse) {
+ for (var i = b - 1, len = siblings.length; i < len; i += a) {
+ if ( i >= 0 && siblings[i] === node ) {
+ return true;
+ }
+ }
+ } else {
+ for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
+ if ( i < len && siblings[i] === node ) {
+ return true;
+ }
+ }
+ }
+ return false;
+};
+
+Y.mix(Y.Selector.pseudos, {
+ 'root': function(node) {
+ return node === node.ownerDocument.documentElement;
+ },
+
+ 'nth-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr);
+ },
+
+ 'nth-last-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr, null, true);
+ },
+
+ 'nth-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName);
+ },
+
+ 'nth-last-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName, true);
+ },
+
+ 'last-child': function(node) {
+ var children = Y.DOM._children(node.parentNode);
+ return children[children.length - 1] === node;
+ },
+
+ 'first-of-type': function(node) {
+ return Y.DOM._children(node.parentNode, node.tagName)[0] === node;
+ },
+
+ 'last-of-type': function(node) {
+ var children = Y.DOM._children(node.parentNode, node.tagName);
+ return children[children.length - 1] === node;
+ },
+
+ 'only-child': function(node) {
+ var children = Y.DOM._children(node.parentNode);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'only-of-type': function(node) {
+ var children = Y.DOM._children(node.parentNode, node.tagName);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'empty': function(node) {
+ return node.childNodes.length === 0;
+ },
+
+ 'not': function(node, expr) {
+ return !Y.Selector.test(node, expr);
+ },
+
+ 'contains': function(node, expr) {
+ var text = node.innerText || node.textContent || '';
+ return text.indexOf(expr) > -1;
+ },
+
+ 'checked': function(node) {
+ return (node.checked === true || node.selected === true);
+ },
+
+ enabled: function(node) {
+ return (node.disabled !== undefined && !node.disabled);
+ },
+
+ disabled: function(node) {
+ return (node.disabled);
+ }
+});
+
+Y.mix(Y.Selector.operators, {
+ '^=': '^{val}', // Match starts with value
+ '$=': '{val}$', // Match ends with value
+ '*=': '{val}' // Match contains value as substring
+});
+
+Y.Selector.combinators['~'] = {
+ axis: 'previousSibling'
+};
+
+
+}, '@VERSION@', {"requires": ["selector-native", "selector-css2"]});
+YUI.add('yui-log', function (Y, NAME) {
+
+/**
+ * Provides console log capability and exposes a custom event for
+ * console implementations. This module is a `core` YUI module,
+ * it's documentation is located under the YUI class.
+ *
+ * @module yui
+ * @submodule yui-log
+ */
+
+var INSTANCE = Y,
+ LOGEVENT = 'yui:log',
+ UNDEFINED = 'undefined',
+ LEVELS = { debug: 1,
+ info: 2,
+ warn: 4,
+ error: 8 };
+
+/**
+ * If the 'debug' config is true, a 'yui:log' event will be
+ * dispatched, which the Console widget and anything else
+ * can consume. If the 'useBrowserConsole' config is true, it will
+ * write to the browser console if available. YUI-specific log
+ * messages will only be present in the -debug versions of the
+ * JS files. The build system is supposed to remove log statements
+ * from the raw and minified versions of the files.
+ *
+ * @method log
+ * @for YUI
+ * @param {String} msg The message to log.
+ * @param {String} cat The log category for the message. Default
+ * categories are "info", "warn", "error", time".
+ * Custom categories can be used as well. (opt).
+ * @param {String} src The source of the the message (opt).
+ * @param {boolean} silent If true, the log event won't fire.
+ * @return {YUI} YUI instance.
+ */
+INSTANCE.log = function(msg, cat, src, silent) {
+ var bail, excl, incl, m, f, minlevel,
+ Y = INSTANCE,
+ c = Y.config,
+ publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
+ // suppress log message if the config is off or the event stack
+ // or the event call stack contains a consumer of the yui:log event
+ if (c.debug) {
+ // apply source filters
+ src = src || "";
+ if (typeof src !== "undefined") {
+ excl = c.logExclude;
+ incl = c.logInclude;
+ if (incl && !(src in incl)) {
+ bail = 1;
+ } else if (incl && (src in incl)) {
+ bail = !incl[src];
+ } else if (excl && (src in excl)) {
+ bail = excl[src];
+ }
+
+ // Determine the current minlevel as defined in configuration
+ Y.config.logLevel = Y.config.logLevel || 'debug';
+ minlevel = LEVELS[Y.config.logLevel.toLowerCase()];
+
+ if (cat in LEVELS && LEVELS[cat] < minlevel) {
+ // Skip this message if the we don't meet the defined minlevel
+ bail = 1;
+ }
+ }
+ if (!bail) {
+ if (c.useBrowserConsole) {
+ m = (src) ? src + ': ' + msg : msg;
+ if (Y.Lang.isFunction(c.logFn)) {
+ c.logFn.call(Y, msg, cat, src);
+ } else if (typeof console !== UNDEFINED && console.log) {
+ f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
+ console[f](m);
+ } else if (typeof opera !== UNDEFINED) {
+ opera.postError(m);
+ }
+ }
+
+ if (publisher && !silent) {
+
+ if (publisher === Y && (!publisher.getEvent(LOGEVENT))) {
+ publisher.publish(LOGEVENT, {
+ broadcast: 2
+ });
+ }
+
+ publisher.fire(LOGEVENT, {
+ msg: msg,
+ cat: cat,
+ src: src
+ });
+ }
+ }
+ }
+
+ return Y;
+};
+
+/**
+ * Write a system message. This message will be preserved in the
+ * minified and raw versions of the YUI files, unlike log statements.
+ * @method message
+ * @for YUI
+ * @param {String} msg The message to log.
+ * @param {String} cat The log category for the message. Default
+ * categories are "info", "warn", "error", time".
+ * Custom categories can be used as well. (opt).
+ * @param {String} src The source of the the message (opt).
+ * @param {boolean} silent If true, the log event won't fire.
+ * @return {YUI} YUI instance.
+ */
+INSTANCE.message = function() {
+ return INSTANCE.log.apply(INSTANCE, arguments);
+};
+
+
+}, '@VERSION@', {"requires": ["yui-base"]});
+YUI.add('dump', function (Y, NAME) {
+
+/**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ *
+ * If included, the dump method is added to the YUI instance.
+ *
+ * @module dump
+ */
+
+ var L = Y.Lang,
+ OBJ = '{...}',
+ FUN = 'f(){...}',
+ COMMA = ', ',
+ ARROW = ' => ',
+
+ /**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed.
+ *
+ * @method dump
+ * @param {Object} o The object to dump.
+ * @param {Number} d How deep to recurse child objects, default 3.
+ * @return {String} the dump result.
+ * @for YUI
+ */
+ dump = function(o, d) {
+ var i, len, s = [], type = L.type(o);
+
+ // Cast non-objects to string
+ // Skip dates because the std toString is what we want
+ // Skip HTMLElement-like objects because trying to dump
+ // an element will cause an unhandled exception in FF 2.x
+ if (!L.isObject(o)) {
+ return o + '';
+ } else if (type == 'date') {
+ return o;
+ } else if (o.nodeType && o.tagName) {
+ return o.tagName + '#' + o.id;
+ } else if (o.document && o.navigator) {
+ return 'window';
+ } else if (o.location && o.body) {
+ return 'document';
+ } else if (type == 'function') {
+ return FUN;
+ }
+
+ // dig into child objects the depth specifed. Default 3
+ d = (L.isNumber(d)) ? d : 3;
+
+ // arrays [1, 2, 3]
+ if (type == 'array') {
+ s.push('[');
+ for (i = 0, len = o.length; i < len; i = i + 1) {
+ if (L.isObject(o[i])) {
+ s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push(']');
+ // regexp /foo/
+ } else if (type == 'regexp') {
+ s.push(o.toString());
+ // objects {k1 => v1, k2 => v2}
+ } else {
+ s.push('{');
+ for (i in o) {
+ if (o.hasOwnProperty(i)) {
+ try {
+ s.push(i + ARROW);
+ if (L.isObject(o[i])) {
+ s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ } catch (e) {
+ s.push('Error: ' + e.message);
+ }
+ }
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push('}');
+ }
+
+ return s.join('');
+ };
+
+ Y.dump = dump;
+ L.dump = dump;
+
+
+
+}, '@VERSION@', {"requires": ["yui-base"]});
+YUI.add('transition-timer', function (Y, NAME) {
+
+/**
+* Provides the base Transition class, for animating numeric properties.
+*
+* @module transition
+* @submodule transition-timer
+*/
+
+
+var Transition = Y.Transition;
+
+Y.mix(Transition.prototype, {
+ _start: function() {
+ if (Transition.useNative) {
+ this._runNative();
+ } else {
+ this._runTimer();
+ }
+ },
+
+ _runTimer: function() {
+ var anim = this;
+ anim._initAttrs();
+
+ Transition._running[Y.stamp(anim)] = anim;
+ anim._startTime = new Date();
+ Transition._startTimer();
+ },
+
+ _endTimer: function() {
+ var anim = this;
+ delete Transition._running[Y.stamp(anim)];
+ anim._startTime = null;
+ },
+
+ _runFrame: function() {
+ var t = new Date() - this._startTime;
+ this._runAttrs(t);
+ },
+
+ _runAttrs: function(time) {
+ var anim = this,
+ node = anim._node,
+ config = anim._config,
+ uid = Y.stamp(node),
+ attrs = Transition._nodeAttrs[uid],
+ customAttr = Transition.behaviors,
+ done = false,
+ allDone = false,
+ data,
+ name,
+ attribute,
+ setter,
+ elapsed,
+ delay,
+ d,
+ t,
+ i;
+
+ for (name in attrs) {
+ if ((attribute = attrs[name]) && attribute.transition === anim) {
+ d = attribute.duration;
+ delay = attribute.delay;
+ elapsed = (time - delay) / 1000;
+ t = time;
+ data = {
+ type: 'propertyEnd',
+ propertyName: name,
+ config: config,
+ elapsedTime: elapsed
+ };
+
+ setter = (i in customAttr && 'set' in customAttr[i]) ?
+ customAttr[i].set : Transition.DEFAULT_SETTER;
+
+ done = (t >= d);
+
+ if (t > d) {
+ t = d;
+ }
+
+ if (!delay || time >= delay) {
+ setter(anim, name, attribute.from, attribute.to, t - delay, d - delay,
+ attribute.easing, attribute.unit);
+
+ if (done) {
+ delete attrs[name];
+ anim._count--;
+
+ if (config[name] && config[name].on && config[name].on.end) {
+ config[name].on.end.call(Y.one(node), data);
+ }
+
+ //node.fire('transition:propertyEnd', data);
+
+ if (!allDone && anim._count <= 0) {
+ allDone = true;
+ anim._end(elapsed);
+ anim._endTimer();
+ }
+ }
+ }
+
+ }
+ }
+ },
+
+ _initAttrs: function() {
+ var anim = this,
+ customAttr = Transition.behaviors,
+ uid = Y.stamp(anim._node),
+ attrs = Transition._nodeAttrs[uid],
+ attribute,
+ duration,
+ delay,
+ easing,
+ val,
+ name,
+ mTo,
+ mFrom,
+ unit, begin, end;
+
+ for (name in attrs) {
+ if ((attribute = attrs[name]) && attribute.transition === anim) {
+ duration = attribute.duration * 1000;
+ delay = attribute.delay * 1000;
+ easing = attribute.easing;
+ val = attribute.value;
+
+ // only allow supported properties
+ if (name in anim._node.style || name in Y.DOM.CUSTOM_STYLES) {
+ begin = (name in customAttr && 'get' in customAttr[name]) ?
+ customAttr[name].get(anim, name) : Transition.DEFAULT_GETTER(anim, name);
+
+ mFrom = Transition.RE_UNITS.exec(begin);
+ mTo = Transition.RE_UNITS.exec(val);
+
+ begin = mFrom ? mFrom[1] : begin;
+ end = mTo ? mTo[1] : val;
+ unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units
+
+ if (!unit && Transition.RE_DEFAULT_UNIT.test(name)) {
+ unit = Transition.DEFAULT_UNIT;
+ }
+
+ if (typeof easing === 'string') {
+ if (easing.indexOf('cubic-bezier') > -1) {
+ easing = easing.substring(13, easing.length - 1).split(',');
+ } else if (Transition.easings[easing]) {
+ easing = Transition.easings[easing];
+ }
+ }
+
+ attribute.from = Number(begin);
+ attribute.to = Number(end);
+ attribute.unit = unit;
+ attribute.easing = easing;
+ attribute.duration = duration + delay;
+ attribute.delay = delay;
+ } else {
+ delete attrs[name];
+ anim._count--;
+ }
+ }
+ }
+ },
+
+ destroy: function() {
+ this.detachAll();
+ this._node = null;
+ }
+}, true);
+
+Y.mix(Y.Transition, {
+ _runtimeAttrs: {},
+ /*
+ * Regex of properties that should use the default unit.
+ *
+ * @property RE_DEFAULT_UNIT
+ * @static
+ */
+ RE_DEFAULT_UNIT: /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i,
+
+ /*
+ * The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
+ *
+ * @property DEFAULT_UNIT
+ * @static
+ */
+ DEFAULT_UNIT: 'px',
+
+ /*
+ * Time in milliseconds passed to setInterval for frame processing
+ *
+ * @property intervalTime
+ * @default 20
+ * @static
+ */
+ intervalTime: 20,
+
+ /*
+ * Bucket for custom getters and setters
+ *
+ * @property behaviors
+ * @static
+ */
+ behaviors: {
+ left: {
+ get: function(anim, attr) {
+ return Y.DOM._getAttrOffset(anim._node, attr);
+ }
+ }
+ },
+
+ /*
+ * The default setter to use when setting object properties.
+ *
+ * @property DEFAULT_SETTER
+ * @static
+ */
+ DEFAULT_SETTER: function(anim, att, from, to, elapsed, duration, fn, unit) {
+ from = Number(from);
+ to = Number(to);
+
+ var node = anim._node,
+ val = Transition.cubicBezier(fn, elapsed / duration);
+
+ val = from + val[0] * (to - from);
+
+ if (node) {
+ if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
+ unit = unit || '';
+ Y.DOM.setStyle(node, att, val + unit);
+ }
+ } else {
+ anim._end();
+ }
+ },
+
+ /*
+ * The default getter to use when getting object properties.
+ *
+ * @property DEFAULT_GETTER
+ * @static
+ */
+ DEFAULT_GETTER: function(anim, att) {
+ var node = anim._node,
+ val = '';
+
+ if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
+ val = Y.DOM.getComputedStyle(node, att);
+ }
+
+ return val;
+ },
+
+ _startTimer: function() {
+ if (!Transition._timer) {
+ Transition._timer = setInterval(Transition._runFrame, Transition.intervalTime);
+ }
+ },
+
+ _stopTimer: function() {
+ clearInterval(Transition._timer);
+ Transition._timer = null;
+ },
+
+ /*
+ * Called per Interval to handle each animation frame.
+ * @method _runFrame
+ * @private
+ * @static
+ */
+ _runFrame: function() {
+ var done = true,
+ anim;
+ for (anim in Transition._running) {
+ if (Transition._running[anim]._runFrame) {
+ done = false;
+ Transition._running[anim]._runFrame();
+ }
+ }
+
+ if (done) {
+ Transition._stopTimer();
+ }
+ },
+
+ cubicBezier: function(p, t) {
+ var x0 = 0,
+ y0 = 0,
+ x1 = p[0],
+ y1 = p[1],
+ x2 = p[2],
+ y2 = p[3],
+ x3 = 1,
+ y3 = 0,
+
+ A = x3 - 3 * x2 + 3 * x1 - x0,
+ B = 3 * x2 - 6 * x1 + 3 * x0,
+ C = 3 * x1 - 3 * x0,
+ D = x0,
+ E = y3 - 3 * y2 + 3 * y1 - y0,
+ F = 3 * y2 - 6 * y1 + 3 * y0,
+ G = 3 * y1 - 3 * y0,
+ H = y0,
+
+ x = (((A*t) + B)*t + C)*t + D,
+ y = (((E*t) + F)*t + G)*t + H;
+
+ return [x, y];
+ },
+
+ easings: {
+ ease: [0.25, 0, 1, 0.25],
+ linear: [0, 0, 1, 1],
+ 'ease-in': [0.42, 0, 1, 1],
+ 'ease-out': [0, 0, 0.58, 1],
+ 'ease-in-out': [0.42, 0, 0.58, 1]
+ },
+
+ _running: {},
+ _timer: null,
+
+ RE_UNITS: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/
+}, true);
+
+Transition.behaviors.top = Transition.behaviors.bottom = Transition.behaviors.right = Transition.behaviors.left;
+
+Y.Transition = Transition;
+
+
+}, '@VERSION@', {"requires": ["transition"]});
+YUI.add('yui', function (Y, NAME) {
+
+// empty
+
+
+
+}, '@VERSION@', {
+ "use": [
+ "yui",
+ "oop",
+ "dom",
+ "event-custom-base",
+ "event-base",
+ "pluginhost",
+ "node",
+ "event-delegate",
+ "io-base",
+ "json-parse",
+ "transition",
+ "selector-css3",
+ "dom-style-ie",
+ "querystring-stringify-simple"
+ ]
+});
+var Y = YUI().use('*');