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