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