diff -r d334a616c023 -r e16a97fb364a src/cm/media/js/lib/yui/yui3-3.15.0/build/event-custom-base/event-custom-base.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui3-3.15.0/build/event-custom-base/event-custom-base.js Mon Mar 10 15:19:48 2014 +0100 @@ -0,0 +1,2472 @@ +YUI.add('event-custom-base', function (Y, NAME) { + +/** + * Custom event engine, DOM event listener abstraction layer, synthetic DOM + * events. + * @module event-custom + */ + +Y.Env.evt = { + handles: {}, + plugins: {} +}; + + +/** + * Custom event engine, DOM event listener abstraction layer, synthetic DOM + * events. + * @module event-custom + * @submodule event-custom-base + */ + +/** + * Allows for the insertion of methods that are executed before or after + * a specified method + * @class Do + * @static + */ + +var DO_BEFORE = 0, + DO_AFTER = 1, + +DO = { + + /** + * Cache of objects touched by the utility + * @property objs + * @static + * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object + * replaces the role of this property, but is considered to be private, and + * is only mentioned to provide a migration path. + * + * If you have a use case which warrants migration to the _yuiaop property, + * please file a ticket to let us know what it's used for and we can see if + * we need to expose hooks for that functionality more formally. + */ + objs: null, + + /** + *

Execute the supplied method before the specified function. Wrapping + * function may optionally return an instance of the following classes to + * further alter runtime behavior:

+ *
+ *
Y.Do.Halt(message, returnValue)
+ *
Immediatly stop execution and return + * returnValue. No other wrapping functions will be + * executed.
+ *
Y.Do.AlterArgs(message, newArgArray)
+ *
Replace the arguments that the original function will be + * called with.
+ *
Y.Do.Prevent(message)
+ *
Don't execute the wrapped function. Other before phase + * wrappers will be executed.
+ *
+ * + * @method before + * @param fn {Function} the function to execute + * @param obj the object hosting the method to displace + * @param sFn {string} the name of the method to displace + * @param c The execution context for fn + * @param arg* {mixed} 0..n additional arguments to supply to the subscriber + * when the event fires. + * @return {string} handle for the subscription + * @static + */ + before: function(fn, obj, sFn, c) { + var f = fn, a; + if (c) { + a = [fn, c].concat(Y.Array(arguments, 4, true)); + f = Y.rbind.apply(Y, a); + } + + return this._inject(DO_BEFORE, f, obj, sFn); + }, + + /** + *

Execute the supplied method after the specified function. Wrapping + * function may optionally return an instance of the following classes to + * further alter runtime behavior:

+ *
+ *
Y.Do.Halt(message, returnValue)
+ *
Immediatly stop execution and return + * returnValue. No other wrapping functions will be + * executed.
+ *
Y.Do.AlterReturn(message, returnValue)
+ *
Return returnValue instead of the wrapped + * method's original return value. This can be further altered by + * other after phase wrappers.
+ *
+ * + *

The static properties Y.Do.originalRetVal and + * Y.Do.currentRetVal will be populated for reference.

+ * + * @method after + * @param fn {Function} the function to execute + * @param obj the object hosting the method to displace + * @param sFn {string} the name of the method to displace + * @param c The execution context for fn + * @param arg* {mixed} 0..n additional arguments to supply to the subscriber + * @return {string} handle for the subscription + * @static + */ + after: function(fn, obj, sFn, c) { + var f = fn, a; + if (c) { + a = [fn, c].concat(Y.Array(arguments, 4, true)); + f = Y.rbind.apply(Y, a); + } + + return this._inject(DO_AFTER, f, obj, sFn); + }, + + /** + * Execute the supplied method before or after the specified function. + * Used by before and after. + * + * @method _inject + * @param when {string} before or after + * @param fn {Function} the function to execute + * @param obj the object hosting the method to displace + * @param sFn {string} the name of the method to displace + * @param c The execution context for fn + * @return {string} handle for the subscription + * @private + * @static + */ + _inject: function(when, fn, obj, sFn) { + // object id + var id = Y.stamp(obj), o, sid; + + if (!obj._yuiaop) { + // create a map entry for the obj if it doesn't exist, to hold overridden methods + obj._yuiaop = {}; + } + + o = obj._yuiaop; + + if (!o[sFn]) { + // create a map entry for the method if it doesn't exist + o[sFn] = new Y.Do.Method(obj, sFn); + + // re-route the method to our wrapper + obj[sFn] = function() { + return o[sFn].exec.apply(o[sFn], arguments); + }; + } + + // subscriber id + sid = id + Y.stamp(fn) + sFn; + + // register the callback + o[sFn].register(sid, fn, when); + + return new Y.EventHandle(o[sFn], sid); + }, + + /** + * Detach a before or after subscription. + * + * @method detach + * @param handle {string} the subscription handle + * @static + */ + detach: function(handle) { + if (handle.detach) { + handle.detach(); + } + } +}; + +Y.Do = DO; + +////////////////////////////////////////////////////////////////////////// + +/** + * Contains the return value from the wrapped method, accessible + * by 'after' event listeners. + * + * @property originalRetVal + * @static + * @since 3.2.0 + */ + +/** + * Contains the current state of the return value, consumable by + * 'after' event listeners, and updated if an after subscriber + * changes the return value generated by the wrapped function. + * + * @property currentRetVal + * @static + * @since 3.2.0 + */ + +////////////////////////////////////////////////////////////////////////// + +/** + * Wrapper for a displaced method with aop enabled + * @class Do.Method + * @constructor + * @param obj The object to operate on + * @param sFn The name of the method to displace + */ +DO.Method = function(obj, sFn) { + this.obj = obj; + this.methodName = sFn; + this.method = obj[sFn]; + this.before = {}; + this.after = {}; +}; + +/** + * Register a aop subscriber + * @method register + * @param sid {string} the subscriber id + * @param fn {Function} the function to execute + * @param when {string} when to execute the function + */ +DO.Method.prototype.register = function (sid, fn, when) { + if (when) { + this.after[sid] = fn; + } else { + this.before[sid] = fn; + } +}; + +/** + * Unregister a aop subscriber + * @method delete + * @param sid {string} the subscriber id + * @param fn {Function} the function to execute + * @param when {string} when to execute the function + */ +DO.Method.prototype._delete = function (sid) { + delete this.before[sid]; + delete this.after[sid]; +}; + +/** + *

Execute the wrapped method. All arguments are passed into the wrapping + * functions. If any of the before wrappers return an instance of + * Y.Do.Halt or Y.Do.Prevent, neither the wrapped + * function nor any after phase subscribers will be executed.

+ * + *

The return value will be the return value of the wrapped function or one + * provided by a wrapper function via an instance of Y.Do.Halt or + * Y.Do.AlterReturn. + * + * @method exec + * @param arg* {any} Arguments are passed to the wrapping and wrapped functions + * @return {any} Return value of wrapped function unless overwritten (see above) + */ +DO.Method.prototype.exec = function () { + + var args = Y.Array(arguments, 0, true), + i, ret, newRet, + bf = this.before, + af = this.after, + prevented = false; + + // execute before + for (i in bf) { + if (bf.hasOwnProperty(i)) { + ret = bf[i].apply(this.obj, args); + if (ret) { + switch (ret.constructor) { + case DO.Halt: + return ret.retVal; + case DO.AlterArgs: + args = ret.newArgs; + break; + case DO.Prevent: + prevented = true; + break; + default: + } + } + } + } + + // execute method + if (!prevented) { + ret = this.method.apply(this.obj, args); + } + + DO.originalRetVal = ret; + DO.currentRetVal = ret; + + // execute after methods. + for (i in af) { + if (af.hasOwnProperty(i)) { + newRet = af[i].apply(this.obj, args); + // Stop processing if a Halt object is returned + if (newRet && newRet.constructor === DO.Halt) { + return newRet.retVal; + // Check for a new return value + } else if (newRet && newRet.constructor === DO.AlterReturn) { + ret = newRet.newRetVal; + // Update the static retval state + DO.currentRetVal = ret; + } + } + } + + return ret; +}; + +////////////////////////////////////////////////////////////////////////// + +/** + * Return an AlterArgs object when you want to change the arguments that + * were passed into the function. Useful for Do.before subscribers. An + * example would be a service that scrubs out illegal characters prior to + * executing the core business logic. + * @class Do.AlterArgs + * @constructor + * @param msg {String} (optional) Explanation of the altered return value + * @param newArgs {Array} Call parameters to be used for the original method + * instead of the arguments originally passed in. + */ +DO.AlterArgs = function(msg, newArgs) { + this.msg = msg; + this.newArgs = newArgs; +}; + +/** + * Return an AlterReturn object when you want to change the result returned + * from the core method to the caller. Useful for Do.after subscribers. + * @class Do.AlterReturn + * @constructor + * @param msg {String} (optional) Explanation of the altered return value + * @param newRetVal {any} Return value passed to code that invoked the wrapped + * function. + */ +DO.AlterReturn = function(msg, newRetVal) { + this.msg = msg; + this.newRetVal = newRetVal; +}; + +/** + * Return a Halt object when you want to terminate the execution + * of all subsequent subscribers as well as the wrapped method + * if it has not exectued yet. Useful for Do.before subscribers. + * @class Do.Halt + * @constructor + * @param msg {String} (optional) Explanation of why the termination was done + * @param retVal {any} Return value passed to code that invoked the wrapped + * function. + */ +DO.Halt = function(msg, retVal) { + this.msg = msg; + this.retVal = retVal; +}; + +/** + * Return a Prevent object when you want to prevent the wrapped function + * from executing, but want the remaining listeners to execute. Useful + * for Do.before subscribers. + * @class Do.Prevent + * @constructor + * @param msg {String} (optional) Explanation of why the termination was done + */ +DO.Prevent = function(msg) { + this.msg = msg; +}; + +/** + * Return an Error object when you want to terminate the execution + * of all subsequent method calls. + * @class Do.Error + * @constructor + * @param msg {String} (optional) Explanation of the altered return value + * @param retVal {any} Return value passed to code that invoked the wrapped + * function. + * @deprecated use Y.Do.Halt or Y.Do.Prevent + */ +DO.Error = DO.Halt; + + +////////////////////////////////////////////////////////////////////////// + +/** + * Custom event engine, DOM event listener abstraction layer, synthetic DOM + * events. + * @module event-custom + * @submodule event-custom-base + */ + + +// var onsubscribeType = "_event:onsub", +var YArray = Y.Array, + + AFTER = 'after', + CONFIGS = [ + 'broadcast', + 'monitored', + 'bubbles', + 'context', + 'contextFn', + 'currentTarget', + 'defaultFn', + 'defaultTargetOnly', + 'details', + 'emitFacade', + 'fireOnce', + 'async', + 'host', + 'preventable', + 'preventedFn', + 'queuable', + 'silent', + 'stoppedFn', + 'target', + 'type' + ], + + CONFIGS_HASH = YArray.hash(CONFIGS), + + nativeSlice = Array.prototype.slice, + + YUI3_SIGNATURE = 9, + YUI_LOG = 'yui:log', + + mixConfigs = function(r, s, ov) { + var p; + + for (p in s) { + if (CONFIGS_HASH[p] && (ov || !(p in r))) { + r[p] = s[p]; + } + } + + return r; + }; + +/** + * The CustomEvent class lets you define events for your application + * that can be subscribed to by one or more independent component. + * + * @param {String} type The type of event, which is passed to the callback + * when the event fires. + * @param {object} defaults configuration object. + * @class CustomEvent + * @constructor + */ + + /** + * The type of event, returned to subscribers when the event fires + * @property type + * @type string + */ + +/** + * By default all custom events are logged in the debug build, set silent + * to true to disable debug outpu for this event. + * @property silent + * @type boolean + */ + +Y.CustomEvent = function(type, defaults) { + + this._kds = Y.CustomEvent.keepDeprecatedSubs; + + this.id = Y.guid(); + + this.type = type; + this.silent = this.logSystem = (type === YUI_LOG); + + if (this._kds) { + /** + * The subscribers to this event + * @property subscribers + * @type Subscriber {} + * @deprecated + */ + + /** + * 'After' subscribers + * @property afters + * @type Subscriber {} + * @deprecated + */ + this.subscribers = {}; + this.afters = {}; + } + + if (defaults) { + mixConfigs(this, defaults, true); + } +}; + +/** + * Static flag to enable population of the `subscribers` + * and `afters` properties held on a `CustomEvent` instance. + * + * These properties were changed to private properties (`_subscribers` and `_afters`), and + * converted from objects to arrays for performance reasons. + * + * Setting this property to true will populate the deprecated `subscribers` and `afters` + * properties for people who may be using them (which is expected to be rare). There will + * be a performance hit, compared to the new array based implementation. + * + * If you are using these deprecated properties for a use case which the public API + * does not support, please file an enhancement request, and we can provide an alternate + * public implementation which doesn't have the performance cost required to maintiain the + * properties as objects. + * + * @property keepDeprecatedSubs + * @static + * @for CustomEvent + * @type boolean + * @default false + * @deprecated + */ +Y.CustomEvent.keepDeprecatedSubs = false; + +Y.CustomEvent.mixConfigs = mixConfigs; + +Y.CustomEvent.prototype = { + + constructor: Y.CustomEvent, + + /** + * Monitor when an event is attached or detached. + * + * @property monitored + * @type boolean + */ + + /** + * If 0, this event does not broadcast. If 1, the YUI instance is notified + * every time this event fires. If 2, the YUI instance and the YUI global + * (if event is enabled on the global) are notified every time this event + * fires. + * @property broadcast + * @type int + */ + + /** + * Specifies whether this event should be queued when the host is actively + * processing an event. This will effect exectution order of the callbacks + * for the various events. + * @property queuable + * @type boolean + * @default false + */ + + /** + * This event has fired if true + * + * @property fired + * @type boolean + * @default false; + */ + + /** + * An array containing the arguments the custom event + * was last fired with. + * @property firedWith + * @type Array + */ + + /** + * This event should only fire one time if true, and if + * it has fired, any new subscribers should be notified + * immediately. + * + * @property fireOnce + * @type boolean + * @default false; + */ + + /** + * fireOnce listeners will fire syncronously unless async + * is set to true + * @property async + * @type boolean + * @default false + */ + + /** + * Flag for stopPropagation that is modified during fire() + * 1 means to stop propagation to bubble targets. 2 means + * to also stop additional subscribers on this target. + * @property stopped + * @type int + */ + + /** + * Flag for preventDefault that is modified during fire(). + * if it is not 0, the default behavior for this event + * @property prevented + * @type int + */ + + /** + * Specifies the host for this custom event. This is used + * to enable event bubbling + * @property host + * @type EventTarget + */ + + /** + * The default function to execute after event listeners + * have fire, but only if the default action was not + * prevented. + * @property defaultFn + * @type Function + */ + + /** + * Flag for the default function to execute only if the + * firing event is the current target. This happens only + * when using custom event delegation and setting the + * flag to `true` mimics the behavior of event delegation + * in the DOM. + * + * @property defaultTargetOnly + * @type Boolean + * @default false + */ + + /** + * The function to execute if a subscriber calls + * stopPropagation or stopImmediatePropagation + * @property stoppedFn + * @type Function + */ + + /** + * The function to execute if a subscriber calls + * preventDefault + * @property preventedFn + * @type Function + */ + + /** + * The subscribers to this event + * @property _subscribers + * @type Subscriber [] + * @private + */ + + /** + * 'After' subscribers + * @property _afters + * @type Subscriber [] + * @private + */ + + /** + * If set to true, the custom event will deliver an EventFacade object + * that is similar to a DOM event object. + * @property emitFacade + * @type boolean + * @default false + */ + + /** + * Supports multiple options for listener signatures in order to + * port YUI 2 apps. + * @property signature + * @type int + * @default 9 + */ + signature : YUI3_SIGNATURE, + + /** + * The context the the event will fire from by default. Defaults to the YUI + * instance. + * @property context + * @type object + */ + context : Y, + + /** + * Specifies whether or not this event's default function + * can be cancelled by a subscriber by executing preventDefault() + * on the event facade + * @property preventable + * @type boolean + * @default true + */ + preventable : true, + + /** + * Specifies whether or not a subscriber can stop the event propagation + * via stopPropagation(), stopImmediatePropagation(), or halt() + * + * Events can only bubble if emitFacade is true. + * + * @property bubbles + * @type boolean + * @default true + */ + bubbles : true, + + /** + * Returns the number of subscribers for this event as the sum of the on() + * subscribers and after() subscribers. + * + * @method hasSubs + * @return Number + */ + hasSubs: function(when) { + var s = 0, + a = 0, + subs = this._subscribers, + afters = this._afters, + sib = this.sibling; + + if (subs) { + s = subs.length; + } + + if (afters) { + a = afters.length; + } + + if (sib) { + subs = sib._subscribers; + afters = sib._afters; + + if (subs) { + s += subs.length; + } + + if (afters) { + a += afters.length; + } + } + + if (when) { + return (when === 'after') ? a : s; + } + + return (s + a); + }, + + /** + * Monitor the event state for the subscribed event. The first parameter + * is what should be monitored, the rest are the normal parameters when + * subscribing to an event. + * @method monitor + * @param what {string} what to monitor ('detach', 'attach', 'publish'). + * @return {EventHandle} return value from the monitor event subscription. + */ + monitor: function(what) { + this.monitored = true; + var type = this.id + '|' + this.type + '_' + what, + args = nativeSlice.call(arguments, 0); + args[0] = type; + return this.host.on.apply(this.host, args); + }, + + /** + * Get all of the subscribers to this event and any sibling event + * @method getSubs + * @return {Array} first item is the on subscribers, second the after. + */ + getSubs: function() { + + var sibling = this.sibling, + subs = this._subscribers, + afters = this._afters, + siblingSubs, + siblingAfters; + + if (sibling) { + siblingSubs = sibling._subscribers; + siblingAfters = sibling._afters; + } + + if (siblingSubs) { + if (subs) { + subs = subs.concat(siblingSubs); + } else { + subs = siblingSubs.concat(); + } + } else { + if (subs) { + subs = subs.concat(); + } else { + subs = []; + } + } + + if (siblingAfters) { + if (afters) { + afters = afters.concat(siblingAfters); + } else { + afters = siblingAfters.concat(); + } + } else { + if (afters) { + afters = afters.concat(); + } else { + afters = []; + } + } + + return [subs, afters]; + }, + + /** + * Apply configuration properties. Only applies the CONFIG whitelist + * @method applyConfig + * @param o hash of properties to apply. + * @param force {boolean} if true, properties that exist on the event + * will be overwritten. + */ + applyConfig: function(o, force) { + mixConfigs(this, o, force); + }, + + /** + * Create the Subscription for subscribing function, context, and bound + * arguments. If this is a fireOnce event, the subscriber is immediately + * notified. + * + * @method _on + * @param fn {Function} Subscription callback + * @param [context] {Object} Override `this` in the callback + * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire() + * @param [when] {String} "after" to slot into after subscribers + * @return {EventHandle} + * @protected + */ + _on: function(fn, context, args, when) { + + + var s = new Y.Subscriber(fn, context, args, when), + firedWith; + + if (this.fireOnce && this.fired) { + + firedWith = this.firedWith; + + // It's a little ugly for this to know about facades, + // but given the current breakup, not much choice without + // moving a whole lot of stuff around. + if (this.emitFacade && this._addFacadeToArgs) { + this._addFacadeToArgs(firedWith); + } + + if (this.async) { + setTimeout(Y.bind(this._notify, this, s, firedWith), 0); + } else { + this._notify(s, firedWith); + } + } + + if (when === AFTER) { + if (!this._afters) { + this._afters = []; + } + this._afters.push(s); + } else { + if (!this._subscribers) { + this._subscribers = []; + } + this._subscribers.push(s); + } + + if (this._kds) { + if (when === AFTER) { + this.afters[s.id] = s; + } else { + this.subscribers[s.id] = s; + } + } + + return new Y.EventHandle(this, s); + }, + + /** + * Listen for this event + * @method subscribe + * @param {Function} fn The function to execute. + * @return {EventHandle} Unsubscribe handle. + * @deprecated use on. + */ + subscribe: function(fn, context) { + var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; + return this._on(fn, context, a, true); + }, + + /** + * Listen for this event + * @method on + * @param {Function} fn The function to execute. + * @param {object} context optional execution context. + * @param {mixed} arg* 0..n additional arguments to supply to the subscriber + * when the event fires. + * @return {EventHandle} An object with a detach method to detch the handler(s). + */ + on: function(fn, context) { + var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; + + if (this.monitored && this.host) { + this.host._monitor('attach', this, { + args: arguments + }); + } + return this._on(fn, context, a, true); + }, + + /** + * Listen for this event after the normal subscribers have been notified and + * the default behavior has been applied. If a normal subscriber prevents the + * default behavior, it also prevents after listeners from firing. + * @method after + * @param {Function} fn The function to execute. + * @param {object} context optional execution context. + * @param {mixed} arg* 0..n additional arguments to supply to the subscriber + * when the event fires. + * @return {EventHandle} handle Unsubscribe handle. + */ + after: function(fn, context) { + var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null; + return this._on(fn, context, a, AFTER); + }, + + /** + * Detach listeners. + * @method detach + * @param {Function} fn The subscribed function to remove, if not supplied + * all will be removed. + * @param {Object} context The context object passed to subscribe. + * @return {Number} returns the number of subscribers unsubscribed. + */ + detach: function(fn, context) { + // unsubscribe handle + if (fn && fn.detach) { + return fn.detach(); + } + + var i, s, + found = 0, + subs = this._subscribers, + afters = this._afters; + + if (subs) { + for (i = subs.length; i >= 0; i--) { + s = subs[i]; + if (s && (!fn || fn === s.fn)) { + this._delete(s, subs, i); + found++; + } + } + } + + if (afters) { + for (i = afters.length; i >= 0; i--) { + s = afters[i]; + if (s && (!fn || fn === s.fn)) { + this._delete(s, afters, i); + found++; + } + } + } + + return found; + }, + + /** + * Detach listeners. + * @method unsubscribe + * @param {Function} fn The subscribed function to remove, if not supplied + * all will be removed. + * @param {Object} context The context object passed to subscribe. + * @return {int|undefined} returns the number of subscribers unsubscribed. + * @deprecated use detach. + */ + unsubscribe: function() { + return this.detach.apply(this, arguments); + }, + + /** + * Notify a single subscriber + * @method _notify + * @param {Subscriber} s the subscriber. + * @param {Array} args the arguments array to apply to the listener. + * @protected + */ + _notify: function(s, args, ef) { + + + var ret; + + ret = s.notify(args, this); + + if (false === ret || this.stopped > 1) { + return false; + } + + return true; + }, + + /** + * Logger abstraction to centralize the application of the silent flag + * @method log + * @param {string} msg message to log. + * @param {string} cat log category. + */ + log: function(msg, cat) { + }, + + /** + * Notifies the subscribers. The callback functions will be executed + * from the context specified when the event was created, and with the + * following parameters: + *

+ * @method fire + * @param {Object*} arguments an arbitrary set of parameters to pass to + * the handler. + * @return {boolean} false if one of the subscribers returned false, + * true otherwise. + * + */ + fire: function() { + + // push is the fastest way to go from arguments to arrays + // for most browsers currently + // http://jsperf.com/push-vs-concat-vs-slice/2 + + var args = []; + args.push.apply(args, arguments); + + return this._fire(args); + }, + + /** + * Private internal implementation for `fire`, which is can be used directly by + * `EventTarget` and other event module classes which have already converted from + * an `arguments` list to an array, to avoid the repeated overhead. + * + * @method _fire + * @private + * @param {Array} args The array of arguments passed to be passed to handlers. + * @return {boolean} false if one of the subscribers returned false, true otherwise. + */ + _fire: function(args) { + + if (this.fireOnce && this.fired) { + return true; + } else { + + // this doesn't happen if the event isn't published + // this.host._monitor('fire', this.type, args); + + this.fired = true; + + if (this.fireOnce) { + this.firedWith = args; + } + + if (this.emitFacade) { + return this.fireComplex(args); + } else { + return this.fireSimple(args); + } + } + }, + + /** + * Set up for notifying subscribers of non-emitFacade events. + * + * @method fireSimple + * @param args {Array} Arguments passed to fire() + * @return Boolean false if a subscriber returned false + * @protected + */ + fireSimple: function(args) { + this.stopped = 0; + this.prevented = 0; + if (this.hasSubs()) { + var subs = this.getSubs(); + this._procSubs(subs[0], args); + this._procSubs(subs[1], args); + } + if (this.broadcast) { + this._broadcast(args); + } + return this.stopped ? false : true; + }, + + // Requires the event-custom-complex module for full funcitonality. + fireComplex: function(args) { + args[0] = args[0] || {}; + return this.fireSimple(args); + }, + + /** + * Notifies a list of subscribers. + * + * @method _procSubs + * @param subs {Array} List of subscribers + * @param args {Array} Arguments passed to fire() + * @param ef {} + * @return Boolean false if a subscriber returns false or stops the event + * propagation via e.stopPropagation(), + * e.stopImmediatePropagation(), or e.halt() + * @private + */ + _procSubs: function(subs, args, ef) { + var s, i, l; + + for (i = 0, l = subs.length; i < l; i++) { + s = subs[i]; + if (s && s.fn) { + if (false === this._notify(s, args, ef)) { + this.stopped = 2; + } + if (this.stopped === 2) { + return false; + } + } + } + + return true; + }, + + /** + * Notifies the YUI instance if the event is configured with broadcast = 1, + * and both the YUI instance and Y.Global if configured with broadcast = 2. + * + * @method _broadcast + * @param args {Array} Arguments sent to fire() + * @private + */ + _broadcast: function(args) { + if (!this.stopped && this.broadcast) { + + var a = args.concat(); + a.unshift(this.type); + + if (this.host !== Y) { + Y.fire.apply(Y, a); + } + + if (this.broadcast === 2) { + Y.Global.fire.apply(Y.Global, a); + } + } + }, + + /** + * Removes all listeners + * @method unsubscribeAll + * @return {Number} The number of listeners unsubscribed. + * @deprecated use detachAll. + */ + unsubscribeAll: function() { + return this.detachAll.apply(this, arguments); + }, + + /** + * Removes all listeners + * @method detachAll + * @return {Number} The number of listeners unsubscribed. + */ + detachAll: function() { + return this.detach(); + }, + + /** + * Deletes the subscriber from the internal store of on() and after() + * subscribers. + * + * @method _delete + * @param s subscriber object. + * @param subs (optional) on or after subscriber array + * @param index (optional) The index found. + * @private + */ + _delete: function(s, subs, i) { + var when = s._when; + + if (!subs) { + subs = (when === AFTER) ? this._afters : this._subscribers; + } + + if (subs) { + i = YArray.indexOf(subs, s, 0); + + if (s && subs[i] === s) { + subs.splice(i, 1); + } + } + + if (this._kds) { + if (when === AFTER) { + delete this.afters[s.id]; + } else { + delete this.subscribers[s.id]; + } + } + + if (this.monitored && this.host) { + this.host._monitor('detach', this, { + ce: this, + sub: s + }); + } + + if (s) { + s.deleted = true; + } + } +}; +/** + * Stores the subscriber information to be used when the event fires. + * @param {Function} fn The wrapped function to execute. + * @param {Object} context The value of the keyword 'this' in the listener. + * @param {Array} args* 0..n additional arguments to supply the listener. + * + * @class Subscriber + * @constructor + */ +Y.Subscriber = function(fn, context, args, when) { + + /** + * The callback that will be execute when the event fires + * This is wrapped by Y.rbind if obj was supplied. + * @property fn + * @type Function + */ + this.fn = fn; + + /** + * Optional 'this' keyword for the listener + * @property context + * @type Object + */ + this.context = context; + + /** + * Unique subscriber id + * @property id + * @type String + */ + this.id = Y.guid(); + + /** + * Additional arguments to propagate to the subscriber + * @property args + * @type Array + */ + this.args = args; + + this._when = when; + + /** + * Custom events for a given fire transaction. + * @property events + * @type {EventTarget} + */ + // this.events = null; + + /** + * This listener only reacts to the event once + * @property once + */ + // this.once = false; + +}; + +Y.Subscriber.prototype = { + constructor: Y.Subscriber, + + _notify: function(c, args, ce) { + if (this.deleted && !this.postponed) { + if (this.postponed) { + delete this.fn; + delete this.context; + } else { + delete this.postponed; + return null; + } + } + var a = this.args, ret; + switch (ce.signature) { + case 0: + ret = this.fn.call(c, ce.type, args, c); + break; + case 1: + ret = this.fn.call(c, args[0] || null, c); + break; + default: + if (a || args) { + args = args || []; + a = (a) ? args.concat(a) : args; + ret = this.fn.apply(c, a); + } else { + ret = this.fn.call(c); + } + } + + if (this.once) { + ce._delete(this); + } + + return ret; + }, + + /** + * Executes the subscriber. + * @method notify + * @param args {Array} Arguments array for the subscriber. + * @param ce {CustomEvent} The custom event that sent the notification. + */ + notify: function(args, ce) { + var c = this.context, + ret = true; + + if (!c) { + c = (ce.contextFn) ? ce.contextFn() : ce.context; + } + + // only catch errors if we will not re-throw them. + if (Y.config && Y.config.throwFail) { + ret = this._notify(c, args, ce); + } else { + try { + ret = this._notify(c, args, ce); + } catch (e) { + Y.error(this + ' failed: ' + e.message, e); + } + } + + return ret; + }, + + /** + * Returns true if the fn and obj match this objects properties. + * Used by the unsubscribe method to match the right subscriber. + * + * @method contains + * @param {Function} fn the function to execute. + * @param {Object} context optional 'this' keyword for the listener. + * @return {boolean} true if the supplied arguments match this + * subscriber's signature. + */ + contains: function(fn, context) { + if (context) { + return ((this.fn === fn) && this.context === context); + } else { + return (this.fn === fn); + } + }, + + valueOf : function() { + return this.id; + } + +}; +/** + * Return value from all subscribe operations + * @class EventHandle + * @constructor + * @param {CustomEvent} evt the custom event. + * @param {Subscriber} sub the subscriber. + */ +Y.EventHandle = function(evt, sub) { + + /** + * The custom event + * + * @property evt + * @type CustomEvent + */ + this.evt = evt; + + /** + * The subscriber object + * + * @property sub + * @type Subscriber + */ + this.sub = sub; +}; + +Y.EventHandle.prototype = { + batch: function(f, c) { + f.call(c || this, this); + if (Y.Lang.isArray(this.evt)) { + Y.Array.each(this.evt, function(h) { + h.batch.call(c || h, f); + }); + } + }, + + /** + * Detaches this subscriber + * @method detach + * @return {Number} the number of detached listeners + */ + detach: function() { + var evt = this.evt, detached = 0, i; + if (evt) { + if (Y.Lang.isArray(evt)) { + for (i = 0; i < evt.length; i++) { + detached += evt[i].detach(); + } + } else { + evt._delete(this.sub); + detached = 1; + } + + } + + return detached; + }, + + /** + * Monitor the event state for the subscribed event. The first parameter + * is what should be monitored, the rest are the normal parameters when + * subscribing to an event. + * @method monitor + * @param what {string} what to monitor ('attach', 'detach', 'publish'). + * @return {EventHandle} return value from the monitor event subscription. + */ + monitor: function(what) { + return this.evt.monitor.apply(this.evt, arguments); + } +}; + +/** + * Custom event engine, DOM event listener abstraction layer, synthetic DOM + * events. + * @module event-custom + * @submodule event-custom-base + */ + +/** + * EventTarget provides the implementation for any object to + * publish, subscribe and fire to custom events, and also + * alows other EventTargets to target the object with events + * sourced from the other object. + * EventTarget is designed to be used with Y.augment to wrap + * EventCustom in an interface that allows events to be listened to + * and fired by name. This makes it possible for implementing code to + * subscribe to an event that either has not been created yet, or will + * not be created at all. + * @class EventTarget + * @param opts a configuration object + * @config emitFacade {boolean} if true, all events will emit event + * facade payloads by default (default false) + * @config prefix {String} the prefix to apply to non-prefixed event names + */ + +var L = Y.Lang, + PREFIX_DELIMITER = ':', + CATEGORY_DELIMITER = '|', + AFTER_PREFIX = '~AFTER~', + WILD_TYPE_RE = /(.*?)(:)(.*?)/, + + _wildType = Y.cached(function(type) { + return type.replace(WILD_TYPE_RE, "*$2$3"); + }), + + /** + * If the instance has a prefix attribute and the + * event type is not prefixed, the instance prefix is + * applied to the supplied type. + * @method _getType + * @private + */ + _getType = function(type, pre) { + + if (!pre || !type || type.indexOf(PREFIX_DELIMITER) > -1) { + return type; + } + + return pre + PREFIX_DELIMITER + type; + }, + + /** + * Returns an array with the detach key (if provided), + * and the prefixed event name from _getType + * Y.on('detachcategory| menu:click', fn) + * @method _parseType + * @private + */ + _parseType = Y.cached(function(type, pre) { + + var t = type, detachcategory, after, i; + + if (!L.isString(t)) { + return t; + } + + i = t.indexOf(AFTER_PREFIX); + + if (i > -1) { + after = true; + t = t.substr(AFTER_PREFIX.length); + } + + i = t.indexOf(CATEGORY_DELIMITER); + + if (i > -1) { + detachcategory = t.substr(0, (i)); + t = t.substr(i+1); + if (t === '*') { + t = null; + } + } + + // detach category, full type with instance prefix, is this an after listener, short type + return [detachcategory, (pre) ? _getType(t, pre) : t, after, t]; + }), + + ET = function(opts) { + + var etState = this._yuievt, + etConfig; + + if (!etState) { + etState = this._yuievt = { + events: {}, // PERF: Not much point instantiating lazily. We're bound to have events + targets: null, // PERF: Instantiate lazily, if user actually adds target, + config: { + host: this, + context: this + }, + chain: Y.config.chain + }; + } + + etConfig = etState.config; + + if (opts) { + mixConfigs(etConfig, opts, true); + + if (opts.chain !== undefined) { + etState.chain = opts.chain; + } + + if (opts.prefix) { + etConfig.prefix = opts.prefix; + } + } + }; + +ET.prototype = { + + constructor: ET, + + /** + * Listen to a custom event hosted by this object one time. + * This is the equivalent to on except the + * listener is immediatelly detached when it is executed. + * @method once + * @param {String} type The name of the event + * @param {Function} fn The callback to execute in response to the event + * @param {Object} [context] Override `this` object in callback + * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber + * @return {EventHandle} A subscription handle capable of detaching the + * subscription + */ + once: function() { + var handle = this.on.apply(this, arguments); + handle.batch(function(hand) { + if (hand.sub) { + hand.sub.once = true; + } + }); + return handle; + }, + + /** + * Listen to a custom event hosted by this object one time. + * This is the equivalent to after except the + * listener is immediatelly detached when it is executed. + * @method onceAfter + * @param {String} type The name of the event + * @param {Function} fn The callback to execute in response to the event + * @param {Object} [context] Override `this` object in callback + * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber + * @return {EventHandle} A subscription handle capable of detaching that + * subscription + */ + onceAfter: function() { + var handle = this.after.apply(this, arguments); + handle.batch(function(hand) { + if (hand.sub) { + hand.sub.once = true; + } + }); + return handle; + }, + + /** + * Takes the type parameter passed to 'on' and parses out the + * various pieces that could be included in the type. If the + * event type is passed without a prefix, it will be expanded + * to include the prefix one is supplied or the event target + * is configured with a default prefix. + * @method parseType + * @param {String} type the type + * @param {String} [pre] The prefix. Defaults to this._yuievt.config.prefix + * @since 3.3.0 + * @return {Array} an array containing: + * * the detach category, if supplied, + * * the prefixed event type, + * * whether or not this is an after listener, + * * the supplied event type + */ + parseType: function(type, pre) { + return _parseType(type, pre || this._yuievt.config.prefix); + }, + + /** + * Subscribe a callback function to a custom event fired by this object or + * from an object that bubbles its events to this object. + * + * Callback functions for events published with `emitFacade = true` will + * receive an `EventFacade` as the first argument (typically named "e"). + * These callbacks can then call `e.preventDefault()` to disable the + * behavior published to that event's `defaultFn`. See the `EventFacade` + * API for all available properties and methods. Subscribers to + * non-`emitFacade` events will receive the arguments passed to `fire()` + * after the event name. + * + * To subscribe to multiple events at once, pass an object as the first + * argument, where the key:value pairs correspond to the eventName:callback, + * or pass an array of event names as the first argument to subscribe to + * all listed events with the same callback. + * + * Returning `false` from a callback is supported as an alternative to + * calling `e.preventDefault(); e.stopPropagation();`. However, it is + * recommended to use the event methods whenever possible. + * + * @method on + * @param {String} type The name of the event + * @param {Function} fn The callback to execute in response to the event + * @param {Object} [context] Override `this` object in callback + * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber + * @return {EventHandle} A subscription handle capable of detaching that + * subscription + */ + on: function(type, fn, context) { + + var yuievt = this._yuievt, + parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce, + detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype, + Node = Y.Node, n, domevent, isArr; + + // full name, args, detachcategory, after + this._monitor('attach', parts[1], { + args: arguments, + category: parts[0], + after: parts[2] + }); + + if (L.isObject(type)) { + + if (L.isFunction(type)) { + return Y.Do.before.apply(Y.Do, arguments); + } + + f = fn; + c = context; + args = nativeSlice.call(arguments, 0); + ret = []; + + if (L.isArray(type)) { + isArr = true; + } + + after = type._after; + delete type._after; + + Y.each(type, function(v, k) { + + if (L.isObject(v)) { + f = v.fn || ((L.isFunction(v)) ? v : f); + c = v.context || c; + } + + var nv = (after) ? AFTER_PREFIX : ''; + + args[0] = nv + ((isArr) ? v : k); + args[1] = f; + args[2] = c; + + ret.push(this.on.apply(this, args)); + + }, this); + + return (yuievt.chain) ? this : new Y.EventHandle(ret); + } + + detachcategory = parts[0]; + after = parts[2]; + shorttype = parts[3]; + + // extra redirection so we catch adaptor events too. take a look at this. + if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) { + args = nativeSlice.call(arguments, 0); + args.splice(2, 0, Node.getDOMNode(this)); + return Y.on.apply(Y, args); + } + + type = parts[1]; + + if (Y.instanceOf(this, YUI)) { + + adapt = Y.Env.evt.plugins[type]; + args = nativeSlice.call(arguments, 0); + args[0] = shorttype; + + if (Node) { + n = args[2]; + + if (Y.instanceOf(n, Y.NodeList)) { + n = Y.NodeList.getDOMNodes(n); + } else if (Y.instanceOf(n, Node)) { + n = Node.getDOMNode(n); + } + + domevent = (shorttype in Node.DOM_EVENTS); + + // Captures both DOM events and event plugins. + if (domevent) { + args[2] = n; + } + } + + // check for the existance of an event adaptor + if (adapt) { + handle = adapt.on.apply(Y, args); + } else if ((!type) || domevent) { + handle = Y.Event._attach(args); + } + + } + + if (!handle) { + ce = yuievt.events[type] || this.publish(type); + handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true); + + // TODO: More robust regex, accounting for category + if (type.indexOf("*:") !== -1) { + this._hasSiblings = true; + } + } + + if (detachcategory) { + store[detachcategory] = store[detachcategory] || {}; + store[detachcategory][type] = store[detachcategory][type] || []; + store[detachcategory][type].push(handle); + } + + return (yuievt.chain) ? this : handle; + + }, + + /** + * subscribe to an event + * @method subscribe + * @deprecated use on + */ + subscribe: function() { + return this.on.apply(this, arguments); + }, + + /** + * Detach one or more listeners the from the specified event + * @method detach + * @param type {string|Object} Either the handle to the subscriber or the + * type of event. If the type + * is not specified, it will attempt to remove + * the listener from all hosted events. + * @param fn {Function} The subscribed function to unsubscribe, if not + * supplied, all subscribers will be removed. + * @param context {Object} The custom object passed to subscribe. This is + * optional, but if supplied will be used to + * disambiguate multiple listeners that are the same + * (e.g., you subscribe many object using a function + * that lives on the prototype) + * @return {EventTarget} the host + */ + detach: function(type, fn, context) { + + var evts = this._yuievt.events, + i, + Node = Y.Node, + isNode = Node && (Y.instanceOf(this, Node)); + + // detachAll disabled on the Y instance. + if (!type && (this !== Y)) { + for (i in evts) { + if (evts.hasOwnProperty(i)) { + evts[i].detach(fn, context); + } + } + if (isNode) { + Y.Event.purgeElement(Node.getDOMNode(this)); + } + + return this; + } + + var parts = _parseType(type, this._yuievt.config.prefix), + detachcategory = L.isArray(parts) ? parts[0] : null, + shorttype = (parts) ? parts[3] : null, + adapt, store = Y.Env.evt.handles, detachhost, cat, args, + ce, + + keyDetacher = function(lcat, ltype, host) { + var handles = lcat[ltype], ce, i; + if (handles) { + for (i = handles.length - 1; i >= 0; --i) { + ce = handles[i].evt; + if (ce.host === host || ce.el === host) { + handles[i].detach(); + } + } + } + }; + + if (detachcategory) { + + cat = store[detachcategory]; + type = parts[1]; + detachhost = (isNode) ? Y.Node.getDOMNode(this) : this; + + if (cat) { + if (type) { + keyDetacher(cat, type, detachhost); + } else { + for (i in cat) { + if (cat.hasOwnProperty(i)) { + keyDetacher(cat, i, detachhost); + } + } + } + + return this; + } + + // If this is an event handle, use it to detach + } else if (L.isObject(type) && type.detach) { + type.detach(); + return this; + // extra redirection so we catch adaptor events too. take a look at this. + } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) { + args = nativeSlice.call(arguments, 0); + args[2] = Node.getDOMNode(this); + Y.detach.apply(Y, args); + return this; + } + + adapt = Y.Env.evt.plugins[shorttype]; + + // The YUI instance handles DOM events and adaptors + if (Y.instanceOf(this, YUI)) { + args = nativeSlice.call(arguments, 0); + // use the adaptor specific detach code if + if (adapt && adapt.detach) { + adapt.detach.apply(Y, args); + return this; + // DOM event fork + } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) { + args[0] = type; + Y.Event.detach.apply(Y.Event, args); + return this; + } + } + + // ce = evts[type]; + ce = evts[parts[1]]; + if (ce) { + ce.detach(fn, context); + } + + return this; + }, + + /** + * detach a listener + * @method unsubscribe + * @deprecated use detach + */ + unsubscribe: function() { + return this.detach.apply(this, arguments); + }, + + /** + * Removes all listeners from the specified event. If the event type + * is not specified, all listeners from all hosted custom events will + * be removed. + * @method detachAll + * @param type {String} The type, or name of the event + */ + detachAll: function(type) { + return this.detach(type); + }, + + /** + * Removes all listeners from the specified event. If the event type + * is not specified, all listeners from all hosted custom events will + * be removed. + * @method unsubscribeAll + * @param type {String} The type, or name of the event + * @deprecated use detachAll + */ + unsubscribeAll: function() { + return this.detachAll.apply(this, arguments); + }, + + /** + * Creates a new custom event of the specified type. If a custom event + * by that name already exists, it will not be re-created. In either + * case the custom event is returned. + * + * @method publish + * + * @param type {String} the type, or name of the event + * @param opts {object} optional config params. Valid properties are: + * + * + * + * @return {CustomEvent} the custom event + * + */ + publish: function(type, opts) { + + var ret, + etState = this._yuievt, + etConfig = etState.config, + pre = etConfig.prefix; + + if (typeof type === "string") { + if (pre) { + type = _getType(type, pre); + } + ret = this._publish(type, etConfig, opts); + } else { + ret = {}; + + Y.each(type, function(v, k) { + if (pre) { + k = _getType(k, pre); + } + ret[k] = this._publish(k, etConfig, v || opts); + }, this); + + } + + return ret; + }, + + /** + * Returns the fully qualified type, given a short type string. + * That is, returns "foo:bar" when given "bar" if "foo" is the configured prefix. + * + * NOTE: This method, unlike _getType, does no checking of the value passed in, and + * is designed to be used with the low level _publish() method, for critical path + * implementations which need to fast-track publish for performance reasons. + * + * @method _getFullType + * @private + * @param {String} type The short type to prefix + * @return {String} The prefixed type, if a prefix is set, otherwise the type passed in + */ + _getFullType : function(type) { + + var pre = this._yuievt.config.prefix; + + if (pre) { + return pre + PREFIX_DELIMITER + type; + } else { + return type; + } + }, + + /** + * The low level event publish implementation. It expects all the massaging to have been done + * outside of this method. e.g. the `type` to `fullType` conversion. It's designed to be a fast + * path publish, which can be used by critical code paths to improve performance. + * + * @method _publish + * @private + * @param {String} fullType The prefixed type of the event to publish. + * @param {Object} etOpts The EventTarget specific configuration to mix into the published event. + * @param {Object} ceOpts The publish specific configuration to mix into the published event. + * @return {CustomEvent} The published event. If called without `etOpts` or `ceOpts`, this will + * be the default `CustomEvent` instance, and can be configured independently. + */ + _publish : function(fullType, etOpts, ceOpts) { + + var ce, + etState = this._yuievt, + etConfig = etState.config, + host = etConfig.host, + context = etConfig.context, + events = etState.events; + + ce = events[fullType]; + + // PERF: Hate to pull the check out of monitor, but trying to keep critical path tight. + if ((etConfig.monitored && !ce) || (ce && ce.monitored)) { + this._monitor('publish', fullType, { + args: arguments + }); + } + + if (!ce) { + // Publish event + ce = events[fullType] = new Y.CustomEvent(fullType, etOpts); + + if (!etOpts) { + ce.host = host; + ce.context = context; + } + } + + if (ceOpts) { + mixConfigs(ce, ceOpts, true); + } + + return ce; + }, + + /** + * This is the entry point for the event monitoring system. + * You can monitor 'attach', 'detach', 'fire', and 'publish'. + * When configured, these events generate an event. click -> + * click_attach, click_detach, click_publish -- these can + * be subscribed to like other events to monitor the event + * system. Inividual published events can have monitoring + * turned on or off (publish can't be turned off before it + * it published) by setting the events 'monitor' config. + * + * @method _monitor + * @param what {String} 'attach', 'detach', 'fire', or 'publish' + * @param eventType {String|CustomEvent} The prefixed name of the event being monitored, or the CustomEvent object. + * @param o {Object} Information about the event interaction, such as + * fire() args, subscription category, publish config + * @private + */ + _monitor: function(what, eventType, o) { + var monitorevt, ce, type; + + if (eventType) { + if (typeof eventType === "string") { + type = eventType; + ce = this.getEvent(eventType, true); + } else { + ce = eventType; + type = eventType.type; + } + + if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { + monitorevt = type + '_' + what; + o.monitored = what; + this.fire.call(this, monitorevt, o); + } + } + }, + + /** + * Fire a custom event by name. The callback functions will be executed + * from the context specified when the event was created, and with the + * following parameters. + * + * The first argument is the event type, and any additional arguments are + * passed to the listeners as parameters. If the first of these is an + * object literal, and the event is configured to emit an event facade, + * that object is mixed into the event facade and the facade is provided + * in place of the original object. + * + * If the custom event object hasn't been created, then the event hasn't + * been published and it has no subscribers. For performance sake, we + * immediate exit in this case. This means the event won't bubble, so + * if the intention is that a bubble target be notified, the event must + * be published on this object first. + * + * @method fire + * @param type {String|Object} The type of the event, or an object that contains + * a 'type' property. + * @param arguments {Object*} an arbitrary set of parameters to pass to + * the handler. If the first of these is an object literal and the event is + * configured to emit an event facade, the event facade will replace that + * parameter after the properties the object literal contains are copied to + * the event facade. + * @return {Boolean} True if the whole lifecycle of the event went through, + * false if at any point the event propagation was halted. + */ + fire: function(type) { + + var typeIncluded = (typeof type === "string"), + argCount = arguments.length, + t = type, + yuievt = this._yuievt, + etConfig = yuievt.config, + pre = etConfig.prefix, + ret, + ce, + ce2, + args; + + if (typeIncluded && argCount <= 3) { + + // PERF: Try to avoid slice/iteration for the common signatures + + // Most common + if (argCount === 2) { + args = [arguments[1]]; // fire("foo", {}) + } else if (argCount === 3) { + args = [arguments[1], arguments[2]]; // fire("foo", {}, opts) + } else { + args = []; // fire("foo") + } + + } else { + args = nativeSlice.call(arguments, ((typeIncluded) ? 1 : 0)); + } + + if (!typeIncluded) { + t = (type && type.type); + } + + if (pre) { + t = _getType(t, pre); + } + + ce = yuievt.events[t]; + + if (this._hasSiblings) { + ce2 = this.getSibling(t, ce); + + if (ce2 && !ce) { + ce = this.publish(t); + } + } + + // PERF: trying to avoid function call, since this is a critical path + if ((etConfig.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) { + this._monitor('fire', (ce || t), { + args: args + }); + } + + // this event has not been published or subscribed to + if (!ce) { + if (yuievt.hasTargets) { + return this.bubble({ type: t }, args, this); + } + + // otherwise there is nothing to be done + ret = true; + } else { + + if (ce2) { + ce.sibling = ce2; + } + + ret = ce._fire(args); + } + + return (yuievt.chain) ? this : ret; + }, + + getSibling: function(type, ce) { + var ce2; + + // delegate to *:type events if there are subscribers + if (type.indexOf(PREFIX_DELIMITER) > -1) { + type = _wildType(type); + ce2 = this.getEvent(type, true); + if (ce2) { + ce2.applyConfig(ce); + ce2.bubbles = false; + ce2.broadcast = 0; + } + } + + return ce2; + }, + + /** + * Returns the custom event of the provided type has been created, a + * falsy value otherwise + * @method getEvent + * @param type {String} the type, or name of the event + * @param prefixed {String} if true, the type is prefixed already + * @return {CustomEvent} the custom event or null + */ + getEvent: function(type, prefixed) { + var pre, e; + + if (!prefixed) { + pre = this._yuievt.config.prefix; + type = (pre) ? _getType(type, pre) : type; + } + e = this._yuievt.events; + return e[type] || null; + }, + + /** + * Subscribe to a custom event hosted by this object. The + * supplied callback will execute after any listeners add + * via the subscribe method, and after the default function, + * if configured for the event, has executed. + * + * @method after + * @param {String} type The name of the event + * @param {Function} fn The callback to execute in response to the event + * @param {Object} [context] Override `this` object in callback + * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber + * @return {EventHandle} A subscription handle capable of detaching the + * subscription + */ + after: function(type, fn) { + + var a = nativeSlice.call(arguments, 0); + + switch (L.type(type)) { + case 'function': + return Y.Do.after.apply(Y.Do, arguments); + case 'array': + // YArray.each(a[0], function(v) { + // v = AFTER_PREFIX + v; + // }); + // break; + case 'object': + a[0]._after = true; + break; + default: + a[0] = AFTER_PREFIX + type; + } + + return this.on.apply(this, a); + + }, + + /** + * Executes the callback before a DOM event, custom event + * or method. If the first argument is a function, it + * is assumed the target is a method. For DOM and custom + * events, this is an alias for Y.on. + * + * For DOM and custom events: + * type, callback, context, 0-n arguments + * + * For methods: + * callback, object (method host), methodName, context, 0-n arguments + * + * @method before + * @return detach handle + */ + before: function() { + return this.on.apply(this, arguments); + } + +}; + +Y.EventTarget = ET; + +// make Y an event target +Y.mix(Y, ET.prototype); +ET.call(Y, { bubbles: false }); + +YUI.Env.globalEvents = YUI.Env.globalEvents || new ET(); + +/** + * Hosts YUI page level events. This is where events bubble to + * when the broadcast config is set to 2. This property is + * only available if the custom event module is loaded. + * @property Global + * @type EventTarget + * @for YUI + */ +Y.Global = YUI.Env.globalEvents; + +// @TODO implement a global namespace function on Y.Global? + +/** +`Y.on()` can do many things: + + + +For custom event subscriptions, pass the custom event name as the first argument +and callback as the second. The `this` object in the callback will be `Y` unless +an override is passed as the third argument. + + Y.on('io:complete', function () { + Y.MyApp.updateStatus('Transaction complete'); + }); + +To subscribe to DOM events, pass the name of a DOM event as the first argument +and a CSS selector string as the third argument after the callback function. +Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`, +array, or simply omitted (the default is the `window` object). + + Y.on('click', function (e) { + e.preventDefault(); + + // proceed with ajax form submission + var url = this.get('action'); + ... + }, '#my-form'); + +The `this` object in DOM event callbacks will be the `Node` targeted by the CSS +selector or other identifier. + +`on()` subscribers for DOM events or custom events `publish`ed with a +`defaultFn` can prevent the default behavior with `e.preventDefault()` from the +event object passed as the first parameter to the subscription callback. + +To subscribe to the execution of an object method, pass arguments corresponding to the call signature for +`Y.Do.before(...)`. + +NOTE: The formal parameter list below is for events, not for function +injection. See `Y.Do.before` for that signature. + +@method on +@param {String} type DOM or custom event name +@param {Function} fn The callback to execute in response to the event +@param {Object} [context] Override `this` object in callback +@param {Any} [arg*] 0..n additional arguments to supply to the subscriber +@return {EventHandle} A subscription handle capable of detaching the + subscription +@see Do.before +@for YUI +**/ + +/** +Listen for an event one time. Equivalent to `on()`, except that +the listener is immediately detached when executed. + +See the `on()` method for additional subscription +options. + +@see on +@method once +@param {String} type DOM or custom event name +@param {Function} fn The callback to execute in response to the event +@param {Object} [context] Override `this` object in callback +@param {Any} [arg*] 0..n additional arguments to supply to the subscriber +@return {EventHandle} A subscription handle capable of detaching the + subscription +@for YUI +**/ + +/** +Listen for an event one time. Equivalent to `once()`, except, like `after()`, +the subscription callback executes after all `on()` subscribers and the event's +`defaultFn` (if configured) have executed. Like `after()` if any `on()` phase +subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()` +subscribers will execute. + +The listener is immediately detached when executed. + +See the `on()` method for additional subscription +options. + +@see once +@method onceAfter +@param {String} type The custom event name +@param {Function} fn The callback to execute in response to the event +@param {Object} [context] Override `this` object in callback +@param {Any} [arg*] 0..n additional arguments to supply to the subscriber +@return {EventHandle} A subscription handle capable of detaching the + subscription +@for YUI +**/ + +/** +Like `on()`, this method creates a subscription to a custom event or to the +execution of a method on an object. + +For events, `after()` subscribers are executed after the event's +`defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber. + +See the `on()` method for additional subscription +options. + +NOTE: The subscription signature shown is for events, not for function +injection. See `Y.Do.after` +for that signature. + +@see on +@see Do.after +@method after +@param {String} type The custom event name +@param {Function} fn The callback to execute in response to the event +@param {Object} [context] Override `this` object in callback +@param {Any} [args*] 0..n additional arguments to supply to the subscriber +@return {EventHandle} A subscription handle capable of detaching the + subscription +@for YUI +**/ + + +}, '@VERSION@', {"requires": ["oop"]});