event-custom-debug.js revision 508ea3dac5e30f55a73a5cc47876c43d7dddf54e
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassYUI.add('event-custom-base', function(Y) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Custom event engine, DOM event listener abstraction layer, synthetic DOM
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @module event-custom
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Env.evt = {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass handles: {},
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass plugins: {}
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Custom event engine, DOM event listener abstraction layer, synthetic DOM
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @module event-custom
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @submodule event-custom-base
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Allows for the insertion of methods that are executed before or after
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * a specified method
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassvar DO_BEFORE = 0,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass DO_AFTER = 1,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO = {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Cache of objects touched by the utility
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property objs
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass objs: {},
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <p>Execute the supplied method before the specified function. Wrapping
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function may optionally return an instance of the following classes to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * further alter runtime behavior:</p>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dl>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dd>Immediatly stop execution and return
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <code>returnValue</code>. No other wrapping functions will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * executed.</dd>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dd>Replace the arguments that the original function will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * called with.</dd>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dt></code>Y.Do.Prevent(message)</code></dt>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dd>Don't execute the wrapped function. Other before phase
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * wrappers will be executed.</dd>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * </dl>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method before
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param fn {Function} the function to execute
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param obj the object hosting the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sFn {string} the name of the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param c The execution context for fn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * when the event fires.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {string} handle for the subscription
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass before: function(fn, obj, sFn, c) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Y.log('Do before: ' + sFn, 'info', 'event');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var f = fn, a;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (c) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass a = [fn, c].concat(Y.Array(arguments, 4, true));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass f = Y.rbind.apply(Y, a);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._inject(DO_BEFORE, f, obj, sFn);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove /**
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove * <p>Execute the supplied method after the specified function. Wrapping
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function may optionally return an instance of the following classes to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * further alter runtime behavior:</p>
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove * <dl>
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove * <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dd>Immediatly stop execution and return
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <code>returnValue</code>. No other wrapping functions will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * executed.</dd>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <dd>Return <code>returnValue</code> instead of the wrapped
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * method's original return value. This can be further altered by
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * other after phase wrappers.</dd>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * </dl>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <p>The static properties <code>Y.Do.originalRetVal</code> and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <code>Y.Do.currentRetVal</code> will be populated for reference.</p>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method after
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param fn {Function} the function to execute
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param obj the object hosting the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sFn {string} the name of the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param c The execution context for fn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {string} handle for the subscription
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass after: function(fn, obj, sFn, c) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var f = fn, a;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (c) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass a = [fn, c].concat(Y.Array(arguments, 4, true));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass f = Y.rbind.apply(Y, a);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._inject(DO_AFTER, f, obj, sFn);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Execute the supplied method before or after the specified function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Used by <code>before</code> and <code>after</code>.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _inject
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param when {string} before or after
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param fn {Function} the function to execute
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param obj the object hosting the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sFn {string} the name of the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param c The execution context for fn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {string} handle for the subscription
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @private
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _inject: function(when, fn, obj, sFn) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // object id
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var id = Y.stamp(obj), o, sid;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (! this.objs[id]) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // create a map entry for the obj if it doesn't exist
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.objs[id] = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass o = this.objs[id];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (! o[sFn]) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // create a map entry for the method if it doesn't exist
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass o[sFn] = new Y.Do.Method(obj, sFn);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // re-route the method to our wrapper
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass obj[sFn] =
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return o[sFn].exec.apply(o[sFn], arguments);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass };
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove // subscriber id
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove sid = id + Y.stamp(fn) + sFn;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove // register the callback
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove o[sFn].register(sid, fn, when);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return new Y.EventHandle(o[sFn], sid);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Detach a before or after subscription.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method detach
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param handle {string} the subscription handle
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove detach: function(handle) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (handle.detach) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass handle.detach();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _unload: function(e, me) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Do = DO;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass//////////////////////////////////////////////////////////////////////////
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Contains the return value from the wrapped method, accessible
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * by 'after' event listeners.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property Do.originalRetVal
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @since 3.2.0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Contains the current state of the return value, consumable by
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * 'after' event listeners, and updated if an after subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * changes the return value generated by the wrapped function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property Do.currentRetVal
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @since 3.2.0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass//////////////////////////////////////////////////////////////////////////
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Wrapper for a displaced method with aop enabled
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.Method
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param obj The object to operate on
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sFn The name of the method to displace
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Method = function(obj, sFn) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.obj = obj;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.methodName = sFn;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.method = obj[sFn];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.before = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Register a aop subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method register
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sid {string} the subscriber id
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param fn {Function} the function to execute
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param when {string} when to execute the function
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Method.prototype.register = function (sid, fn, when) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (when) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after[sid] = fn;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.before[sid] = fn;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Unregister a aop subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method delete
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param sid {string} the subscriber id
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param fn {Function} the function to execute
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param when {string} when to execute the function
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Method.prototype._delete = function (sid) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass delete this.before[sid];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass delete this.after[sid];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <p>Execute the wrapped method. All arguments are passed into the wrapping
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * functions. If any of the before wrappers return an instance of
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function nor any after phase subscribers will be executed.</p>
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <p>The return value will be the return value of the wrapped function or one
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <code>Y.Do.AlterReturn</code>.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method exec
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param arg* {any} Arguments are passed to the wrapping and wrapped functions
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {any} Return value of wrapped function unless overwritten (see above)
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Method.prototype.exec = function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var args = Y.Array(arguments, 0, true),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass i, ret, newRet,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass bf = this.before,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass af = this.after,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass prevented = false;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // execute before
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass for (i in bf) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (bf.hasOwnProperty(i)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ret = bf[i].apply(this.obj, args);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (ret) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass switch (ret.constructor) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass case DO.Halt:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return ret.retVal;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass case DO.AlterArgs:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass args = ret.newArgs;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass break;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass case DO.Prevent:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass prevented = true;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass break;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass default:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove // execute method
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove if (!prevented) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ret = this.method.apply(this.obj, args);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove DO.originalRetVal = ret;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass DO.currentRetVal = ret;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // execute after methods.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass for (i in af) {
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove if (af.hasOwnProperty(i)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass newRet = af[i].apply(this.obj, args);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Stop processing if a Halt object is returned
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (newRet && newRet.constructor == DO.Halt) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return newRet.retVal;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Check for a new return value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else if (newRet && newRet.constructor == DO.AlterReturn) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ret = newRet.newRetVal;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Update the static retval state
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass DO.currentRetVal = ret;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return ret;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass//////////////////////////////////////////////////////////////////////////
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return an AlterArgs object when you want to change the arguments that
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * were passed into the function. Useful for Do.before subscribers. An
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * example would be a service that scrubs out illegal characters prior to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * executing the core business logic.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.AlterArgs
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param msg {String} (optional) Explanation of the altered return value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param newArgs {Array} Call parameters to be used for the original method
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * instead of the arguments originally passed in.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.AlterArgs = function(msg, newArgs) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.msg = msg;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.newArgs = newArgs;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return an AlterReturn object when you want to change the result returned
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * from the core method to the caller. Useful for Do.after subscribers.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.AlterReturn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param msg {String} (optional) Explanation of the altered return value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param newRetVal {any} Return value passed to code that invoked the wrapped
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.AlterReturn = function(msg, newRetVal) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.msg = msg;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.newRetVal = newRetVal;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return a Halt object when you want to terminate the execution
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * of all subsequent subscribers as well as the wrapped method
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * if it has not exectued yet. Useful for Do.before subscribers.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.Halt
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param msg {String} (optional) Explanation of why the termination was done
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param retVal {any} Return value passed to code that invoked the wrapped
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Halt = function(msg, retVal) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.msg = msg;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.retVal = retVal;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return a Prevent object when you want to prevent the wrapped function
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * from executing, but want the remaining listeners to execute. Useful
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * for Do.before subscribers.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.Prevent
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param msg {String} (optional) Explanation of why the termination was done
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Prevent = function(msg) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.msg = msg;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return an Error object when you want to terminate the execution
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * of all subsequent method calls.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Do.Error
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param msg {String} (optional) Explanation of the altered return value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param retVal {any} Return value passed to code that invoked the wrapped
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @deprecated use Y.Do.Halt or Y.Do.Prevent
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassDO.Error = DO.Halt;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass//////////////////////////////////////////////////////////////////////////
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Custom event engine, DOM event listener abstraction layer, synthetic DOM
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @module event-custom
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @submodule event-custom-base
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass// var onsubscribeType = "_event:onsub",
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassvar AFTER = 'after',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CONFIGS = [
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'broadcast',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'monitored',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'bubbles',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'context',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'contextFn',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'currentTarget',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'defaultFn',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'defaultTargetOnly',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'details',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'emitFacade',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'fireOnce',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'async',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'host',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'preventable',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'preventedFn',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'queuable',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'silent',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'stoppedFn',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'target',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass 'type'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ],
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass YUI3_SIGNATURE = 9,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass YUI_LOG = 'yui:log';
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Return value from all subscribe operations
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class EventHandle
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {CustomEvent} evt the custom event.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Subscriber} sub the subscriber.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.EventHandle = function(evt, sub) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The custom event
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type CustomEvent
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.evt = evt;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The subscriber object
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.sub = sub;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.EventHandle.prototype = {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass batch: function(f, c) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass f.call(c || this, this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (Y.Lang.isArray(this.evt)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.Array.each(this.evt, function(h) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass h.batch.call(c || h, f);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Detaches this subscriber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method detach
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {int} the number of detached listeners
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass detach: function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var evt = this.evt, detached = 0, i;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (evt) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Y.log('EventHandle.detach: ' + this.sub, 'info', 'Event');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (Y.Lang.isArray(evt)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass for (i = 0; i < evt.length; i++) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass detached += evt[i].detach();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass evt._delete(this.sub);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass detached = 1;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
753ef90e92d428310b4a07006e8850639c6faaadRyan Grove }
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);
}
};
/**
* 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} o configuration object.
* @class CustomEvent
* @constructor
*/
Y.CustomEvent = function(type, o) {
// if (arguments.length > 2) {
// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
// }
o = o || {};
this.id = Y.stamp(this);
/**
* The type of event, returned to subscribers when the event fires
* @property type
* @type string
*/
this.type = type;
/**
* The context the the event will fire from by default. Defaults to the YUI
* instance.
* @property context
* @type object
*/
this.context = Y;
/**
* Monitor when an event is attached or detached.
*
* @property monitored
* @type boolean
*/
// this.monitored = false;
this.logSystem = (type == YUI_LOG);
/**
* 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
*/
// this.broadcast = 0;
/**
* 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
*/
this.silent = this.logSystem;
/**
* 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.queuable = false;
/**
* The subscribers to this event
* @property subscribers
* @type Subscriber {}
*/
this.subscribers = {};
/**
* 'After' subscribers
* @property afters
* @type Subscriber {}
*/
this.afters = {};
/**
* This event has fired if true
*
* @property fired
* @type boolean
* @default false;
*/
// this.fired = false;
/**
* An array containing the arguments the custom event
* was last fired with.
* @property firedWith
* @type Array
*/
// this.firedWith;
/**
* 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;
*/
// this.fireOnce = false;
/**
* fireOnce listeners will fire syncronously unless async
* is set to true
* @property async
* @type boolean
* @default false
*/
//this.async = 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
*/
// this.stopped = 0;
/**
* Flag for preventDefault that is modified during fire().
* if it is not 0, the default behavior for this event
* @property prevented
* @type int
*/
// this.prevented = 0;
/**
* Specifies the host for this custom event. This is used
* to enable event bubbling
* @property host
* @type EventTarget
*/
// this.host = null;
/**
* The default function to execute after event listeners
* have fire, but only if the default action was not
* prevented.
* @property defaultFn
* @type Function
*/
// this.defaultFn = null;
/**
* The function to execute if a subscriber calls
* stopPropagation or stopImmediatePropagation
* @property stoppedFn
* @type Function
*/
// this.stoppedFn = null;
/**
* The function to execute if a subscriber calls
* preventDefault
* @property preventedFn
* @type Function
*/
// this.preventedFn = null;
/**
* 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
*/
this.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
*/
this.bubbles = true;
/**
* Supports multiple options for listener signatures in order to
* port YUI 2 apps.
* @property signature
* @type int
* @default 9
*/
this.signature = YUI3_SIGNATURE;
this.subCount = 0;
this.afterCount = 0;
// this.hasSubscribers = false;
// this.hasAfters = false;
/**
* 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
*/
// this.emitFacade = false;
this.applyConfig(o, true);
// this.log("Creating " + this.type);
};
Y.CustomEvent.prototype = {
hasSubs: function(when) {
var s = this.subCount, a = this.afterCount, sib = this.sibling;
if (sib) {
s += sib.subCount;
a += sib.afterCount;
}
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 = Y.Array(arguments, 0, true);
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 s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
if (sib) {
Y.mix(s, sib.subscribers);
Y.mix(a, sib.afters);
}
return [s, a];
},
/**
* 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) {
if (o) {
Y.mix(this, o, force, CONFIGS);
}
},
_on: function(fn, context, args, when) {
if (!fn) {
this.log('Invalid callback for CE: ' + this.type);
}
var s = new Y.Subscriber(fn, context, args, when);
if (this.fireOnce && this.fired) {
if (this.async) {
setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
} else {
this._notify(s, this.firedWith);
}
}
if (when == AFTER) {
this.afters[s.id] = s;
this.afterCount++;
} else {
this.subscribers[s.id] = s;
this.subCount++;
}
return new Y.EventHandle(this, s);
},
/**
* Listen for this event
* @method subscribe
* @param {Function} fn The function to execute.
* @return {EventHandle} Unsubscribe handle.
* @deprecated use on.
*/
subscribe: function(fn, context) {
Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : 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) ? Y.Array(arguments, 2, true) : null;
if (this.host) {
this.host._monitor('attach', this.type, {
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) ? Y.Array(arguments, 2, true) : null;
return this._on(fn, context, a, AFTER);
},
/**
* Detach listeners.
* @method detach
* @param {Function} fn The subscribed function to remove, if not supplied
* all will be removed.
* @param {Object} context The context object passed to subscribe.
* @return {int} returns the number of subscribers unsubscribed.
*/
detach: function(fn, context) {
// unsubscribe handle
if (fn && fn.detach) {
return fn.detach();
}
var i, s,
found = 0,
subs = Y.merge(this.subscribers, this.afters);
for (i in subs) {
if (subs.hasOwnProperty(i)) {
s = subs[i];
if (s && (!fn || fn === s.fn)) {
this._delete(s);
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.
* @private
*/
_notify: function(s, args, ef) {
this.log(this.type + '->' + 'sub: ' + s.id);
var ret;
ret = s.notify(args, this);
if (false === ret || this.stopped > 1) {
this.log(this.type + ' cancelled by subscriber');
return false;
}
return true;
},
/**
* Logger abstraction to centralize the application of the silent flag
* @method log
* @param {string} msg message to log.
* @param {string} cat log category.
*/
log: function(msg, cat) {
if (!this.silent) {
Y.log(this.id + ': ' + msg, cat || 'info', 'event');
}
},
/**
* Notifies the subscribers. The callback functions will be executed
* from the context specified when the event was created, and with the
* following parameters:
* <ul>
* <li>The type of event</li>
* <li>All of the arguments fire() was executed with as an array</li>
* <li>The custom object (if any) that was passed into the subscribe()
* method</li>
* </ul>
* @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() {
if (this.fireOnce && this.fired) {
this.log('fireOnce event: ' + this.type + ' already fired');
return true;
} else {
var args = Y.Array(arguments, 0, true);
// this doesn't happen if the event isn't published
// this.host._monitor('fire', this.type, args);
this.fired = true;
this.firedWith = args;
if (this.emitFacade) {
return this.fireComplex(args);
} else {
return this.fireSimple(args);
}
}
},
fireSimple: function(args) {
this.stopped = 0;
this.prevented = 0;
if (this.hasSubs()) {
// this._procSubs(Y.merge(this.subscribers, this.afters), args);
var subs = this.getSubs();
this._procSubs(subs[0], args);
this._procSubs(subs[1], args);
}
this._broadcast(args);
return this.stopped ? false : true;
},
// Requires the event-custom-complex module for full funcitonality.
fireComplex: function(args) {
Y.log('Missing event-custom-complex needed to emit a facade for: ' + this.type);
args[0] = args[0] || {};
return this.fireSimple(args);
},
_procSubs: function(subs, args, ef) {
var s, i;
for (i in subs) {
if (subs.hasOwnProperty(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;
},
_broadcast: function(args) {
if (!this.stopped && this.broadcast) {
var a = Y.Array(args);
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 {int} The number of listeners unsubscribed.
* @deprecated use detachAll.
*/
unsubscribeAll: function() {
return this.detachAll.apply(this, arguments);
},
/**
* Removes all listeners
* @method detachAll
* @return {int} The number of listeners unsubscribed.
*/
detachAll: function() {
return this.detach();
},
/**
* @method _delete
* @param subscriber object.
* @private
*/
_delete: function(s) {
if (s) {
if (this.subscribers[s.id]) {
delete this.subscribers[s.id];
this.subCount--;
}
if (this.afters[s.id]) {
delete this.afters[s.id];
this.afterCount--;
}
}
if (this.host) {
this.host._monitor('detach', this.type, {
ce: this,
sub: s
});
}
if (s) {
// delete s.fn;
// delete s.context;
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) {
/**
* 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.stamp(this);
/**
* Additional arguments to propagate to the subscriber
* @property args
* @type Array
*/
this.args = args;
/**
* 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 = {
_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.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);
}
}
};
/**
* 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
* @config chain {boolean} if true, on/after/detach return the host to allow
* chaining, otherwise they return an EventHandle (default false)
*/
var L = Y.Lang,
PREFIX_DELIMITER = ':',
CATEGORY_DELIMITER = '|',
AFTER_PREFIX = '~AFTER~',
YArray = Y.Array,
_wildType = Y.cached(function(type) {
return type.replace(/(.*)(:)(.*)/, "*$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 = Y.cached(function(type, pre) {
if (!pre || !L.isString(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);
// Y.log(t);
}
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) {
// Y.log('EventTarget constructor executed: ' + this._yuid);
var o = (L.isObject(opts)) ? opts : {};
this._yuievt = this._yuievt || {
id: Y.guid(),
events: {},
targets: {},
config: o,
chain: ('chain' in o) ? o.chain : Y.config.chain,
bubbling: false,
defaults: {
context: o.context || this,
host: this,
emitFacade: o.emitFacade,
fireOnce: o.fireOnce,
queuable: o.queuable,
monitored: o.monitored,
broadcast: o.broadcast,
defaultTargetOnly: o.defaultTargetOnly,
bubbles: ('bubbles' in o) ? o.bubbles : true
}
};
};
ET.prototype = {
/**
* Listen to a custom event hosted by this object one time.
* This is the equivalent to <code>on</code> except the
* listener is immediatelly detached when it is executed.
* @method once
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
once: function() {
var handle = this.on.apply(this, arguments);
handle.batch(function(hand) {
if (hand.sub) {
hand.sub.once = true;
}
});
return handle;
},
/**
* Takes the type parameter passed to 'on' and parses out the
* various pieces that could be included in the type. If the
* event type is passed without a prefix, it will be expanded
* to include the prefix one is supplied or the event target
* is configured with a default prefix.
* @method parseType
* @param {string} type the type
* @param {string} [pre=this._yuievt.config.prefix] the prefix
* @since 3.3.0
* @return {Array} an array containing:
* * the detach category, if supplied,
* * the prefixed event type,
* * whether or not this is an after listener,
* * the supplied event type
*/
parseType: function(type, pre) {
return _parseType(type, pre || this._yuievt.config.prefix);
},
/**
* Subscribe to a custom event hosted by this object
* @method on
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
on: function(type, fn, context) {
var parts = _parseType(type, this._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 = YArray(arguments, 0, true);
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 (this._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 = YArray(arguments, 0, true);
args.splice(2, 0, Node.getDOMNode(this));
// Y.log("Node detected, redirecting with these args: " + args);
return Y.on.apply(Y, args);
}
type = parts[1];
if (Y.instanceOf(this, YUI)) {
adapt = Y.Env.evt.plugins[type];
args = YArray(arguments, 0, true);
args[0] = shorttype;
if (Node) {
n = args[2];
if (Y.instanceOf(n, Y.NodeList)) {
n = Y.NodeList.getDOMNodes(n);
} else if (Y.instanceOf(n, Node)) {
n = Node.getDOMNode(n);
}
domevent = (shorttype in Node.DOM_EVENTS);
// Captures both DOM events and event plugins.
if (domevent) {
args[2] = n;
}
}
// check for the existance of an event adaptor
if (adapt) {
Y.log('Using adaptor for ' + shorttype + ', ' + n, 'info', 'event');
handle = adapt.on.apply(Y, args);
} else if ((!type) || domevent) {
handle = Y.Event._attach(args);
}
}
if (!handle) {
ce = this._yuievt.events[type] || this.publish(type);
handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
}
if (detachcategory) {
store[detachcategory] = store[detachcategory] || {};
store[detachcategory][type] = store[detachcategory][type] || [];
store[detachcategory][type].push(handle);
}
return (this._yuievt.chain) ? this : handle;
},
/**
* subscribe to an event
* @method subscribe
* @deprecated use on
*/
subscribe: function() {
Y.log('EventTarget subscribe() is deprecated, use on()', 'warn', 'deprecated');
return this.on.apply(this, arguments);
},
/**
* Detach one or more listeners the from the specified event
* @method detach
* @param type {string|Object} Either the handle to the subscriber or the
* type of event. If the type
* is not specified, it will attempt to remove
* the listener from all hosted events.
* @param fn {Function} The subscribed function to unsubscribe, if not
* supplied, all subscribers will be removed.
* @param context {Object} The custom object passed to subscribe. This is
* optional, but if supplied will be used to
* disambiguate multiple listeners that are the same
* (e.g., you subscribe many object using a function
* that lives on the prototype)
* @return {EventTarget} the host
*/
detach: function(type, fn, context) {
var evts = this._yuievt.events, i,
Node = Y.Node, isNode = Node && (Y.instanceOf(this, Node));
// detachAll disabled on the Y instance.
if (!type && (this !== Y)) {
for (i in evts) {
if (evts.hasOwnProperty(i)) {
evts[i].detach(fn, context);
}
}
if (isNode) {
Y.Event.purgeElement(Node.getDOMNode(this));
}
return this;
}
var parts = _parseType(type, this._yuievt.config.prefix),
detachcategory = L.isArray(parts) ? parts[0] : null,
shorttype = (parts) ? parts[3] : null,
adapt, store = Y.Env.evt.handles, detachhost, cat, args,
ce,
keyDetacher = function(lcat, ltype, host) {
var handles = lcat[ltype], ce, i;
if (handles) {
for (i = handles.length - 1; i >= 0; --i) {
ce = handles[i].evt;
if (ce.host === host || ce.el === host) {
handles[i].detach();
}
}
}
};
if (detachcategory) {
cat = store[detachcategory];
type = parts[1];
detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
if (cat) {
if (type) {
keyDetacher(cat, type, detachhost);
} else {
for (i in cat) {
if (cat.hasOwnProperty(i)) {
keyDetacher(cat, i, detachhost);
}
}
}
return this;
}
// If this is an event handle, use it to detach
} else if (L.isObject(type) && type.detach) {
type.detach();
return this;
// extra redirection so we catch adaptor events too. take a look at this.
} else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
args = YArray(arguments, 0, true);
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 = YArray(arguments, 0, true);
// use the adaptor specific detach code if
if (adapt && adapt.detach) {
adapt.detach.apply(Y, args);
return this;
// DOM event fork
} else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
args[0] = type;
Y.Event.detach.apply(Y.Event, args);
return this;
}
}
// ce = evts[type];
ce = evts[parts[1]];
if (ce) {
ce.detach(fn, context);
}
return this;
},
/**
* detach a listener
* @method unsubscribe
* @deprecated use detach
*/
unsubscribe: function() {
Y.log('EventTarget unsubscribe() is deprecated, use detach()', 'warn', 'deprecated');
return this.detach.apply(this, arguments);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method detachAll
* @param type {string} The type, or name of the event
*/
detachAll: function(type) {
return this.detach(type);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method unsubscribeAll
* @param type {string} The type, or name of the event
* @deprecated use detachAll
*/
unsubscribeAll: function() {
Y.log('EventTarget unsubscribeAll() is deprecated, use detachAll()', 'warn', 'deprecated');
return this.detachAll.apply(this, arguments);
},
/**
* Creates a new custom event of the specified type. If a custom event
* by that name already exists, it will not be re-created. In either
* case the custom event is returned.
*
* @method publish
*
* @param type {string} the type, or name of the event
* @param opts {object} optional config params. Valid properties are:
*
* <ul>
* <li>
* 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
* </li>
* <li>
* 'bubbles': whether or not this event bubbles (true)
* Events can only bubble if emitFacade is true.
* </li>
* <li>
* 'context': the default execution context for the listeners (this)
* </li>
* <li>
* 'defaultFn': the default function to execute when this event fires if preventDefault was not called
* </li>
* <li>
* 'emitFacade': whether or not this event emits a facade (false)
* </li>
* <li>
* 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
* </li>
* <li>
* 'fireOnce': if an event is configured to fire once, new subscribers after
* the fire will be notified immediately.
* </li>
* <li>
* 'async': fireOnce event listeners will fire synchronously if the event has already
* fired unless async is true.
* </li>
* <li>
* 'preventable': whether or not preventDefault() has an effect (true)
* </li>
* <li>
* 'preventedFn': a function that is executed when preventDefault is called
* </li>
* <li>
* 'queuable': whether or not this event can be queued during bubbling (false)
* </li>
* <li>
* 'silent': if silent is true, debug messages are not provided for this event.
* </li>
* <li>
* 'stoppedFn': a function that is executed when stopPropagation is called
* </li>
*
* <li>
* 'monitored': specifies whether or not this event should send notifications about
* when the event has been attached, detached, or published.
* </li>
* <li>
* 'type': the event type (valid option if not provided as the first parameter to publish)
* </li>
* </ul>
*
* @return {CustomEvent} the custom event
*
*/
publish: function(type, opts) {
var events, ce, ret, defaults,
edata = this._yuievt,
pre = edata.config.prefix;
type = (pre) ? _getType(type, pre) : type;
this._monitor('publish', type, {
args: arguments
});
if (L.isObject(type)) {
ret = {};
Y.each(type, function(v, k) {
ret[k] = this.publish(k, v || opts);
}, this);
return ret;
}
events = edata.events;
ce = events[type];
if (ce) {
// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
if (opts) {
ce.applyConfig(opts, true);
}
} else {
defaults = edata.defaults;
// apply defaults
ce = new Y.CustomEvent(type,
(opts) ? Y.merge(defaults, opts) : defaults);
events[type] = ce;
}
// make sure we turn the broadcast flag off if this
// event was published as a result of bubbling
// if (opts instanceof Y.CustomEvent) {
// events[type].broadcast = false;
// }
return events[type];
},
/**
* 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.
*
* @private
*/
_monitor: function(what, type, o) {
var monitorevt, ce = this.getEvent(type);
if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
monitorevt = type + '_' + what;
// Y.log('monitoring: ' + monitorevt);
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.
*
* 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.
*
* 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.
*
* @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 {EventTarget} the event host
*
*/
fire: function(type) {
var typeIncluded = L.isString(type),
t = (typeIncluded) ? type : (type && type.type),
ce, ret, pre = this._yuievt.config.prefix, ce2,
args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
t = (pre) ? _getType(t, pre) : t;
this._monitor('fire', t, {
args: args
});
ce = this.getEvent(t, true);
ce2 = this.getSibling(t, ce);
if (ce2 && !ce) {
ce = this.publish(t);
}
// this event has not been published or subscribed to
if (!ce) {
if (this._yuievt.hasTargets) {
return this.bubble({ type: t }, args, this);
}
// otherwise there is nothing to be done
ret = true;
} else {
ce.sibling = ce2;
ret = ce.fire.apply(ce, args);
}
return (this._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);
// console.log(type);
ce2 = this.getEvent(type, true);
if (ce2) {
// console.log("GOT ONE: " + type);
ce2.applyConfig(ce);
ce2.bubbles = false;
ce2.broadcast = 0;
// ret = ce2.fire.apply(ce2, a);
}
}
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 type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
after: function(type, fn) {
var a = YArray(arguments, 0, true);
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, false, false, {
bubbles: false
});
ET.call(Y);
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?
/**
* <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events, DOM events, and
* function events. <code>detach</code> is also provided to remove listeners
* serviced by this function.
*
* The signature that <code>on</code> accepts varies depending on the type
* of event being consumed. Refer to the specific methods that will
* service a specific request for additional information about subscribing
* to that type of event.
*
* <ul>
* <li>Custom events. These events are defined by various
* modules in the library. This type of event is delegated to
* <code>EventTarget</code>'s <code>on</code> method.
* <ul>
* <li>The type of the event</li>
* <li>The callback to execute</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example:
* <code>Y.on('drag:drophit', function() { // start work });</code>
* </li>
* <li>DOM events. These are moments reported by the browser related
* to browser functionality and user interaction.
* This type of event is delegated to <code>Event</code>'s
* <code>attach</code> method.
* <ul>
* <li>The type of the event</li>
* <li>The callback to execute</li>
* <li>The specification for the Node(s) to attach the listener
* to. This can be a selector, collections, or Node/Element
* refereces.</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example:
* <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
* </li>
* <li>Function events. These events can be used to react before or after a
* function is executed. This type of event is delegated to <code>Event.Do</code>'s
* <code>before</code> method.
* <ul>
* <li>The callback to execute</li>
* <li>The object that has the function that will be listened for.</li>
* <li>The name of the function to listen for.</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
* </li>
* </ul>
*
* <code>on</code> corresponds to the moment before any default behavior of
* the event. <code>after</code> works the same way, but these listeners
* execute after the event's default behavior. <code>before</code> is an
* alias for <code>on</code>.
*
* @method on
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* Listen for an event one time. Equivalent to <code>on</code>, except that
* the listener is immediately detached when executed.
* @see on
* @method once
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* after() is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events,
* DOM events, and AOP events. This works the same way as
* the on() function, only it operates after any default
* behavior for the event has executed. @see <code>on</code> for more
* information.
* @method after
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
}, '@VERSION@' ,{requires:['oop']});
YUI.add('event-custom-complex', function(Y) {
/**
* Adds event facades, preventable default behavior, and bubbling.
* events.
* @module event-custom
* @submodule event-custom-complex
*/
var FACADE,
FACADE_KEYS,
EMPTY = {},
CEProto = Y.CustomEvent.prototype,
ETProto = Y.EventTarget.prototype;
/**
* Wraps and protects a custom event for use when emitFacade is set to true.
* Requires the event-custom-complex module
* @class EventFacade
* @param e {Event} the custom event
* @param currentTarget {HTMLElement} the element the listener was attached to
*/
Y.EventFacade = function(e, currentTarget) {
e = e || EMPTY;
this._event = e;
/**
* The arguments passed to fire
* @property details
* @type Array
*/
this.details = e.details;
/**
* The event type, this can be overridden by the fire() payload
* @property type
* @type string
*/
this.type = e.type;
/**
* The real event type
* @property type
* @type string
*/
this._type = e.type;
//////////////////////////////////////////////////////
/**
* Node reference for the targeted eventtarget
* @propery target
* @type Node
*/
this.target = e.target;
/**
* Node reference for the element that the listener was attached to.
* @propery currentTarget
* @type Node
*/
this.currentTarget = currentTarget;
/**
* Node reference to the relatedTarget
* @propery relatedTarget
* @type Node
*/
this.relatedTarget = e.relatedTarget;
};
Y.extend(Y.EventFacade, Object, {
/**
* Stops the propagation to the next bubble target
* @method stopPropagation
*/
stopPropagation: function() {
this._event.stopPropagation();
this.stopped = 1;
},
/**
* Stops the propagation to the next bubble target and
* prevents any additional listeners from being exectued
* on the current target.
* @method stopImmediatePropagation
*/
stopImmediatePropagation: function() {
this._event.stopImmediatePropagation();
this.stopped = 2;
},
/**
* Prevents the event's default behavior
* @method preventDefault
*/
preventDefault: function() {
this._event.preventDefault();
this.prevented = 1;
},
/**
* 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
*/
halt: function(immediate) {
this._event.halt(immediate);
this.prevented = 1;
this.stopped = (immediate) ? 2 : 1;
}
});
CEProto.fireComplex = function(args) {
var es, ef, q, queue, ce, ret, events, subs, postponed,
self = this, host = self.host || self, next, oldbubble;
if (self.stack) {
// queue this event if the current item in the queue bubbles
if (self.queuable && self.type != self.stack.next.type) {
self.log('queue ' + self.type);
self.stack.queue.push([self, args]);
return true;
}
}
es = self.stack || {
// id of the first event in the stack
id: self.id,
next: self,
silent: self.silent,
stopped: 0,
prevented: 0,
bubbling: null,
type: self.type,
// defaultFnQueue: new Y.Queue(),
afterQueue: new Y.Queue(),
defaultTargetOnly: self.defaultTargetOnly,
queue: []
};
subs = self.getSubs();
self.stopped = (self.type !== es.type) ? 0 : es.stopped;
self.prevented = (self.type !== es.type) ? 0 : es.prevented;
self.target = self.target || host;
events = new Y.EventTarget({
fireOnce: true,
context: host
});
self.events = events;
if (self.stoppedFn) {
events.on('stopped', self.stoppedFn);
}
self.currentTarget = host;
self.details = args.slice(); // original arguments in the details
// self.log("Firing " + self + ", " + "args: " + args);
self.log("Firing " + self.type);
self._facade = null; // kill facade to eliminate stale properties
ef = self._getFacade(args);
if (Y.Lang.isObject(args[0])) {
args[0] = ef;
} else {
args.unshift(ef);
}
// if (subCount) {
if (subs[0]) {
// self._procSubs(Y.merge(self.subscribers), args, ef);
self._procSubs(subs[0], args, ef);
}
// bubble if this is hosted in an event target and propagation has not been stopped
if (self.bubbles && host.bubble && !self.stopped) {
oldbubble = es.bubbling;
// self.bubbling = true;
es.bubbling = self.type;
// if (host !== ef.target || es.type != self.type) {
if (es.type != self.type) {
es.stopped = 0;
es.prevented = 0;
}
ret = host.bubble(self, args, null, es);
self.stopped = Math.max(self.stopped, es.stopped);
self.prevented = Math.max(self.prevented, es.prevented);
// self.bubbling = false;
es.bubbling = oldbubble;
}
if (self.prevented) {
if (self.preventedFn) {
self.preventedFn.apply(host, args);
}
} else if (self.defaultFn &&
((!self.defaultTargetOnly && !es.defaultTargetOnly) ||
host === ef.target)) {
self.defaultFn.apply(host, args);
}
// broadcast listeners are fired as discreet events on the
// YUI instance and potentially the YUI global.
self._broadcast(args);
// Queue the after
if (subs[1] && !self.prevented && self.stopped < 2) {
if (es.id === self.id || self.type != host._yuievt.bubbling) {
self._procSubs(subs[1], args, ef);
while ((next = es.afterQueue.last())) {
next();
}
} else {
postponed = subs[1];
if (es.execDefaultCnt) {
postponed = Y.merge(postponed);
Y.each(postponed, function(s) {
s.postponed = true;
});
}
es.afterQueue.add(function() {
self._procSubs(postponed, args, ef);
});
}
}
self.target = null;
if (es.id === self.id) {
queue = es.queue;
while (queue.length) {
q = queue.pop();
ce = q[0];
// set up stack to allow the next item to be processed
es.next = ce;
ce.fire.apply(ce, q[1]);
}
self.stack = null;
}
ret = !(self.stopped);
if (self.type != host._yuievt.bubbling) {
es.stopped = 0;
es.prevented = 0;
self.stopped = 0;
self.prevented = 0;
}
return ret;
};
CEProto._getFacade = function() {
var ef = this._facade, o, o2,
args = this.details;
if (!ef) {
ef = new Y.EventFacade(this, this.currentTarget);
}
// if the first argument is an object literal, apply the
// properties to the event facade
o = args && args[0];
if (Y.Lang.isObject(o, true)) {
o2 = {};
// protect the event facade properties
Y.mix(o2, ef, true, FACADE_KEYS);
// mix the data
Y.mix(ef, o, true);
// restore ef
Y.mix(ef, o2, true, FACADE_KEYS);
// Allow the event type to be faked
// http://yuilibrary.com/projects/yui3/ticket/2528376
ef.type = o.type || ef.type;
}
// update the details field with the arguments
// ef.type = this.type;
ef.details = this.details;
// use the original target when the event bubbled to this target
ef.target = this.originalTarget || this.target;
ef.currentTarget = this.currentTarget;
ef.stopped = 0;
ef.prevented = 0;
this._facade = ef;
return this._facade;
};
/**
* Stop propagation to bubble targets
* @for CustomEvent
* @method stopPropagation
*/
CEProto.stopPropagation = function() {
this.stopped = 1;
if (this.stack) {
this.stack.stopped = 1;
}
this.events.fire('stopped', this);
};
/**
* Stops propagation to bubble targets, and prevents any remaining
* subscribers on the current target from executing.
* @method stopImmediatePropagation
*/
CEProto.stopImmediatePropagation = function() {
this.stopped = 2;
if (this.stack) {
this.stack.stopped = 2;
}
this.events.fire('stopped', this);
};
/**
* Prevents the execution of this event's defaultFn
* @method preventDefault
*/
CEProto.preventDefault = function() {
if (this.preventable) {
this.prevented = 1;
if (this.stack) {
this.stack.prevented = 1;
}
}
};
/**
* 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
*/
CEProto.halt = function(immediate) {
if (immediate) {
this.stopImmediatePropagation();
} else {
this.stopPropagation();
}
this.preventDefault();
};
/**
* Registers another EventTarget as a bubble target. Bubble order
* is determined by the order registered. Multiple targets can
* be specified.
*
* Events can only bubble if emitFacade is true.
*
* Included in the event-custom-complex submodule.
*
* @method addTarget
* @param o {EventTarget} the target to add
* @for EventTarget
*/
ETProto.addTarget = function(o) {
this._yuievt.targets[Y.stamp(o)] = o;
this._yuievt.hasTargets = true;
};
/**
* Returns an array of bubble targets for this object.
* @method getTargets
* @return EventTarget[]
*/
ETProto.getTargets = function() {
return Y.Object.values(this._yuievt.targets);
};
/**
* Removes a bubble target
* @method removeTarget
* @param o {EventTarget} the target to remove
* @for EventTarget
*/
ETProto.removeTarget = function(o) {
delete this._yuievt.targets[Y.stamp(o)];
};
/**
* Propagate an event. Requires the event-custom-complex module.
* @method bubble
* @param evt {CustomEvent} the custom event to propagate
* @return {boolean} the aggregated return value from Event.Custom.fire
* @for EventTarget
*/
ETProto.bubble = function(evt, args, target, es) {
var targs = this._yuievt.targets, ret = true,
t, type = evt && evt.type, ce, i, bc, ce2,
originalTarget = target || (evt && evt.target) || this,
oldbubble;
if (!evt || ((!evt.stopped) && targs)) {
// Y.log('Bubbling ' + evt.type);
for (i in targs) {
if (targs.hasOwnProperty(i)) {
t = targs[i];
ce = t.getEvent(type, true);
ce2 = t.getSibling(type, ce);
if (ce2 && !ce) {
ce = t.publish(type);
}
oldbubble = t._yuievt.bubbling;
t._yuievt.bubbling = type;
// if this event was not published on the bubble target,
// continue propagating the event.
if (!ce) {
if (t._yuievt.hasTargets) {
t.bubble(evt, args, originalTarget, es);
}
} else {
ce.sibling = ce2;
// set the original target to that the target payload on the
// facade is correct.
ce.target = originalTarget;
ce.originalTarget = originalTarget;
ce.currentTarget = t;
bc = ce.broadcast;
ce.broadcast = false;
// default publish may not have emitFacade true -- that
// shouldn't be what the implementer meant to do
ce.emitFacade = true;
ce.stack = es;
ret = ret && ce.fire.apply(ce, args || evt.details || []);
ce.broadcast = bc;
ce.originalTarget = null;
// stopPropagation() was called
if (ce.stopped) {
break;
}
}
t._yuievt.bubbling = oldbubble;
}
}
}
return ret;
};
FACADE = new Y.EventFacade();
FACADE_KEYS = Y.Object.keys(FACADE);
}, '@VERSION@' ,{requires:['event-custom-base']});
YUI.add('event-custom', function(Y){}, '@VERSION@' ,{use:['event-custom-base', 'event-custom-complex']});