src/cm/media/js/lib/yui/yui3-3.15.0/build/event-custom-base/event-custom-base.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('event-custom-base', function (Y, NAME) {
       
     2 
       
     3 /**
       
     4  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
       
     5  * events.
       
     6  * @module event-custom
       
     7  */
       
     8 
       
     9 Y.Env.evt = {
       
    10     handles: {},
       
    11     plugins: {}
       
    12 };
       
    13 
       
    14 
       
    15 /**
       
    16  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
       
    17  * events.
       
    18  * @module event-custom
       
    19  * @submodule event-custom-base
       
    20  */
       
    21 
       
    22 /**
       
    23  * Allows for the insertion of methods that are executed before or after
       
    24  * a specified method
       
    25  * @class Do
       
    26  * @static
       
    27  */
       
    28 
       
    29 var DO_BEFORE = 0,
       
    30     DO_AFTER = 1,
       
    31 
       
    32 DO = {
       
    33 
       
    34     /**
       
    35      * Cache of objects touched by the utility
       
    36      * @property objs
       
    37      * @static
       
    38      * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object
       
    39      * replaces the role of this property, but is considered to be private, and
       
    40      * is only mentioned to provide a migration path.
       
    41      *
       
    42      * If you have a use case which warrants migration to the _yuiaop property,
       
    43      * please file a ticket to let us know what it's used for and we can see if
       
    44      * we need to expose hooks for that functionality more formally.
       
    45      */
       
    46     objs: null,
       
    47 
       
    48     /**
       
    49      * <p>Execute the supplied method before the specified function.  Wrapping
       
    50      * function may optionally return an instance of the following classes to
       
    51      * further alter runtime behavior:</p>
       
    52      * <dl>
       
    53      *     <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
       
    54      *         <dd>Immediatly stop execution and return
       
    55      *         <code>returnValue</code>.  No other wrapping functions will be
       
    56      *         executed.</dd>
       
    57      *     <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt>
       
    58      *         <dd>Replace the arguments that the original function will be
       
    59      *         called with.</dd>
       
    60      *     <dt></code>Y.Do.Prevent(message)</code></dt>
       
    61      *         <dd>Don't execute the wrapped function.  Other before phase
       
    62      *         wrappers will be executed.</dd>
       
    63      * </dl>
       
    64      *
       
    65      * @method before
       
    66      * @param fn {Function} the function to execute
       
    67      * @param obj the object hosting the method to displace
       
    68      * @param sFn {string} the name of the method to displace
       
    69      * @param c The execution context for fn
       
    70      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
       
    71      * when the event fires.
       
    72      * @return {string} handle for the subscription
       
    73      * @static
       
    74      */
       
    75     before: function(fn, obj, sFn, c) {
       
    76         var f = fn, a;
       
    77         if (c) {
       
    78             a = [fn, c].concat(Y.Array(arguments, 4, true));
       
    79             f = Y.rbind.apply(Y, a);
       
    80         }
       
    81 
       
    82         return this._inject(DO_BEFORE, f, obj, sFn);
       
    83     },
       
    84 
       
    85     /**
       
    86      * <p>Execute the supplied method after the specified function.  Wrapping
       
    87      * function may optionally return an instance of the following classes to
       
    88      * further alter runtime behavior:</p>
       
    89      * <dl>
       
    90      *     <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
       
    91      *         <dd>Immediatly stop execution and return
       
    92      *         <code>returnValue</code>.  No other wrapping functions will be
       
    93      *         executed.</dd>
       
    94      *     <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt>
       
    95      *         <dd>Return <code>returnValue</code> instead of the wrapped
       
    96      *         method's original return value.  This can be further altered by
       
    97      *         other after phase wrappers.</dd>
       
    98      * </dl>
       
    99      *
       
   100      * <p>The static properties <code>Y.Do.originalRetVal</code> and
       
   101      * <code>Y.Do.currentRetVal</code> will be populated for reference.</p>
       
   102      *
       
   103      * @method after
       
   104      * @param fn {Function} the function to execute
       
   105      * @param obj the object hosting the method to displace
       
   106      * @param sFn {string} the name of the method to displace
       
   107      * @param c The execution context for fn
       
   108      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
       
   109      * @return {string} handle for the subscription
       
   110      * @static
       
   111      */
       
   112     after: function(fn, obj, sFn, c) {
       
   113         var f = fn, a;
       
   114         if (c) {
       
   115             a = [fn, c].concat(Y.Array(arguments, 4, true));
       
   116             f = Y.rbind.apply(Y, a);
       
   117         }
       
   118 
       
   119         return this._inject(DO_AFTER, f, obj, sFn);
       
   120     },
       
   121 
       
   122     /**
       
   123      * Execute the supplied method before or after the specified function.
       
   124      * Used by <code>before</code> and <code>after</code>.
       
   125      *
       
   126      * @method _inject
       
   127      * @param when {string} before or after
       
   128      * @param fn {Function} the function to execute
       
   129      * @param obj the object hosting the method to displace
       
   130      * @param sFn {string} the name of the method to displace
       
   131      * @param c The execution context for fn
       
   132      * @return {string} handle for the subscription
       
   133      * @private
       
   134      * @static
       
   135      */
       
   136     _inject: function(when, fn, obj, sFn) {
       
   137         // object id
       
   138         var id = Y.stamp(obj), o, sid;
       
   139 
       
   140         if (!obj._yuiaop) {
       
   141             // create a map entry for the obj if it doesn't exist, to hold overridden methods
       
   142             obj._yuiaop = {};
       
   143         }
       
   144 
       
   145         o = obj._yuiaop;
       
   146 
       
   147         if (!o[sFn]) {
       
   148             // create a map entry for the method if it doesn't exist
       
   149             o[sFn] = new Y.Do.Method(obj, sFn);
       
   150 
       
   151             // re-route the method to our wrapper
       
   152             obj[sFn] = function() {
       
   153                 return o[sFn].exec.apply(o[sFn], arguments);
       
   154             };
       
   155         }
       
   156 
       
   157         // subscriber id
       
   158         sid = id + Y.stamp(fn) + sFn;
       
   159 
       
   160         // register the callback
       
   161         o[sFn].register(sid, fn, when);
       
   162 
       
   163         return new Y.EventHandle(o[sFn], sid);
       
   164     },
       
   165 
       
   166     /**
       
   167      * Detach a before or after subscription.
       
   168      *
       
   169      * @method detach
       
   170      * @param handle {string} the subscription handle
       
   171      * @static
       
   172      */
       
   173     detach: function(handle) {
       
   174         if (handle.detach) {
       
   175             handle.detach();
       
   176         }
       
   177     }
       
   178 };
       
   179 
       
   180 Y.Do = DO;
       
   181 
       
   182 //////////////////////////////////////////////////////////////////////////
       
   183 
       
   184 /**
       
   185  * Contains the return value from the wrapped method, accessible
       
   186  * by 'after' event listeners.
       
   187  *
       
   188  * @property originalRetVal
       
   189  * @static
       
   190  * @since 3.2.0
       
   191  */
       
   192 
       
   193 /**
       
   194  * Contains the current state of the return value, consumable by
       
   195  * 'after' event listeners, and updated if an after subscriber
       
   196  * changes the return value generated by the wrapped function.
       
   197  *
       
   198  * @property currentRetVal
       
   199  * @static
       
   200  * @since 3.2.0
       
   201  */
       
   202 
       
   203 //////////////////////////////////////////////////////////////////////////
       
   204 
       
   205 /**
       
   206  * Wrapper for a displaced method with aop enabled
       
   207  * @class Do.Method
       
   208  * @constructor
       
   209  * @param obj The object to operate on
       
   210  * @param sFn The name of the method to displace
       
   211  */
       
   212 DO.Method = function(obj, sFn) {
       
   213     this.obj = obj;
       
   214     this.methodName = sFn;
       
   215     this.method = obj[sFn];
       
   216     this.before = {};
       
   217     this.after = {};
       
   218 };
       
   219 
       
   220 /**
       
   221  * Register a aop subscriber
       
   222  * @method register
       
   223  * @param sid {string} the subscriber id
       
   224  * @param fn {Function} the function to execute
       
   225  * @param when {string} when to execute the function
       
   226  */
       
   227 DO.Method.prototype.register = function (sid, fn, when) {
       
   228     if (when) {
       
   229         this.after[sid] = fn;
       
   230     } else {
       
   231         this.before[sid] = fn;
       
   232     }
       
   233 };
       
   234 
       
   235 /**
       
   236  * Unregister a aop subscriber
       
   237  * @method delete
       
   238  * @param sid {string} the subscriber id
       
   239  * @param fn {Function} the function to execute
       
   240  * @param when {string} when to execute the function
       
   241  */
       
   242 DO.Method.prototype._delete = function (sid) {
       
   243     delete this.before[sid];
       
   244     delete this.after[sid];
       
   245 };
       
   246 
       
   247 /**
       
   248  * <p>Execute the wrapped method.  All arguments are passed into the wrapping
       
   249  * functions.  If any of the before wrappers return an instance of
       
   250  * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped
       
   251  * function nor any after phase subscribers will be executed.</p>
       
   252  *
       
   253  * <p>The return value will be the return value of the wrapped function or one
       
   254  * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or
       
   255  * <code>Y.Do.AlterReturn</code>.
       
   256  *
       
   257  * @method exec
       
   258  * @param arg* {any} Arguments are passed to the wrapping and wrapped functions
       
   259  * @return {any} Return value of wrapped function unless overwritten (see above)
       
   260  */
       
   261 DO.Method.prototype.exec = function () {
       
   262 
       
   263     var args = Y.Array(arguments, 0, true),
       
   264         i, ret, newRet,
       
   265         bf = this.before,
       
   266         af = this.after,
       
   267         prevented = false;
       
   268 
       
   269     // execute before
       
   270     for (i in bf) {
       
   271         if (bf.hasOwnProperty(i)) {
       
   272             ret = bf[i].apply(this.obj, args);
       
   273             if (ret) {
       
   274                 switch (ret.constructor) {
       
   275                     case DO.Halt:
       
   276                         return ret.retVal;
       
   277                     case DO.AlterArgs:
       
   278                         args = ret.newArgs;
       
   279                         break;
       
   280                     case DO.Prevent:
       
   281                         prevented = true;
       
   282                         break;
       
   283                     default:
       
   284                 }
       
   285             }
       
   286         }
       
   287     }
       
   288 
       
   289     // execute method
       
   290     if (!prevented) {
       
   291         ret = this.method.apply(this.obj, args);
       
   292     }
       
   293 
       
   294     DO.originalRetVal = ret;
       
   295     DO.currentRetVal = ret;
       
   296 
       
   297     // execute after methods.
       
   298     for (i in af) {
       
   299         if (af.hasOwnProperty(i)) {
       
   300             newRet = af[i].apply(this.obj, args);
       
   301             // Stop processing if a Halt object is returned
       
   302             if (newRet && newRet.constructor === DO.Halt) {
       
   303                 return newRet.retVal;
       
   304             // Check for a new return value
       
   305             } else if (newRet && newRet.constructor === DO.AlterReturn) {
       
   306                 ret = newRet.newRetVal;
       
   307                 // Update the static retval state
       
   308                 DO.currentRetVal = ret;
       
   309             }
       
   310         }
       
   311     }
       
   312 
       
   313     return ret;
       
   314 };
       
   315 
       
   316 //////////////////////////////////////////////////////////////////////////
       
   317 
       
   318 /**
       
   319  * Return an AlterArgs object when you want to change the arguments that
       
   320  * were passed into the function.  Useful for Do.before subscribers.  An
       
   321  * example would be a service that scrubs out illegal characters prior to
       
   322  * executing the core business logic.
       
   323  * @class Do.AlterArgs
       
   324  * @constructor
       
   325  * @param msg {String} (optional) Explanation of the altered return value
       
   326  * @param newArgs {Array} Call parameters to be used for the original method
       
   327  *                        instead of the arguments originally passed in.
       
   328  */
       
   329 DO.AlterArgs = function(msg, newArgs) {
       
   330     this.msg = msg;
       
   331     this.newArgs = newArgs;
       
   332 };
       
   333 
       
   334 /**
       
   335  * Return an AlterReturn object when you want to change the result returned
       
   336  * from the core method to the caller.  Useful for Do.after subscribers.
       
   337  * @class Do.AlterReturn
       
   338  * @constructor
       
   339  * @param msg {String} (optional) Explanation of the altered return value
       
   340  * @param newRetVal {any} Return value passed to code that invoked the wrapped
       
   341  *                      function.
       
   342  */
       
   343 DO.AlterReturn = function(msg, newRetVal) {
       
   344     this.msg = msg;
       
   345     this.newRetVal = newRetVal;
       
   346 };
       
   347 
       
   348 /**
       
   349  * Return a Halt object when you want to terminate the execution
       
   350  * of all subsequent subscribers as well as the wrapped method
       
   351  * if it has not exectued yet.  Useful for Do.before subscribers.
       
   352  * @class Do.Halt
       
   353  * @constructor
       
   354  * @param msg {String} (optional) Explanation of why the termination was done
       
   355  * @param retVal {any} Return value passed to code that invoked the wrapped
       
   356  *                      function.
       
   357  */
       
   358 DO.Halt = function(msg, retVal) {
       
   359     this.msg = msg;
       
   360     this.retVal = retVal;
       
   361 };
       
   362 
       
   363 /**
       
   364  * Return a Prevent object when you want to prevent the wrapped function
       
   365  * from executing, but want the remaining listeners to execute.  Useful
       
   366  * for Do.before subscribers.
       
   367  * @class Do.Prevent
       
   368  * @constructor
       
   369  * @param msg {String} (optional) Explanation of why the termination was done
       
   370  */
       
   371 DO.Prevent = function(msg) {
       
   372     this.msg = msg;
       
   373 };
       
   374 
       
   375 /**
       
   376  * Return an Error object when you want to terminate the execution
       
   377  * of all subsequent method calls.
       
   378  * @class Do.Error
       
   379  * @constructor
       
   380  * @param msg {String} (optional) Explanation of the altered return value
       
   381  * @param retVal {any} Return value passed to code that invoked the wrapped
       
   382  *                      function.
       
   383  * @deprecated use Y.Do.Halt or Y.Do.Prevent
       
   384  */
       
   385 DO.Error = DO.Halt;
       
   386 
       
   387 
       
   388 //////////////////////////////////////////////////////////////////////////
       
   389 
       
   390 /**
       
   391  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
       
   392  * events.
       
   393  * @module event-custom
       
   394  * @submodule event-custom-base
       
   395  */
       
   396 
       
   397 
       
   398 // var onsubscribeType = "_event:onsub",
       
   399 var YArray = Y.Array,
       
   400 
       
   401     AFTER = 'after',
       
   402     CONFIGS = [
       
   403         'broadcast',
       
   404         'monitored',
       
   405         'bubbles',
       
   406         'context',
       
   407         'contextFn',
       
   408         'currentTarget',
       
   409         'defaultFn',
       
   410         'defaultTargetOnly',
       
   411         'details',
       
   412         'emitFacade',
       
   413         'fireOnce',
       
   414         'async',
       
   415         'host',
       
   416         'preventable',
       
   417         'preventedFn',
       
   418         'queuable',
       
   419         'silent',
       
   420         'stoppedFn',
       
   421         'target',
       
   422         'type'
       
   423     ],
       
   424 
       
   425     CONFIGS_HASH = YArray.hash(CONFIGS),
       
   426 
       
   427     nativeSlice = Array.prototype.slice,
       
   428 
       
   429     YUI3_SIGNATURE = 9,
       
   430     YUI_LOG = 'yui:log',
       
   431 
       
   432     mixConfigs = function(r, s, ov) {
       
   433         var p;
       
   434 
       
   435         for (p in s) {
       
   436             if (CONFIGS_HASH[p] && (ov || !(p in r))) {
       
   437                 r[p] = s[p];
       
   438             }
       
   439         }
       
   440 
       
   441         return r;
       
   442     };
       
   443 
       
   444 /**
       
   445  * The CustomEvent class lets you define events for your application
       
   446  * that can be subscribed to by one or more independent component.
       
   447  *
       
   448  * @param {String} type The type of event, which is passed to the callback
       
   449  * when the event fires.
       
   450  * @param {object} defaults configuration object.
       
   451  * @class CustomEvent
       
   452  * @constructor
       
   453  */
       
   454 
       
   455  /**
       
   456  * The type of event, returned to subscribers when the event fires
       
   457  * @property type
       
   458  * @type string
       
   459  */
       
   460 
       
   461 /**
       
   462  * By default all custom events are logged in the debug build, set silent
       
   463  * to true to disable debug outpu for this event.
       
   464  * @property silent
       
   465  * @type boolean
       
   466  */
       
   467 
       
   468 Y.CustomEvent = function(type, defaults) {
       
   469 
       
   470     this._kds = Y.CustomEvent.keepDeprecatedSubs;
       
   471 
       
   472     this.id = Y.guid();
       
   473 
       
   474     this.type = type;
       
   475     this.silent = this.logSystem = (type === YUI_LOG);
       
   476 
       
   477     if (this._kds) {
       
   478         /**
       
   479          * The subscribers to this event
       
   480          * @property subscribers
       
   481          * @type Subscriber {}
       
   482          * @deprecated
       
   483          */
       
   484 
       
   485         /**
       
   486          * 'After' subscribers
       
   487          * @property afters
       
   488          * @type Subscriber {}
       
   489          * @deprecated
       
   490          */
       
   491         this.subscribers = {};
       
   492         this.afters = {};
       
   493     }
       
   494 
       
   495     if (defaults) {
       
   496         mixConfigs(this, defaults, true);
       
   497     }
       
   498 };
       
   499 
       
   500 /**
       
   501  * Static flag to enable population of the <a href="#property_subscribers">`subscribers`</a>
       
   502  * and  <a href="#property_subscribers">`afters`</a> properties held on a `CustomEvent` instance.
       
   503  *
       
   504  * These properties were changed to private properties (`_subscribers` and `_afters`), and
       
   505  * converted from objects to arrays for performance reasons.
       
   506  *
       
   507  * Setting this property to true will populate the deprecated `subscribers` and `afters`
       
   508  * properties for people who may be using them (which is expected to be rare). There will
       
   509  * be a performance hit, compared to the new array based implementation.
       
   510  *
       
   511  * If you are using these deprecated properties for a use case which the public API
       
   512  * does not support, please file an enhancement request, and we can provide an alternate
       
   513  * public implementation which doesn't have the performance cost required to maintiain the
       
   514  * properties as objects.
       
   515  *
       
   516  * @property keepDeprecatedSubs
       
   517  * @static
       
   518  * @for CustomEvent
       
   519  * @type boolean
       
   520  * @default false
       
   521  * @deprecated
       
   522  */
       
   523 Y.CustomEvent.keepDeprecatedSubs = false;
       
   524 
       
   525 Y.CustomEvent.mixConfigs = mixConfigs;
       
   526 
       
   527 Y.CustomEvent.prototype = {
       
   528 
       
   529     constructor: Y.CustomEvent,
       
   530 
       
   531     /**
       
   532      * Monitor when an event is attached or detached.
       
   533      *
       
   534      * @property monitored
       
   535      * @type boolean
       
   536      */
       
   537 
       
   538     /**
       
   539      * If 0, this event does not broadcast.  If 1, the YUI instance is notified
       
   540      * every time this event fires.  If 2, the YUI instance and the YUI global
       
   541      * (if event is enabled on the global) are notified every time this event
       
   542      * fires.
       
   543      * @property broadcast
       
   544      * @type int
       
   545      */
       
   546 
       
   547     /**
       
   548      * Specifies whether this event should be queued when the host is actively
       
   549      * processing an event.  This will effect exectution order of the callbacks
       
   550      * for the various events.
       
   551      * @property queuable
       
   552      * @type boolean
       
   553      * @default false
       
   554      */
       
   555 
       
   556     /**
       
   557      * This event has fired if true
       
   558      *
       
   559      * @property fired
       
   560      * @type boolean
       
   561      * @default false;
       
   562      */
       
   563 
       
   564     /**
       
   565      * An array containing the arguments the custom event
       
   566      * was last fired with.
       
   567      * @property firedWith
       
   568      * @type Array
       
   569      */
       
   570 
       
   571     /**
       
   572      * This event should only fire one time if true, and if
       
   573      * it has fired, any new subscribers should be notified
       
   574      * immediately.
       
   575      *
       
   576      * @property fireOnce
       
   577      * @type boolean
       
   578      * @default false;
       
   579      */
       
   580 
       
   581     /**
       
   582      * fireOnce listeners will fire syncronously unless async
       
   583      * is set to true
       
   584      * @property async
       
   585      * @type boolean
       
   586      * @default false
       
   587      */
       
   588 
       
   589     /**
       
   590      * Flag for stopPropagation that is modified during fire()
       
   591      * 1 means to stop propagation to bubble targets.  2 means
       
   592      * to also stop additional subscribers on this target.
       
   593      * @property stopped
       
   594      * @type int
       
   595      */
       
   596 
       
   597     /**
       
   598      * Flag for preventDefault that is modified during fire().
       
   599      * if it is not 0, the default behavior for this event
       
   600      * @property prevented
       
   601      * @type int
       
   602      */
       
   603 
       
   604     /**
       
   605      * Specifies the host for this custom event.  This is used
       
   606      * to enable event bubbling
       
   607      * @property host
       
   608      * @type EventTarget
       
   609      */
       
   610 
       
   611     /**
       
   612      * The default function to execute after event listeners
       
   613      * have fire, but only if the default action was not
       
   614      * prevented.
       
   615      * @property defaultFn
       
   616      * @type Function
       
   617      */
       
   618 
       
   619     /**
       
   620      * Flag for the default function to execute only if the
       
   621      * firing event is the current target. This happens only
       
   622      * when using custom event delegation and setting the
       
   623      * flag to `true` mimics the behavior of event delegation
       
   624      * in the DOM.
       
   625      *
       
   626      * @property defaultTargetOnly
       
   627      * @type Boolean
       
   628      * @default false
       
   629      */
       
   630 
       
   631     /**
       
   632      * The function to execute if a subscriber calls
       
   633      * stopPropagation or stopImmediatePropagation
       
   634      * @property stoppedFn
       
   635      * @type Function
       
   636      */
       
   637 
       
   638     /**
       
   639      * The function to execute if a subscriber calls
       
   640      * preventDefault
       
   641      * @property preventedFn
       
   642      * @type Function
       
   643      */
       
   644 
       
   645     /**
       
   646      * The subscribers to this event
       
   647      * @property _subscribers
       
   648      * @type Subscriber []
       
   649      * @private
       
   650      */
       
   651 
       
   652     /**
       
   653      * 'After' subscribers
       
   654      * @property _afters
       
   655      * @type Subscriber []
       
   656      * @private
       
   657      */
       
   658 
       
   659     /**
       
   660      * If set to true, the custom event will deliver an EventFacade object
       
   661      * that is similar to a DOM event object.
       
   662      * @property emitFacade
       
   663      * @type boolean
       
   664      * @default false
       
   665      */
       
   666 
       
   667     /**
       
   668      * Supports multiple options for listener signatures in order to
       
   669      * port YUI 2 apps.
       
   670      * @property signature
       
   671      * @type int
       
   672      * @default 9
       
   673      */
       
   674     signature : YUI3_SIGNATURE,
       
   675 
       
   676     /**
       
   677      * The context the the event will fire from by default.  Defaults to the YUI
       
   678      * instance.
       
   679      * @property context
       
   680      * @type object
       
   681      */
       
   682     context : Y,
       
   683 
       
   684     /**
       
   685      * Specifies whether or not this event's default function
       
   686      * can be cancelled by a subscriber by executing preventDefault()
       
   687      * on the event facade
       
   688      * @property preventable
       
   689      * @type boolean
       
   690      * @default true
       
   691      */
       
   692     preventable : true,
       
   693 
       
   694     /**
       
   695      * Specifies whether or not a subscriber can stop the event propagation
       
   696      * via stopPropagation(), stopImmediatePropagation(), or halt()
       
   697      *
       
   698      * Events can only bubble if emitFacade is true.
       
   699      *
       
   700      * @property bubbles
       
   701      * @type boolean
       
   702      * @default true
       
   703      */
       
   704     bubbles : true,
       
   705 
       
   706     /**
       
   707      * Returns the number of subscribers for this event as the sum of the on()
       
   708      * subscribers and after() subscribers.
       
   709      *
       
   710      * @method hasSubs
       
   711      * @return Number
       
   712      */
       
   713     hasSubs: function(when) {
       
   714         var s = 0,
       
   715             a = 0,
       
   716             subs = this._subscribers,
       
   717             afters = this._afters,
       
   718             sib = this.sibling;
       
   719 
       
   720         if (subs) {
       
   721             s = subs.length;
       
   722         }
       
   723 
       
   724         if (afters) {
       
   725             a = afters.length;
       
   726         }
       
   727 
       
   728         if (sib) {
       
   729             subs = sib._subscribers;
       
   730             afters = sib._afters;
       
   731 
       
   732             if (subs) {
       
   733                 s += subs.length;
       
   734             }
       
   735 
       
   736             if (afters) {
       
   737                 a += afters.length;
       
   738             }
       
   739         }
       
   740 
       
   741         if (when) {
       
   742             return (when === 'after') ? a : s;
       
   743         }
       
   744 
       
   745         return (s + a);
       
   746     },
       
   747 
       
   748     /**
       
   749      * Monitor the event state for the subscribed event.  The first parameter
       
   750      * is what should be monitored, the rest are the normal parameters when
       
   751      * subscribing to an event.
       
   752      * @method monitor
       
   753      * @param what {string} what to monitor ('detach', 'attach', 'publish').
       
   754      * @return {EventHandle} return value from the monitor event subscription.
       
   755      */
       
   756     monitor: function(what) {
       
   757         this.monitored = true;
       
   758         var type = this.id + '|' + this.type + '_' + what,
       
   759             args = nativeSlice.call(arguments, 0);
       
   760         args[0] = type;
       
   761         return this.host.on.apply(this.host, args);
       
   762     },
       
   763 
       
   764     /**
       
   765      * Get all of the subscribers to this event and any sibling event
       
   766      * @method getSubs
       
   767      * @return {Array} first item is the on subscribers, second the after.
       
   768      */
       
   769     getSubs: function() {
       
   770 
       
   771         var sibling = this.sibling,
       
   772             subs = this._subscribers,
       
   773             afters = this._afters,
       
   774             siblingSubs,
       
   775             siblingAfters;
       
   776 
       
   777         if (sibling) {
       
   778             siblingSubs = sibling._subscribers;
       
   779             siblingAfters = sibling._afters;
       
   780         }
       
   781 
       
   782         if (siblingSubs) {
       
   783             if (subs) {
       
   784                 subs = subs.concat(siblingSubs);
       
   785             } else {
       
   786                 subs = siblingSubs.concat();
       
   787             }
       
   788         } else {
       
   789             if (subs) {
       
   790                 subs = subs.concat();
       
   791             } else {
       
   792                 subs = [];
       
   793             }
       
   794         }
       
   795 
       
   796         if (siblingAfters) {
       
   797             if (afters) {
       
   798                 afters = afters.concat(siblingAfters);
       
   799             } else {
       
   800                 afters = siblingAfters.concat();
       
   801             }
       
   802         } else {
       
   803             if (afters) {
       
   804                 afters = afters.concat();
       
   805             } else {
       
   806                 afters = [];
       
   807             }
       
   808         }
       
   809 
       
   810         return [subs, afters];
       
   811     },
       
   812 
       
   813     /**
       
   814      * Apply configuration properties.  Only applies the CONFIG whitelist
       
   815      * @method applyConfig
       
   816      * @param o hash of properties to apply.
       
   817      * @param force {boolean} if true, properties that exist on the event
       
   818      * will be overwritten.
       
   819      */
       
   820     applyConfig: function(o, force) {
       
   821         mixConfigs(this, o, force);
       
   822     },
       
   823 
       
   824     /**
       
   825      * Create the Subscription for subscribing function, context, and bound
       
   826      * arguments.  If this is a fireOnce event, the subscriber is immediately
       
   827      * notified.
       
   828      *
       
   829      * @method _on
       
   830      * @param fn {Function} Subscription callback
       
   831      * @param [context] {Object} Override `this` in the callback
       
   832      * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire()
       
   833      * @param [when] {String} "after" to slot into after subscribers
       
   834      * @return {EventHandle}
       
   835      * @protected
       
   836      */
       
   837     _on: function(fn, context, args, when) {
       
   838 
       
   839 
       
   840         var s = new Y.Subscriber(fn, context, args, when),
       
   841             firedWith;
       
   842 
       
   843         if (this.fireOnce && this.fired) {
       
   844 
       
   845             firedWith = this.firedWith;
       
   846 
       
   847             // It's a little ugly for this to know about facades,
       
   848             // but given the current breakup, not much choice without
       
   849             // moving a whole lot of stuff around.
       
   850             if (this.emitFacade && this._addFacadeToArgs) {
       
   851                 this._addFacadeToArgs(firedWith);
       
   852             }
       
   853 
       
   854             if (this.async) {
       
   855                 setTimeout(Y.bind(this._notify, this, s, firedWith), 0);
       
   856             } else {
       
   857                 this._notify(s, firedWith);
       
   858             }
       
   859         }
       
   860 
       
   861         if (when === AFTER) {
       
   862             if (!this._afters) {
       
   863                 this._afters = [];
       
   864             }
       
   865             this._afters.push(s);
       
   866         } else {
       
   867             if (!this._subscribers) {
       
   868                 this._subscribers = [];
       
   869             }
       
   870             this._subscribers.push(s);
       
   871         }
       
   872 
       
   873         if (this._kds) {
       
   874             if (when === AFTER) {
       
   875                 this.afters[s.id] = s;
       
   876             } else {
       
   877                 this.subscribers[s.id] = s;
       
   878             }
       
   879         }
       
   880 
       
   881         return new Y.EventHandle(this, s);
       
   882     },
       
   883 
       
   884     /**
       
   885      * Listen for this event
       
   886      * @method subscribe
       
   887      * @param {Function} fn The function to execute.
       
   888      * @return {EventHandle} Unsubscribe handle.
       
   889      * @deprecated use on.
       
   890      */
       
   891     subscribe: function(fn, context) {
       
   892         var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
       
   893         return this._on(fn, context, a, true);
       
   894     },
       
   895 
       
   896     /**
       
   897      * Listen for this event
       
   898      * @method on
       
   899      * @param {Function} fn The function to execute.
       
   900      * @param {object} context optional execution context.
       
   901      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
       
   902      * when the event fires.
       
   903      * @return {EventHandle} An object with a detach method to detch the handler(s).
       
   904      */
       
   905     on: function(fn, context) {
       
   906         var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
       
   907 
       
   908         if (this.monitored && this.host) {
       
   909             this.host._monitor('attach', this, {
       
   910                 args: arguments
       
   911             });
       
   912         }
       
   913         return this._on(fn, context, a, true);
       
   914     },
       
   915 
       
   916     /**
       
   917      * Listen for this event after the normal subscribers have been notified and
       
   918      * the default behavior has been applied.  If a normal subscriber prevents the
       
   919      * default behavior, it also prevents after listeners from firing.
       
   920      * @method after
       
   921      * @param {Function} fn The function to execute.
       
   922      * @param {object} context optional execution context.
       
   923      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
       
   924      * when the event fires.
       
   925      * @return {EventHandle} handle Unsubscribe handle.
       
   926      */
       
   927     after: function(fn, context) {
       
   928         var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
       
   929         return this._on(fn, context, a, AFTER);
       
   930     },
       
   931 
       
   932     /**
       
   933      * Detach listeners.
       
   934      * @method detach
       
   935      * @param {Function} fn  The subscribed function to remove, if not supplied
       
   936      *                       all will be removed.
       
   937      * @param {Object}   context The context object passed to subscribe.
       
   938      * @return {Number} returns the number of subscribers unsubscribed.
       
   939      */
       
   940     detach: function(fn, context) {
       
   941         // unsubscribe handle
       
   942         if (fn && fn.detach) {
       
   943             return fn.detach();
       
   944         }
       
   945 
       
   946         var i, s,
       
   947             found = 0,
       
   948             subs = this._subscribers,
       
   949             afters = this._afters;
       
   950 
       
   951         if (subs) {
       
   952             for (i = subs.length; i >= 0; i--) {
       
   953                 s = subs[i];
       
   954                 if (s && (!fn || fn === s.fn)) {
       
   955                     this._delete(s, subs, i);
       
   956                     found++;
       
   957                 }
       
   958             }
       
   959         }
       
   960 
       
   961         if (afters) {
       
   962             for (i = afters.length; i >= 0; i--) {
       
   963                 s = afters[i];
       
   964                 if (s && (!fn || fn === s.fn)) {
       
   965                     this._delete(s, afters, i);
       
   966                     found++;
       
   967                 }
       
   968             }
       
   969         }
       
   970 
       
   971         return found;
       
   972     },
       
   973 
       
   974     /**
       
   975      * Detach listeners.
       
   976      * @method unsubscribe
       
   977      * @param {Function} fn  The subscribed function to remove, if not supplied
       
   978      *                       all will be removed.
       
   979      * @param {Object}   context The context object passed to subscribe.
       
   980      * @return {int|undefined} returns the number of subscribers unsubscribed.
       
   981      * @deprecated use detach.
       
   982      */
       
   983     unsubscribe: function() {
       
   984         return this.detach.apply(this, arguments);
       
   985     },
       
   986 
       
   987     /**
       
   988      * Notify a single subscriber
       
   989      * @method _notify
       
   990      * @param {Subscriber} s the subscriber.
       
   991      * @param {Array} args the arguments array to apply to the listener.
       
   992      * @protected
       
   993      */
       
   994     _notify: function(s, args, ef) {
       
   995 
       
   996 
       
   997         var ret;
       
   998 
       
   999         ret = s.notify(args, this);
       
  1000 
       
  1001         if (false === ret || this.stopped > 1) {
       
  1002             return false;
       
  1003         }
       
  1004 
       
  1005         return true;
       
  1006     },
       
  1007 
       
  1008     /**
       
  1009      * Logger abstraction to centralize the application of the silent flag
       
  1010      * @method log
       
  1011      * @param {string} msg message to log.
       
  1012      * @param {string} cat log category.
       
  1013      */
       
  1014     log: function(msg, cat) {
       
  1015     },
       
  1016 
       
  1017     /**
       
  1018      * Notifies the subscribers.  The callback functions will be executed
       
  1019      * from the context specified when the event was created, and with the
       
  1020      * following parameters:
       
  1021      *   <ul>
       
  1022      *   <li>The type of event</li>
       
  1023      *   <li>All of the arguments fire() was executed with as an array</li>
       
  1024      *   <li>The custom object (if any) that was passed into the subscribe()
       
  1025      *       method</li>
       
  1026      *   </ul>
       
  1027      * @method fire
       
  1028      * @param {Object*} arguments an arbitrary set of parameters to pass to
       
  1029      *                            the handler.
       
  1030      * @return {boolean} false if one of the subscribers returned false,
       
  1031      *                   true otherwise.
       
  1032      *
       
  1033      */
       
  1034     fire: function() {
       
  1035 
       
  1036         // push is the fastest way to go from arguments to arrays
       
  1037         // for most browsers currently
       
  1038         // http://jsperf.com/push-vs-concat-vs-slice/2
       
  1039 
       
  1040         var args = [];
       
  1041         args.push.apply(args, arguments);
       
  1042 
       
  1043         return this._fire(args);
       
  1044     },
       
  1045 
       
  1046     /**
       
  1047      * Private internal implementation for `fire`, which is can be used directly by
       
  1048      * `EventTarget` and other event module classes which have already converted from
       
  1049      * an `arguments` list to an array, to avoid the repeated overhead.
       
  1050      *
       
  1051      * @method _fire
       
  1052      * @private
       
  1053      * @param {Array} args The array of arguments passed to be passed to handlers.
       
  1054      * @return {boolean} false if one of the subscribers returned false, true otherwise.
       
  1055      */
       
  1056     _fire: function(args) {
       
  1057 
       
  1058         if (this.fireOnce && this.fired) {
       
  1059             return true;
       
  1060         } else {
       
  1061 
       
  1062             // this doesn't happen if the event isn't published
       
  1063             // this.host._monitor('fire', this.type, args);
       
  1064 
       
  1065             this.fired = true;
       
  1066 
       
  1067             if (this.fireOnce) {
       
  1068                 this.firedWith = args;
       
  1069             }
       
  1070 
       
  1071             if (this.emitFacade) {
       
  1072                 return this.fireComplex(args);
       
  1073             } else {
       
  1074                 return this.fireSimple(args);
       
  1075             }
       
  1076         }
       
  1077     },
       
  1078 
       
  1079     /**
       
  1080      * Set up for notifying subscribers of non-emitFacade events.
       
  1081      *
       
  1082      * @method fireSimple
       
  1083      * @param args {Array} Arguments passed to fire()
       
  1084      * @return Boolean false if a subscriber returned false
       
  1085      * @protected
       
  1086      */
       
  1087     fireSimple: function(args) {
       
  1088         this.stopped = 0;
       
  1089         this.prevented = 0;
       
  1090         if (this.hasSubs()) {
       
  1091             var subs = this.getSubs();
       
  1092             this._procSubs(subs[0], args);
       
  1093             this._procSubs(subs[1], args);
       
  1094         }
       
  1095         if (this.broadcast) {
       
  1096             this._broadcast(args);
       
  1097         }
       
  1098         return this.stopped ? false : true;
       
  1099     },
       
  1100 
       
  1101     // Requires the event-custom-complex module for full funcitonality.
       
  1102     fireComplex: function(args) {
       
  1103         args[0] = args[0] || {};
       
  1104         return this.fireSimple(args);
       
  1105     },
       
  1106 
       
  1107     /**
       
  1108      * Notifies a list of subscribers.
       
  1109      *
       
  1110      * @method _procSubs
       
  1111      * @param subs {Array} List of subscribers
       
  1112      * @param args {Array} Arguments passed to fire()
       
  1113      * @param ef {}
       
  1114      * @return Boolean false if a subscriber returns false or stops the event
       
  1115      *              propagation via e.stopPropagation(),
       
  1116      *              e.stopImmediatePropagation(), or e.halt()
       
  1117      * @private
       
  1118      */
       
  1119     _procSubs: function(subs, args, ef) {
       
  1120         var s, i, l;
       
  1121 
       
  1122         for (i = 0, l = subs.length; i < l; i++) {
       
  1123             s = subs[i];
       
  1124             if (s && s.fn) {
       
  1125                 if (false === this._notify(s, args, ef)) {
       
  1126                     this.stopped = 2;
       
  1127                 }
       
  1128                 if (this.stopped === 2) {
       
  1129                     return false;
       
  1130                 }
       
  1131             }
       
  1132         }
       
  1133 
       
  1134         return true;
       
  1135     },
       
  1136 
       
  1137     /**
       
  1138      * Notifies the YUI instance if the event is configured with broadcast = 1,
       
  1139      * and both the YUI instance and Y.Global if configured with broadcast = 2.
       
  1140      *
       
  1141      * @method _broadcast
       
  1142      * @param args {Array} Arguments sent to fire()
       
  1143      * @private
       
  1144      */
       
  1145     _broadcast: function(args) {
       
  1146         if (!this.stopped && this.broadcast) {
       
  1147 
       
  1148             var a = args.concat();
       
  1149             a.unshift(this.type);
       
  1150 
       
  1151             if (this.host !== Y) {
       
  1152                 Y.fire.apply(Y, a);
       
  1153             }
       
  1154 
       
  1155             if (this.broadcast === 2) {
       
  1156                 Y.Global.fire.apply(Y.Global, a);
       
  1157             }
       
  1158         }
       
  1159     },
       
  1160 
       
  1161     /**
       
  1162      * Removes all listeners
       
  1163      * @method unsubscribeAll
       
  1164      * @return {Number} The number of listeners unsubscribed.
       
  1165      * @deprecated use detachAll.
       
  1166      */
       
  1167     unsubscribeAll: function() {
       
  1168         return this.detachAll.apply(this, arguments);
       
  1169     },
       
  1170 
       
  1171     /**
       
  1172      * Removes all listeners
       
  1173      * @method detachAll
       
  1174      * @return {Number} The number of listeners unsubscribed.
       
  1175      */
       
  1176     detachAll: function() {
       
  1177         return this.detach();
       
  1178     },
       
  1179 
       
  1180     /**
       
  1181      * Deletes the subscriber from the internal store of on() and after()
       
  1182      * subscribers.
       
  1183      *
       
  1184      * @method _delete
       
  1185      * @param s subscriber object.
       
  1186      * @param subs (optional) on or after subscriber array
       
  1187      * @param index (optional) The index found.
       
  1188      * @private
       
  1189      */
       
  1190     _delete: function(s, subs, i) {
       
  1191         var when = s._when;
       
  1192 
       
  1193         if (!subs) {
       
  1194             subs = (when === AFTER) ? this._afters : this._subscribers;
       
  1195         }
       
  1196 
       
  1197         if (subs) {
       
  1198             i = YArray.indexOf(subs, s, 0);
       
  1199 
       
  1200             if (s && subs[i] === s) {
       
  1201                 subs.splice(i, 1);
       
  1202             }
       
  1203         }
       
  1204 
       
  1205         if (this._kds) {
       
  1206             if (when === AFTER) {
       
  1207                 delete this.afters[s.id];
       
  1208             } else {
       
  1209                 delete this.subscribers[s.id];
       
  1210             }
       
  1211         }
       
  1212 
       
  1213         if (this.monitored && this.host) {
       
  1214             this.host._monitor('detach', this, {
       
  1215                 ce: this,
       
  1216                 sub: s
       
  1217             });
       
  1218         }
       
  1219 
       
  1220         if (s) {
       
  1221             s.deleted = true;
       
  1222         }
       
  1223     }
       
  1224 };
       
  1225 /**
       
  1226  * Stores the subscriber information to be used when the event fires.
       
  1227  * @param {Function} fn       The wrapped function to execute.
       
  1228  * @param {Object}   context  The value of the keyword 'this' in the listener.
       
  1229  * @param {Array} args*       0..n additional arguments to supply the listener.
       
  1230  *
       
  1231  * @class Subscriber
       
  1232  * @constructor
       
  1233  */
       
  1234 Y.Subscriber = function(fn, context, args, when) {
       
  1235 
       
  1236     /**
       
  1237      * The callback that will be execute when the event fires
       
  1238      * This is wrapped by Y.rbind if obj was supplied.
       
  1239      * @property fn
       
  1240      * @type Function
       
  1241      */
       
  1242     this.fn = fn;
       
  1243 
       
  1244     /**
       
  1245      * Optional 'this' keyword for the listener
       
  1246      * @property context
       
  1247      * @type Object
       
  1248      */
       
  1249     this.context = context;
       
  1250 
       
  1251     /**
       
  1252      * Unique subscriber id
       
  1253      * @property id
       
  1254      * @type String
       
  1255      */
       
  1256     this.id = Y.guid();
       
  1257 
       
  1258     /**
       
  1259      * Additional arguments to propagate to the subscriber
       
  1260      * @property args
       
  1261      * @type Array
       
  1262      */
       
  1263     this.args = args;
       
  1264 
       
  1265     this._when = when;
       
  1266 
       
  1267     /**
       
  1268      * Custom events for a given fire transaction.
       
  1269      * @property events
       
  1270      * @type {EventTarget}
       
  1271      */
       
  1272     // this.events = null;
       
  1273 
       
  1274     /**
       
  1275      * This listener only reacts to the event once
       
  1276      * @property once
       
  1277      */
       
  1278     // this.once = false;
       
  1279 
       
  1280 };
       
  1281 
       
  1282 Y.Subscriber.prototype = {
       
  1283     constructor: Y.Subscriber,
       
  1284 
       
  1285     _notify: function(c, args, ce) {
       
  1286         if (this.deleted && !this.postponed) {
       
  1287             if (this.postponed) {
       
  1288                 delete this.fn;
       
  1289                 delete this.context;
       
  1290             } else {
       
  1291                 delete this.postponed;
       
  1292                 return null;
       
  1293             }
       
  1294         }
       
  1295         var a = this.args, ret;
       
  1296         switch (ce.signature) {
       
  1297             case 0:
       
  1298                 ret = this.fn.call(c, ce.type, args, c);
       
  1299                 break;
       
  1300             case 1:
       
  1301                 ret = this.fn.call(c, args[0] || null, c);
       
  1302                 break;
       
  1303             default:
       
  1304                 if (a || args) {
       
  1305                     args = args || [];
       
  1306                     a = (a) ? args.concat(a) : args;
       
  1307                     ret = this.fn.apply(c, a);
       
  1308                 } else {
       
  1309                     ret = this.fn.call(c);
       
  1310                 }
       
  1311         }
       
  1312 
       
  1313         if (this.once) {
       
  1314             ce._delete(this);
       
  1315         }
       
  1316 
       
  1317         return ret;
       
  1318     },
       
  1319 
       
  1320     /**
       
  1321      * Executes the subscriber.
       
  1322      * @method notify
       
  1323      * @param args {Array} Arguments array for the subscriber.
       
  1324      * @param ce {CustomEvent} The custom event that sent the notification.
       
  1325      */
       
  1326     notify: function(args, ce) {
       
  1327         var c = this.context,
       
  1328             ret = true;
       
  1329 
       
  1330         if (!c) {
       
  1331             c = (ce.contextFn) ? ce.contextFn() : ce.context;
       
  1332         }
       
  1333 
       
  1334         // only catch errors if we will not re-throw them.
       
  1335         if (Y.config && Y.config.throwFail) {
       
  1336             ret = this._notify(c, args, ce);
       
  1337         } else {
       
  1338             try {
       
  1339                 ret = this._notify(c, args, ce);
       
  1340             } catch (e) {
       
  1341                 Y.error(this + ' failed: ' + e.message, e);
       
  1342             }
       
  1343         }
       
  1344 
       
  1345         return ret;
       
  1346     },
       
  1347 
       
  1348     /**
       
  1349      * Returns true if the fn and obj match this objects properties.
       
  1350      * Used by the unsubscribe method to match the right subscriber.
       
  1351      *
       
  1352      * @method contains
       
  1353      * @param {Function} fn the function to execute.
       
  1354      * @param {Object} context optional 'this' keyword for the listener.
       
  1355      * @return {boolean} true if the supplied arguments match this
       
  1356      *                   subscriber's signature.
       
  1357      */
       
  1358     contains: function(fn, context) {
       
  1359         if (context) {
       
  1360             return ((this.fn === fn) && this.context === context);
       
  1361         } else {
       
  1362             return (this.fn === fn);
       
  1363         }
       
  1364     },
       
  1365 
       
  1366     valueOf : function() {
       
  1367         return this.id;
       
  1368     }
       
  1369 
       
  1370 };
       
  1371 /**
       
  1372  * Return value from all subscribe operations
       
  1373  * @class EventHandle
       
  1374  * @constructor
       
  1375  * @param {CustomEvent} evt the custom event.
       
  1376  * @param {Subscriber} sub the subscriber.
       
  1377  */
       
  1378 Y.EventHandle = function(evt, sub) {
       
  1379 
       
  1380     /**
       
  1381      * The custom event
       
  1382      *
       
  1383      * @property evt
       
  1384      * @type CustomEvent
       
  1385      */
       
  1386     this.evt = evt;
       
  1387 
       
  1388     /**
       
  1389      * The subscriber object
       
  1390      *
       
  1391      * @property sub
       
  1392      * @type Subscriber
       
  1393      */
       
  1394     this.sub = sub;
       
  1395 };
       
  1396 
       
  1397 Y.EventHandle.prototype = {
       
  1398     batch: function(f, c) {
       
  1399         f.call(c || this, this);
       
  1400         if (Y.Lang.isArray(this.evt)) {
       
  1401             Y.Array.each(this.evt, function(h) {
       
  1402                 h.batch.call(c || h, f);
       
  1403             });
       
  1404         }
       
  1405     },
       
  1406 
       
  1407     /**
       
  1408      * Detaches this subscriber
       
  1409      * @method detach
       
  1410      * @return {Number} the number of detached listeners
       
  1411      */
       
  1412     detach: function() {
       
  1413         var evt = this.evt, detached = 0, i;
       
  1414         if (evt) {
       
  1415             if (Y.Lang.isArray(evt)) {
       
  1416                 for (i = 0; i < evt.length; i++) {
       
  1417                     detached += evt[i].detach();
       
  1418                 }
       
  1419             } else {
       
  1420                 evt._delete(this.sub);
       
  1421                 detached = 1;
       
  1422             }
       
  1423 
       
  1424         }
       
  1425 
       
  1426         return detached;
       
  1427     },
       
  1428 
       
  1429     /**
       
  1430      * Monitor the event state for the subscribed event.  The first parameter
       
  1431      * is what should be monitored, the rest are the normal parameters when
       
  1432      * subscribing to an event.
       
  1433      * @method monitor
       
  1434      * @param what {string} what to monitor ('attach', 'detach', 'publish').
       
  1435      * @return {EventHandle} return value from the monitor event subscription.
       
  1436      */
       
  1437     monitor: function(what) {
       
  1438         return this.evt.monitor.apply(this.evt, arguments);
       
  1439     }
       
  1440 };
       
  1441 
       
  1442 /**
       
  1443  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
       
  1444  * events.
       
  1445  * @module event-custom
       
  1446  * @submodule event-custom-base
       
  1447  */
       
  1448 
       
  1449 /**
       
  1450  * EventTarget provides the implementation for any object to
       
  1451  * publish, subscribe and fire to custom events, and also
       
  1452  * alows other EventTargets to target the object with events
       
  1453  * sourced from the other object.
       
  1454  * EventTarget is designed to be used with Y.augment to wrap
       
  1455  * EventCustom in an interface that allows events to be listened to
       
  1456  * and fired by name.  This makes it possible for implementing code to
       
  1457  * subscribe to an event that either has not been created yet, or will
       
  1458  * not be created at all.
       
  1459  * @class EventTarget
       
  1460  * @param opts a configuration object
       
  1461  * @config emitFacade {boolean} if true, all events will emit event
       
  1462  * facade payloads by default (default false)
       
  1463  * @config prefix {String} the prefix to apply to non-prefixed event names
       
  1464  */
       
  1465 
       
  1466 var L = Y.Lang,
       
  1467     PREFIX_DELIMITER = ':',
       
  1468     CATEGORY_DELIMITER = '|',
       
  1469     AFTER_PREFIX = '~AFTER~',
       
  1470     WILD_TYPE_RE = /(.*?)(:)(.*?)/,
       
  1471 
       
  1472     _wildType = Y.cached(function(type) {
       
  1473         return type.replace(WILD_TYPE_RE, "*$2$3");
       
  1474     }),
       
  1475 
       
  1476     /**
       
  1477      * If the instance has a prefix attribute and the
       
  1478      * event type is not prefixed, the instance prefix is
       
  1479      * applied to the supplied type.
       
  1480      * @method _getType
       
  1481      * @private
       
  1482      */
       
  1483     _getType = function(type, pre) {
       
  1484 
       
  1485         if (!pre || !type || type.indexOf(PREFIX_DELIMITER) > -1) {
       
  1486             return type;
       
  1487         }
       
  1488 
       
  1489         return pre + PREFIX_DELIMITER + type;
       
  1490     },
       
  1491 
       
  1492     /**
       
  1493      * Returns an array with the detach key (if provided),
       
  1494      * and the prefixed event name from _getType
       
  1495      * Y.on('detachcategory| menu:click', fn)
       
  1496      * @method _parseType
       
  1497      * @private
       
  1498      */
       
  1499     _parseType = Y.cached(function(type, pre) {
       
  1500 
       
  1501         var t = type, detachcategory, after, i;
       
  1502 
       
  1503         if (!L.isString(t)) {
       
  1504             return t;
       
  1505         }
       
  1506 
       
  1507         i = t.indexOf(AFTER_PREFIX);
       
  1508 
       
  1509         if (i > -1) {
       
  1510             after = true;
       
  1511             t = t.substr(AFTER_PREFIX.length);
       
  1512         }
       
  1513 
       
  1514         i = t.indexOf(CATEGORY_DELIMITER);
       
  1515 
       
  1516         if (i > -1) {
       
  1517             detachcategory = t.substr(0, (i));
       
  1518             t = t.substr(i+1);
       
  1519             if (t === '*') {
       
  1520                 t = null;
       
  1521             }
       
  1522         }
       
  1523 
       
  1524         // detach category, full type with instance prefix, is this an after listener, short type
       
  1525         return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
       
  1526     }),
       
  1527 
       
  1528     ET = function(opts) {
       
  1529 
       
  1530         var etState = this._yuievt,
       
  1531             etConfig;
       
  1532 
       
  1533         if (!etState) {
       
  1534             etState = this._yuievt = {
       
  1535                 events: {},    // PERF: Not much point instantiating lazily. We're bound to have events
       
  1536                 targets: null, // PERF: Instantiate lazily, if user actually adds target,
       
  1537                 config: {
       
  1538                     host: this,
       
  1539                     context: this
       
  1540                 },
       
  1541                 chain: Y.config.chain
       
  1542             };
       
  1543         }
       
  1544 
       
  1545         etConfig = etState.config;
       
  1546 
       
  1547         if (opts) {
       
  1548             mixConfigs(etConfig, opts, true);
       
  1549 
       
  1550             if (opts.chain !== undefined) {
       
  1551                 etState.chain = opts.chain;
       
  1552             }
       
  1553 
       
  1554             if (opts.prefix) {
       
  1555                 etConfig.prefix = opts.prefix;
       
  1556             }
       
  1557         }
       
  1558     };
       
  1559 
       
  1560 ET.prototype = {
       
  1561 
       
  1562     constructor: ET,
       
  1563 
       
  1564     /**
       
  1565      * Listen to a custom event hosted by this object one time.
       
  1566      * This is the equivalent to <code>on</code> except the
       
  1567      * listener is immediatelly detached when it is executed.
       
  1568      * @method once
       
  1569      * @param {String} type The name of the event
       
  1570      * @param {Function} fn The callback to execute in response to the event
       
  1571      * @param {Object} [context] Override `this` object in callback
       
  1572      * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  1573      * @return {EventHandle} A subscription handle capable of detaching the
       
  1574      *                       subscription
       
  1575      */
       
  1576     once: function() {
       
  1577         var handle = this.on.apply(this, arguments);
       
  1578         handle.batch(function(hand) {
       
  1579             if (hand.sub) {
       
  1580                 hand.sub.once = true;
       
  1581             }
       
  1582         });
       
  1583         return handle;
       
  1584     },
       
  1585 
       
  1586     /**
       
  1587      * Listen to a custom event hosted by this object one time.
       
  1588      * This is the equivalent to <code>after</code> except the
       
  1589      * listener is immediatelly detached when it is executed.
       
  1590      * @method onceAfter
       
  1591      * @param {String} type The name of the event
       
  1592      * @param {Function} fn The callback to execute in response to the event
       
  1593      * @param {Object} [context] Override `this` object in callback
       
  1594      * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  1595      * @return {EventHandle} A subscription handle capable of detaching that
       
  1596      *                       subscription
       
  1597      */
       
  1598     onceAfter: function() {
       
  1599         var handle = this.after.apply(this, arguments);
       
  1600         handle.batch(function(hand) {
       
  1601             if (hand.sub) {
       
  1602                 hand.sub.once = true;
       
  1603             }
       
  1604         });
       
  1605         return handle;
       
  1606     },
       
  1607 
       
  1608     /**
       
  1609      * Takes the type parameter passed to 'on' and parses out the
       
  1610      * various pieces that could be included in the type.  If the
       
  1611      * event type is passed without a prefix, it will be expanded
       
  1612      * to include the prefix one is supplied or the event target
       
  1613      * is configured with a default prefix.
       
  1614      * @method parseType
       
  1615      * @param {String} type the type
       
  1616      * @param {String} [pre] The prefix. Defaults to this._yuievt.config.prefix
       
  1617      * @since 3.3.0
       
  1618      * @return {Array} an array containing:
       
  1619      *  * the detach category, if supplied,
       
  1620      *  * the prefixed event type,
       
  1621      *  * whether or not this is an after listener,
       
  1622      *  * the supplied event type
       
  1623      */
       
  1624     parseType: function(type, pre) {
       
  1625         return _parseType(type, pre || this._yuievt.config.prefix);
       
  1626     },
       
  1627 
       
  1628     /**
       
  1629      * Subscribe a callback function to a custom event fired by this object or
       
  1630      * from an object that bubbles its events to this object.
       
  1631      *
       
  1632      * Callback functions for events published with `emitFacade = true` will
       
  1633      * receive an `EventFacade` as the first argument (typically named "e").
       
  1634      * These callbacks can then call `e.preventDefault()` to disable the
       
  1635      * behavior published to that event's `defaultFn`.  See the `EventFacade`
       
  1636      * API for all available properties and methods. Subscribers to
       
  1637      * non-`emitFacade` events will receive the arguments passed to `fire()`
       
  1638      * after the event name.
       
  1639      *
       
  1640      * To subscribe to multiple events at once, pass an object as the first
       
  1641      * argument, where the key:value pairs correspond to the eventName:callback,
       
  1642      * or pass an array of event names as the first argument to subscribe to
       
  1643      * all listed events with the same callback.
       
  1644      *
       
  1645      * Returning `false` from a callback is supported as an alternative to
       
  1646      * calling `e.preventDefault(); e.stopPropagation();`.  However, it is
       
  1647      * recommended to use the event methods whenever possible.
       
  1648      *
       
  1649      * @method on
       
  1650      * @param {String} type The name of the event
       
  1651      * @param {Function} fn The callback to execute in response to the event
       
  1652      * @param {Object} [context] Override `this` object in callback
       
  1653      * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  1654      * @return {EventHandle} A subscription handle capable of detaching that
       
  1655      *                       subscription
       
  1656      */
       
  1657     on: function(type, fn, context) {
       
  1658 
       
  1659         var yuievt = this._yuievt,
       
  1660             parts = _parseType(type, yuievt.config.prefix), f, c, args, ret, ce,
       
  1661             detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
       
  1662             Node = Y.Node, n, domevent, isArr;
       
  1663 
       
  1664         // full name, args, detachcategory, after
       
  1665         this._monitor('attach', parts[1], {
       
  1666             args: arguments,
       
  1667             category: parts[0],
       
  1668             after: parts[2]
       
  1669         });
       
  1670 
       
  1671         if (L.isObject(type)) {
       
  1672 
       
  1673             if (L.isFunction(type)) {
       
  1674                 return Y.Do.before.apply(Y.Do, arguments);
       
  1675             }
       
  1676 
       
  1677             f = fn;
       
  1678             c = context;
       
  1679             args = nativeSlice.call(arguments, 0);
       
  1680             ret = [];
       
  1681 
       
  1682             if (L.isArray(type)) {
       
  1683                 isArr = true;
       
  1684             }
       
  1685 
       
  1686             after = type._after;
       
  1687             delete type._after;
       
  1688 
       
  1689             Y.each(type, function(v, k) {
       
  1690 
       
  1691                 if (L.isObject(v)) {
       
  1692                     f = v.fn || ((L.isFunction(v)) ? v : f);
       
  1693                     c = v.context || c;
       
  1694                 }
       
  1695 
       
  1696                 var nv = (after) ? AFTER_PREFIX : '';
       
  1697 
       
  1698                 args[0] = nv + ((isArr) ? v : k);
       
  1699                 args[1] = f;
       
  1700                 args[2] = c;
       
  1701 
       
  1702                 ret.push(this.on.apply(this, args));
       
  1703 
       
  1704             }, this);
       
  1705 
       
  1706             return (yuievt.chain) ? this : new Y.EventHandle(ret);
       
  1707         }
       
  1708 
       
  1709         detachcategory = parts[0];
       
  1710         after = parts[2];
       
  1711         shorttype = parts[3];
       
  1712 
       
  1713         // extra redirection so we catch adaptor events too.  take a look at this.
       
  1714         if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
       
  1715             args = nativeSlice.call(arguments, 0);
       
  1716             args.splice(2, 0, Node.getDOMNode(this));
       
  1717             return Y.on.apply(Y, args);
       
  1718         }
       
  1719 
       
  1720         type = parts[1];
       
  1721 
       
  1722         if (Y.instanceOf(this, YUI)) {
       
  1723 
       
  1724             adapt = Y.Env.evt.plugins[type];
       
  1725             args  = nativeSlice.call(arguments, 0);
       
  1726             args[0] = shorttype;
       
  1727 
       
  1728             if (Node) {
       
  1729                 n = args[2];
       
  1730 
       
  1731                 if (Y.instanceOf(n, Y.NodeList)) {
       
  1732                     n = Y.NodeList.getDOMNodes(n);
       
  1733                 } else if (Y.instanceOf(n, Node)) {
       
  1734                     n = Node.getDOMNode(n);
       
  1735                 }
       
  1736 
       
  1737                 domevent = (shorttype in Node.DOM_EVENTS);
       
  1738 
       
  1739                 // Captures both DOM events and event plugins.
       
  1740                 if (domevent) {
       
  1741                     args[2] = n;
       
  1742                 }
       
  1743             }
       
  1744 
       
  1745             // check for the existance of an event adaptor
       
  1746             if (adapt) {
       
  1747                 handle = adapt.on.apply(Y, args);
       
  1748             } else if ((!type) || domevent) {
       
  1749                 handle = Y.Event._attach(args);
       
  1750             }
       
  1751 
       
  1752         }
       
  1753 
       
  1754         if (!handle) {
       
  1755             ce = yuievt.events[type] || this.publish(type);
       
  1756             handle = ce._on(fn, context, (arguments.length > 3) ? nativeSlice.call(arguments, 3) : null, (after) ? 'after' : true);
       
  1757 
       
  1758             // TODO: More robust regex, accounting for category
       
  1759             if (type.indexOf("*:") !== -1) {
       
  1760                 this._hasSiblings = true;
       
  1761             }
       
  1762         }
       
  1763 
       
  1764         if (detachcategory) {
       
  1765             store[detachcategory] = store[detachcategory] || {};
       
  1766             store[detachcategory][type] = store[detachcategory][type] || [];
       
  1767             store[detachcategory][type].push(handle);
       
  1768         }
       
  1769 
       
  1770         return (yuievt.chain) ? this : handle;
       
  1771 
       
  1772     },
       
  1773 
       
  1774     /**
       
  1775      * subscribe to an event
       
  1776      * @method subscribe
       
  1777      * @deprecated use on
       
  1778      */
       
  1779     subscribe: function() {
       
  1780         return this.on.apply(this, arguments);
       
  1781     },
       
  1782 
       
  1783     /**
       
  1784      * Detach one or more listeners the from the specified event
       
  1785      * @method detach
       
  1786      * @param type {string|Object}   Either the handle to the subscriber or the
       
  1787      *                        type of event.  If the type
       
  1788      *                        is not specified, it will attempt to remove
       
  1789      *                        the listener from all hosted events.
       
  1790      * @param fn   {Function} The subscribed function to unsubscribe, if not
       
  1791      *                          supplied, all subscribers will be removed.
       
  1792      * @param context  {Object}   The custom object passed to subscribe.  This is
       
  1793      *                        optional, but if supplied will be used to
       
  1794      *                        disambiguate multiple listeners that are the same
       
  1795      *                        (e.g., you subscribe many object using a function
       
  1796      *                        that lives on the prototype)
       
  1797      * @return {EventTarget} the host
       
  1798      */
       
  1799     detach: function(type, fn, context) {
       
  1800 
       
  1801         var evts = this._yuievt.events,
       
  1802             i,
       
  1803             Node = Y.Node,
       
  1804             isNode = Node && (Y.instanceOf(this, Node));
       
  1805 
       
  1806         // detachAll disabled on the Y instance.
       
  1807         if (!type && (this !== Y)) {
       
  1808             for (i in evts) {
       
  1809                 if (evts.hasOwnProperty(i)) {
       
  1810                     evts[i].detach(fn, context);
       
  1811                 }
       
  1812             }
       
  1813             if (isNode) {
       
  1814                 Y.Event.purgeElement(Node.getDOMNode(this));
       
  1815             }
       
  1816 
       
  1817             return this;
       
  1818         }
       
  1819 
       
  1820         var parts = _parseType(type, this._yuievt.config.prefix),
       
  1821         detachcategory = L.isArray(parts) ? parts[0] : null,
       
  1822         shorttype = (parts) ? parts[3] : null,
       
  1823         adapt, store = Y.Env.evt.handles, detachhost, cat, args,
       
  1824         ce,
       
  1825 
       
  1826         keyDetacher = function(lcat, ltype, host) {
       
  1827             var handles = lcat[ltype], ce, i;
       
  1828             if (handles) {
       
  1829                 for (i = handles.length - 1; i >= 0; --i) {
       
  1830                     ce = handles[i].evt;
       
  1831                     if (ce.host === host || ce.el === host) {
       
  1832                         handles[i].detach();
       
  1833                     }
       
  1834                 }
       
  1835             }
       
  1836         };
       
  1837 
       
  1838         if (detachcategory) {
       
  1839 
       
  1840             cat = store[detachcategory];
       
  1841             type = parts[1];
       
  1842             detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
       
  1843 
       
  1844             if (cat) {
       
  1845                 if (type) {
       
  1846                     keyDetacher(cat, type, detachhost);
       
  1847                 } else {
       
  1848                     for (i in cat) {
       
  1849                         if (cat.hasOwnProperty(i)) {
       
  1850                             keyDetacher(cat, i, detachhost);
       
  1851                         }
       
  1852                     }
       
  1853                 }
       
  1854 
       
  1855                 return this;
       
  1856             }
       
  1857 
       
  1858         // If this is an event handle, use it to detach
       
  1859         } else if (L.isObject(type) && type.detach) {
       
  1860             type.detach();
       
  1861             return this;
       
  1862         // extra redirection so we catch adaptor events too.  take a look at this.
       
  1863         } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
       
  1864             args = nativeSlice.call(arguments, 0);
       
  1865             args[2] = Node.getDOMNode(this);
       
  1866             Y.detach.apply(Y, args);
       
  1867             return this;
       
  1868         }
       
  1869 
       
  1870         adapt = Y.Env.evt.plugins[shorttype];
       
  1871 
       
  1872         // The YUI instance handles DOM events and adaptors
       
  1873         if (Y.instanceOf(this, YUI)) {
       
  1874             args = nativeSlice.call(arguments, 0);
       
  1875             // use the adaptor specific detach code if
       
  1876             if (adapt && adapt.detach) {
       
  1877                 adapt.detach.apply(Y, args);
       
  1878                 return this;
       
  1879             // DOM event fork
       
  1880             } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
       
  1881                 args[0] = type;
       
  1882                 Y.Event.detach.apply(Y.Event, args);
       
  1883                 return this;
       
  1884             }
       
  1885         }
       
  1886 
       
  1887         // ce = evts[type];
       
  1888         ce = evts[parts[1]];
       
  1889         if (ce) {
       
  1890             ce.detach(fn, context);
       
  1891         }
       
  1892 
       
  1893         return this;
       
  1894     },
       
  1895 
       
  1896     /**
       
  1897      * detach a listener
       
  1898      * @method unsubscribe
       
  1899      * @deprecated use detach
       
  1900      */
       
  1901     unsubscribe: function() {
       
  1902         return this.detach.apply(this, arguments);
       
  1903     },
       
  1904 
       
  1905     /**
       
  1906      * Removes all listeners from the specified event.  If the event type
       
  1907      * is not specified, all listeners from all hosted custom events will
       
  1908      * be removed.
       
  1909      * @method detachAll
       
  1910      * @param type {String}   The type, or name of the event
       
  1911      */
       
  1912     detachAll: function(type) {
       
  1913         return this.detach(type);
       
  1914     },
       
  1915 
       
  1916     /**
       
  1917      * Removes all listeners from the specified event.  If the event type
       
  1918      * is not specified, all listeners from all hosted custom events will
       
  1919      * be removed.
       
  1920      * @method unsubscribeAll
       
  1921      * @param type {String}   The type, or name of the event
       
  1922      * @deprecated use detachAll
       
  1923      */
       
  1924     unsubscribeAll: function() {
       
  1925         return this.detachAll.apply(this, arguments);
       
  1926     },
       
  1927 
       
  1928     /**
       
  1929      * Creates a new custom event of the specified type.  If a custom event
       
  1930      * by that name already exists, it will not be re-created.  In either
       
  1931      * case the custom event is returned.
       
  1932      *
       
  1933      * @method publish
       
  1934      *
       
  1935      * @param type {String} the type, or name of the event
       
  1936      * @param opts {object} optional config params.  Valid properties are:
       
  1937      *
       
  1938      *  <ul>
       
  1939      *    <li>
       
  1940      *   'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
       
  1941      *    </li>
       
  1942      *    <li>
       
  1943      *   'bubbles': whether or not this event bubbles (true)
       
  1944      *              Events can only bubble if emitFacade is true.
       
  1945      *    </li>
       
  1946      *    <li>
       
  1947      *   'context': the default execution context for the listeners (this)
       
  1948      *    </li>
       
  1949      *    <li>
       
  1950      *   'defaultFn': the default function to execute when this event fires if preventDefault was not called
       
  1951      *    </li>
       
  1952      *    <li>
       
  1953      *   'emitFacade': whether or not this event emits a facade (false)
       
  1954      *    </li>
       
  1955      *    <li>
       
  1956      *   'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
       
  1957      *    </li>
       
  1958      *    <li>
       
  1959      *   'fireOnce': if an event is configured to fire once, new subscribers after
       
  1960      *   the fire will be notified immediately.
       
  1961      *    </li>
       
  1962      *    <li>
       
  1963      *   'async': fireOnce event listeners will fire synchronously if the event has already
       
  1964      *    fired unless async is true.
       
  1965      *    </li>
       
  1966      *    <li>
       
  1967      *   'preventable': whether or not preventDefault() has an effect (true)
       
  1968      *    </li>
       
  1969      *    <li>
       
  1970      *   'preventedFn': a function that is executed when preventDefault is called
       
  1971      *    </li>
       
  1972      *    <li>
       
  1973      *   'queuable': whether or not this event can be queued during bubbling (false)
       
  1974      *    </li>
       
  1975      *    <li>
       
  1976      *   'silent': if silent is true, debug messages are not provided for this event.
       
  1977      *    </li>
       
  1978      *    <li>
       
  1979      *   'stoppedFn': a function that is executed when stopPropagation is called
       
  1980      *    </li>
       
  1981      *
       
  1982      *    <li>
       
  1983      *   'monitored': specifies whether or not this event should send notifications about
       
  1984      *   when the event has been attached, detached, or published.
       
  1985      *    </li>
       
  1986      *    <li>
       
  1987      *   'type': the event type (valid option if not provided as the first parameter to publish)
       
  1988      *    </li>
       
  1989      *  </ul>
       
  1990      *
       
  1991      *  @return {CustomEvent} the custom event
       
  1992      *
       
  1993      */
       
  1994     publish: function(type, opts) {
       
  1995 
       
  1996         var ret,
       
  1997             etState = this._yuievt,
       
  1998             etConfig = etState.config,
       
  1999             pre = etConfig.prefix;
       
  2000 
       
  2001         if (typeof type === "string")  {
       
  2002             if (pre) {
       
  2003                 type = _getType(type, pre);
       
  2004             }
       
  2005             ret = this._publish(type, etConfig, opts);
       
  2006         } else {
       
  2007             ret = {};
       
  2008 
       
  2009             Y.each(type, function(v, k) {
       
  2010                 if (pre) {
       
  2011                     k = _getType(k, pre);
       
  2012                 }
       
  2013                 ret[k] = this._publish(k, etConfig, v || opts);
       
  2014             }, this);
       
  2015 
       
  2016         }
       
  2017 
       
  2018         return ret;
       
  2019     },
       
  2020 
       
  2021     /**
       
  2022      * Returns the fully qualified type, given a short type string.
       
  2023      * That is, returns "foo:bar" when given "bar" if "foo" is the configured prefix.
       
  2024      *
       
  2025      * NOTE: This method, unlike _getType, does no checking of the value passed in, and
       
  2026      * is designed to be used with the low level _publish() method, for critical path
       
  2027      * implementations which need to fast-track publish for performance reasons.
       
  2028      *
       
  2029      * @method _getFullType
       
  2030      * @private
       
  2031      * @param {String} type The short type to prefix
       
  2032      * @return {String} The prefixed type, if a prefix is set, otherwise the type passed in
       
  2033      */
       
  2034     _getFullType : function(type) {
       
  2035 
       
  2036         var pre = this._yuievt.config.prefix;
       
  2037 
       
  2038         if (pre) {
       
  2039             return pre + PREFIX_DELIMITER + type;
       
  2040         } else {
       
  2041             return type;
       
  2042         }
       
  2043     },
       
  2044 
       
  2045     /**
       
  2046      * The low level event publish implementation. It expects all the massaging to have been done
       
  2047      * outside of this method. e.g. the `type` to `fullType` conversion. It's designed to be a fast
       
  2048      * path publish, which can be used by critical code paths to improve performance.
       
  2049      *
       
  2050      * @method _publish
       
  2051      * @private
       
  2052      * @param {String} fullType The prefixed type of the event to publish.
       
  2053      * @param {Object} etOpts The EventTarget specific configuration to mix into the published event.
       
  2054      * @param {Object} ceOpts The publish specific configuration to mix into the published event.
       
  2055      * @return {CustomEvent} The published event. If called without `etOpts` or `ceOpts`, this will
       
  2056      * be the default `CustomEvent` instance, and can be configured independently.
       
  2057      */
       
  2058     _publish : function(fullType, etOpts, ceOpts) {
       
  2059 
       
  2060         var ce,
       
  2061             etState = this._yuievt,
       
  2062             etConfig = etState.config,
       
  2063             host = etConfig.host,
       
  2064             context = etConfig.context,
       
  2065             events = etState.events;
       
  2066 
       
  2067         ce = events[fullType];
       
  2068 
       
  2069         // PERF: Hate to pull the check out of monitor, but trying to keep critical path tight.
       
  2070         if ((etConfig.monitored && !ce) || (ce && ce.monitored)) {
       
  2071             this._monitor('publish', fullType, {
       
  2072                 args: arguments
       
  2073             });
       
  2074         }
       
  2075 
       
  2076         if (!ce) {
       
  2077             // Publish event
       
  2078             ce = events[fullType] = new Y.CustomEvent(fullType, etOpts);
       
  2079 
       
  2080             if (!etOpts) {
       
  2081                 ce.host = host;
       
  2082                 ce.context = context;
       
  2083             }
       
  2084         }
       
  2085 
       
  2086         if (ceOpts) {
       
  2087             mixConfigs(ce, ceOpts, true);
       
  2088         }
       
  2089 
       
  2090         return ce;
       
  2091     },
       
  2092 
       
  2093     /**
       
  2094      * This is the entry point for the event monitoring system.
       
  2095      * You can monitor 'attach', 'detach', 'fire', and 'publish'.
       
  2096      * When configured, these events generate an event.  click ->
       
  2097      * click_attach, click_detach, click_publish -- these can
       
  2098      * be subscribed to like other events to monitor the event
       
  2099      * system.  Inividual published events can have monitoring
       
  2100      * turned on or off (publish can't be turned off before it
       
  2101      * it published) by setting the events 'monitor' config.
       
  2102      *
       
  2103      * @method _monitor
       
  2104      * @param what {String} 'attach', 'detach', 'fire', or 'publish'
       
  2105      * @param eventType {String|CustomEvent} The prefixed name of the event being monitored, or the CustomEvent object.
       
  2106      * @param o {Object} Information about the event interaction, such as
       
  2107      *                  fire() args, subscription category, publish config
       
  2108      * @private
       
  2109      */
       
  2110     _monitor: function(what, eventType, o) {
       
  2111         var monitorevt, ce, type;
       
  2112 
       
  2113         if (eventType) {
       
  2114             if (typeof eventType === "string") {
       
  2115                 type = eventType;
       
  2116                 ce = this.getEvent(eventType, true);
       
  2117             } else {
       
  2118                 ce = eventType;
       
  2119                 type = eventType.type;
       
  2120             }
       
  2121 
       
  2122             if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
       
  2123                 monitorevt = type + '_' + what;
       
  2124                 o.monitored = what;
       
  2125                 this.fire.call(this, monitorevt, o);
       
  2126             }
       
  2127         }
       
  2128     },
       
  2129 
       
  2130     /**
       
  2131      * Fire a custom event by name.  The callback functions will be executed
       
  2132      * from the context specified when the event was created, and with the
       
  2133      * following parameters.
       
  2134      *
       
  2135      * The first argument is the event type, and any additional arguments are
       
  2136      * passed to the listeners as parameters.  If the first of these is an
       
  2137      * object literal, and the event is configured to emit an event facade,
       
  2138      * that object is mixed into the event facade and the facade is provided
       
  2139      * in place of the original object.
       
  2140      *
       
  2141      * If the custom event object hasn't been created, then the event hasn't
       
  2142      * been published and it has no subscribers.  For performance sake, we
       
  2143      * immediate exit in this case.  This means the event won't bubble, so
       
  2144      * if the intention is that a bubble target be notified, the event must
       
  2145      * be published on this object first.
       
  2146      *
       
  2147      * @method fire
       
  2148      * @param type {String|Object} The type of the event, or an object that contains
       
  2149      * a 'type' property.
       
  2150      * @param arguments {Object*} an arbitrary set of parameters to pass to
       
  2151      * the handler.  If the first of these is an object literal and the event is
       
  2152      * configured to emit an event facade, the event facade will replace that
       
  2153      * parameter after the properties the object literal contains are copied to
       
  2154      * the event facade.
       
  2155      * @return {Boolean} True if the whole lifecycle of the event went through,
       
  2156      * false if at any point the event propagation was halted.
       
  2157      */
       
  2158     fire: function(type) {
       
  2159 
       
  2160         var typeIncluded = (typeof type === "string"),
       
  2161             argCount = arguments.length,
       
  2162             t = type,
       
  2163             yuievt = this._yuievt,
       
  2164             etConfig = yuievt.config,
       
  2165             pre = etConfig.prefix,
       
  2166             ret,
       
  2167             ce,
       
  2168             ce2,
       
  2169             args;
       
  2170 
       
  2171         if (typeIncluded && argCount <= 3) {
       
  2172 
       
  2173             // PERF: Try to avoid slice/iteration for the common signatures
       
  2174 
       
  2175             // Most common
       
  2176             if (argCount === 2) {
       
  2177                 args = [arguments[1]]; // fire("foo", {})
       
  2178             } else if (argCount === 3) {
       
  2179                 args = [arguments[1], arguments[2]]; // fire("foo", {}, opts)
       
  2180             } else {
       
  2181                 args = []; // fire("foo")
       
  2182             }
       
  2183 
       
  2184         } else {
       
  2185             args = nativeSlice.call(arguments, ((typeIncluded) ? 1 : 0));
       
  2186         }
       
  2187 
       
  2188         if (!typeIncluded) {
       
  2189             t = (type && type.type);
       
  2190         }
       
  2191 
       
  2192         if (pre) {
       
  2193             t = _getType(t, pre);
       
  2194         }
       
  2195 
       
  2196         ce = yuievt.events[t];
       
  2197 
       
  2198         if (this._hasSiblings) {
       
  2199             ce2 = this.getSibling(t, ce);
       
  2200 
       
  2201             if (ce2 && !ce) {
       
  2202                 ce = this.publish(t);
       
  2203             }
       
  2204         }
       
  2205 
       
  2206         // PERF: trying to avoid function call, since this is a critical path
       
  2207         if ((etConfig.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
       
  2208             this._monitor('fire', (ce || t), {
       
  2209                 args: args
       
  2210             });
       
  2211         }
       
  2212 
       
  2213         // this event has not been published or subscribed to
       
  2214         if (!ce) {
       
  2215             if (yuievt.hasTargets) {
       
  2216                 return this.bubble({ type: t }, args, this);
       
  2217             }
       
  2218 
       
  2219             // otherwise there is nothing to be done
       
  2220             ret = true;
       
  2221         } else {
       
  2222 
       
  2223             if (ce2) {
       
  2224                 ce.sibling = ce2;
       
  2225             }
       
  2226 
       
  2227             ret = ce._fire(args);
       
  2228         }
       
  2229 
       
  2230         return (yuievt.chain) ? this : ret;
       
  2231     },
       
  2232 
       
  2233     getSibling: function(type, ce) {
       
  2234         var ce2;
       
  2235 
       
  2236         // delegate to *:type events if there are subscribers
       
  2237         if (type.indexOf(PREFIX_DELIMITER) > -1) {
       
  2238             type = _wildType(type);
       
  2239             ce2 = this.getEvent(type, true);
       
  2240             if (ce2) {
       
  2241                 ce2.applyConfig(ce);
       
  2242                 ce2.bubbles = false;
       
  2243                 ce2.broadcast = 0;
       
  2244             }
       
  2245         }
       
  2246 
       
  2247         return ce2;
       
  2248     },
       
  2249 
       
  2250     /**
       
  2251      * Returns the custom event of the provided type has been created, a
       
  2252      * falsy value otherwise
       
  2253      * @method getEvent
       
  2254      * @param type {String} the type, or name of the event
       
  2255      * @param prefixed {String} if true, the type is prefixed already
       
  2256      * @return {CustomEvent} the custom event or null
       
  2257      */
       
  2258     getEvent: function(type, prefixed) {
       
  2259         var pre, e;
       
  2260 
       
  2261         if (!prefixed) {
       
  2262             pre = this._yuievt.config.prefix;
       
  2263             type = (pre) ? _getType(type, pre) : type;
       
  2264         }
       
  2265         e = this._yuievt.events;
       
  2266         return e[type] || null;
       
  2267     },
       
  2268 
       
  2269     /**
       
  2270      * Subscribe to a custom event hosted by this object.  The
       
  2271      * supplied callback will execute after any listeners add
       
  2272      * via the subscribe method, and after the default function,
       
  2273      * if configured for the event, has executed.
       
  2274      *
       
  2275      * @method after
       
  2276      * @param {String} type The name of the event
       
  2277      * @param {Function} fn The callback to execute in response to the event
       
  2278      * @param {Object} [context] Override `this` object in callback
       
  2279      * @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  2280      * @return {EventHandle} A subscription handle capable of detaching the
       
  2281      *                       subscription
       
  2282      */
       
  2283     after: function(type, fn) {
       
  2284 
       
  2285         var a = nativeSlice.call(arguments, 0);
       
  2286 
       
  2287         switch (L.type(type)) {
       
  2288             case 'function':
       
  2289                 return Y.Do.after.apply(Y.Do, arguments);
       
  2290             case 'array':
       
  2291             //     YArray.each(a[0], function(v) {
       
  2292             //         v = AFTER_PREFIX + v;
       
  2293             //     });
       
  2294             //     break;
       
  2295             case 'object':
       
  2296                 a[0]._after = true;
       
  2297                 break;
       
  2298             default:
       
  2299                 a[0] = AFTER_PREFIX + type;
       
  2300         }
       
  2301 
       
  2302         return this.on.apply(this, a);
       
  2303 
       
  2304     },
       
  2305 
       
  2306     /**
       
  2307      * Executes the callback before a DOM event, custom event
       
  2308      * or method.  If the first argument is a function, it
       
  2309      * is assumed the target is a method.  For DOM and custom
       
  2310      * events, this is an alias for Y.on.
       
  2311      *
       
  2312      * For DOM and custom events:
       
  2313      * type, callback, context, 0-n arguments
       
  2314      *
       
  2315      * For methods:
       
  2316      * callback, object (method host), methodName, context, 0-n arguments
       
  2317      *
       
  2318      * @method before
       
  2319      * @return detach handle
       
  2320      */
       
  2321     before: function() {
       
  2322         return this.on.apply(this, arguments);
       
  2323     }
       
  2324 
       
  2325 };
       
  2326 
       
  2327 Y.EventTarget = ET;
       
  2328 
       
  2329 // make Y an event target
       
  2330 Y.mix(Y, ET.prototype);
       
  2331 ET.call(Y, { bubbles: false });
       
  2332 
       
  2333 YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
       
  2334 
       
  2335 /**
       
  2336  * Hosts YUI page level events.  This is where events bubble to
       
  2337  * when the broadcast config is set to 2.  This property is
       
  2338  * only available if the custom event module is loaded.
       
  2339  * @property Global
       
  2340  * @type EventTarget
       
  2341  * @for YUI
       
  2342  */
       
  2343 Y.Global = YUI.Env.globalEvents;
       
  2344 
       
  2345 // @TODO implement a global namespace function on Y.Global?
       
  2346 
       
  2347 /**
       
  2348 `Y.on()` can do many things:
       
  2349 
       
  2350 <ul>
       
  2351     <li>Subscribe to custom events `publish`ed and `fire`d from Y</li>
       
  2352     <li>Subscribe to custom events `publish`ed with `broadcast` 1 or 2 and
       
  2353         `fire`d from any object in the YUI instance sandbox</li>
       
  2354     <li>Subscribe to DOM events</li>
       
  2355     <li>Subscribe to the execution of a method on any object, effectively
       
  2356     treating that method as an event</li>
       
  2357 </ul>
       
  2358 
       
  2359 For custom event subscriptions, pass the custom event name as the first argument
       
  2360 and callback as the second. The `this` object in the callback will be `Y` unless
       
  2361 an override is passed as the third argument.
       
  2362 
       
  2363     Y.on('io:complete', function () {
       
  2364         Y.MyApp.updateStatus('Transaction complete');
       
  2365     });
       
  2366 
       
  2367 To subscribe to DOM events, pass the name of a DOM event as the first argument
       
  2368 and a CSS selector string as the third argument after the callback function.
       
  2369 Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`,
       
  2370 array, or simply omitted (the default is the `window` object).
       
  2371 
       
  2372     Y.on('click', function (e) {
       
  2373         e.preventDefault();
       
  2374 
       
  2375         // proceed with ajax form submission
       
  2376         var url = this.get('action');
       
  2377         ...
       
  2378     }, '#my-form');
       
  2379 
       
  2380 The `this` object in DOM event callbacks will be the `Node` targeted by the CSS
       
  2381 selector or other identifier.
       
  2382 
       
  2383 `on()` subscribers for DOM events or custom events `publish`ed with a
       
  2384 `defaultFn` can prevent the default behavior with `e.preventDefault()` from the
       
  2385 event object passed as the first parameter to the subscription callback.
       
  2386 
       
  2387 To subscribe to the execution of an object method, pass arguments corresponding to the call signature for
       
  2388 <a href="../classes/Do.html#methods_before">`Y.Do.before(...)`</a>.
       
  2389 
       
  2390 NOTE: The formal parameter list below is for events, not for function
       
  2391 injection.  See `Y.Do.before` for that signature.
       
  2392 
       
  2393 @method on
       
  2394 @param {String} type DOM or custom event name
       
  2395 @param {Function} fn The callback to execute in response to the event
       
  2396 @param {Object} [context] Override `this` object in callback
       
  2397 @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  2398 @return {EventHandle} A subscription handle capable of detaching the
       
  2399                       subscription
       
  2400 @see Do.before
       
  2401 @for YUI
       
  2402 **/
       
  2403 
       
  2404 /**
       
  2405 Listen for an event one time.  Equivalent to `on()`, except that
       
  2406 the listener is immediately detached when executed.
       
  2407 
       
  2408 See the <a href="#methods_on">`on()` method</a> for additional subscription
       
  2409 options.
       
  2410 
       
  2411 @see on
       
  2412 @method once
       
  2413 @param {String} type DOM or custom event name
       
  2414 @param {Function} fn The callback to execute in response to the event
       
  2415 @param {Object} [context] Override `this` object in callback
       
  2416 @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  2417 @return {EventHandle} A subscription handle capable of detaching the
       
  2418                       subscription
       
  2419 @for YUI
       
  2420 **/
       
  2421 
       
  2422 /**
       
  2423 Listen for an event one time.  Equivalent to `once()`, except, like `after()`,
       
  2424 the subscription callback executes after all `on()` subscribers and the event's
       
  2425 `defaultFn` (if configured) have executed.  Like `after()` if any `on()` phase
       
  2426 subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()`
       
  2427 subscribers will execute.
       
  2428 
       
  2429 The listener is immediately detached when executed.
       
  2430 
       
  2431 See the <a href="#methods_on">`on()` method</a> for additional subscription
       
  2432 options.
       
  2433 
       
  2434 @see once
       
  2435 @method onceAfter
       
  2436 @param {String} type The custom event name
       
  2437 @param {Function} fn The callback to execute in response to the event
       
  2438 @param {Object} [context] Override `this` object in callback
       
  2439 @param {Any} [arg*] 0..n additional arguments to supply to the subscriber
       
  2440 @return {EventHandle} A subscription handle capable of detaching the
       
  2441                       subscription
       
  2442 @for YUI
       
  2443 **/
       
  2444 
       
  2445 /**
       
  2446 Like `on()`, this method creates a subscription to a custom event or to the
       
  2447 execution of a method on an object.
       
  2448 
       
  2449 For events, `after()` subscribers are executed after the event's
       
  2450 `defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber.
       
  2451 
       
  2452 See the <a href="#methods_on">`on()` method</a> for additional subscription
       
  2453 options.
       
  2454 
       
  2455 NOTE: The subscription signature shown is for events, not for function
       
  2456 injection.  See <a href="../classes/Do.html#methods_after">`Y.Do.after`</a>
       
  2457 for that signature.
       
  2458 
       
  2459 @see on
       
  2460 @see Do.after
       
  2461 @method after
       
  2462 @param {String} type The custom event name
       
  2463 @param {Function} fn The callback to execute in response to the event
       
  2464 @param {Object} [context] Override `this` object in callback
       
  2465 @param {Any} [args*] 0..n additional arguments to supply to the subscriber
       
  2466 @return {EventHandle} A subscription handle capable of detaching the
       
  2467                       subscription
       
  2468 @for YUI
       
  2469 **/
       
  2470 
       
  2471 
       
  2472 }, '@VERSION@', {"requires": ["oop"]});