4 ? Y.Array(arguments, 4, true) : null;
+ return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
+ }
+};
+
+/**
+ * Executes the callback as soon as the specified element
+ * is detected in the DOM with a nextSibling property
+ * (indicating that the element's children are available).
+ * This function expects a selector
+ * string for the element(s) to detect. If you already have
+ * an element reference, you don't need this event.
+ * @event contentready
+ * @param type {string} 'contentready'
+ * @param fn {function} the callback function to execute.
+ * @param el {string} an selector for the element(s) to attach.
+ * @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.Env.evt.plugins.contentready = {
+ on: function(type, fn, id, o) {
+ var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
+ return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
+ }
+};
+
+
+}, '@VERSION@', {"requires": ["event-custom-base"]});
+(function() {
+
+var stateChangeListener,
+ GLOBAL_ENV = YUI.Env,
+ config = YUI.config,
+ doc = config.doc,
+ docElement = doc && doc.documentElement,
+ EVENT_NAME = 'onreadystatechange',
+ pollInterval = config.pollInterval || 40;
+
+if (docElement.doScroll && !GLOBAL_ENV._ieready) {
+ GLOBAL_ENV._ieready = function() {
+ GLOBAL_ENV._ready();
+ };
+
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+// Internet Explorer: use the doScroll() method on the root element.
+// This isolates what appears to be a safe moment to manipulate the
+// DOM prior to when the document's readyState suggests it is safe to do so.
+ if (self !== self.top) {
+ stateChangeListener = function() {
+ if (doc.readyState == 'complete') {
+ GLOBAL_ENV.remove(doc, EVENT_NAME, stateChangeListener);
+ GLOBAL_ENV.ieready();
+ }
+ };
+ GLOBAL_ENV.add(doc, EVENT_NAME, stateChangeListener);
+ } else {
+ GLOBAL_ENV._dri = setInterval(function() {
+ try {
+ docElement.doScroll('left');
+ clearInterval(GLOBAL_ENV._dri);
+ GLOBAL_ENV._dri = null;
+ GLOBAL_ENV._ieready();
+ } catch (domNotReady) { }
+ }, pollInterval);
+ }
+}
+
+})();
+YUI.add('event-base-ie', function (Y, NAME) {
+
+/*
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event
+ * @submodule event-base
+ */
+
+function IEEventFacade() {
+ // IEEventFacade.superclass.constructor.apply(this, arguments);
+ Y.DOM2EventFacade.apply(this, arguments);
+}
+
+/*
+ * (intentially left out of API docs)
+ * Alternate Facade implementation that is based on Object.defineProperty, which
+ * is partially supported in IE8. Properties that involve setup work are
+ * deferred to temporary getters using the static _define method.
+ */
+function IELazyFacade(e) {
+ var proxy = Y.config.doc.createEventObject(e),
+ proto = IELazyFacade.prototype;
+
+ // TODO: necessary?
+ proxy.hasOwnProperty = function () { return true; };
+
+ proxy.init = proto.init;
+ proxy.halt = proto.halt;
+ proxy.preventDefault = proto.preventDefault;
+ proxy.stopPropagation = proto.stopPropagation;
+ proxy.stopImmediatePropagation = proto.stopImmediatePropagation;
+
+ Y.DOM2EventFacade.apply(proxy, arguments);
+
+ return proxy;
+}
+
+
+var imp = Y.config.doc && Y.config.doc.implementation,
+ useLazyFacade = Y.config.lazyEventFacade,
+
+ buttonMap = {
+ 0: 1, // left click
+ 4: 2, // middle click
+ 2: 3 // right click
+ },
+ relatedTargetMap = {
+ mouseout: 'toElement',
+ mouseover: 'fromElement'
+ },
+
+ resolve = Y.DOM2EventFacade.resolve,
+
+ proto = {
+ init: function() {
+
+ IEEventFacade.superclass.init.apply(this, arguments);
+
+ var e = this._event,
+ x, y, d, b, de, t;
+
+ this.target = resolve(e.srcElement);
+
+ if (('clientX' in e) && (!x) && (0 !== x)) {
+ x = e.clientX;
+ y = e.clientY;
+
+ d = Y.config.doc;
+ b = d.body;
+ de = d.documentElement;
+
+ x += (de.scrollLeft || (b && b.scrollLeft) || 0);
+ y += (de.scrollTop || (b && b.scrollTop) || 0);
+
+ this.pageX = x;
+ this.pageY = y;
+ }
+
+ if (e.type == "mouseout") {
+ t = e.toElement;
+ } else if (e.type == "mouseover") {
+ t = e.fromElement;
+ }
+
+ // fallback to t.relatedTarget to support simulated events.
+ // IE doesn't support setting toElement or fromElement on generic
+ // events, so Y.Event.simulate sets relatedTarget instead.
+ this.relatedTarget = resolve(t || e.relatedTarget);
+
+ // which should contain the unicode key code if this is a key event.
+ // For click events, which is normalized for which mouse button was
+ // clicked.
+ this.which = // chained assignment
+ this.button = e.keyCode || buttonMap[e.button] || e.button;
+ },
+
+ stopPropagation: function() {
+ this._event.cancelBubble = true;
+ this._wrapper.stopped = 1;
+ this.stopped = 1;
+ },
+
+ stopImmediatePropagation: function() {
+ this.stopPropagation();
+ this._wrapper.stopped = 2;
+ this.stopped = 2;
+ },
+
+ preventDefault: function(returnValue) {
+ this._event.returnValue = returnValue || false;
+ this._wrapper.prevented = 1;
+ this.prevented = 1;
+ }
+ };
+
+Y.extend(IEEventFacade, Y.DOM2EventFacade, proto);
+
+Y.extend(IELazyFacade, Y.DOM2EventFacade, proto);
+IELazyFacade.prototype.init = function () {
+ var e = this._event,
+ overrides = this._wrapper.overrides,
+ define = IELazyFacade._define,
+ lazyProperties = IELazyFacade._lazyProperties,
+ prop;
+
+ this.altKey = e.altKey;
+ this.ctrlKey = e.ctrlKey;
+ this.metaKey = e.metaKey;
+ this.shiftKey = e.shiftKey;
+ this.type = (overrides && overrides.type) || e.type;
+ this.clientX = e.clientX;
+ this.clientY = e.clientY;
+ this.keyCode = // chained assignment
+ this.charCode = e.keyCode;
+ this.which = // chained assignment
+ this.button = e.keyCode || buttonMap[e.button] || e.button;
+
+ for (prop in lazyProperties) {
+ if (lazyProperties.hasOwnProperty(prop)) {
+ define(this, prop, lazyProperties[prop]);
+ }
+ }
+
+ if (this._touch) {
+ this._touch(e, this._currentTarget, this._wrapper);
+ }
+};
+
+IELazyFacade._lazyProperties = {
+ target: function () {
+ return resolve(this._event.srcElement);
+ },
+ relatedTarget: function () {
+ var e = this._event,
+ targetProp = relatedTargetMap[e.type] || 'relatedTarget';
+
+ // fallback to t.relatedTarget to support simulated events.
+ // IE doesn't support setting toElement or fromElement on generic
+ // events, so Y.Event.simulate sets relatedTarget instead.
+ return resolve(e[targetProp] || e.relatedTarget);
+ },
+ currentTarget: function () {
+ return resolve(this._currentTarget);
+ },
+
+ wheelDelta: function () {
+ var e = this._event;
+
+ if (e.type === "mousewheel" || e.type === "DOMMouseScroll") {
+ return (e.detail) ?
+ (e.detail * -1) :
+ // wheelDelta between -80 and 80 result in -1 or 1
+ Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
+ }
+ },
+
+ pageX: function () {
+ var e = this._event,
+ val = e.pageX,
+ doc, bodyScroll, docScroll;
+
+ if (val === undefined) {
+ doc = Y.config.doc;
+ bodyScroll = doc.body && doc.body.scrollLeft;
+ docScroll = doc.documentElement.scrollLeft;
+
+ val = e.clientX + (docScroll || bodyScroll || 0);
+ }
+
+ return val;
+ },
+ pageY: function () {
+ var e = this._event,
+ val = e.pageY,
+ doc, bodyScroll, docScroll;
+
+ if (val === undefined) {
+ doc = Y.config.doc;
+ bodyScroll = doc.body && doc.body.scrollTop;
+ docScroll = doc.documentElement.scrollTop;
+
+ val = e.clientY + (docScroll || bodyScroll || 0);
+ }
+
+ return val;
+ }
+};
+
+
+/**
+ * Wrapper function for Object.defineProperty that creates a property whose
+ * value will be calulated only when asked for. After calculating the value,
+ * the getter wll be removed, so it will behave as a normal property beyond that
+ * point. A setter is also assigned so assigning to the property will clear
+ * the getter, so foo.prop = 'a'; foo.prop; won't trigger the getter,
+ * overwriting value 'a'.
+ *
+ * Used only by the DOMEventFacades used by IE8 when the YUI configuration
+ * lazyEventFacade 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):
+ *
+ * var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]});
+ *
+ *
+ *
+ * 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 {
+ // Create new instance
+ this[ns] = new Plugin(config);
+ this._plugins[ns] = 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
+ * 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) {
+ 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
+ */
+
+/**
+ * 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
+ * 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.
+ *
+ * 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.
+ * @chainable
+ */
+Y.NodeList.prototype.plug = function() {
+ var args = arguments;
+ Y.NodeList.each(this, function(node) {
+ Y.Node.prototype.plug.apply(Y.one(node), args);
+ });
+ return this;
+};
+
+/**
+ * Removes a plugin from all nodes in the NodeList. This will destroy the
+ * plugin instance and delete the namespace each node.
+ * @method unplug
+ * @for NodeList
+ * @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.
+ * @chainable
+ */
+Y.NodeList.prototype.unplug = function() {
+ var args = arguments;
+ Y.NodeList.each(this, function(node) {
+ Y.Node.prototype.unplug.apply(Y.one(node), args);
+ });
+ return this;
+};
+
+
+}, '@VERSION@', {"requires": ["node-base", "pluginhost"]});
+YUI.add('node-screen', function (Y, NAME) {
+
+/**
+ * Extended Node interface for managing regions and screen positioning.
+ * Adds support for positioning elements and normalizes window size and scroll detection.
+ * @module node
+ * @submodule node-screen
+ */
+
+// these are all "safe" returns, no wrapping required
+Y.each([
+ /**
+ * Returns the inner width of the viewport (exludes scrollbar).
+ * @config winWidth
+ * @for Node
+ * @type {Int}
+ */
+ 'winWidth',
+
+ /**
+ * Returns the inner height of the viewport (exludes scrollbar).
+ * @config winHeight
+ * @type {Int}
+ */
+ 'winHeight',
+
+ /**
+ * Document width
+ * @config docWidth
+ * @type {Int}
+ */
+ 'docWidth',
+
+ /**
+ * Document height
+ * @config docHeight
+ * @type {Int}
+ */
+ 'docHeight',
+
+ /**
+ * Pixel distance the page has been scrolled horizontally
+ * @config docScrollX
+ * @type {Int}
+ */
+ 'docScrollX',
+
+ /**
+ * Pixel distance the page has been scrolled vertically
+ * @config docScrollY
+ * @type {Int}
+ */
+ 'docScrollY'
+ ],
+ function(name) {
+ Y.Node.ATTRS[name] = {
+ getter: function() {
+ var args = Array.prototype.slice.call(arguments);
+ args.unshift(Y.Node.getDOMNode(this));
+
+ return Y.DOM[name].apply(this, args);
+ }
+ };
+ }
+);
+
+Y.Node.ATTRS.scrollLeft = {
+ getter: function() {
+ var node = Y.Node.getDOMNode(this);
+ return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
+ },
+
+ setter: function(val) {
+ var node = Y.Node.getDOMNode(this);
+ if (node) {
+ if ('scrollLeft' in node) {
+ node.scrollLeft = val;
+ } else if (node.document || node.nodeType === 9) {
+ Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
+ }
+ } else {
+ }
+ }
+};
+
+Y.Node.ATTRS.scrollTop = {
+ getter: function() {
+ var node = Y.Node.getDOMNode(this);
+ return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
+ },
+
+ setter: function(val) {
+ var node = Y.Node.getDOMNode(this);
+ if (node) {
+ if ('scrollTop' in node) {
+ node.scrollTop = val;
+ } else if (node.document || node.nodeType === 9) {
+ Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
+ }
+ } else {
+ }
+ }
+};
+
+Y.Node.importMethod(Y.DOM, [
+/**
+ * Gets the current position of the node in page coordinates.
+ * @method getXY
+ * @for Node
+ * @return {Array} The XY position of the node
+*/
+ 'getXY',
+
+/**
+ * Set the position of the node in page coordinates, regardless of how the node is positioned.
+ * @method setXY
+ * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
+ * @chainable
+ */
+ 'setXY',
+
+/**
+ * Gets the current position of the node in page coordinates.
+ * @method getX
+ * @return {Int} The X position of the node
+*/
+ 'getX',
+
+/**
+ * Set the position of the node in page coordinates, regardless of how the node is positioned.
+ * @method setX
+ * @param {Int} x X value for new position (coordinates are page-based)
+ * @chainable
+ */
+ 'setX',
+
+/**
+ * Gets the current position of the node in page coordinates.
+ * @method getY
+ * @return {Int} The Y position of the node
+*/
+ 'getY',
+
+/**
+ * Set the position of the node in page coordinates, regardless of how the node is positioned.
+ * @method setY
+ * @param {Int} y Y value for new position (coordinates are page-based)
+ * @chainable
+ */
+ 'setY',
+
+/**
+ * Swaps the XY position of this node with another node.
+ * @method swapXY
+ * @param {Node | HTMLElement} otherNode The node to swap with.
+ * @chainable
+ */
+ 'swapXY'
+]);
+
+/**
+ * @module node
+ * @submodule node-screen
+ */
+
+/**
+ * Returns a region object for the node
+ * @config region
+ * @for Node
+ * @type Node
+ */
+Y.Node.ATTRS.region = {
+ getter: function() {
+ var node = this.getDOMNode(),
+ region;
+
+ if (node && !node.tagName) {
+ if (node.nodeType === 9) { // document
+ node = node.documentElement;
+ }
+ }
+ if (Y.DOM.isWindow(node)) {
+ region = Y.DOM.viewportRegion(node);
+ } else {
+ region = Y.DOM.region(node);
+ }
+ return region;
+ }
+};
+
+/**
+ * Returns a region object for the node's viewport
+ * @config viewportRegion
+ * @type Node
+ */
+Y.Node.ATTRS.viewportRegion = {
+ getter: function() {
+ return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
+ }
+};
+
+Y.Node.importMethod(Y.DOM, 'inViewportRegion');
+
+// these need special treatment to extract 2nd node arg
+/**
+ * Compares the intersection of the node with another node or region
+ * @method intersect
+ * @for Node
+ * @param {Node|Object} node2 The node or region to compare with.
+ * @param {Object} altRegion An alternate region to use (rather than this node's).
+ * @return {Object} An object representing the intersection of the regions.
+ */
+Y.Node.prototype.intersect = function(node2, altRegion) {
+ var node1 = Y.Node.getDOMNode(this);
+ if (Y.instanceOf(node2, Y.Node)) { // might be a region object
+ node2 = Y.Node.getDOMNode(node2);
+ }
+ return Y.DOM.intersect(node1, node2, altRegion);
+};
+
+/**
+ * Determines whether or not the node is within the giving region.
+ * @method inRegion
+ * @param {Node|Object} node2 The node or region to compare with.
+ * @param {Boolean} all Whether or not all of the node must be in the region.
+ * @param {Object} altRegion An alternate region to use (rather than this node's).
+ * @return {Boolean} True if in region, false if not.
+ */
+Y.Node.prototype.inRegion = function(node2, all, altRegion) {
+ var node1 = Y.Node.getDOMNode(this);
+ if (Y.instanceOf(node2, Y.Node)) { // might be a region object
+ node2 = Y.Node.getDOMNode(node2);
+ }
+ return Y.DOM.inRegion(node1, node2, all, altRegion);
+};
+
+
+}, '@VERSION@', {"requires": ["dom-screen", "node-base"]});
+YUI.add('node-style', function (Y, NAME) {
+
+(function(Y) {
+/**
+ * Extended Node interface for managing node styles.
+ * @module node
+ * @submodule node-style
+ */
+
+Y.mix(Y.Node.prototype, {
+ /**
+ * Sets a style property of the node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method setStyle
+ * @param {String} attr The style attribute to set.
+ * @param {String|Number} val The value.
+ * @chainable
+ */
+ setStyle: function(attr, val) {
+ Y.DOM.setStyle(this._node, attr, val);
+ return this;
+ },
+
+ /**
+ * Sets multiple style properties on the node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method setStyles
+ * @param {Object} hash An object literal of property:value pairs.
+ * @chainable
+ */
+ setStyles: function(hash) {
+ Y.DOM.setStyles(this._node, hash);
+ return this;
+ },
+
+ /**
+ * Returns the style's current value.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method getStyle
+ * @for Node
+ * @param {String} attr The style attribute to retrieve.
+ * @return {String} The current value of the style property for the element.
+ */
+
+ getStyle: function(attr) {
+ return Y.DOM.getStyle(this._node, attr);
+ },
+
+ /**
+ * Returns the computed value for the given style property.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method getComputedStyle
+ * @param {String} attr The style attribute to retrieve.
+ * @return {String} The computed value of the style property for the element.
+ */
+ getComputedStyle: function(attr) {
+ return Y.DOM.getComputedStyle(this._node, attr);
+ }
+});
+
+/**
+ * Returns an array of values for each node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method getStyle
+ * @for NodeList
+ * @see Node.getStyle
+ * @param {String} attr The style attribute to retrieve.
+ * @return {Array} The current values of the style property for the element.
+ */
+
+/**
+ * Returns an array of the computed value for each node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method getComputedStyle
+ * @see Node.getComputedStyle
+ * @param {String} attr The style attribute to retrieve.
+ * @return {Array} The computed values for each node.
+ */
+
+/**
+ * Sets a style property on each node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method setStyle
+ * @see Node.setStyle
+ * @param {String} attr The style attribute to set.
+ * @param {String|Number} val The value.
+ * @chainable
+ */
+
+/**
+ * Sets multiple style properties on each node.
+ * Use camelCase (e.g. 'backgroundColor') for multi-word properties.
+ * @method setStyles
+ * @see Node.setStyles
+ * @param {Object} hash An object literal of property:value pairs.
+ * @chainable
+ */
+
+// These are broken out to handle undefined return (avoid false positive for
+// chainable)
+
+Y.NodeList.importMethod(Y.Node.prototype, ['getStyle', 'getComputedStyle', 'setStyle', 'setStyles']);
+})(Y);
+
+
+}, '@VERSION@', {"requires": ["dom-style", "node-base"]});
+YUI.add('querystring-stringify-simple', function (Y, NAME) {
+
+/*global Y */
+/**
+ * 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.
+ *
+ * @module querystring
+ * @submodule querystring-stringify-simple
+ */
+
+var QueryString = Y.namespace("QueryString"),
+ EUC = encodeURIComponent;
+
+
+QueryString.stringify = function (obj, c) {
+ var qs = [],
+ // Default behavior is false; standard key notation.
+ s = c && c.arrayKey ? true : false,
+ key, i, l;
+
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (Y.Lang.isArray(obj[key])) {
+ for (i = 0, l = obj[key].length; i < l; i++) {
+ qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i]));
+ }
+ }
+ else {
+ qs.push(EUC(key) + '=' + EUC(obj[key]));
+ }
+ }
+ }
+
+ return qs.join('&');
+};
+
+
+}, '@VERSION@', {"requires": ["yui-base"]});
+YUI.add('io-base', function (Y, NAME) {
+
+/**
+Base IO functionality. Provides basic XHR transport support.
+
+@module io
+@submodule io-base
+@for IO
+**/
+
+var // List of events that comprise the IO event lifecycle.
+ EVENTS = ['start', 'complete', 'end', 'success', 'failure', 'progress'],
+
+ // Whitelist of used XHR response object properties.
+ XHR_PROPS = ['status', 'statusText', 'responseText', 'responseXML'],
+
+ win = Y.config.win,
+ uid = 0;
+
+/**
+The IO class is a utility that brokers HTTP requests through a simplified
+interface. Specifically, it allows JavaScript to make HTTP requests to
+a resource without a page reload. The underlying transport for making
+same-domain requests is the XMLHttpRequest object. IO can also use
+Flash, if specified as a transport, for cross-domain requests.
+
+@class IO
+@constructor
+@param {Object} config Object of EventTarget's publish method configurations
+ used to configure IO's events.
+**/
+function IO (config) {
+ var io = this;
+
+ io._uid = 'io:' + uid++;
+ io._init(config);
+ Y.io._map[io._uid] = io;
+}
+
+IO.prototype = {
+ //--------------------------------------
+ // Properties
+ //--------------------------------------
+
+ /**
+ * A counter that increments for each transaction.
+ *
+ * @property _id
+ * @private
+ * @type {Number}
+ */
+ _id: 0,
+
+ /**
+ * Object of IO HTTP headers sent with each transaction.
+ *
+ * @property _headers
+ * @private
+ * @type {Object}
+ */
+ _headers: {
+ 'X-Requested-With' : 'XMLHttpRequest'
+ },
+
+ /**
+ * Object that stores timeout values for any transaction with a defined
+ * "timeout" configuration property.
+ *
+ * @property _timeout
+ * @private
+ * @type {Object}
+ */
+ _timeout: {},
+
+ //--------------------------------------
+ // Methods
+ //--------------------------------------
+
+ _init: function(config) {
+ var io = this, i, len;
+
+ io.cfg = config || {};
+
+ Y.augment(io, Y.EventTarget);
+ for (i = 0, len = EVENTS.length; i < len; ++i) {
+ // Publish IO global events with configurations, if any.
+ // IO global events are set to broadcast by default.
+ // These events use the "io:" namespace.
+ io.publish('io:' + EVENTS[i], Y.merge({ broadcast: 1 }, config));
+ // Publish IO transaction events with configurations, if
+ // any. These events use the "io-trn:" namespace.
+ io.publish('io-trn:' + EVENTS[i], config);
+ }
+ },
+
+ /**
+ * Method that creates a unique transaction object for each request.
+ *
+ * @method _create
+ * @private
+ * @param {Object} cfg Configuration object subset to determine if
+ * the transaction is an XDR or file upload,
+ * requiring an alternate transport.
+ * @param {Number} id Transaction id
+ * @return {Object} The transaction object
+ */
+ _create: function(config, id) {
+ var io = this,
+ transaction = {
+ id : Y.Lang.isNumber(id) ? id : io._id++,
+ uid: io._uid
+ },
+ alt = config.xdr ? config.xdr.use : null,
+ form = config.form && config.form.upload ? 'iframe' : null,
+ use;
+
+ if (alt === 'native') {
+ // Non-IE and IE >= 10 can use XHR level 2 and not rely on an
+ // external transport.
+ alt = Y.UA.ie && !SUPPORTS_CORS ? 'xdr' : null;
+
+ // Prevent "pre-flight" OPTIONS request by removing the
+ // `X-Requested-With` HTTP header from CORS requests. This header
+ // can be added back on a per-request basis, if desired.
+ io.setHeader('X-Requested-With');
+ }
+
+ use = alt || form;
+ transaction = use ? Y.merge(Y.IO.customTransport(use), transaction) :
+ Y.merge(Y.IO.defaultTransport(), transaction);
+
+ if (transaction.notify) {
+ config.notify = function (e, t, c) { io.notify(e, t, c); };
+ }
+
+ if (!use) {
+ if (win && win.FormData && config.data instanceof win.FormData) {
+ transaction.c.upload.onprogress = function (e) {
+ io.progress(transaction, e, config);
+ };
+ transaction.c.onload = function (e) {
+ io.load(transaction, e, config);
+ };
+ transaction.c.onerror = function (e) {
+ io.error(transaction, e, config);
+ };
+ transaction.upload = true;
+ }
+ }
+
+ return transaction;
+ },
+
+ _destroy: function(transaction) {
+ if (win && !transaction.notify && !transaction.xdr) {
+ if (XHR && !transaction.upload) {
+ transaction.c.onreadystatechange = null;
+ } else if (transaction.upload) {
+ transaction.c.upload.onprogress = null;
+ transaction.c.onload = null;
+ transaction.c.onerror = null;
+ } else if (Y.UA.ie && !transaction.e) {
+ // IE, when using XMLHttpRequest as an ActiveX Object, will throw
+ // a "Type Mismatch" error if the event handler is set to "null".
+ transaction.c.abort();
+ }
+ }
+
+ transaction = transaction.c = null;
+ },
+
+ /**
+ * Method for creating and firing events.
+ *
+ * @method _evt
+ * @private
+ * @param {String} eventName Event to be published.
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration data subset for event subscription.
+ */
+ _evt: function(eventName, transaction, config) {
+ var io = this, params,
+ args = config['arguments'],
+ emitFacade = io.cfg.emitFacade,
+ globalEvent = "io:" + eventName,
+ trnEvent = "io-trn:" + eventName;
+
+ // Workaround for #2532107
+ this.detach(trnEvent);
+
+ if (transaction.e) {
+ transaction.c = { status: 0, statusText: transaction.e };
+ }
+
+ // Fire event with parameters or an Event Facade.
+ params = [ emitFacade ?
+ {
+ id: transaction.id,
+ data: transaction.c,
+ cfg: config,
+ 'arguments': args
+ } :
+ transaction.id
+ ];
+
+ if (!emitFacade) {
+ if (eventName === EVENTS[0] || eventName === EVENTS[2]) {
+ if (args) {
+ params.push(args);
+ }
+ } else {
+ if (transaction.evt) {
+ params.push(transaction.evt);
+ } else {
+ params.push(transaction.c);
+ }
+ if (args) {
+ params.push(args);
+ }
+ }
+ }
+
+ params.unshift(globalEvent);
+ // Fire global events.
+ io.fire.apply(io, params);
+ // Fire transaction events, if receivers are defined.
+ if (config.on) {
+ params[0] = trnEvent;
+ io.once(trnEvent, config.on[eventName], config.context || Y);
+ io.fire.apply(io, params);
+ }
+ },
+
+ /**
+ * Fires event "io:start" and creates, fires a transaction-specific
+ * start event, if `config.on.start` is defined.
+ *
+ * @method start
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ start: function(transaction, config) {
+ /**
+ * Signals the start of an IO request.
+ * @event io:start
+ */
+ this._evt(EVENTS[0], transaction, config);
+ },
+
+ /**
+ * Fires event "io:complete" and creates, fires a
+ * transaction-specific "complete" event, if config.on.complete is
+ * defined.
+ *
+ * @method complete
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ complete: function(transaction, config) {
+ /**
+ * Signals the completion of the request-response phase of a
+ * transaction. Response status and data are accessible, if
+ * available, in this event.
+ * @event io:complete
+ */
+ this._evt(EVENTS[1], transaction, config);
+ },
+
+ /**
+ * Fires event "io:end" and creates, fires a transaction-specific "end"
+ * event, if config.on.end is defined.
+ *
+ * @method end
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ end: function(transaction, config) {
+ /**
+ * Signals the end of the transaction lifecycle.
+ * @event io:end
+ */
+ this._evt(EVENTS[2], transaction, config);
+ this._destroy(transaction);
+ },
+
+ /**
+ * Fires event "io:success" and creates, fires a transaction-specific
+ * "success" event, if config.on.success is defined.
+ *
+ * @method success
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ success: function(transaction, config) {
+ /**
+ * Signals an HTTP response with status in the 2xx range.
+ * Fires after io:complete.
+ * @event io:success
+ */
+ this._evt(EVENTS[3], transaction, config);
+ this.end(transaction, config);
+ },
+
+ /**
+ * Fires event "io:failure" and creates, fires a transaction-specific
+ * "failure" event, if config.on.failure is defined.
+ *
+ * @method failure
+ * @param {Object} transaction Transaction object.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ failure: function(transaction, config) {
+ /**
+ * Signals an HTTP response with status outside of the 2xx range.
+ * Fires after io:complete.
+ * @event io:failure
+ */
+ this._evt(EVENTS[4], transaction, config);
+ this.end(transaction, config);
+ },
+
+ /**
+ * Fires event "io:progress" and creates, fires a transaction-specific
+ * "progress" event -- for XMLHttpRequest file upload -- if
+ * config.on.progress is defined.
+ *
+ * @method progress
+ * @param {Object} transaction Transaction object.
+ * @param {Object} progress event.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ progress: function(transaction, e, config) {
+ /**
+ * Signals the interactive state during a file upload transaction.
+ * This event fires after io:start and before io:complete.
+ * @event io:progress
+ */
+ transaction.evt = e;
+ this._evt(EVENTS[5], transaction, config);
+ },
+
+ /**
+ * Fires event "io:complete" and creates, fires a transaction-specific
+ * "complete" event -- for XMLHttpRequest file upload -- if
+ * config.on.complete is defined.
+ *
+ * @method load
+ * @param {Object} transaction Transaction object.
+ * @param {Object} load event.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ load: function (transaction, e, config) {
+ transaction.evt = e.target;
+ this._evt(EVENTS[1], transaction, config);
+ },
+
+ /**
+ * Fires event "io:failure" and creates, fires a transaction-specific
+ * "failure" event -- for XMLHttpRequest file upload -- if
+ * config.on.failure is defined.
+ *
+ * @method error
+ * @param {Object} transaction Transaction object.
+ * @param {Object} error event.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ error: function (transaction, e, config) {
+ transaction.evt = e;
+ this._evt(EVENTS[4], transaction, config);
+ },
+
+ /**
+ * Retry an XDR transaction, using the Flash tranport, if the native
+ * transport fails.
+ *
+ * @method _retry
+ * @private
+ * @param {Object} transaction Transaction object.
+ * @param {String} uri Qualified path to transaction resource.
+ * @param {Object} config Configuration object for the transaction.
+ */
+ _retry: function(transaction, uri, config) {
+ this._destroy(transaction);
+ config.xdr.use = 'flash';
+ return this.send(uri, config, transaction.id);
+ },
+
+ /**
+ * Method that concatenates string data for HTTP GET transactions.
+ *
+ * @method _concat
+ * @private
+ * @param {String} uri URI or root data.
+ * @param {String} data Data to be concatenated onto URI.
+ * @return {String}
+ */
+ _concat: function(uri, data) {
+ uri += (uri.indexOf('?') === -1 ? '?' : '&') + data;
+ return uri;
+ },
+
+ /**
+ * Stores default client headers for all transactions. If a label is
+ * passed with no value argument, the header will be deleted.
+ *
+ * @method setHeader
+ * @param {String} name HTTP header
+ * @param {String} value HTTP header value
+ */
+ setHeader: function(name, value) {
+ if (value) {
+ this._headers[name] = value;
+ } else {
+ delete this._headers[name];
+ }
+ },
+
+ /**
+ * Method that sets all HTTP headers to be sent in a transaction.
+ *
+ * @method _setHeaders
+ * @private
+ * @param {Object} transaction - XHR instance for the specific transaction.
+ * @param {Object} headers - HTTP headers for the specific transaction, as
+ * defined in the configuration object passed to YUI.io().
+ */
+ _setHeaders: function(transaction, headers) {
+ headers = Y.merge(this._headers, headers);
+ Y.Object.each(headers, function(value, name) {
+ if (value !== 'disable') {
+ transaction.setRequestHeader(name, headers[name]);
+ }
+ });
+ },
+
+ /**
+ * Starts timeout count if the configuration object has a defined
+ * timeout property.
+ *
+ * @method _startTimeout
+ * @private
+ * @param {Object} transaction Transaction object generated by _create().
+ * @param {Object} timeout Timeout in milliseconds.
+ */
+ _startTimeout: function(transaction, timeout) {
+ var io = this;
+
+ io._timeout[transaction.id] = setTimeout(function() {
+ io._abort(transaction, 'timeout');
+ }, timeout);
+ },
+
+ /**
+ * Clears the timeout interval started by _startTimeout().
+ *
+ * @method _clearTimeout
+ * @private
+ * @param {Number} id - Transaction id.
+ */
+ _clearTimeout: function(id) {
+ clearTimeout(this._timeout[id]);
+ delete this._timeout[id];
+ },
+
+ /**
+ * Method that determines if a transaction response qualifies as success
+ * or failure, based on the response HTTP status code, and fires the
+ * appropriate success or failure events.
+ *
+ * @method _result
+ * @private
+ * @static
+ * @param {Object} transaction Transaction object generated by _create().
+ * @param {Object} config Configuration object passed to io().
+ */
+ _result: function(transaction, config) {
+ var status;
+ // Firefox will throw an exception if attempting to access
+ // an XHR object's status property, after a request is aborted.
+ try {
+ status = transaction.c.status;
+ } catch(e) {
+ status = 0;
+ }
+
+ // IE reports HTTP 204 as HTTP 1223.
+ if (status >= 200 && status < 300 || status === 304 || status === 1223) {
+ this.success(transaction, config);
+ } else {
+ this.failure(transaction, config);
+ }
+ },
+
+ /**
+ * Event handler bound to onreadystatechange.
+ *
+ * @method _rS
+ * @private
+ * @param {Object} transaction Transaction object generated by _create().
+ * @param {Object} config Configuration object passed to YUI.io().
+ */
+ _rS: function(transaction, config) {
+ var io = this;
+
+ if (transaction.c.readyState === 4) {
+ if (config.timeout) {
+ io._clearTimeout(transaction.id);
+ }
+
+ // Yield in the event of request timeout or abort.
+ setTimeout(function() {
+ io.complete(transaction, config);
+ io._result(transaction, config);
+ }, 0);
+ }
+ },
+
+ /**
+ * Terminates a transaction due to an explicit abort or timeout.
+ *
+ * @method _abort
+ * @private
+ * @param {Object} transaction Transaction object generated by _create().
+ * @param {String} type Identifies timed out or aborted transaction.
+ */
+ _abort: function(transaction, type) {
+ if (transaction && transaction.c) {
+ transaction.e = type;
+ transaction.c.abort();
+ }
+ },
+
+ /**
+ * Requests a transaction. `send()` is implemented as `Y.io()`. Each
+ * transaction may include a configuration object. Its properties are:
+ *
+ *
+ * - method
+ * - HTTP method verb (e.g., GET or POST). If this property is not
+ * not defined, the default value will be GET.
+ *
+ * - data
+ * - This is the name-value string that will be sent as the
+ * transaction data. If the request is HTTP GET, the data become
+ * part of querystring. If HTTP POST, the data are sent in the
+ * message body.
+ *
+ * - xdr
+ * - Defines the transport to be used for cross-domain requests.
+ * By setting this property, the transaction will use the specified
+ * transport instead of XMLHttpRequest. The properties of the
+ * transport object are:
+ *
+ * - use
+ * - The transport to be used: 'flash' or 'native'
+ * - dataType
+ * - Set the value to 'XML' if that is the expected response
+ * content type.
+ * - credentials
+ * - Set the value to 'true' to set XHR.withCredentials property to true.
+ *
+ *
+ * - form
+ * - Form serialization configuration object. Its properties are:
+ *
+ * - id
+ * - Node object or id of HTML form
+ * - useDisabled
+ * - `true` to also serialize disabled form field values
+ * (defaults to `false`)
+ *
+ *
+ * - on
+ * - Assigns transaction event subscriptions. Available events are:
+ *
+ * - start
+ * - Fires when a request is sent to a resource.
+ * - complete
+ * - Fires when the transaction is complete.
+ * - success
+ * - Fires when the HTTP response status is within the 2xx
+ * range.
+ * - failure
+ * - Fires when the HTTP response status is outside the 2xx
+ * range, if an exception occurs, if the transation is aborted,
+ * or if the transaction exceeds a configured `timeout`.
+ * - end
+ * - Fires at the conclusion of the transaction
+ * lifecycle, after `success` or `failure`.
+ *
+ *
+ * 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.
+ *
+ *
+ * - sync
+ * - Pass `true` to make a same-domain transaction synchronous.
+ * CAVEAT: This will negatively impact the user
+ * experience. Have a very good reason if you intend to use
+ * this.
+ *
+ * - context
+ * - The "`this'" object for all configured event handlers. If a
+ * specific context is needed for individual callbacks, bind the
+ * callback to a context using `Y.bind()`.
+ *
+ * - headers
+ * - Object map of transaction headers to send to the server. The
+ * object keys are the header names and the values are the header
+ * values.
+ *
+ * - timeout
+ * - Millisecond threshold for the transaction before being
+ * automatically aborted.
+ *
+ * - arguments
+ * - User-defined data passed to all registered event handlers.
+ * This value is available as the second argument in the "start" and
+ * "end" event handlers. It is the third argument in the "complete",
+ * "success", and "failure" event handlers. Be sure to quote
+ * this property name in the transaction configuration as
+ * "arguments" is a reserved word in JavaScript (e.g.
+ * `Y.io({ ..., "arguments": stuff })`).
+ *
+ *
+ * @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) {
+ config.data = data = Y.QueryString.stringify(data);
+ } else {
+ }
+ }
+
+ 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 = '';
+ 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);
+ }
+
+ 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
+ - HTTP method verb (e.g., GET or POST). If this property is not
+ not defined, the default value will be GET.
+
+ - data
+ - This is the name-value string that will be sent as the
+ transaction data. If the request is HTTP GET, the data become
+ part of querystring. If HTTP POST, the data are sent in the
+ message body.
+
+ - xdr
+ - Defines the transport to be used for cross-domain requests.
+ By setting this property, the transaction will use the specified
+ transport instead of XMLHttpRequest. The properties of the
+ transport object are:
+
+ - use
+ - The transport to be used: 'flash' or 'native'
+ - dataType
+ - Set the value to 'XML' if that is the expected response
+ content type.
+
+
+ - form
+ - Form serialization configuration object. Its properties are:
+
+ - id
+ - Node object or id of HTML form
+ - useDisabled
+ - `true` to also serialize disabled form field values
+ (defaults to `false`)
+
+
+ - on
+ - Assigns transaction event subscriptions. Available events are:
+
+ - start
+ - Fires when a request is sent to a resource.
+ - complete
+ - Fires when the transaction is complete.
+ - success
+ - Fires when the HTTP response status is within the 2xx
+ range.
+ - failure
+ - Fires when the HTTP response status is outside the 2xx
+ range, if an exception occurs, if the transation is aborted,
+ or if the transaction exceeds a configured `timeout`.
+ - end
+ - Fires at the conclusion of the transaction
+ lifecycle, after `success` or `failure`.
+
+
+ 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.
+
+
+ - sync
+ - Pass `true` to make a same-domain transaction synchronous.
+ CAVEAT: This will negatively impact the user
+ experience. Have a very good reason if you intend to use
+ this.
+
+ - context
+ - The "`this'" object for all configured event handlers. If a
+ specific context is needed for individual callbacks, bind the
+ callback to a context using `Y.bind()`.
+
+ - headers
+ - Object map of transaction headers to send to the server. The
+ object keys are the header names and the values are the header
+ values.
+
+ - timeout
+ - Millisecond threshold for the transaction before being
+ automatically aborted.
+
+ - arguments
+ - User-defined data passed to all registered event handlers.
+ This value is available as the second argument in the "start" and
+ "end" event handlers. It is the third argument in the "complete",
+ "success", and "failure" event handlers. Be sure to quote
+ this property name in the transaction configuration as
+ "arguments" is a reserved word in JavaScript (e.g.
+ `Y.io({ ..., "arguments": stuff })`).
+
+
+@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.IO._default = id;
+ } else {
+ var o = {
+ c: Y.IO.transports[Y.IO._default](),
+ notify: Y.IO._default === 'xhr' ? false : true
+ };
+ 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);
+ }
+ 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 {
+ 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
+ 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('*');