Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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