PageSourceSearch

https://kirjanpitolautakunta.fi/o/frontend-js-aui-web/aui/event-custom-base/event-custom-base.js

js kirjanpitolautakunta.fi collected 2026-10-02 18:16:23 UTC 74,764 bytes, 2,449 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.