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