/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ var GLOBAL_ENV = YUI.Env; if (!GLOBAL_ENV._ready) { GLOBAL_ENV._ready = function() { GLOBAL_ENV.DOMReady = true; GLOBAL_ENV.remove(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready); }; // if (!YUI.UA.ie) { GLOBAL_ENV.add(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready); // } } YUI.add('event-base', function(Y) { /* * DOM event listener abstraction layer * @module event * @submodule event-base */ /** * The domready event fires at the moment the browser's DOM is * usable. In most cases, this is before images are fully * downloaded, allowing you to provide a more responsive user * interface. * * In YUI 3, domready subscribers will be notified immediately if * that moment has already passed when the subscription is created. * * One exception is if the yui.js file is dynamically injected into * the page. If this is done, you must tell the YUI instance that * you did this in order for DOMReady (and window load events) to * fire normally. That configuration option is 'injected' -- set * it to true if the yui.js script is not included inline. * * This method is part of the 'event-ready' module, which is a * submodule of 'event'. * * @event domready * @for YUI */ Y.publish('domready', { fireOnce: true, async: true }); if (GLOBAL_ENV.DOMReady) { Y.fire('domready'); } else { Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready'); } /** * Custom event engine, DOM event listener abstraction layer, synthetic DOM * events. * @module event * @submodule event-base */ /** * Wraps a DOM event, properties requiring browser abstraction are * fixed here. Provids a security layer when required. * @class DOMEventFacade * @param ev {Event} the DOM event * @param currentTarget {HTMLElement} the element the listener was attached to * @param wrapper {Event.Custom} the custom event wrapper for this DOM event */ var ua = Y.UA, EMPTY = {}, /** * webkit key remapping required for Safari < 3.1 * @property webkitKeymap * @private */ webkitKeymap = { 63232: 38, // up 63233: 40, // down 63234: 37, // left 63235: 39, // right 63276: 33, // page up 63277: 34, // page down 25: 9, // SHIFT-TAB (Safari provides a different key code in // this case, even though the shiftKey modifier is set) 63272: 46, // delete 63273: 36, // home 63275: 35 // end }, /** * Returns a wrapped node. Intended to be used on event targets, * so it will return the node's parent if the target is a text * node. * * If accessing a property of the node throws an error, this is * probably the anonymous div wrapper Gecko adds inside text * nodes. This likely will only occur when attempting to access * the relatedTarget. In this case, we now return null because * the anonymous div is completely useless and we do not know * what the related target was because we can't even get to * the element's parent node. * * @method resolve * @private */ resolve = function(n) { if (!n) { return n; } try { if (n && 3 == n.nodeType) { n = n.parentNode; } } catch(e) { return null; } return Y.one(n); }, DOMEventFacade = function(ev, currentTarget, wrapper) { this._event = ev; this._currentTarget = currentTarget; this._wrapper = wrapper || EMPTY; // if not lazy init this.init(); }; Y.extend(DOMEventFacade, Object, { init: function() { var e = this._event, overrides = this._wrapper.overrides, x = e.pageX, y = e.pageY, c, currentTarget = this._currentTarget; 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.pageX = x; this.pageY = y; c = e.keyCode || e.charCode; if (ua.webkit && (c in webkitKeymap)) { c = webkitKeymap[c]; } this.keyCode = c; this.charCode = c; this.which = e.which || e.charCode || c; // this.button = e.button; this.button = this.which; this.target = resolve(e.target); this.currentTarget = resolve(currentTarget); this.relatedTarget = resolve(e.relatedTarget); if (e.type == "mousewheel" || e.type == "DOMMouseScroll") { this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1); } if (this._touch) { this._touch(e, currentTarget, this._wrapper); } }, stopPropagation: function() { this._event.stopPropagation(); this._wrapper.stopped = 1; this.stopped = 1; }, stopImmediatePropagation: function() { var e = this._event; if (e.stopImmediatePropagation) { e.stopImmediatePropagation(); } else { this.stopPropagation(); } this._wrapper.stopped = 2; this.stopped = 2; }, preventDefault: function(returnValue) { var e = this._event; e.preventDefault(); e.returnValue = returnValue || false; this._wrapper.prevented = 1; this.prevented = 1; }, halt: function(immediate) { if (immediate) { this.stopImmediatePropagation(); } else { this.stopPropagation(); } this.preventDefault(); } }); DOMEventFacade.resolve = resolve; Y.DOM2EventFacade = DOMEventFacade; Y.DOMEventFacade = DOMEventFacade; /** * The native event * @property _event */ /** * The X location of the event on the page (including scroll) * @property pageX * @type int */ /** * The Y location of the event on the page (including scroll) * @property pageY * @type int */ /** * The keyCode for key events. Uses charCode if keyCode is not available * @property keyCode * @type int */ /** * The charCode for key events. Same as keyCode * @property charCode * @type int */ /** * The button that was pushed. * @property button * @type int */ /** * The button that was pushed. Same as button. * @property which * @type int */ /** * Node reference for the targeted element * @propery target * @type Node */ /** * Node reference for the element that the listener was attached to. * @propery currentTarget * @type Node */ /** * Node reference to the relatedTarget * @propery relatedTarget * @type Node */ /** * Number representing the direction and velocity of the movement of the mousewheel. * Negative is down, the higher the number, the faster. Applies to the mousewheel event. * @property wheelDelta * @type int */ /** * Stops the propagation to the next bubble target * @method stopPropagation */ /** * Stops the propagation to the next bubble target and * prevents any additional listeners from being exectued * on the current target. * @method stopImmediatePropagation */ /** * Prevents the event's default behavior * @method preventDefault * @param returnValue {string} sets the returnValue of the event to this value * (rather than the default false value). This can be used to add a customized * confirmation query to the beforeunload event). */ /** * Stops the event propagation and prevents the default * event behavior. * @method halt * @param immediate {boolean} if true additional listeners * on the current target will not be executed */ (function() { /** * DOM event listener abstraction layer * @module event * @submodule event-base */ /** * The event utility provides functions to add and remove event listeners, * event cleansing. It also tries to automatically remove listeners it * registers during the unload event. * * @class Event * @static */ Y.Env.evt.dom_wrappers = {}; Y.Env.evt.dom_map = {}; var _eventenv = Y.Env.evt, config = Y.config, win = config.win, add = YUI.Env.add, remove = YUI.Env.remove, onLoad = function() { YUI.Env.windowLoaded = true; Y.Event._load(); remove(win, "load", onLoad); }, onUnload = function() { Y.Event._unload(); }, EVENT_READY = 'domready', COMPAT_ARG = '~yui|2|compat~', shouldIterate = function(o) { try { return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !o.alert); } catch(ex) { return false; } }, Event = function() { /** * True after the onload event has fired * @property _loadComplete * @type boolean * @static * @private */ var _loadComplete = false, /** * The number of times to poll after window.onload. This number is * increased if additional late-bound handlers are requested after * the page load. * @property _retryCount * @static * @private */ _retryCount = 0, /** * onAvailable listeners * @property _avail * @static * @private */ _avail = [], /** * Custom event wrappers for DOM events. Key is * 'event:' + Element uid stamp + event type * @property _wrappers * @type Y.Event.Custom * @static * @private */ _wrappers = _eventenv.dom_wrappers, _windowLoadKey = null, /** * Custom event wrapper map DOM events. Key is * Element uid stamp. Each item is a hash of custom event * wrappers as provided in the _wrappers collection. This * provides the infrastructure for getListeners. * @property _el_events * @static * @private */ _el_events = _eventenv.dom_map; return { /** * The number of times we should look for elements that are not * in the DOM at the time the event is requested after the document * has been loaded. The default is 1000@amp;40 ms, so it will poll * for 40 seconds or until all outstanding handlers are bound * (whichever comes first). * @property POLL_RETRYS * @type int * @static * @final */ POLL_RETRYS: 1000, /** * The poll interval in milliseconds * @property POLL_INTERVAL * @type int * @static * @final */ POLL_INTERVAL: 40, /** * addListener/removeListener can throw errors in unexpected scenarios. * These errors are suppressed, the method returns false, and this property * is set * @property lastError * @static * @type Error */ lastError: null, /** * poll handle * @property _interval * @static * @private */ _interval: null, /** * document readystate poll handle * @property _dri * @static * @private */ _dri: null, /** * True when the document is initially usable * @property DOMReady * @type boolean * @static */ DOMReady: false, /** * @method startInterval * @static * @private */ startInterval: function() { if (!Event._interval) { Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL); } }, /** * Executes the supplied callback when the item with the supplied * id is found. This is meant to be used to execute behavior as * soon as possible as the page loads. If you use this after the * initial page load it will poll for a fixed time for the element. * The number of times it will poll and the frequency are * configurable. By default it will poll for 10 seconds. * *

The callback is executed with a single parameter: * the custom object parameter, if provided.

* * @method onAvailable * * @param {string||string[]} id the id of the element, or an array * of ids to look for. * @param {function} fn what to execute when the element is found. * @param {object} p_obj an optional object to be passed back as * a parameter to fn. * @param {boolean|object} p_override If set to true, fn will execute * in the context of p_obj, if set to an object it * will execute in the context of that object * @param checkContent {boolean} check child node readiness (onContentReady) * @static * @deprecated Use Y.on("available") */ // @TODO fix arguments onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) { var a = Y.Array(id), i, availHandle; for (i=0; iThe callback is executed with a single parameter: * the custom object parameter, if provided.

* * @method onContentReady * * @param {string} id the id of the element to look for. * @param {function} fn what to execute when the element is ready. * @param {object} obj an optional object to be passed back as * a parameter to fn. * @param {boolean|object} override If set to true, fn will execute * in the context of p_obj. If an object, fn will * exectute in the context of that object * * @static * @deprecated Use Y.on("contentready") */ // @TODO fix arguments onContentReady: function(id, fn, obj, override, compat) { return Event.onAvailable(id, fn, obj, override, true, compat); }, /** * Adds an event listener * * @method attach * * @param {String} type The type of event to append * @param {Function} fn The method the event invokes * @param {String|HTMLElement|Array|NodeList} el An id, an element * reference, or a collection of ids and/or elements to assign the * listener to. * @param {Object} context optional context object * @param {Boolean|object} args 0..n arguments to pass to the callback * @return {EventHandle} an object to that can be used to detach the listener * * @static */ attach: function(type, fn, el, context) { return Event._attach(Y.Array(arguments, 0, true)); }, _createWrapper: function (el, type, capture, compat, facade) { var cewrapper, ek = Y.stamp(el), key = 'event:' + ek + type; if (false === facade) { key += 'native'; } if (capture) { key += 'capture'; } cewrapper = _wrappers[key]; if (!cewrapper) { // create CE wrapper cewrapper = Y.publish(key, { silent: true, bubbles: false, contextFn: function() { if (compat) { return cewrapper.el; } else { cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el); return cewrapper.nodeRef; } } }); cewrapper.overrides = {}; // for later removeListener calls cewrapper.el = el; cewrapper.key = key; cewrapper.domkey = ek; cewrapper.type = type; cewrapper.fn = function(e) { cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade)))); }; cewrapper.capture = capture; if (el == win && type == "load") { // window load happens once cewrapper.fireOnce = true; _windowLoadKey = key; } _wrappers[key] = cewrapper; _el_events[ek] = _el_events[ek] || {}; _el_events[ek][key] = cewrapper; add(el, type, cewrapper.fn, capture); } return cewrapper; }, _attach: function(args, conf) { var compat, handles, oEl, cewrapper, context, fireNow = false, ret, type = args[0], fn = args[1], el = args[2] || win, facade = conf && conf.facade, capture = conf && conf.capture, overrides = conf && conf.overrides; if (args[args.length-1] === COMPAT_ARG) { compat = true; // trimmedArgs.pop(); } if (!fn || !fn.call) { // throw new TypeError(type + " attach call failed, callback undefined"); return false; } // The el argument can be an array of elements or element ids. if (shouldIterate(el)) { handles=[]; Y.each(el, function(v, k) { args[2] = v; handles.push(Event._attach(args, conf)); }); // return (handles.length === 1) ? handles[0] : handles; return new Y.EventHandle(handles); // If the el argument is a string, we assume it is // actually the id of the element. If the page is loaded // we convert el to the actual element, otherwise we // defer attaching the event until the element is // ready } else if (Y.Lang.isString(el)) { // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el); if (compat) { oEl = Y.DOM.byId(el); } else { oEl = Y.Selector.query(el); switch (oEl.length) { case 0: oEl = null; break; case 1: oEl = oEl[0]; break; default: args[2] = oEl; return Event._attach(args, conf); } } if (oEl) { el = oEl; // Not found = defer adding the event until the element is available } else { ret = Event.onAvailable(el, function() { ret.handle = Event._attach(args, conf); }, Event, true, false, compat); return ret; } } // Element should be an html element or node if (!el) { return false; } if (Y.Node && Y.instanceOf(el, Y.Node)) { el = Y.Node.getDOMNode(el); } cewrapper = Event._createWrapper(el, type, capture, compat, facade); if (overrides) { Y.mix(cewrapper.overrides, overrides); } if (el == win && type == "load") { // if the load is complete, fire immediately. // all subscribers, including the current one // will be notified. if (YUI.Env.windowLoaded) { fireNow = true; } } if (compat) { args.pop(); } context = args[3]; // set context to the Node if not specified // ret = cewrapper.on.apply(cewrapper, trimmedArgs); ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null); if (fireNow) { cewrapper.fire(); } return ret; }, /** * Removes an event listener. Supports the signature the event was bound * with, but the preferred way to remove listeners is using the handle * that is returned when using Y.on * * @method detach * * @param {String} type the type of event to remove. * @param {Function} fn the method the event invokes. If fn is * undefined, then all event handlers for the type of event are * removed. * @param {String|HTMLElement|Array|NodeList|EventHandle} el An * event handle, an id, an element reference, or a collection * of ids and/or elements to remove the listener from. * @return {boolean} true if the unbind was successful, false otherwise. * @static */ detach: function(type, fn, el, obj) { var args=Y.Array(arguments, 0, true), compat, l, ok, i, id, ce; if (args[args.length-1] === COMPAT_ARG) { compat = true; // args.pop(); } if (type && type.detach) { return type.detach(); } // The el argument can be a string if (typeof el == "string") { // el = (compat) ? Y.DOM.byId(el) : Y.all(el); if (compat) { el = Y.DOM.byId(el); } else { el = Y.Selector.query(el); l = el.length; if (l < 1) { el = null; } else if (l == 1) { el = el[0]; } } // return Event.detach.apply(Event, args); } if (!el) { return false; } if (el.detach) { args.splice(2, 1); return el.detach.apply(el, args); // The el argument can be an array of elements or element ids. } else if (shouldIterate(el)) { ok = true; for (i=0, l=el.length; i 0); } // onAvailable notAvail = []; executeItem = function (el, item) { var context, ov = item.override; if (item.compat) { if (item.override) { if (ov === true) { context = item.obj; } else { context = ov; } } else { context = el; } item.fn.call(context, item.obj); } else { context = item.obj || Y.one(el); item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []); } }; // onAvailable for (i=0,len=_avail.length; i 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); } }; }, '3.3.0' ,{requires:['event-custom-base']}); YUI.add('event-delegate', function(Y) { /** * 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 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 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 */ 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 }, context, filter, ...); // and Y.delegate(['click', 'key'], fn, context, 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}, context, filter) => // Y.delegate('click', fn, context, 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(); 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. * * @method delegate.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.

* * @method delegate.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._node); }; }); /** * 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. * * @method delegate._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; } // 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; }, '3.3.0' ,{requires:['node-base']}); YUI.add('event-synthetic', function(Y) { /** * Define new DOM events that can be subscribed to from Nodes. * * @module event * @submodule event-synthetic */ var DOMMap = Y.Env.evt.dom_map, toArray = Y.Array, YLang = Y.Lang, isObject = YLang.isObject, isString = YLang.isString, query = Y.Selector.query, noop = function () {}; /** *

The triggering mechanism used by SyntheticEvents.

* *

Implementers should not instantiate these directly. Use the Notifier * provided to the event's implemented on(node, sub, notifier) or * delegate(node, sub, notifier, filter) methods.

* * @class SyntheticEvent.Notifier * @constructor * @param handle {EventHandle} the detach handle for the subscription to an * internal custom event used to execute the callback passed to * on(..) or delegate(..) * @param emitFacade {Boolean} take steps to ensure the first arg received by * the subscription callback is an event facade * @private * @since 3.2.0 */ function Notifier(handle, emitFacade) { this.handle = handle; this.emitFacade = emitFacade; } /** *

Executes the subscription callback, passing the firing arguments as the * first parameters to that callback. For events that are configured with * emitFacade=true, it is common practice to pass the triggering DOMEventFacade * as the first parameter. Barring a proper DOMEventFacade or EventFacade * (from a CustomEvent), a new EventFacade will be generated. In that case, if * fire() is called with a simple object, it will be mixed into the facade. * Otherwise, the facade will be prepended to the callback parameters.

* *

For notifiers provided to delegate logic, the first argument should be an * object with a "currentTarget" property to identify what object to * default as 'this' in the callback. Typically this is gleaned from the * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an * object must be provided. In that case, the object will be removed from the * callback parameters.

* *

Additional arguments passed during event subscription will be * automatically added after those passed to fire().

* * @method fire * @param e {EventFacade|DOMEventFacade|Object|any} (see description) * @param arg* {any} additional arguments received by all subscriptions * @private */ Notifier.prototype.fire = function (e) { // first arg to delegate notifier should be an object with currentTarget var args = toArray(arguments, 0, true), handle = this.handle, ce = handle.evt, sub = handle.sub, thisObj = sub.context, delegate = sub.filter, event = e || {}; if (this.emitFacade) { if (!e || !e.preventDefault) { event = ce._getFacade(); if (isObject(e) && !e.preventDefault) { Y.mix(event, e, true); args[0] = event; } else { args.unshift(event); } } event.type = ce.type; event.details = args.slice(); if (delegate) { event.container = ce.host; } } else if (delegate && isObject(e) && e.currentTarget) { args.shift(); } sub.context = thisObj || event.currentTarget || ce.host; ce.fire.apply(ce, args); sub.context = thisObj; // reset for future firing }; /** *

Wrapper class for the integration of new events into the YUI event * infrastructure. Don't instantiate this object directly, use * Y.Event.define(type, config). See that method for details.

* *

Properties that MAY or SHOULD be specified in the configuration are noted * below and in the description of Y.Event.define.

* * @class SyntheticEvent * @constructor * @param cfg {Object} Implementation pieces and configuration * @since 3.1.0 * @in event-synthetic */ function SyntheticEvent() { this._init.apply(this, arguments); } Y.mix(SyntheticEvent, { Notifier: Notifier, /** * Returns the array of subscription handles for a node for the given event * type. Passing true as the third argument will create a registry entry * in the event system's DOM map to host the array if one doesn't yet exist. * * @method getRegistry * @param node {Node} the node * @param type {String} the event * @param create {Boolean} create a registration entry to host a new array * if one doesn't exist. * @return {Array} * @static * @protected * @since 3.2.0 */ getRegistry: function (node, type, create) { var el = node._node, yuid = Y.stamp(el), key = 'event:' + yuid + type + '_synth', events = DOMMap[yuid] || (DOMMap[yuid] = {}); if (!events[key] && create) { events[key] = { type : '_synth', fn : noop, capture : false, el : el, key : key, domkey : yuid, notifiers : [], detachAll : function () { var notifiers = this.notifiers, i = notifiers.length; while (--i >= 0) { notifiers[i].detach(); } } }; } return (events[key]) ? events[key].notifiers : null; }, /** * Alternate _delete() method for the CustomEvent object * created to manage SyntheticEvent subscriptions. * * @method _deleteSub * @param sub {Subscription} the subscription to clean up * @private * @since 3.2.0 */ _deleteSub: function (sub) { if (sub && sub.fn) { var synth = this.eventDef, method = (sub.filter) ? 'detachDelegate' : 'detach'; this.subscribers = {}; this.subCount = 0; synth[method](sub.node, sub, this.notifier, sub.filter); synth._unregisterSub(sub); delete sub.fn; delete sub.node; delete sub.context; } }, prototype: { constructor: SyntheticEvent, /** * Construction logic for the event. * * @method _init * @protected */ _init: function () { var config = this.publishConfig || (this.publishConfig = {}); // The notification mechanism handles facade creation this.emitFacade = ('emitFacade' in config) ? config.emitFacade : true; config.emitFacade = false; }, /** *

Implementers MAY provide this method definition.

* *

Implement this function if the event supports a different * subscription signature. This function is used by both * on() and delegate(). The second parameter * indicates that the event is being subscribed via * delegate().

* *

Implementations must remove extra arguments from the args list * before returning. The required args for on() * subscriptions are

*
[type, callback, target, context, argN...]
* *

The required args for delegate() * subscriptions are

* *
[type, callback, target, filter, context, argN...]
* *

The return value from this function will be stored on the * subscription in the '_extra' property for reference elsewhere.

* * @method processArgs * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..) * @param delegate {Boolean} true if the subscription is from Y.delegate * @return {any} */ processArgs: noop, /** *

Implementers MAY override this property.

* *

Whether to prevent multiple subscriptions to this event that are * classified as being the same. By default, this means the subscribed * callback is the same function. See the subMatch * method. Setting this to true will impact performance for high volume * events.

* * @property preventDups * @type {Boolean} * @default false */ //preventDups : false, /** *

Implementers SHOULD provide this method definition.

* * Implementation logic for subscriptions done via node.on(type, * fn) or Y.on(type, fn, target). This * function should set up the monitor(s) that will eventually fire the * event. Typically this involves subscribing to at least one DOM * event. It is recommended to store detach handles from any DOM * subscriptions to make for easy cleanup in the detach * method. Typically these handles are added to the sub * object. Also for SyntheticEvents that leverage a single DOM * subscription under the hood, it is recommended to pass the DOM event * object to notifier.fire(e). (The event name on the * object will be updated). * * @method on * @param node {Node} the node the subscription is being applied to * @param sub {Subscription} the object to track this subscription * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to * trigger the execution of the subscribers */ on: noop, /** *

Implementers SHOULD provide this method definition.

* *

Implementation logic for detaching subscriptions done via * node.on(type, fn). This function should clean up any * subscriptions made in the on() phase.

* * @method detach * @param node {Node} the node the subscription was applied to * @param sub {Subscription} the object tracking this subscription * @param notifier {SyntheticEvent.Notifier} the Notifier used to * trigger the execution of the subscribers */ detach: noop, /** *

Implementers SHOULD provide this method definition.

* *

Implementation logic for subscriptions done via * node.delegate(type, fn, filter) or * Y.delegate(type, fn, container, filter). Like with * on() above, this function should monitor the environment * for the event being fired, and trigger subscription execution by * calling notifier.fire(e).

* *

This function receives a fourth argument, which is the filter * used to identify which Node's are of interest to the subscription. * The filter will be either a boolean function that accepts a target * Node for each hierarchy level as the event bubbles, or a selector * string. To translate selector strings into filter functions, use * Y.delegate.compileFilter(filter).

* * @method delegate * @param node {Node} the node the subscription is being applied to * @param sub {Subscription} the object to track this subscription * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to * trigger the execution of the subscribers * @param filter {String|Function} Selector string or function that * accepts an event object and returns null, a Node, or an * array of Nodes matching the criteria for processing. * @since 3.2.0 */ delegate : noop, /** *

Implementers SHOULD provide this method definition.

* *

Implementation logic for detaching subscriptions done via * node.delegate(type, fn, filter) or * Y.delegate(type, fn, container, filter). This function * should clean up any subscriptions made in the * delegate() phase.

* * @method detachDelegate * @param node {Node} the node the subscription was applied to * @param sub {Subscription} the object tracking this subscription * @param notifier {SyntheticEvent.Notifier} the Notifier used to * trigger the execution of the subscribers * @param filter {String|Function} Selector string or function that * accepts an event object and returns null, a Node, or an * array of Nodes matching the criteria for processing. * @since 3.2.0 */ detachDelegate : noop, /** * Sets up the boilerplate for detaching the event and facilitating the * execution of subscriber callbacks. * * @method _on * @param args {Array} array of arguments passed to * Y.on(...) or Y.delegate(...) * @param delegate {Boolean} true if called from * Y.delegate(...) * @return {EventHandle} the detach handle for this subscription * @private * since 3.2.0 */ _on: function (args, delegate) { var handles = [], extra = this.processArgs(args, delegate), selector = args[2], method = delegate ? 'delegate' : 'on', nodes, handle; // Can't just use Y.all because it doesn't support window (yet?) nodes = (isString(selector)) ? query(selector) : toArray(selector); if (!nodes.length && isString(selector)) { handle = Y.on('available', function () { Y.mix(handle, Y[method].apply(Y, args), true); }, selector); return handle; } Y.Array.each(nodes, function (node) { var subArgs = args.slice(), filter; node = Y.one(node); if (node) { if (delegate) { filter = subArgs.splice(3, 1)[0]; } // (type, fn, el, thisObj, ...) => (fn, thisObj, ...) subArgs.splice(0, 4, subArgs[1], subArgs[3]); if (!this.preventDups || !this.getSubs(node, args,null,true)) { handle = this._getNotifier(node, subArgs, extra,filter); this[method](node, handle.sub, handle.notifier, filter); handles.push(handle); } } }, this); return (handles.length === 1) ? handles[0] : new Y.EventHandle(handles); }, /** * Creates a new Notifier object for use by this event's * on(...) or delegate(...) implementation. * * @method _getNotifier * @param node {Node} the Node hosting the event * @param args {Array} the subscription arguments passed to either * Y.on(...) or Y.delegate(...) * after running through processArgs(args) to * normalize the argument signature * @param extra {any} Extra data parsed from * processArgs(args) * @param filter {String|Function} the selector string or function * filter passed to Y.delegate(...) (not * present when called from Y.on(...)) * @return {SyntheticEvent.Notifier} * @private * @since 3.2.0 */ _getNotifier: function (node, args, extra, filter) { var dispatcher = new Y.CustomEvent(this.type, this.publishConfig), handle = dispatcher.on.apply(dispatcher, args), notifier = new Notifier(handle, this.emitFacade), registry = SyntheticEvent.getRegistry(node, this.type, true), sub = handle.sub; handle.notifier = notifier; sub.node = node; sub.filter = filter; if (extra) { this.applyArgExtras(extra, sub); } Y.mix(dispatcher, { eventDef : this, notifier : notifier, host : node, // I forget what this is for currentTarget: node, // for generating facades target : node, // for generating facades el : node._node, // For category detach _delete : SyntheticEvent._deleteSub }, true); registry.push(handle); return handle; }, /** *

Implementers MAY provide this method definition.

* *

Implement this function if you want extra data extracted during * processArgs to be propagated to subscriptions on a per-node basis. * That is to say, if you call Y.on('xyz', fn, xtra, 'div') * the data returned from processArgs will be shared * across the subscription objects for all the divs. If you want each * subscription to receive unique information, do that processing * here.

* *

The default implementation adds the data extracted by processArgs * to the subscription object as sub._extra.

* * @method applyArgExtras * @param extra {any} Any extra data extracted from processArgs * @param sub {Subscription} the individual subscription */ applyArgExtras: function (extra, sub) { sub._extra = extra; }, /** * Removes the subscription from the Notifier registry. * * @method _unregisterSub * @param sub {Subscription} the subscription * @private * @since 3.2.0 */ _unregisterSub: function (sub) { var notifiers = SyntheticEvent.getRegistry(sub.node, this.type), i; if (notifiers) { for (i = notifiers.length - 1; i >= 0; --i) { if (notifiers[i].sub === sub) { notifiers.splice(i, 1); break; } } } }, /** * Removes the subscription(s) from the internal subscription dispatch * mechanism. See SyntheticEvent._deleteSub. * * @method _detach * @param args {Array} The arguments passed to * node.detach(...) * @private * @since 3.2.0 */ _detach: function (args) { // Can't use Y.all because it doesn't support window (yet?) // TODO: Does Y.all support window now? var target = args[2], els = (isString(target)) ? query(target) : toArray(target), node, i, len, handles, j; // (type, fn, el, context, filter?) => (type, fn, context, filter?) args.splice(2, 1); for (i = 0, len = els.length; i < len; ++i) { node = Y.one(els[i]); if (node) { handles = this.getSubs(node, args); if (handles) { for (j = handles.length - 1; j >= 0; --j) { handles[j].detach(); } } } } }, /** * Returns the detach handles of subscriptions on a node that satisfy a * search/filter function. By default, the filter used is the * subMatch method. * * @method getSubs * @param node {Node} the node hosting the event * @param args {Array} the array of original subscription args passed * to Y.on(...) (before * processArgs * @param filter {Function} function used to identify a subscription * for inclusion in the returned array * @param first {Boolean} stop after the first match (used to check for * duplicate subscriptions) * @return {Array} detach handles for the matching subscriptions */ getSubs: function (node, args, filter, first) { var notifiers = SyntheticEvent.getRegistry(node, this.type), handles = [], i, len, handle; if (notifiers) { if (!filter) { filter = this.subMatch; } for (i = 0, len = notifiers.length; i < len; ++i) { handle = notifiers[i]; if (filter.call(this, handle.sub, args)) { if (first) { return handle; } else { handles.push(notifiers[i]); } } } } return handles.length && handles; }, /** *

Implementers MAY override this to define what constitutes a * "same" subscription. Override implementations should * consider the lack of a comparator as a match, so calling * getSubs() with no arguments will return all subs.

* *

Compares a set of subscription arguments against a Subscription * object to determine if they match. The default implementation * compares the callback function against the second argument passed to * Y.on(...) or node.detach(...) etc.

* * @method subMatch * @param sub {Subscription} the existing subscription * @param args {Array} the calling arguments passed to * Y.on(...) etc. * @return {Boolean} true if the sub can be described by the args * present * @since 3.2.0 */ subMatch: function (sub, args) { // Default detach cares only about the callback matching return !args[1] || sub.fn === args[1]; } } }, true); Y.SyntheticEvent = SyntheticEvent; /** *

Defines a new event in the DOM event system. Implementers are * responsible for monitoring for a scenario whereby the event is fired. A * notifier object is provided to the functions identified below. When the * criteria defining the event are met, call notifier.fire( [args] ); to * execute event subscribers.

* *

The first parameter is the name of the event. The second parameter is a * configuration object which define the behavior of the event system when the * new event is subscribed to or detached from. The methods that should be * defined in this configuration object are on, * detach, delegate, and detachDelegate. * You are free to define any other methods or properties needed to define your * event. Be aware, however, that since the object is used to subclass * SyntheticEvent, you should avoid method names used by SyntheticEvent unless * your intention is to override the default behavior.

* *

This is a list of properties and methods that you can or should specify * in the configuration object:

* *
*
on
*
function (node, subscription, notifier) The * implementation logic for subscription. Any special setup you need to * do to create the environment for the event being fired--E.g. native * DOM event subscriptions. Store subscription related objects and * state on the subscription object. When the * criteria have been met to fire the synthetic event, call * notifier.fire(e). See Notifier's fire() * method for details about what to pass as parameters.
* *
detach
*
function (node, subscription, notifier) The * implementation logic for cleaning up a detached subscription. E.g. * detach any DOM subscriptions added in on.
* *
delegate
*
function (node, subscription, notifier, filter) The * implementation logic for subscription via Y.delegate or * node.delegate. The filter is typically either a selector * string or a function. You can use * Y.delegate.compileFilter(selectorString) to create a * filter function from a selector string if needed. The filter function * expects an event object as input and should output either null, a * matching Node, or an array of matching Nodes. Otherwise, this acts * like on DOM event subscriptions. Store subscription * related objects and information on the subscription * object. When the criteria have been met to fire the synthetic event, * call notifier.fire(e) as noted above.
* *
detachDelegate
*
function (node, subscription, notifier) The * implementation logic for cleaning up a detached delegate subscription. * E.g. detach any DOM delegate subscriptions added in * delegate.
* *
publishConfig
*
(Object) The configuration object that will be used to instantiate * the underlying CustomEvent. See Notifier's fire method * for details.
* *
processArgs
*

function (argArray, fromDelegate) Optional method * to extract any additional arguments from the subscription * signature. Using this allows on or * delegate signatures like * node.on("hover", overCallback, * outCallback).

*

When processing an atypical argument signature, make sure the * args array is returned to the normal signature before returning * from the function. For example, in the "hover" example * above, the outCallback needs to be spliced * out of the array. The expected signature of the args array for * on() subscriptions is:

*
 *              [type, callback, target, contextOverride, argN...]
 *          
*

And for delegate():

*
 *              [type, callback, target, filter, contextOverride, argN...]
 *          
*

where target is the node the event is being * subscribed for. You can see these signatures documented for * Y.on() and Y.delegate() respectively.

*

Whatever gets returned from the function will be stored on the * subscription object under * subscription._extra.

*
subMatch
*
*

function (sub, args) Compares a set of * subscription arguments against a Subscription object to determine * if they match. The default implementation compares the callback * function against the second argument passed to * Y.on(...) or node.detach(...) etc.

*
*
* * @method Event.define * @param type {String} the name of the event * @param config {Object} the prototype definition for the new event (see above) * @param force {Boolean} override an existing event (use with caution) * @static * @return {SyntheticEvent} the subclass implementation instance created to * handle event subscriptions of this type * @for Event * @since 3.1.0 * @in event-synthetic */ Y.Event.define = function (type, config, force) { if (!config) { config = {}; } var eventDef = (isObject(type)) ? type : Y.merge({ type: type }, config), Impl, synth; if (force || !Y.Node.DOM_EVENTS[eventDef.type]) { Impl = function () { SyntheticEvent.apply(this, arguments); }; Y.extend(Impl, SyntheticEvent, eventDef); synth = new Impl(); type = synth.type; Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = { eventDef: synth, on: function () { return synth._on(toArray(arguments)); }, delegate: function () { return synth._on(toArray(arguments), true); }, detach: function () { return synth._detach(toArray(arguments)); } }; } return synth; }; }, '3.3.0' ,{requires:['node-base', 'event-custom']}); YUI.add('event-mousewheel', function(Y) { /** * Adds mousewheel event support * @module event * @submodule event-mousewheel */ var DOM_MOUSE_SCROLL = 'DOMMouseScroll', fixArgs = function(args) { var a = Y.Array(args, 0, true), target; if (Y.UA.gecko) { a[0] = DOM_MOUSE_SCROLL; target = Y.config.win; } else { target = Y.config.doc; } if (a.length < 3) { a[2] = target; } else { a.splice(2, 0, target); } return a; }; /** * Mousewheel event. This listener is automatically attached to the * correct target, so one should not be supplied. Mouse wheel * direction and velocity is stored in the 'mouseDelta' field. * @event mousewheel * @param type {string} 'mousewheel' * @param fn {function} the callback to execute * @param context optional context object * @param args 0..n additional arguments to provide to the listener. * @return {EventHandle} the detach handle * @for YUI */ Y.Env.evt.plugins.mousewheel = { on: function() { return Y.Event._attach(fixArgs(arguments)); }, detach: function() { return Y.Event.detach.apply(Y.Event, fixArgs(arguments)); } }; }, '3.3.0' ,{requires:['node-base']}); YUI.add('event-mouseenter', function(Y) { /** *

Adds subscription and delegation support for mouseenter and mouseleave * events. Unlike mouseover and mouseout, these events aren't fired from child * elements of a subscribed node.

* *

This avoids receiving three mouseover notifications from a setup like

* *
div#container > p > a[href]
* *

where

* *
Y.one('#container').on('mouseover', callback)
* *

When the mouse moves over the link, one mouseover event is fired from * #container, then when the mouse moves over the p, another mouseover event is * fired and bubbles to #container, causing a second notification, and finally * when the mouse moves over the link, a third mouseover event is fired and * bubbles to #container for a third notification.

* *

By contrast, using mouseenter instead of mouseover, the callback would be * executed only once when the mouse moves over #container.

* * @module event * @submodule event-mouseenter */ function notify(e, notifier) { var current = e.currentTarget, related = e.relatedTarget; if (current !== related && !current.contains(related)) { notifier.fire(e); } } var config = { proxyType: "mouseover", on: function (node, sub, notifier) { sub.onHandle = node.on(this.proxyType, notify, null, notifier); }, detach: function (node, sub) { sub.onHandle.detach(); }, delegate: function (node, sub, notifier, filter) { sub.delegateHandle = Y.delegate(this.proxyType, notify, node, filter, null, notifier); }, detachDelegate: function (node, sub) { sub.delegateHandle.detach(); } }; Y.Event.define("mouseenter", config, true); Y.Event.define("mouseleave", Y.merge(config, { proxyType: "mouseout" }), true); }, '3.3.0' ,{requires:['event-synthetic']}); YUI.add('event-key', function(Y) { /** * Functionality to listen for one or more specific key combinations. * @module event * @submodule event-key */ /** * Add a key listener. The listener will only be notified if the * keystroke detected meets the supplied specification. The * spec consists of the key event type, followed by a colon, * followed by zero or more comma separated key codes, followed * by zero or more modifiers delimited by a plus sign. Ex: * press:12,65+shift+ctrl * @event key * @for YUI * @param type {string} 'key' * @param fn {function} the function to execute * @param id {string|HTMLElement|collection} the element(s) to bind * @param spec {string} the keyCode and modifier specification * @param o optional context object * @param args 0..n additional arguments to provide to the listener. * @return {Event.Handle} the detach handle */ Y.Env.evt.plugins.key = { on: function(type, fn, id, spec, o) { var a = Y.Array(arguments, 0, true), parsed, etype, criteria, ename; parsed = spec && spec.split(':'); if (!spec || spec.indexOf(':') == -1 || !parsed[1]) { a[0] = 'key' + ((parsed && parsed[0]) || 'press'); return Y.on.apply(Y, a); } // key event type: 'down', 'up', or 'press' etype = parsed[0]; // list of key codes optionally followed by modifiers criteria = (parsed[1]) ? parsed[1].split(/,|\+/) : null; // the name of the custom event that will be created for the spec ename = (Y.Lang.isString(id) ? id : Y.stamp(id)) + spec; ename = ename.replace(/,/g, '_'); if (!Y.getEvent(ename)) { // subscribe spec validator to the DOM event Y.on(type + etype, function(e) { var passed = false, failed = false, i, crit, critInt; for (i=0; i').onbeforeactivate); function define(type, proxy, directEvent) { var nodeDataKey = '_' + type + 'Notifiers'; Y.Event.define(type, { _attach: function (el, notifier, delegate) { if (Y.DOM.isWindow(el)) { return Event._attach([type, function (e) { notifier.fire(e); }, el]); } else { return Event._attach( [proxy, this._proxy, el, this, notifier, delegate], { capture: true }); } }, _proxy: function (e, notifier, delegate) { var node = e.target, notifiers = node.getData(nodeDataKey), yuid = Y.stamp(e.currentTarget._node), defer = (useActivate || e.target !== e.currentTarget), sub = notifier.handle.sub, filterArgs = [node, e].concat(sub.args || []), directSub; notifier.currentTarget = (delegate) ? node : e.currentTarget; notifier.container = (delegate) ? e.currentTarget : null; if (!sub.filter || sub.filter.apply(node, filterArgs)) { // Maintain a list to handle subscriptions from nested // containers div#a>div#b>input #a.on(focus..) #b.on(focus..), // use one focus or blur subscription that fires notifiers from // #b then #a to emulate bubble sequence. if (!notifiers) { notifiers = {}; node.setData(nodeDataKey, notifiers); // only subscribe to the element's focus if the target is // not the current target ( if (defer) { directSub = Event._attach( [directEvent, this._notify, node._node]).sub; directSub.once = true; } } if (!notifiers[yuid]) { notifiers[yuid] = []; } notifiers[yuid].push(notifier); if (!defer) { this._notify(e); } } }, _notify: function (e, container) { var node = e.currentTarget, notifiers = node.getData(nodeDataKey), // document.get('ownerDocument') returns null doc = node.get('ownerDocument') || node, target = node, nots = [], notifier, i, len; if (notifiers) { // Walk up the parent axis until the origin node, while (target && target !== doc) { nots.push.apply(nots, notifiers[Y.stamp(target)] || []); target = target.get('parentNode'); } nots.push.apply(nots, notifiers[Y.stamp(doc)] || []); for (i = 0, len = nots.length; i < len; ++i) { notifier = nots[i]; e.currentTarget = nots[i].currentTarget; if (notifier.container) { e.container = notifier.container; } else { delete e.container; } notifier.fire(e); } // clear the notifications list (mainly for delegation) node.clearData(nodeDataKey); } }, on: function (node, sub, notifier) { sub.onHandle = this._attach(node._node, notifier); }, detach: function (node, sub) { sub.onHandle.detach(); }, delegate: function (node, sub, notifier, filter) { if (isString(filter)) { sub.filter = Y.delegate.compileFilter(filter); } sub.delegateHandle = this._attach(node._node, notifier, true); }, detachDelegate: function (node, sub) { sub.delegateHandle.detach(); } }, true); } // For IE, we need to defer to focusin rather than focus because // `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate, // el.onfocusin, doSomething, then el.onfocus. All others support capture // phase focus, which executes before doSomething. To guarantee consistent // behavior for this use case, IE's direct subscriptions are made against // focusin so subscribers will be notified before js following el.focus() is // executed. if (useActivate) { // name capture phase direct subscription define("focus", "beforeactivate", "focusin"); define("blur", "beforedeactivate", "focusout"); } else { define("focus", "focus", "focus"); define("blur", "blur", "blur"); } }, '3.3.0' ,{requires:['event-synthetic']}); YUI.add('event-resize', function(Y) { /** * Adds a window resize event that has its behavior normalized to fire at the * end of the resize rather than constantly during the resize. * @module event * @submodule event-resize */ (function() { var detachHandle, timerHandle, CE_NAME = 'window:resize', handler = function(e) { if (Y.UA.gecko) { Y.fire(CE_NAME, e); } else { if (timerHandle) { timerHandle.cancel(); } timerHandle = Y.later(Y.config.windowResizeDelay || 40, Y, function() { Y.fire(CE_NAME, e); }); } }; /** * Firefox fires the window resize event once when the resize action * finishes, other browsers fire the event periodically during the * resize. This code uses timeout logic to simulate the Firefox * behavior in other browsers. * @event windowresize * @for YUI */ Y.Env.evt.plugins.windowresize = { on: function(type, fn) { // check for single window listener and add if needed if (!detachHandle) { detachHandle = Y.Event._attach(['resize', handler]); } var a = Y.Array(arguments, 0, true); a[0] = CE_NAME; return Y.on.apply(Y, a); } }; })(); }, '3.3.0' ,{requires:['node-base']}); YUI.add('event-hover', function(Y) { /** * Adds support for a "hover" event. The event provides a convenience wrapper * for subscribing separately to mouseenter and mouseleave. The signature for * subscribing to the event is

* *
node.on("hover", overFn, outFn);
 * node.delegate("hover", overFn, outFn, ".filterSelector");
 * Y.on("hover", overFn, outFn, ".targetSelector");
 * Y.delegate("hover", overFn, outFn, "#container", ".filterSelector");
 * 
* *

Additionally, for compatibility with a more typical subscription * signature, the following are also supported:

* *
Y.on("hover", overFn, ".targetSelector", outFn);
 * Y.delegate("hover", overFn, "#container", outFn, ".filterSelector");
 * 
* * @module event * @submodule event-hover */ var isFunction = Y.Lang.isFunction, noop = function () {}, conf = { processArgs: function (args) { // Y.delegate('hover', over, out, '#container', '.filter') // comes in as ['hover', over, out, '#container', '.filter'], but // node.delegate('hover', over, out, '.filter') // comes in as ['hover', over, containerEl, out, '.filter'] var i = isFunction(args[2]) ? 2 : 3; return (isFunction(args[i])) ? args.splice(i,1)[0] : noop; }, on: function (node, sub, notifier, filter) { sub._detach = node[(filter) ? "delegate" : "on"]({ mouseenter: Y.bind(notifier.fire, notifier), mouseleave: sub._extra }, filter); }, detach: function (node, sub, notifier) { sub._detacher.detach(); } }; conf.delegate = conf.on; conf.detachDelegate = conf.detach; Y.Event.define("hover", conf); }, '3.3.0' ,{requires:['event-mouseenter']}); YUI.add('event', function(Y){}, '3.3.0' ,{use:['event-base', 'event-delegate', 'event-synthetic', 'event-mousewheel', 'event-mouseenter', 'event-key', 'event-focus', 'event-resize', 'event-hover']});