~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/event-custom/event-custom-base.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

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