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
        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
 
179
Y.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
 */
211
DO.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
 */
226
DO.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
 */
241
DO.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
 */
260
DO.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
 */
328
DO.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
 */
342
DO.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
 */
357
DO.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
 */
370
DO.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
 */
384
DO.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",
398
var 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
 
467
Y.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
 */
522
Y.CustomEvent.keepDeprecatedSubs = false;
523
 
524
Y.CustomEvent.mixConfigs = mixConfigs;
525
 
526
Y.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
 */
1233
Y.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
 
1281
Y.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
 */
1377
Y.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
 
1396
Y.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
 
1465
var 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 || !type || 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
 
1559
ET.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
 
2304
Y.EventTarget = ET;
2305
 
2306
// make Y an event target
2307
Y.mix(Y, ET.prototype);
2308
ET.call(Y, { bubbles: false });
2309
 
2310
YUI.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
 */
2320
Y.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
 
2336
For custom event subscriptions, pass the custom event name as the first argument
2337
and callback as the second. The `this` object in the callback will be `Y` unless
2338
an override is passed as the third argument.
2339
 
2340
    Y.on('io:complete', function () {
2341
        Y.MyApp.updateStatus('Transaction complete');
2342
    });
2343
 
2344
To subscribe to DOM events, pass the name of a DOM event as the first argument
2345
and a CSS selector string as the third argument after the callback function.
2346
Alternately, the third argument can be a `Node`, `NodeList`, `HTMLElement`,
2347
array, 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
 
2357
The `this` object in DOM event callbacks will be the `Node` targeted by the CSS
2358
selector 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
2362
event object passed as the first parameter to the subscription callback.
2363
 
2364
To 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
 
2367
NOTE: The formal parameter list below is for events, not for function
2368
injection.  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
/**
2382
Listen for an event one time.  Equivalent to `on()`, except that
2383
the listener is immediately detached when executed.
2384
 
2385
See the <a href="#methods_on">`on()` method</a> for additional subscription
2386
options.
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
/**
2400
Listen for an event one time.  Equivalent to `once()`, except, like `after()`,
2401
the subscription callback executes after all `on()` subscribers and the event's
2402
`defaultFn` (if configured) have executed.  Like `after()` if any `on()` phase
2403
subscriber calls `e.preventDefault()`, neither the `defaultFn` nor the `after()`
2404
subscribers will execute.
2405
 
2406
The listener is immediately detached when executed.
2407
 
2408
See the <a href="#methods_on">`on()` method</a> for additional subscription
2409
options.
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
/**
2423
Like `on()`, this method creates a subscription to a custom event or to the
2424
execution of a method on an object.
2425
 
2426
For events, `after()` subscribers are executed after the event's
2427
`defaultFn` unless `e.preventDefault()` was called from an `on()` subscriber.
2428
 
2429
See the <a href="#methods_on">`on()` method</a> for additional subscription
2430
options.
2431
 
2432
NOTE: The subscription signature shown is for events, not for function
2433
injection.  See <a href="../classes/Do.html#methods_after">`Y.Do.after`</a>
2434
for 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
}, '3.18.1', {"requires": ["oop"]});