]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-base.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / event-custom / event-custom-base.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('event-custom-base', function(Y) {
9
10 /**
11  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
12  * events.
13  * @module event-custom
14  */
15
16 Y.Env.evt = {
17     handles: {},
18     plugins: {}
19 };
20
21
22 /**
23  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
24  * events.
25  * @module event-custom
26  * @submodule event-custom-base
27  */
28
29 /**
30  * Allows for the insertion of methods that are executed before or after
31  * a specified method
32  * @class Do
33  * @static
34  */
35
36 var DO_BEFORE = 0,
37     DO_AFTER = 1,
38
39 DO = {
40
41     /**
42      * Cache of objects touched by the utility
43      * @property objs
44      * @static
45      */
46     objs: {},
47
48     /**
49      * Execute the supplied method before the specified function
50      * @method before
51      * @param fn {Function} the function to execute
52      * @param obj the object hosting the method to displace
53      * @param sFn {string} the name of the method to displace
54      * @param c The execution context for fn
55      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
56      * when the event fires.
57      * @return {string} handle for the subscription
58      * @static
59      */
60     before: function(fn, obj, sFn, c) {
61         var f = fn, a;
62         if (c) {
63             a = [fn, c].concat(Y.Array(arguments, 4, true));
64             f = Y.rbind.apply(Y, a);
65         }
66
67         return this._inject(DO_BEFORE, f, obj, sFn);
68     },
69
70     /**
71      * Execute the supplied method after the specified function
72      * @method after
73      * @param fn {Function} the function to execute
74      * @param obj the object hosting the method to displace
75      * @param sFn {string} the name of the method to displace
76      * @param c The execution context for fn
77      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
78      * @return {string} handle for the subscription
79      * @static
80      */
81     after: function(fn, obj, sFn, c) {
82         var f = fn, a;
83         if (c) {
84             a = [fn, c].concat(Y.Array(arguments, 4, true));
85             f = Y.rbind.apply(Y, a);
86         }
87
88         return this._inject(DO_AFTER, f, obj, sFn);
89     },
90
91     /**
92      * Execute the supplied method after the specified function
93      * @method _inject
94      * @param when {string} before or after
95      * @param fn {Function} the function to execute
96      * @param obj the object hosting the method to displace
97      * @param sFn {string} the name of the method to displace
98      * @param c The execution context for fn
99      * @return {string} handle for the subscription
100      * @private
101      * @static
102      */
103     _inject: function(when, fn, obj, sFn) {
104
105         // object id
106         var id = Y.stamp(obj), o, sid;
107
108         if (! this.objs[id]) {
109             // create a map entry for the obj if it doesn't exist
110             this.objs[id] = {};
111         }
112
113         o = this.objs[id];
114
115         if (! o[sFn]) {
116             // create a map entry for the method if it doesn't exist
117             o[sFn] = new Y.Do.Method(obj, sFn);
118
119             // re-route the method to our wrapper
120             obj[sFn] =
121                 function() {
122                     return o[sFn].exec.apply(o[sFn], arguments);
123                 };
124         }
125
126         // subscriber id
127         sid = id + Y.stamp(fn) + sFn;
128
129         // register the callback
130         o[sFn].register(sid, fn, when);
131
132         return new Y.EventHandle(o[sFn], sid);
133
134     },
135
136     /**
137      * Detach a before or after subscription
138      * @method detach
139      * @param handle {string} the subscription handle
140      */
141     detach: function(handle) {
142
143         if (handle.detach) {
144             handle.detach();
145         }
146
147     },
148
149     _unload: function(e, me) {
150
151     }
152 };
153
154 Y.Do = DO;
155
156 //////////////////////////////////////////////////////////////////////////
157
158 /**
159  * Contains the return value from the wrapped method, accessible
160  * by 'after' event listeners.
161  *
162  * @property Do.originalRetVal
163  * @static
164  * @since 2.3.0
165  */
166
167 /**
168  * Contains the current state of the return value, consumable by
169  * 'after' event listeners, and updated if an after subscriber
170  * changes the return value generated by the wrapped function.
171  *
172  * @property Do.currentRetVal
173  * @static
174  * @since 2.3.0
175  */
176
177 //////////////////////////////////////////////////////////////////////////
178
179 /**
180  * Wrapper for a displaced method with aop enabled
181  * @class Do.Method
182  * @constructor
183  * @param obj The object to operate on
184  * @param sFn The name of the method to displace
185  */
186 DO.Method = function(obj, sFn) {
187     this.obj = obj;
188     this.methodName = sFn;
189     this.method = obj[sFn];
190     this.before = {};
191     this.after = {};
192 };
193
194 /**
195  * Register a aop subscriber
196  * @method register
197  * @param sid {string} the subscriber id
198  * @param fn {Function} the function to execute
199  * @param when {string} when to execute the function
200  */
201 DO.Method.prototype.register = function (sid, fn, when) {
202     if (when) {
203         this.after[sid] = fn;
204     } else {
205         this.before[sid] = fn;
206     }
207 };
208
209 /**
210  * Unregister a aop subscriber
211  * @method delete
212  * @param sid {string} the subscriber id
213  * @param fn {Function} the function to execute
214  * @param when {string} when to execute the function
215  */
216 DO.Method.prototype._delete = function (sid) {
217     delete this.before[sid];
218     delete this.after[sid];
219 };
220
221 /**
222  * Execute the wrapped method
223  * @method exec
224  */
225 DO.Method.prototype.exec = function () {
226
227     var args = Y.Array(arguments, 0, true),
228         i, ret, newRet,
229         bf = this.before,
230         af = this.after,
231         prevented = false;
232
233     // execute before
234     for (i in bf) {
235         if (bf.hasOwnProperty(i)) {
236             ret = bf[i].apply(this.obj, args);
237             if (ret) {
238                 switch (ret.constructor) {
239                     case DO.Halt:
240                         return ret.retVal;
241                     case DO.AlterArgs:
242                         args = ret.newArgs;
243                         break;
244                     case DO.Prevent:
245                         prevented = true;
246                         break;
247                     default:
248                 }
249             }
250         }
251     }
252
253     // execute method
254     if (!prevented) {
255         ret = this.method.apply(this.obj, args);
256     }
257
258     DO.originalRetVal = ret;
259     DO.currentRetVal = ret;
260
261     // execute after methods.
262     for (i in af) {
263         if (af.hasOwnProperty(i)) {
264             newRet = af[i].apply(this.obj, args);
265             // Stop processing if a Halt object is returned
266             if (newRet && newRet.constructor == DO.Halt) {
267                 return newRet.retVal;
268             // Check for a new return value
269             } else if (newRet && newRet.constructor == DO.AlterReturn) {
270                 ret = newRet.newRetVal;
271                 // Update the static retval state
272                 DO.currentRetVal = ret;
273             }
274         }
275     }
276
277     return ret;
278 };
279
280 //////////////////////////////////////////////////////////////////////////
281
282 /**
283  * Return an AlterArgs object when you want to change the arguments that
284  * were passed into the function.  An example would be a service that scrubs
285  * out illegal characters prior to executing the core business logic.
286  * @class Do.AlterArgs
287  */
288 DO.AlterArgs = function(msg, newArgs) {
289     this.msg = msg;
290     this.newArgs = newArgs;
291 };
292
293 /**
294  * Return an AlterReturn object when you want to change the result returned
295  * from the core method to the caller
296  * @class Do.AlterReturn
297  */
298 DO.AlterReturn = function(msg, newRetVal) {
299     this.msg = msg;
300     this.newRetVal = newRetVal;
301 };
302
303 /**
304  * Return a Halt object when you want to terminate the execution
305  * of all subsequent subscribers as well as the wrapped method
306  * if it has not exectued yet.
307  * @class Do.Halt
308  */
309 DO.Halt = function(msg, retVal) {
310     this.msg = msg;
311     this.retVal = retVal;
312 };
313
314 /**
315  * Return a Prevent object when you want to prevent the wrapped function
316  * from executing, but want the remaining listeners to execute
317  * @class Do.Prevent
318  */
319 DO.Prevent = function(msg) {
320     this.msg = msg;
321 };
322
323 /**
324  * Return an Error object when you want to terminate the execution
325  * of all subsequent method calls.
326  * @class Do.Error
327  * @deprecated use Y.Do.Halt or Y.Do.Prevent
328  */
329 DO.Error = DO.Halt;
330
331
332 //////////////////////////////////////////////////////////////////////////
333
334 // Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
335
336
337 /**
338  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
339  * events.
340  * @module event-custom
341  * @submodule event-custom-base
342  */
343
344
345 // var onsubscribeType = "_event:onsub",
346 var AFTER = 'after',
347     CONFIGS = [
348         'broadcast',
349         'monitored',
350         'bubbles',
351         'context',
352         'contextFn',
353         'currentTarget',
354         'defaultFn',
355         'defaultTargetOnly',
356         'details',
357         'emitFacade',
358         'fireOnce',
359         'async',
360         'host',
361         'preventable',
362         'preventedFn',
363         'queuable',
364         'silent',
365         'stoppedFn',
366         'target',
367         'type'
368     ],
369
370     YUI3_SIGNATURE = 9,
371     YUI_LOG = 'yui:log';
372
373 /**
374  * Return value from all subscribe operations
375  * @class EventHandle
376  * @constructor
377  * @param {CustomEvent} evt the custom event.
378  * @param {Subscriber} sub the subscriber.
379  */
380 Y.EventHandle = function(evt, sub) {
381
382     /**
383      * The custom event
384      * @type CustomEvent
385      */
386     this.evt = evt;
387
388     /**
389      * The subscriber object
390      * @type Subscriber
391      */
392     this.sub = sub;
393 };
394
395 Y.EventHandle.prototype = {
396     batch: function(f, c) {
397         f.call(c || this, this);
398         if (Y.Lang.isArray(this.evt)) {
399             Y.Array.each(this.evt, function(h) {
400                 h.batch.call(c || h, f);
401             });
402         }
403     },
404
405     /**
406      * Detaches this subscriber
407      * @method detach
408      * @return {int} the number of detached listeners
409      */
410     detach: function() {
411         var evt = this.evt, detached = 0, i;
412         if (evt) {
413             if (Y.Lang.isArray(evt)) {
414                 for (i = 0; i < evt.length; i++) {
415                     detached += evt[i].detach();
416                 }
417             } else {
418                 evt._delete(this.sub);
419                 detached = 1;
420             }
421
422         }
423
424         return detached;
425     },
426
427     /**
428      * Monitor the event state for the subscribed event.  The first parameter
429      * is what should be monitored, the rest are the normal parameters when
430      * subscribing to an event.
431      * @method monitor
432      * @param what {string} what to monitor ('attach', 'detach', 'publish').
433      * @return {EventHandle} return value from the monitor event subscription.
434      */
435     monitor: function(what) {
436         return this.evt.monitor.apply(this.evt, arguments);
437     }
438 };
439
440 /**
441  * The CustomEvent class lets you define events for your application
442  * that can be subscribed to by one or more independent component.
443  *
444  * @param {String} type The type of event, which is passed to the callback
445  * when the event fires.
446  * @param {object} o configuration object.
447  * @class CustomEvent
448  * @constructor
449  */
450 Y.CustomEvent = function(type, o) {
451
452     // if (arguments.length > 2) {
453 // this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
454     // }
455
456     o = o || {};
457
458     this.id = Y.stamp(this);
459
460     /**
461      * The type of event, returned to subscribers when the event fires
462      * @property type
463      * @type string
464      */
465     this.type = type;
466
467     /**
468      * The context the the event will fire from by default.  Defaults to the YUI
469      * instance.
470      * @property context
471      * @type object
472      */
473     this.context = Y;
474
475     /**
476      * Monitor when an event is attached or detached.
477      *
478      * @property monitored
479      * @type boolean
480      */
481     // this.monitored = false;
482
483     this.logSystem = (type == YUI_LOG);
484
485     /**
486      * If 0, this event does not broadcast.  If 1, the YUI instance is notified
487      * every time this event fires.  If 2, the YUI instance and the YUI global
488      * (if event is enabled on the global) are notified every time this event
489      * fires.
490      * @property broadcast
491      * @type int
492      */
493     // this.broadcast = 0;
494
495     /**
496      * By default all custom events are logged in the debug build, set silent
497      * to true to disable debug outpu for this event.
498      * @property silent
499      * @type boolean
500      */
501     this.silent = this.logSystem;
502
503     /**
504      * Specifies whether this event should be queued when the host is actively
505      * processing an event.  This will effect exectution order of the callbacks
506      * for the various events.
507      * @property queuable
508      * @type boolean
509      * @default false
510      */
511     // this.queuable = false;
512
513     /**
514      * The subscribers to this event
515      * @property subscribers
516      * @type Subscriber {}
517      */
518     this.subscribers = {};
519
520     /**
521      * 'After' subscribers
522      * @property afters
523      * @type Subscriber {}
524      */
525     this.afters = {};
526
527     /**
528      * This event has fired if true
529      *
530      * @property fired
531      * @type boolean
532      * @default false;
533      */
534     // this.fired = false;
535
536     /**
537      * An array containing the arguments the custom event
538      * was last fired with.
539      * @property firedWith
540      * @type Array
541      */
542     // this.firedWith;
543
544     /**
545      * This event should only fire one time if true, and if
546      * it has fired, any new subscribers should be notified
547      * immediately.
548      *
549      * @property fireOnce
550      * @type boolean
551      * @default false;
552      */
553     // this.fireOnce = false;
554
555     /**
556      * fireOnce listeners will fire syncronously unless async
557      * is set to true
558      * @property async
559      * @type boolean
560      * @default false
561      */
562     //this.async = false;
563
564     /**
565      * Flag for stopPropagation that is modified during fire()
566      * 1 means to stop propagation to bubble targets.  2 means
567      * to also stop additional subscribers on this target.
568      * @property stopped
569      * @type int
570      */
571     // this.stopped = 0;
572
573     /**
574      * Flag for preventDefault that is modified during fire().
575      * if it is not 0, the default behavior for this event
576      * @property prevented
577      * @type int
578      */
579     // this.prevented = 0;
580
581     /**
582      * Specifies the host for this custom event.  This is used
583      * to enable event bubbling
584      * @property host
585      * @type EventTarget
586      */
587     // this.host = null;
588
589     /**
590      * The default function to execute after event listeners
591      * have fire, but only if the default action was not
592      * prevented.
593      * @property defaultFn
594      * @type Function
595      */
596     // this.defaultFn = null;
597
598     /**
599      * The function to execute if a subscriber calls
600      * stopPropagation or stopImmediatePropagation
601      * @property stoppedFn
602      * @type Function
603      */
604     // this.stoppedFn = null;
605
606     /**
607      * The function to execute if a subscriber calls
608      * preventDefault
609      * @property preventedFn
610      * @type Function
611      */
612     // this.preventedFn = null;
613
614     /**
615      * Specifies whether or not this event's default function
616      * can be cancelled by a subscriber by executing preventDefault()
617      * on the event facade
618      * @property preventable
619      * @type boolean
620      * @default true
621      */
622     this.preventable = true;
623
624     /**
625      * Specifies whether or not a subscriber can stop the event propagation
626      * via stopPropagation(), stopImmediatePropagation(), or halt()
627      *
628      * Events can only bubble if emitFacade is true.
629      *
630      * @property bubbles
631      * @type boolean
632      * @default true
633      */
634     this.bubbles = true;
635
636     /**
637      * Supports multiple options for listener signatures in order to
638      * port YUI 2 apps.
639      * @property signature
640      * @type int
641      * @default 9
642      */
643     this.signature = YUI3_SIGNATURE;
644
645     this.subCount = 0;
646     this.afterCount = 0;
647
648     // this.hasSubscribers = false;
649
650     // this.hasAfters = false;
651
652     /**
653      * If set to true, the custom event will deliver an EventFacade object
654      * that is similar to a DOM event object.
655      * @property emitFacade
656      * @type boolean
657      * @default false
658      */
659     // this.emitFacade = false;
660
661     this.applyConfig(o, true);
662
663     // this.log("Creating " + this.type);
664
665 };
666
667 Y.CustomEvent.prototype = {
668
669     hasSubs: function(when) {
670         var s = this.subCount, a = this.afterCount, sib = this.sibling;
671
672         if (sib) {
673             s += sib.subCount;
674             a += sib.afterCount;
675         }
676
677         if (when) {
678             return (when == 'after') ? a : s;
679         }
680
681         return (s + a);
682     },
683
684     /**
685      * Monitor the event state for the subscribed event.  The first parameter
686      * is what should be monitored, the rest are the normal parameters when
687      * subscribing to an event.
688      * @method monitor
689      * @param what {string} what to monitor ('detach', 'attach', 'publish').
690      * @return {EventHandle} return value from the monitor event subscription.
691      */
692     monitor: function(what) {
693         this.monitored = true;
694         var type = this.id + '|' + this.type + '_' + what,
695             args = Y.Array(arguments, 0, true);
696         args[0] = type;
697         return this.host.on.apply(this.host, args);
698     },
699
700     /**
701      * Get all of the subscribers to this event and any sibling event
702      * @method getSubs
703      * @return {Array} first item is the on subscribers, second the after.
704      */
705     getSubs: function() {
706         var s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
707
708         if (sib) {
709             Y.mix(s, sib.subscribers);
710             Y.mix(a, sib.afters);
711         }
712
713         return [s, a];
714     },
715
716     /**
717      * Apply configuration properties.  Only applies the CONFIG whitelist
718      * @method applyConfig
719      * @param o hash of properties to apply.
720      * @param force {boolean} if true, properties that exist on the event
721      * will be overwritten.
722      */
723     applyConfig: function(o, force) {
724         if (o) {
725             Y.mix(this, o, force, CONFIGS);
726         }
727     },
728
729     _on: function(fn, context, args, when) {
730
731         if (!fn) {
732             this.log('Invalid callback for CE: ' + this.type);
733         }
734
735         var s = new Y.Subscriber(fn, context, args, when);
736
737         if (this.fireOnce && this.fired) {
738             if (this.async) {
739                 setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
740             } else {
741                 this._notify(s, this.firedWith);
742             }
743         }
744
745         if (when == AFTER) {
746             this.afters[s.id] = s;
747             this.afterCount++;
748         } else {
749             this.subscribers[s.id] = s;
750             this.subCount++;
751         }
752
753         return new Y.EventHandle(this, s);
754
755     },
756
757     /**
758      * Listen for this event
759      * @method subscribe
760      * @param {Function} fn The function to execute.
761      * @return {EventHandle} Unsubscribe handle.
762      * @deprecated use on.
763      */
764     subscribe: function(fn, context) {
765         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
766         return this._on(fn, context, a, true);
767     },
768
769     /**
770      * Listen for this event
771      * @method on
772      * @param {Function} fn The function to execute.
773      * @param {object} context optional execution context.
774      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
775      * when the event fires.
776      * @return {EventHandle} An object with a detach method to detch the handler(s).
777      */
778     on: function(fn, context) {
779         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
780         if (this.host) {
781             this.host._monitor('attach', this.type, {
782                 args: arguments
783             });
784         }
785         return this._on(fn, context, a, true);
786     },
787
788     /**
789      * Listen for this event after the normal subscribers have been notified and
790      * the default behavior has been applied.  If a normal subscriber prevents the
791      * default behavior, it also prevents after listeners from firing.
792      * @method after
793      * @param {Function} fn The function to execute.
794      * @param {object} context optional execution context.
795      * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
796      * when the event fires.
797      * @return {EventHandle} handle Unsubscribe handle.
798      */
799     after: function(fn, context) {
800         var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
801         return this._on(fn, context, a, AFTER);
802     },
803
804     /**
805      * Detach listeners.
806      * @method detach
807      * @param {Function} fn  The subscribed function to remove, if not supplied
808      *                       all will be removed.
809      * @param {Object}   context The context object passed to subscribe.
810      * @return {int} returns the number of subscribers unsubscribed.
811      */
812     detach: function(fn, context) {
813         // unsubscribe handle
814         if (fn && fn.detach) {
815             return fn.detach();
816         }
817
818         var i, s,
819             found = 0,
820             subs = Y.merge(this.subscribers, this.afters);
821
822         for (i in subs) {
823             if (subs.hasOwnProperty(i)) {
824                 s = subs[i];
825                 if (s && (!fn || fn === s.fn)) {
826                     this._delete(s);
827                     found++;
828                 }
829             }
830         }
831
832         return found;
833     },
834
835     /**
836      * Detach listeners.
837      * @method unsubscribe
838      * @param {Function} fn  The subscribed function to remove, if not supplied
839      *                       all will be removed.
840      * @param {Object}   context The context object passed to subscribe.
841      * @return {int|undefined} returns the number of subscribers unsubscribed.
842      * @deprecated use detach.
843      */
844     unsubscribe: function() {
845         return this.detach.apply(this, arguments);
846     },
847
848     /**
849      * Notify a single subscriber
850      * @method _notify
851      * @param {Subscriber} s the subscriber.
852      * @param {Array} args the arguments array to apply to the listener.
853      * @private
854      */
855     _notify: function(s, args, ef) {
856
857         this.log(this.type + '->' + 'sub: ' + s.id);
858
859         var ret;
860
861         ret = s.notify(args, this);
862
863         if (false === ret || this.stopped > 1) {
864             this.log(this.type + ' cancelled by subscriber');
865             return false;
866         }
867
868         return true;
869     },
870
871     /**
872      * Logger abstraction to centralize the application of the silent flag
873      * @method log
874      * @param {string} msg message to log.
875      * @param {string} cat log category.
876      */
877     log: function(msg, cat) {
878         if (!this.silent) {
879         }
880     },
881
882     /**
883      * Notifies the subscribers.  The callback functions will be executed
884      * from the context specified when the event was created, and with the
885      * following parameters:
886      *   <ul>
887      *   <li>The type of event</li>
888      *   <li>All of the arguments fire() was executed with as an array</li>
889      *   <li>The custom object (if any) that was passed into the subscribe()
890      *       method</li>
891      *   </ul>
892      * @method fire
893      * @param {Object*} arguments an arbitrary set of parameters to pass to
894      *                            the handler.
895      * @return {boolean} false if one of the subscribers returned false,
896      *                   true otherwise.
897      *
898      */
899     fire: function() {
900         if (this.fireOnce && this.fired) {
901             this.log('fireOnce event: ' + this.type + ' already fired');
902             return true;
903         } else {
904
905             var args = Y.Array(arguments, 0, true);
906
907             // this doesn't happen if the event isn't published
908             // this.host._monitor('fire', this.type, args);
909
910             this.fired = true;
911             this.firedWith = args;
912
913             if (this.emitFacade) {
914                 return this.fireComplex(args);
915             } else {
916                 return this.fireSimple(args);
917             }
918         }
919     },
920
921     fireSimple: function(args) {
922         this.stopped = 0;
923         this.prevented = 0;
924         if (this.hasSubs()) {
925             // this._procSubs(Y.merge(this.subscribers, this.afters), args);
926             var subs = this.getSubs();
927             this._procSubs(subs[0], args);
928             this._procSubs(subs[1], args);
929         }
930         this._broadcast(args);
931         return this.stopped ? false : true;
932     },
933
934     // Requires the event-custom-complex module for full funcitonality.
935     fireComplex: function(args) {
936         args[0] = args[0] || {};
937         return this.fireSimple(args);
938     },
939
940     _procSubs: function(subs, args, ef) {
941         var s, i;
942         for (i in subs) {
943             if (subs.hasOwnProperty(i)) {
944                 s = subs[i];
945                 if (s && s.fn) {
946                     if (false === this._notify(s, args, ef)) {
947                         this.stopped = 2;
948                     }
949                     if (this.stopped == 2) {
950                         return false;
951                     }
952                 }
953             }
954         }
955
956         return true;
957     },
958
959     _broadcast: function(args) {
960         if (!this.stopped && this.broadcast) {
961
962             var a = Y.Array(args);
963             a.unshift(this.type);
964
965             if (this.host !== Y) {
966                 Y.fire.apply(Y, a);
967             }
968
969             if (this.broadcast == 2) {
970                 Y.Global.fire.apply(Y.Global, a);
971             }
972         }
973     },
974
975     /**
976      * Removes all listeners
977      * @method unsubscribeAll
978      * @return {int} The number of listeners unsubscribed.
979      * @deprecated use detachAll.
980      */
981     unsubscribeAll: function() {
982         return this.detachAll.apply(this, arguments);
983     },
984
985     /**
986      * Removes all listeners
987      * @method detachAll
988      * @return {int} The number of listeners unsubscribed.
989      */
990     detachAll: function() {
991         return this.detach();
992     },
993
994     /**
995      * @method _delete
996      * @param subscriber object.
997      * @private
998      */
999     _delete: function(s) {
1000         if (s) {
1001             if (this.subscribers[s.id]) {
1002                 delete this.subscribers[s.id];
1003                 this.subCount--;
1004             }
1005             if (this.afters[s.id]) {
1006                 delete this.afters[s.id];
1007                 this.afterCount--;
1008             }
1009         }
1010
1011         if (this.host) {
1012             this.host._monitor('detach', this.type, {
1013                 ce: this,
1014                 sub: s
1015             });
1016         }
1017
1018         if (s) {
1019             // delete s.fn;
1020             // delete s.context;
1021             s.deleted = true;
1022         }
1023     }
1024 };
1025
1026 /////////////////////////////////////////////////////////////////////
1027
1028 /**
1029  * Stores the subscriber information to be used when the event fires.
1030  * @param {Function} fn       The wrapped function to execute.
1031  * @param {Object}   context  The value of the keyword 'this' in the listener.
1032  * @param {Array} args*       0..n additional arguments to supply the listener.
1033  *
1034  * @class Subscriber
1035  * @constructor
1036  */
1037 Y.Subscriber = function(fn, context, args) {
1038
1039     /**
1040      * The callback that will be execute when the event fires
1041      * This is wrapped by Y.rbind if obj was supplied.
1042      * @property fn
1043      * @type Function
1044      */
1045     this.fn = fn;
1046
1047     /**
1048      * Optional 'this' keyword for the listener
1049      * @property context
1050      * @type Object
1051      */
1052     this.context = context;
1053
1054     /**
1055      * Unique subscriber id
1056      * @property id
1057      * @type String
1058      */
1059     this.id = Y.stamp(this);
1060
1061     /**
1062      * Additional arguments to propagate to the subscriber
1063      * @property args
1064      * @type Array
1065      */
1066     this.args = args;
1067
1068     /**
1069      * Custom events for a given fire transaction.
1070      * @property events
1071      * @type {EventTarget}
1072      */
1073     // this.events = null;
1074
1075     /**
1076      * This listener only reacts to the event once
1077      * @property once
1078      */
1079     // this.once = false;
1080
1081 };
1082
1083 Y.Subscriber.prototype = {
1084
1085     _notify: function(c, args, ce) {
1086         if (this.deleted && !this.postponed) {
1087             if (this.postponed) {
1088                 delete this.fn;
1089                 delete this.context;
1090             } else {
1091                 delete this.postponed;
1092                 return null;
1093             }
1094         }
1095         var a = this.args, ret;
1096         switch (ce.signature) {
1097             case 0:
1098                 ret = this.fn.call(c, ce.type, args, c);
1099                 break;
1100             case 1:
1101                 ret = this.fn.call(c, args[0] || null, c);
1102                 break;
1103             default:
1104                 if (a || args) {
1105                     args = args || [];
1106                     a = (a) ? args.concat(a) : args;
1107                     ret = this.fn.apply(c, a);
1108                 } else {
1109                     ret = this.fn.call(c);
1110                 }
1111         }
1112
1113         if (this.once) {
1114             ce._delete(this);
1115         }
1116
1117         return ret;
1118     },
1119
1120     /**
1121      * Executes the subscriber.
1122      * @method notify
1123      * @param args {Array} Arguments array for the subscriber.
1124      * @param ce {CustomEvent} The custom event that sent the notification.
1125      */
1126     notify: function(args, ce) {
1127         var c = this.context,
1128             ret = true;
1129
1130         if (!c) {
1131             c = (ce.contextFn) ? ce.contextFn() : ce.context;
1132         }
1133
1134         // only catch errors if we will not re-throw them.
1135         if (Y.config.throwFail) {
1136             ret = this._notify(c, args, ce);
1137         } else {
1138             try {
1139                 ret = this._notify(c, args, ce);
1140             } catch (e) {
1141                 Y.error(this + ' failed: ' + e.message, e);
1142             }
1143         }
1144
1145         return ret;
1146     },
1147
1148     /**
1149      * Returns true if the fn and obj match this objects properties.
1150      * Used by the unsubscribe method to match the right subscriber.
1151      *
1152      * @method contains
1153      * @param {Function} fn the function to execute.
1154      * @param {Object} context optional 'this' keyword for the listener.
1155      * @return {boolean} true if the supplied arguments match this
1156      *                   subscriber's signature.
1157      */
1158     contains: function(fn, context) {
1159         if (context) {
1160             return ((this.fn == fn) && this.context == context);
1161         } else {
1162             return (this.fn == fn);
1163         }
1164     }
1165
1166 };
1167
1168 /**
1169  * Custom event engine, DOM event listener abstraction layer, synthetic DOM
1170  * events.
1171  * @module event-custom
1172  * @submodule event-custom-base
1173  */
1174
1175 /**
1176  * EventTarget provides the implementation for any object to
1177  * publish, subscribe and fire to custom events, and also
1178  * alows other EventTargets to target the object with events
1179  * sourced from the other object.
1180  * EventTarget is designed to be used with Y.augment to wrap
1181  * EventCustom in an interface that allows events to be listened to
1182  * and fired by name.  This makes it possible for implementing code to
1183  * subscribe to an event that either has not been created yet, or will
1184  * not be created at all.
1185  * @class EventTarget
1186  * @param opts a configuration object
1187  * @config emitFacade {boolean} if true, all events will emit event
1188  * facade payloads by default (default false)
1189  * @config prefix {string} the prefix to apply to non-prefixed event names
1190  * @config chain {boolean} if true, on/after/detach return the host to allow
1191  * chaining, otherwise they return an EventHandle (default false)
1192  */
1193
1194 var L = Y.Lang,
1195     PREFIX_DELIMITER = ':',
1196     CATEGORY_DELIMITER = '|',
1197     AFTER_PREFIX = '~AFTER~',
1198     YArray = Y.Array,
1199
1200     _wildType = Y.cached(function(type) {
1201         return type.replace(/(.*)(:)(.*)/, "*$2$3");
1202     }),
1203
1204     /**
1205      * If the instance has a prefix attribute and the
1206      * event type is not prefixed, the instance prefix is
1207      * applied to the supplied type.
1208      * @method _getType
1209      * @private
1210      */
1211     _getType = Y.cached(function(type, pre) {
1212
1213         if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
1214             return type;
1215         }
1216
1217         return pre + PREFIX_DELIMITER + type;
1218     }),
1219
1220     /**
1221      * Returns an array with the detach key (if provided),
1222      * and the prefixed event name from _getType
1223      * Y.on('detachcategory| menu:click', fn)
1224      * @method _parseType
1225      * @private
1226      */
1227     _parseType = Y.cached(function(type, pre) {
1228
1229         var t = type, detachcategory, after, i;
1230
1231         if (!L.isString(t)) {
1232             return t;
1233         }
1234
1235         i = t.indexOf(AFTER_PREFIX);
1236
1237         if (i > -1) {
1238             after = true;
1239             t = t.substr(AFTER_PREFIX.length);
1240         }
1241
1242         i = t.indexOf(CATEGORY_DELIMITER);
1243
1244         if (i > -1) {
1245             detachcategory = t.substr(0, (i));
1246             t = t.substr(i+1);
1247             if (t == '*') {
1248                 t = null;
1249             }
1250         }
1251
1252         // detach category, full type with instance prefix, is this an after listener, short type
1253         return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
1254     }),
1255
1256     ET = function(opts) {
1257
1258
1259         var o = (L.isObject(opts)) ? opts : {};
1260
1261         this._yuievt = this._yuievt || {
1262
1263             id: Y.guid(),
1264
1265             events: {},
1266
1267             targets: {},
1268
1269             config: o,
1270
1271             chain: ('chain' in o) ? o.chain : Y.config.chain,
1272
1273             bubbling: false,
1274
1275             defaults: {
1276                 context: o.context || this,
1277                 host: this,
1278                 emitFacade: o.emitFacade,
1279                 fireOnce: o.fireOnce,
1280                 queuable: o.queuable,
1281                 monitored: o.monitored,
1282                 broadcast: o.broadcast,
1283                 defaultTargetOnly: o.defaultTargetOnly,
1284                 bubbles: ('bubbles' in o) ? o.bubbles : true
1285             }
1286         };
1287
1288     };
1289
1290
1291 ET.prototype = {
1292
1293     /**
1294      * Listen to a custom event hosted by this object one time.
1295      * This is the equivalent to <code>on</code> except the
1296      * listener is immediatelly detached when it is executed.
1297      * @method once
1298      * @param type    {string}   The type of the event
1299      * @param fn {Function} The callback
1300      * @param context {object} optional execution context.
1301      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1302      * @return the event target or a detach handle per 'chain' config
1303      */
1304     once: function() {
1305         var handle = this.on.apply(this, arguments);
1306         handle.batch(function(hand) {
1307             if (hand.sub) {
1308                 hand.sub.once = true;
1309             }
1310         });
1311         return handle;
1312     },
1313
1314     /**
1315      * Takes the type parameter passed to 'on' and parses out the
1316      * various pieces that could be included in the type.  If the
1317      * event type is passed without a prefix, it will be expanded
1318      * to include the prefix one is supplied or the event target
1319      * is configured with a default prefix.
1320      * @method parseType
1321      * @param {string} type the type
1322      * @param {string} [pre=this._yuievt.config.prefix] the prefix
1323      * @since 3.3.0
1324      * @return {Array} an array containing:
1325      *  * the detach category, if supplied,
1326      *  * the prefixed event type,
1327      *  * whether or not this is an after listener,
1328      *  * the supplied event type
1329      */
1330     parseType: function(type, pre) {
1331         return _parseType(type, pre || this._yuievt.config.prefix);
1332     },
1333
1334     /**
1335      * Subscribe to a custom event hosted by this object
1336      * @method on
1337      * @param type    {string}   The type of the event
1338      * @param fn {Function} The callback
1339      * @param context {object} optional execution context.
1340      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1341      * @return the event target or a detach handle per 'chain' config
1342      */
1343     on: function(type, fn, context) {
1344
1345         var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
1346             detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
1347             Node = Y.Node, n, domevent, isArr;
1348
1349         // full name, args, detachcategory, after
1350         this._monitor('attach', parts[1], {
1351             args: arguments,
1352             category: parts[0],
1353             after: parts[2]
1354         });
1355
1356         if (L.isObject(type)) {
1357
1358             if (L.isFunction(type)) {
1359                 return Y.Do.before.apply(Y.Do, arguments);
1360             }
1361
1362             f = fn;
1363             c = context;
1364             args = YArray(arguments, 0, true);
1365             ret = [];
1366
1367             if (L.isArray(type)) {
1368                 isArr = true;
1369             }
1370
1371             after = type._after;
1372             delete type._after;
1373
1374             Y.each(type, function(v, k) {
1375
1376                 if (L.isObject(v)) {
1377                     f = v.fn || ((L.isFunction(v)) ? v : f);
1378                     c = v.context || c;
1379                 }
1380
1381                 var nv = (after) ? AFTER_PREFIX : '';
1382
1383                 args[0] = nv + ((isArr) ? v : k);
1384                 args[1] = f;
1385                 args[2] = c;
1386
1387                 ret.push(this.on.apply(this, args));
1388
1389             }, this);
1390
1391             return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
1392
1393         }
1394
1395         detachcategory = parts[0];
1396         after = parts[2];
1397         shorttype = parts[3];
1398
1399         // extra redirection so we catch adaptor events too.  take a look at this.
1400         if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
1401             args = YArray(arguments, 0, true);
1402             args.splice(2, 0, Node.getDOMNode(this));
1403             return Y.on.apply(Y, args);
1404         }
1405
1406         type = parts[1];
1407
1408         if (Y.instanceOf(this, YUI)) {
1409
1410             adapt = Y.Env.evt.plugins[type];
1411             args  = YArray(arguments, 0, true);
1412             args[0] = shorttype;
1413
1414             if (Node) {
1415                 n = args[2];
1416
1417                 if (Y.instanceOf(n, Y.NodeList)) {
1418                     n = Y.NodeList.getDOMNodes(n);
1419                 } else if (Y.instanceOf(n, Node)) {
1420                     n = Node.getDOMNode(n);
1421                 }
1422
1423                 domevent = (shorttype in Node.DOM_EVENTS);
1424
1425                 // Captures both DOM events and event plugins.
1426                 if (domevent) {
1427                     args[2] = n;
1428                 }
1429             }
1430
1431             // check for the existance of an event adaptor
1432             if (adapt) {
1433                 handle = adapt.on.apply(Y, args);
1434             } else if ((!type) || domevent) {
1435                 handle = Y.Event._attach(args);
1436             }
1437
1438         }
1439
1440         if (!handle) {
1441             ce = this._yuievt.events[type] || this.publish(type);
1442             handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
1443         }
1444
1445         if (detachcategory) {
1446             store[detachcategory] = store[detachcategory] || {};
1447             store[detachcategory][type] = store[detachcategory][type] || [];
1448             store[detachcategory][type].push(handle);
1449         }
1450
1451         return (this._yuievt.chain) ? this : handle;
1452
1453     },
1454
1455     /**
1456      * subscribe to an event
1457      * @method subscribe
1458      * @deprecated use on
1459      */
1460     subscribe: function() {
1461         return this.on.apply(this, arguments);
1462     },
1463
1464     /**
1465      * Detach one or more listeners the from the specified event
1466      * @method detach
1467      * @param type {string|Object}   Either the handle to the subscriber or the
1468      *                        type of event.  If the type
1469      *                        is not specified, it will attempt to remove
1470      *                        the listener from all hosted events.
1471      * @param fn   {Function} The subscribed function to unsubscribe, if not
1472      *                          supplied, all subscribers will be removed.
1473      * @param context  {Object}   The custom object passed to subscribe.  This is
1474      *                        optional, but if supplied will be used to
1475      *                        disambiguate multiple listeners that are the same
1476      *                        (e.g., you subscribe many object using a function
1477      *                        that lives on the prototype)
1478      * @return {EventTarget} the host
1479      */
1480     detach: function(type, fn, context) {
1481         var evts = this._yuievt.events, i,
1482             Node = Y.Node, isNode = Node && (Y.instanceOf(this, Node));
1483
1484         // detachAll disabled on the Y instance.
1485         if (!type && (this !== Y)) {
1486             for (i in evts) {
1487                 if (evts.hasOwnProperty(i)) {
1488                     evts[i].detach(fn, context);
1489                 }
1490             }
1491             if (isNode) {
1492                 Y.Event.purgeElement(Node.getDOMNode(this));
1493             }
1494
1495             return this;
1496         }
1497
1498         var parts = _parseType(type, this._yuievt.config.prefix),
1499         detachcategory = L.isArray(parts) ? parts[0] : null,
1500         shorttype = (parts) ? parts[3] : null,
1501         adapt, store = Y.Env.evt.handles, detachhost, cat, args,
1502         ce,
1503
1504         keyDetacher = function(lcat, ltype, host) {
1505             var handles = lcat[ltype], ce, i;
1506             if (handles) {
1507                 for (i = handles.length - 1; i >= 0; --i) {
1508                     ce = handles[i].evt;
1509                     if (ce.host === host || ce.el === host) {
1510                         handles[i].detach();
1511                     }
1512                 }
1513             }
1514         };
1515
1516         if (detachcategory) {
1517
1518             cat = store[detachcategory];
1519             type = parts[1];
1520             detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
1521
1522             if (cat) {
1523                 if (type) {
1524                     keyDetacher(cat, type, detachhost);
1525                 } else {
1526                     for (i in cat) {
1527                         if (cat.hasOwnProperty(i)) {
1528                             keyDetacher(cat, i, detachhost);
1529                         }
1530                     }
1531                 }
1532
1533                 return this;
1534             }
1535
1536         // If this is an event handle, use it to detach
1537         } else if (L.isObject(type) && type.detach) {
1538             type.detach();
1539             return this;
1540         // extra redirection so we catch adaptor events too.  take a look at this.
1541         } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
1542             args = YArray(arguments, 0, true);
1543             args[2] = Node.getDOMNode(this);
1544             Y.detach.apply(Y, args);
1545             return this;
1546         }
1547
1548         adapt = Y.Env.evt.plugins[shorttype];
1549
1550         // The YUI instance handles DOM events and adaptors
1551         if (Y.instanceOf(this, YUI)) {
1552             args = YArray(arguments, 0, true);
1553             // use the adaptor specific detach code if
1554             if (adapt && adapt.detach) {
1555                 adapt.detach.apply(Y, args);
1556                 return this;
1557             // DOM event fork
1558             } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
1559                 args[0] = type;
1560                 Y.Event.detach.apply(Y.Event, args);
1561                 return this;
1562             }
1563         }
1564
1565         // ce = evts[type];
1566         ce = evts[parts[1]];
1567         if (ce) {
1568             ce.detach(fn, context);
1569         }
1570
1571         return this;
1572     },
1573
1574     /**
1575      * detach a listener
1576      * @method unsubscribe
1577      * @deprecated use detach
1578      */
1579     unsubscribe: function() {
1580         return this.detach.apply(this, arguments);
1581     },
1582
1583     /**
1584      * Removes all listeners from the specified event.  If the event type
1585      * is not specified, all listeners from all hosted custom events will
1586      * be removed.
1587      * @method detachAll
1588      * @param type {string}   The type, or name of the event
1589      */
1590     detachAll: function(type) {
1591         return this.detach(type);
1592     },
1593
1594     /**
1595      * Removes all listeners from the specified event.  If the event type
1596      * is not specified, all listeners from all hosted custom events will
1597      * be removed.
1598      * @method unsubscribeAll
1599      * @param type {string}   The type, or name of the event
1600      * @deprecated use detachAll
1601      */
1602     unsubscribeAll: function() {
1603         return this.detachAll.apply(this, arguments);
1604     },
1605
1606     /**
1607      * Creates a new custom event of the specified type.  If a custom event
1608      * by that name already exists, it will not be re-created.  In either
1609      * case the custom event is returned.
1610      *
1611      * @method publish
1612      *
1613      * @param type {string} the type, or name of the event
1614      * @param opts {object} optional config params.  Valid properties are:
1615      *
1616      *  <ul>
1617      *    <li>
1618      *   'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
1619      *    </li>
1620      *    <li>
1621      *   'bubbles': whether or not this event bubbles (true)
1622      *              Events can only bubble if emitFacade is true.
1623      *    </li>
1624      *    <li>
1625      *   'context': the default execution context for the listeners (this)
1626      *    </li>
1627      *    <li>
1628      *   'defaultFn': the default function to execute when this event fires if preventDefault was not called
1629      *    </li>
1630      *    <li>
1631      *   'emitFacade': whether or not this event emits a facade (false)
1632      *    </li>
1633      *    <li>
1634      *   'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
1635      *    </li>
1636      *    <li>
1637      *   'fireOnce': if an event is configured to fire once, new subscribers after
1638      *   the fire will be notified immediately.
1639      *    </li>
1640      *    <li>
1641      *   'async': fireOnce event listeners will fire synchronously if the event has already
1642      *    fired unless async is true.
1643      *    </li>
1644      *    <li>
1645      *   'preventable': whether or not preventDefault() has an effect (true)
1646      *    </li>
1647      *    <li>
1648      *   'preventedFn': a function that is executed when preventDefault is called
1649      *    </li>
1650      *    <li>
1651      *   'queuable': whether or not this event can be queued during bubbling (false)
1652      *    </li>
1653      *    <li>
1654      *   'silent': if silent is true, debug messages are not provided for this event.
1655      *    </li>
1656      *    <li>
1657      *   'stoppedFn': a function that is executed when stopPropagation is called
1658      *    </li>
1659      *
1660      *    <li>
1661      *   'monitored': specifies whether or not this event should send notifications about
1662      *   when the event has been attached, detached, or published.
1663      *    </li>
1664      *    <li>
1665      *   'type': the event type (valid option if not provided as the first parameter to publish)
1666      *    </li>
1667      *  </ul>
1668      *
1669      *  @return {CustomEvent} the custom event
1670      *
1671      */
1672     publish: function(type, opts) {
1673         var events, ce, ret, defaults,
1674             edata    = this._yuievt,
1675             pre      = edata.config.prefix;
1676
1677         type = (pre) ? _getType(type, pre) : type;
1678
1679         this._monitor('publish', type, {
1680             args: arguments
1681         });
1682
1683         if (L.isObject(type)) {
1684             ret = {};
1685             Y.each(type, function(v, k) {
1686                 ret[k] = this.publish(k, v || opts);
1687             }, this);
1688
1689             return ret;
1690         }
1691
1692         events = edata.events;
1693         ce = events[type];
1694
1695         if (ce) {
1696 // ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
1697             if (opts) {
1698                 ce.applyConfig(opts, true);
1699             }
1700         } else {
1701
1702             defaults = edata.defaults;
1703
1704             // apply defaults
1705             ce = new Y.CustomEvent(type,
1706                                   (opts) ? Y.merge(defaults, opts) : defaults);
1707             events[type] = ce;
1708         }
1709
1710         // make sure we turn the broadcast flag off if this
1711         // event was published as a result of bubbling
1712         // if (opts instanceof Y.CustomEvent) {
1713           //   events[type].broadcast = false;
1714         // }
1715
1716         return events[type];
1717     },
1718
1719     /**
1720      * This is the entry point for the event monitoring system.
1721      * You can monitor 'attach', 'detach', 'fire', and 'publish'.
1722      * When configured, these events generate an event.  click ->
1723      * click_attach, click_detach, click_publish -- these can
1724      * be subscribed to like other events to monitor the event
1725      * system.  Inividual published events can have monitoring
1726      * turned on or off (publish can't be turned off before it
1727      * it published) by setting the events 'monitor' config.
1728      *
1729      * @private
1730      */
1731     _monitor: function(what, type, o) {
1732         var monitorevt, ce = this.getEvent(type);
1733         if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
1734             monitorevt = type + '_' + what;
1735             o.monitored = what;
1736             this.fire.call(this, monitorevt, o);
1737         }
1738     },
1739
1740    /**
1741      * Fire a custom event by name.  The callback functions will be executed
1742      * from the context specified when the event was created, and with the
1743      * following parameters.
1744      *
1745      * If the custom event object hasn't been created, then the event hasn't
1746      * been published and it has no subscribers.  For performance sake, we
1747      * immediate exit in this case.  This means the event won't bubble, so
1748      * if the intention is that a bubble target be notified, the event must
1749      * be published on this object first.
1750      *
1751      * The first argument is the event type, and any additional arguments are
1752      * passed to the listeners as parameters.  If the first of these is an
1753      * object literal, and the event is configured to emit an event facade,
1754      * that object is mixed into the event facade and the facade is provided
1755      * in place of the original object.
1756      *
1757      * @method fire
1758      * @param type {String|Object} The type of the event, or an object that contains
1759      * a 'type' property.
1760      * @param arguments {Object*} an arbitrary set of parameters to pass to
1761      * the handler.  If the first of these is an object literal and the event is
1762      * configured to emit an event facade, the event facade will replace that
1763      * parameter after the properties the object literal contains are copied to
1764      * the event facade.
1765      * @return {EventTarget} the event host
1766      *
1767      */
1768     fire: function(type) {
1769
1770         var typeIncluded = L.isString(type),
1771             t = (typeIncluded) ? type : (type && type.type),
1772             ce, ret, pre = this._yuievt.config.prefix, ce2,
1773             args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
1774
1775         t = (pre) ? _getType(t, pre) : t;
1776
1777         this._monitor('fire', t, {
1778             args: args
1779         });
1780
1781         ce = this.getEvent(t, true);
1782         ce2 = this.getSibling(t, ce);
1783
1784         if (ce2 && !ce) {
1785             ce = this.publish(t);
1786         }
1787
1788         // this event has not been published or subscribed to
1789         if (!ce) {
1790             if (this._yuievt.hasTargets) {
1791                 return this.bubble({ type: t }, args, this);
1792             }
1793
1794             // otherwise there is nothing to be done
1795             ret = true;
1796         } else {
1797             ce.sibling = ce2;
1798             ret = ce.fire.apply(ce, args);
1799         }
1800
1801         return (this._yuievt.chain) ? this : ret;
1802     },
1803
1804     getSibling: function(type, ce) {
1805         var ce2;
1806         // delegate to *:type events if there are subscribers
1807         if (type.indexOf(PREFIX_DELIMITER) > -1) {
1808             type = _wildType(type);
1809             // console.log(type);
1810             ce2 = this.getEvent(type, true);
1811             if (ce2) {
1812                 // console.log("GOT ONE: " + type);
1813                 ce2.applyConfig(ce);
1814                 ce2.bubbles = false;
1815                 ce2.broadcast = 0;
1816                 // ret = ce2.fire.apply(ce2, a);
1817             }
1818         }
1819
1820         return ce2;
1821     },
1822
1823     /**
1824      * Returns the custom event of the provided type has been created, a
1825      * falsy value otherwise
1826      * @method getEvent
1827      * @param type {string} the type, or name of the event
1828      * @param prefixed {string} if true, the type is prefixed already
1829      * @return {CustomEvent} the custom event or null
1830      */
1831     getEvent: function(type, prefixed) {
1832         var pre, e;
1833         if (!prefixed) {
1834             pre = this._yuievt.config.prefix;
1835             type = (pre) ? _getType(type, pre) : type;
1836         }
1837         e = this._yuievt.events;
1838         return e[type] || null;
1839     },
1840
1841     /**
1842      * Subscribe to a custom event hosted by this object.  The
1843      * supplied callback will execute after any listeners add
1844      * via the subscribe method, and after the default function,
1845      * if configured for the event, has executed.
1846      * @method after
1847      * @param type    {string}   The type of the event
1848      * @param fn {Function} The callback
1849      * @param context {object} optional execution context.
1850      * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1851      * @return the event target or a detach handle per 'chain' config
1852      */
1853     after: function(type, fn) {
1854
1855         var a = YArray(arguments, 0, true);
1856
1857         switch (L.type(type)) {
1858             case 'function':
1859                 return Y.Do.after.apply(Y.Do, arguments);
1860             case 'array':
1861             //     YArray.each(a[0], function(v) {
1862             //         v = AFTER_PREFIX + v;
1863             //     });
1864             //     break;
1865             case 'object':
1866                 a[0]._after = true;
1867                 break;
1868             default:
1869                 a[0] = AFTER_PREFIX + type;
1870         }
1871
1872         return this.on.apply(this, a);
1873
1874     },
1875
1876     /**
1877      * Executes the callback before a DOM event, custom event
1878      * or method.  If the first argument is a function, it
1879      * is assumed the target is a method.  For DOM and custom
1880      * events, this is an alias for Y.on.
1881      *
1882      * For DOM and custom events:
1883      * type, callback, context, 0-n arguments
1884      *
1885      * For methods:
1886      * callback, object (method host), methodName, context, 0-n arguments
1887      *
1888      * @method before
1889      * @return detach handle
1890      */
1891     before: function() {
1892         return this.on.apply(this, arguments);
1893     }
1894
1895 };
1896
1897 Y.EventTarget = ET;
1898
1899 // make Y an event target
1900 Y.mix(Y, ET.prototype, false, false, {
1901     bubbles: false
1902 });
1903
1904 ET.call(Y);
1905
1906 YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
1907
1908 /**
1909  * Hosts YUI page level events.  This is where events bubble to
1910  * when the broadcast config is set to 2.  This property is
1911  * only available if the custom event module is loaded.
1912  * @property Global
1913  * @type EventTarget
1914  * @for YUI
1915  */
1916 Y.Global = YUI.Env.globalEvents;
1917
1918 // @TODO implement a global namespace function on Y.Global?
1919
1920 /**
1921  * <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
1922  * most events exposed by YUI.  This includes custom events, DOM events, and
1923  * function events.  <code>detach</code> is also provided to remove listeners
1924  * serviced by this function.
1925  *
1926  * The signature that <code>on</code> accepts varies depending on the type
1927  * of event being consumed.  Refer to the specific methods that will
1928  * service a specific request for additional information about subscribing
1929  * to that type of event.
1930  *
1931  * <ul>
1932  * <li>Custom events.  These events are defined by various
1933  * modules in the library.  This type of event is delegated to
1934  * <code>EventTarget</code>'s <code>on</code> method.
1935  *   <ul>
1936  *     <li>The type of the event</li>
1937  *     <li>The callback to execute</li>
1938  *     <li>An optional context object</li>
1939  *     <li>0..n additional arguments to supply the callback.</li>
1940  *   </ul>
1941  *   Example:
1942  *   <code>Y.on('drag:drophit', function() { // start work });</code>
1943  * </li>
1944  * <li>DOM events.  These are moments reported by the browser related
1945  * to browser functionality and user interaction.
1946  * This type of event is delegated to <code>Event</code>'s
1947  * <code>attach</code> method.
1948  *   <ul>
1949  *     <li>The type of the event</li>
1950  *     <li>The callback to execute</li>
1951  *     <li>The specification for the Node(s) to attach the listener
1952  *     to.  This can be a selector, collections, or Node/Element
1953  *     refereces.</li>
1954  *     <li>An optional context object</li>
1955  *     <li>0..n additional arguments to supply the callback.</li>
1956  *   </ul>
1957  *   Example:
1958  *   <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
1959  * </li>
1960  * <li>Function events.  These events can be used to react before or after a
1961  * function is executed.  This type of event is delegated to <code>Event.Do</code>'s
1962  * <code>before</code> method.
1963  *   <ul>
1964  *     <li>The callback to execute</li>
1965  *     <li>The object that has the function that will be listened for.</li>
1966  *     <li>The name of the function to listen for.</li>
1967  *     <li>An optional context object</li>
1968  *     <li>0..n additional arguments to supply the callback.</li>
1969  *   </ul>
1970  *   Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
1971  * </li>
1972  * </ul>
1973  *
1974  * <code>on</code> corresponds to the moment before any default behavior of
1975  * the event.  <code>after</code> works the same way, but these listeners
1976  * execute after the event's default behavior.  <code>before</code> is an
1977  * alias for <code>on</code>.
1978  *
1979  * @method on
1980  * @param type event type (this parameter does not apply for function events)
1981  * @param fn the callback
1982  * @param context optionally change the value of 'this' in the callback
1983  * @param args* 0..n additional arguments to pass to the callback.
1984  * @return the event target or a detach handle per 'chain' config
1985  * @for YUI
1986  */
1987
1988  /**
1989   * Listen for an event one time.  Equivalent to <code>on</code>, except that
1990   * the listener is immediately detached when executed.
1991   * @see on
1992   * @method once
1993   * @param type event type (this parameter does not apply for function events)
1994   * @param fn the callback
1995   * @param context optionally change the value of 'this' in the callback
1996   * @param args* 0..n additional arguments to pass to the callback.
1997   * @return the event target or a detach handle per 'chain' config
1998   * @for YUI
1999   */
2000
2001 /**
2002  * after() is a unified interface for subscribing to
2003  * most events exposed by YUI.  This includes custom events,
2004  * DOM events, and AOP events.  This works the same way as
2005  * the on() function, only it operates after any default
2006  * behavior for the event has executed. @see <code>on</code> for more
2007  * information.
2008  * @method after
2009  * @param type event type (this parameter does not apply for function events)
2010  * @param fn the callback
2011  * @param context optionally change the value of 'this' in the callback
2012  * @param args* 0..n additional arguments to pass to the callback.
2013  * @return the event target or a detach handle per 'chain' config
2014  * @for YUI
2015  */
2016
2017
2018 }, '3.3.0' ,{requires:['oop']});