/loggerhead/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/loggerhead/trunk

« back to all changes in this revision

Viewing changes to loggerhead/static/javascript/yui/build/event/event.js

  • Committer: Colin Watson
  • Date: 2020-06-08 09:55:03 UTC
  • mfrom: (498.2.2 jquery)
  • Revision ID: cjwatson@canonical.com-20200608095503-n387xggxud2khqsw
[r=cjwatson] Port loggerhead from YUI to jQuery.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.net/yui/license.txt
5
 
version: 3.0.0pr2
6
 
*/
7
 
/**
8
 
 * The YUI event system
9
 
 * @module event
10
 
 */
11
 
YUI.add("event", function(Y) {
12
 
 
13
 
    var FOCUS = Y.UA.ie ? "focusin" : "focus",
14
 
        BLUR = Y.UA.ie ? "focusout" : "blur",
15
 
        CAPTURE = "capture_",
16
 
        Lang = Y.Lang;
17
 
 
18
 
    Y.Env.eventAdaptors = {
19
 
 
20
 
        /**
21
 
         * Adds a DOM focus listener.  Uses the focusin event in IE,
22
 
         * and the capture phase otherwise so that
23
 
         * the event propagates properly.
24
 
         * @for YUI
25
 
         * @event focus
26
 
         */
27
 
        focus: {
28
 
            on: function() {
29
 
                arguments[0] = CAPTURE + FOCUS;
30
 
                return Y.Event.attach.apply(Y.Event, arguments);
31
 
            },
32
 
 
33
 
            detach: function() {
34
 
                arguments[0] = CAPTURE + FOCUS;
35
 
                return Y.Event.detach.apply(Y.Event, arguments);
36
 
 
37
 
            }
38
 
        },
39
 
 
40
 
        /**
41
 
         * Adds a DOM focus listener.  Uses the focusout event in IE,
42
 
         * and the capture phase otherwise so that
43
 
         * the event propagates properly.
44
 
         * @for YUI
45
 
         * @event blur
46
 
         */
47
 
        blur: {
48
 
            on: function() {
49
 
                arguments[0] = CAPTURE + BLUR;
50
 
                return Y.Event.attach.apply(Y.Event, arguments);
51
 
            },
52
 
 
53
 
            detach: function() {
54
 
                arguments[0] = CAPTURE + BLUR;
55
 
                return Y.Event.detach.apply(Y.Event, arguments);
56
 
            }
57
 
        },
58
 
 
59
 
        /**
60
 
         * Executes the callback as soon as the specified element 
61
 
         * is detected in the DOM.
62
 
         * @for YUI
63
 
         * @event available
64
 
         */
65
 
        available: {
66
 
            on: function(type, fn, id, o) {
67
 
                var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : [];
68
 
                return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
69
 
            }
70
 
        },
71
 
 
72
 
        /**
73
 
         * Executes the callback as soon as the specified element 
74
 
         * is detected in the DOM with a nextSibling property
75
 
         * (indicating that the element's children are available)
76
 
         * @for YUI
77
 
         * @event contentready
78
 
         */
79
 
        contentready: {
80
 
            on: function(type, fn, id, o) {
81
 
                var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : [];
82
 
                return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
83
 
            }
84
 
        },
85
 
 
86
 
        /**
87
 
         * Add a key listener.  The listener will only be notified if the
88
 
         * keystroke detected meets the supplied specification.  The
89
 
         * spec consists of the key event type, followed by a colon,
90
 
         * followed by zero or more comma separated key codes, followed
91
 
         * by zero or more modifiers delimited by a plus sign.  Ex:
92
 
         * press:12,65+shift+ctrl
93
 
         * @event key
94
 
         * @param fn {string} the function to execute
95
 
         * @param id {string} the element(s) to bind
96
 
         * @param spec {string} the keyCode and modifier specification
97
 
         * @param o optional context object
98
 
         * @param args 0..n additional arguments that should be provided 
99
 
         * to the listener.
100
 
         */
101
 
        key: {
102
 
 
103
 
            on: function(type, fn, id, spec, o) {
104
 
 
105
 
                if (!spec || spec.indexOf(':') == -1) {
106
 
                    arguments[0] = 'keypress';
107
 
                    return Y.on.apply(Y, arguments);
108
 
                }
109
 
 
110
 
                // parse spec ([key event type]:[criteria])
111
 
                var parsed = spec.split(':'),
112
 
 
113
 
                    // key event type: 'down', 'up', or 'press'
114
 
                    etype = parsed[0],
115
 
 
116
 
                    // list of key codes optionally followed by modifiers
117
 
                    criteria = (parsed[1]) ? parsed[1].split(/,|\+/) : null,
118
 
 
119
 
                    // the name of the custom event that will be created for the spec
120
 
                    ename = (Lang.isString(id) ? id : Y.stamp(id)) + spec,
121
 
 
122
 
                    a = Y.Array(arguments, 0, true);
123
 
 
124
 
 
125
 
 
126
 
                // subscribe spec validator to the DOM event
127
 
                Y.on(type + etype, function(e) {
128
 
 
129
 
                    
130
 
                    var passed = false, failed = false;
131
 
 
132
 
                    for (var i=0; i<criteria.length; i=i+1) {
133
 
                        var crit = criteria[i], critInt = parseInt(crit, 10);
134
 
 
135
 
                        // pass this section if any supplied keyCode 
136
 
                        // is found
137
 
                        if (Lang.isNumber(critInt)) {
138
 
 
139
 
                            if (e.charCode === critInt) {
140
 
                                passed = true;
141
 
                            } else {
142
 
                                failed = true;
143
 
                            }
144
 
 
145
 
                        // only check modifier if no keyCode was specified
146
 
                        // or the keyCode check was successful.  pass only 
147
 
                        // if every modifier passes
148
 
                        } else if (passed || !failed) {
149
 
                            passed = (e[crit + 'Key']);
150
 
                            failed = !passed;
151
 
                        }                    
152
 
                    }
153
 
 
154
 
                    // fire spec custom event if spec if met
155
 
                    if (passed) {
156
 
                        Y.fire(ename, e);
157
 
                    }
158
 
 
159
 
                }, id);
160
 
 
161
 
                // subscribe supplied listener to custom event for spec validator
162
 
                // remove element and spec.
163
 
                a.splice(2, 2);
164
 
                a[0] = ename;
165
 
 
166
 
                return Y.on.apply(Y, a);
167
 
            }
168
 
        }
169
 
 
170
 
    };
171
 
 
172
 
    /**
173
 
     * Attach an event listener, either to a DOM object
174
 
     * or to an Event.Target.
175
 
     * @param type {string} the event type
176
 
     * @param f {Function} the function to execute
177
 
     * @param o the Event.Target or element to attach to
178
 
     * @param context Optional execution context
179
 
     * @param args* 0..n additional arguments to append
180
 
     * to the signature provided when the event fires.
181
 
     * @method on
182
 
     * @for YUI
183
 
     * @return {Event.Handle} a handle object for 
184
 
     * unsubscribing to this event.
185
 
     */
186
 
    Y.on = function(type, f, o) {
187
 
        
188
 
       var adapt = Y.Env.eventAdaptors[type];
189
 
        
190
 
        if (adapt && adapt.on) {
191
 
            return adapt.on.apply(Y, arguments);
192
 
        } else {
193
 
            if (adapt || type.indexOf(':') > -1) {
194
 
                return Y.subscribe.apply(Y, arguments);
195
 
            } else {
196
 
                return Y.Event.attach.apply(Y.Event, arguments);
197
 
            }
198
 
        }
199
 
 
200
 
    };
201
 
 
202
 
    /**
203
 
     * Detach an event listener (either a custom event or a
204
 
     * DOM event
205
 
     * @method detach
206
 
     * @param type the type of event, or a Event.Handle to
207
 
     * for the subscription.  If the Event.Handle is passed
208
 
     * in, the other parameters are not used.
209
 
     * @param f {Function} the subscribed function
210
 
     * @param o the object or element the listener is subscribed
211
 
     * to.
212
 
     * @method detach
213
 
     * @return {YUI} the YUI instance
214
 
     */
215
 
    Y.detach = function(type, f, o) {
216
 
 
217
 
        var adapt = Y.Env.eventAdaptors[type];
218
 
 
219
 
        if (Lang.isObject(type) && type.detach) {
220
 
            return type.detach();
221
 
        } else {
222
 
            if (adapt && adapt.detach) {
223
 
                return adapt.detach.apply(Y, arguments);
224
 
            } else if (adapt || type.indexOf(':') > -1) {
225
 
                return Y.unsubscribe.apply(Y, arguments);
226
 
            } else {
227
 
                return Y.Event.detach.apply(Y.Event, arguments);
228
 
            }
229
 
        }
230
 
    };
231
 
 
232
 
    /**
233
 
     * Executes the callback before a DOM event, custom event
234
 
     * or method.  If the first argument is a function, it
235
 
     * is assumed the target is a method.  For DOM and custom
236
 
     * events, this is an alias for Y.on.
237
 
     *
238
 
     * For DOM and custom events:
239
 
     * type, callback, context, 1-n arguments
240
 
     *  
241
 
     * For methods:
242
 
     * callback, object (method host), methodName, context, 1-n arguments
243
 
     *
244
 
     * @method before
245
 
     * @return unsubscribe handle
246
 
     */
247
 
    Y.before = function(type, f, o) { 
248
 
        if (Lang.isFunction(type)) {
249
 
            return Y.Do.before.apply(Y.Do, arguments);
250
 
        } else {
251
 
            return Y.on.apply(Y, arguments);
252
 
        }
253
 
    };
254
 
 
255
 
    var after = Y.after;
256
 
 
257
 
    /**
258
 
     * Executes the callback after a DOM event, custom event
259
 
     * or method.  If the first argument is a function, it
260
 
     * is assumed the target is a method.
261
 
     *
262
 
     * For DOM and custom events:
263
 
     * type, callback, context, 1-n arguments
264
 
     *  
265
 
     * For methods:
266
 
     * callback, object (method host), methodName, context, 1-n arguments
267
 
     *
268
 
     * @method after
269
 
     * @return {Event.Handle} unsubscribe handle
270
 
     */
271
 
    Y.after = function(type, f, o) {
272
 
        if (Lang.isFunction(type)) {
273
 
            return Y.Do.after.apply(Y.Do, arguments);
274
 
        } else {
275
 
            return after.apply(Y, arguments);
276
 
        }
277
 
    };
278
 
 
279
 
 
280
 
}, "3.0.0", {
281
 
    use: [
282
 
          "aop", 
283
 
          "event-custom", 
284
 
          "event-target", 
285
 
          "event-ready",
286
 
          "event-dom", 
287
 
          "event-facade",
288
 
          "event-simulate"
289
 
          ]
290
 
});
291
 
/*
292
 
 * Method displacement
293
 
 * @submodule event-aop
294
 
 * @module event
295
 
 */
296
 
YUI.add("aop", function(Y) {
297
 
 
298
 
    var BEFORE = 0,
299
 
        AFTER = 1;
300
 
 
301
 
    /**
302
 
     * Allows for the insertion of methods that are executed before or after
303
 
     * a specified method
304
 
     * @class Do
305
 
     * @static
306
 
     */
307
 
    Y.Do = {
308
 
 
309
 
        /**
310
 
         * Cache of objects touched by the utility
311
 
         * @property objs
312
 
         * @static
313
 
         */
314
 
        objs: {},
315
 
 
316
 
        /**
317
 
         * Execute the supplied method before the specified function
318
 
         * @method before
319
 
         * @param fn {Function} the function to execute
320
 
         * @param obj the object hosting the method to displace
321
 
         * @param sFn {string} the name of the method to displace
322
 
         * @param c The execution context for fn
323
 
         * @return {string} handle for the subscription
324
 
         * @static
325
 
         */
326
 
        before: function(fn, obj, sFn, c) {
327
 
            var f = fn;
328
 
            if (c) {
329
 
                var a = [fn, c].concat(Y.Array(arguments, 4, true));
330
 
                f = Y.bind.apply(Y, a);
331
 
            }
332
 
 
333
 
            return this._inject(BEFORE, f, obj, sFn);
334
 
        },
335
 
 
336
 
        /**
337
 
         * Execute the supplied method after the specified function
338
 
         * @method after
339
 
         * @param fn {Function} the function to execute
340
 
         * @param obj the object hosting the method to displace
341
 
         * @param sFn {string} the name of the method to displace
342
 
         * @param c The execution context for fn
343
 
         * @return {string} handle for the subscription
344
 
         * @static
345
 
         */
346
 
        after: function(fn, obj, sFn, c) {
347
 
            var f = fn;
348
 
            if (c) {
349
 
                var a = [fn, c].concat(Y.Array(arguments, 4, true));
350
 
                f = Y.bind.apply(Y, a);
351
 
            }
352
 
 
353
 
            return this._inject(AFTER, f, obj, sFn);
354
 
        },
355
 
 
356
 
        /**
357
 
         * Execute the supplied method after the specified function
358
 
         * @method _inject
359
 
         * @param when {string} before or after
360
 
         * @param fn {Function} the function to execute
361
 
         * @param obj the object hosting the method to displace
362
 
         * @param sFn {string} the name of the method to displace
363
 
         * @param c The execution context for fn
364
 
         * @return {string} handle for the subscription
365
 
         * @private
366
 
         * @static
367
 
         */
368
 
        _inject: function(when, fn, obj, sFn) {
369
 
 
370
 
            // object id
371
 
            var id = Y.stamp(obj);
372
 
 
373
 
            if (! this.objs[id]) {
374
 
                // create a map entry for the obj if it doesn't exist
375
 
                this.objs[id] = {};
376
 
            }
377
 
            var o = this.objs[id];
378
 
 
379
 
            if (! o[sFn]) {
380
 
                // create a map entry for the method if it doesn't exist
381
 
                o[sFn] = new Y.Do.Method(obj, sFn);
382
 
 
383
 
                // re-route the method to our wrapper
384
 
                obj[sFn] = 
385
 
                    function() {
386
 
                        return o[sFn].exec.apply(o[sFn], arguments);
387
 
                    };
388
 
            }
389
 
 
390
 
            // subscriber id
391
 
            var sid = id + Y.stamp(fn) + sFn;
392
 
 
393
 
            // register the callback
394
 
            o[sFn].register(sid, fn, when);
395
 
 
396
 
            return new Y.EventHandle(o[sFn], sid);
397
 
 
398
 
        },
399
 
 
400
 
        /**
401
 
         * Detach a before or after subscription
402
 
         * @method detach
403
 
         * @param handle {string} the subscription handle
404
 
         */
405
 
        detach: function(handle) {
406
 
 
407
 
            if (handle.detach) {
408
 
                handle.detach();
409
 
            }
410
 
 
411
 
        },
412
 
 
413
 
        _unload: function(e, me) {
414
 
 
415
 
        }
416
 
    };
417
 
 
418
 
    //////////////////////////////////////////////////////////////////////////
419
 
 
420
 
    /**
421
 
     * Wrapper for a displaced method with aop enabled
422
 
     * @class Do.Method
423
 
     * @constructor
424
 
     * @param obj The object to operate on
425
 
     * @param sFn The name of the method to displace
426
 
     */
427
 
    Y.Do.Method = function(obj, sFn) {
428
 
        this.obj = obj;
429
 
        this.methodName = sFn;
430
 
        this.method = obj[sFn];
431
 
        // this.before = [];
432
 
        // this.after = [];
433
 
        this.before = {};
434
 
        this.after = {};
435
 
    };
436
 
 
437
 
    /**
438
 
     * Register a aop subscriber
439
 
     * @method register
440
 
     * @param sid {string} the subscriber id
441
 
     * @param fn {Function} the function to execute
442
 
     * @param when {string} when to execute the function
443
 
     */
444
 
    Y.Do.Method.prototype.register = function (sid, fn, when) {
445
 
        if (when) {
446
 
            // this.after.push(fn);
447
 
            this.after[sid] = fn;
448
 
        } else {
449
 
            // this.before.push(fn);
450
 
            this.before[sid] = fn;
451
 
        }
452
 
    };
453
 
 
454
 
    /**
455
 
     * Unregister a aop subscriber
456
 
     * @method delete
457
 
     * @param sid {string} the subscriber id
458
 
     * @param fn {Function} the function to execute
459
 
     * @param when {string} when to execute the function
460
 
     */
461
 
    Y.Do.Method.prototype._delete = function (sid) {
462
 
        delete this.before[sid];
463
 
        delete this.after[sid];
464
 
    };
465
 
 
466
 
    /**
467
 
     * Execute the wrapped method
468
 
     * @method exec
469
 
     */
470
 
    Y.Do.Method.prototype.exec = function () {
471
 
 
472
 
        var args = Y.Array(arguments, 0, true), 
473
 
            i, ret, newRet, 
474
 
            bf = this.before,
475
 
            af = this.after,
476
 
            prevented = false;
477
 
 
478
 
        // execute before
479
 
        for (i in bf) {
480
 
            if (bf.hasOwnProperty(i)) {
481
 
                ret = bf[i].apply(this.obj, args);
482
 
                if (ret) {
483
 
                    switch (ret.constructor) {
484
 
                        case Y.Do.Halt:
485
 
                            return ret.retVal;
486
 
                        case Y.Do.AlterArgs:
487
 
                            args = ret.newArgs;
488
 
                            break;
489
 
                        case Y.Do.Prevent:
490
 
                            prevented = true;
491
 
                            break;
492
 
                        default:
493
 
                    }
494
 
                }
495
 
            }
496
 
        }
497
 
 
498
 
        // execute method
499
 
        if (!prevented) {
500
 
            ret = this.method.apply(this.obj, args);
501
 
        }
502
 
 
503
 
        // execute after methods.
504
 
        for (i in af) {
505
 
            if (af.hasOwnProperty(i)) {
506
 
                newRet = af[i].apply(this.obj, args);
507
 
                // Stop processing if a Halt object is returned
508
 
                if (newRet && newRet.constructor == Y.Do.Halt) {
509
 
                    return newRet.retVal;
510
 
                // Check for a new return value
511
 
                } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
512
 
                    ret = newRet.newRetVal;
513
 
                }
514
 
            }
515
 
        }
516
 
 
517
 
        return ret;
518
 
    };
519
 
 
520
 
    //////////////////////////////////////////////////////////////////////////
521
 
 
522
 
 
523
 
    /**
524
 
     * Return an AlterArgs object when you want to change the arguments that
525
 
     * were passed into the function.  An example would be a service that scrubs
526
 
     * out illegal characters prior to executing the core business logic.
527
 
     * @class Do.AlterArgs
528
 
     */
529
 
    Y.Do.AlterArgs = function(msg, newArgs) {
530
 
        this.msg = msg;
531
 
        this.newArgs = newArgs;
532
 
    };
533
 
 
534
 
    /**
535
 
     * Return an AlterReturn object when you want to change the result returned
536
 
     * from the core method to the caller
537
 
     * @class Do.AlterReturn
538
 
     */
539
 
    Y.Do.AlterReturn = function(msg, newRetVal) {
540
 
        this.msg = msg;
541
 
        this.newRetVal = newRetVal;
542
 
    };
543
 
 
544
 
    /**
545
 
     * Return a Halt object when you want to terminate the execution
546
 
     * of all subsequent subscribers as well as the wrapped method
547
 
     * if it has not exectued yet.
548
 
     * @class Do.Halt
549
 
     */
550
 
    Y.Do.Halt = function(msg, retVal) {
551
 
        this.msg = msg;
552
 
        this.retVal = retVal;
553
 
    };
554
 
 
555
 
    /**
556
 
     * Return a Prevent object when you want to prevent the wrapped function
557
 
     * from executing, but want the remaining listeners to execute
558
 
     * @class Do.Halt
559
 
     */
560
 
    Y.Do.Prevent = function(msg) {
561
 
        this.msg = msg;
562
 
    };
563
 
 
564
 
    /**
565
 
     * Return an Error object when you want to terminate the execution
566
 
     * of all subsequent method calls.
567
 
     * @class Do.Error
568
 
     * @deprecated
569
 
     */
570
 
    Y.Do.Error = Y.Do.Halt;
571
 
 
572
 
    //////////////////////////////////////////////////////////////////////////
573
 
 
574
 
// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
575
 
 
576
 
}, "3.0.0");
577
 
/*
578
 
 * YUI Custom Events
579
 
 * @submodule event-custom
580
 
 * @module event
581
 
 */
582
 
YUI.add("event-custom", function(Y) {
583
 
 
584
 
    var onsubscribeType = "_event:onsub",
585
 
        AFTER = 'after', 
586
 
        CONFIGS = [
587
 
            'broadcast',
588
 
            'bubbles',
589
 
            'context',
590
 
            'configured',
591
 
            'currentTarget',
592
 
            'defaultFn',
593
 
            'details',
594
 
            'emitFacade',
595
 
            'fireOnce',
596
 
            'host',
597
 
            'preventable',
598
 
            'preventedFn',
599
 
            'queuable',
600
 
            'silent',
601
 
            'stoppedFn',
602
 
            'target',
603
 
            'type'
604
 
        ],
605
 
 
606
 
        YUI3_SIGNATURE = 9;
607
 
 
608
 
    /**
609
 
     * Return value from all subscribe operations
610
 
     * @class Event.Handle
611
 
     * @constructor
612
 
     * @param evt {Event.Custom} the custom event
613
 
     * @param sub {Event.Subscriber} the subscriber
614
 
     */
615
 
    Y.EventHandle = function(evt, sub) {
616
 
 
617
 
        /**
618
 
         * The custom event
619
 
         * @type Event.Custom
620
 
         */
621
 
        this.evt = evt;
622
 
 
623
 
        /**
624
 
         * The subscriber object
625
 
         * @type Event.Subscriber
626
 
         */
627
 
        this.sub = sub;
628
 
    };
629
 
 
630
 
    Y.EventHandle.prototype = {
631
 
        /**
632
 
         * Detaches this subscriber
633
 
         * @method detach
634
 
         */
635
 
        detach: function() {
636
 
 
637
 
            if (this.evt) {
638
 
                this.evt._delete(this.sub);
639
 
            }
640
 
        }
641
 
    };
642
 
 
643
 
    /**
644
 
     * The Event.Custom class lets you define events for your application
645
 
     * that can be subscribed to by one or more independent component.
646
 
     *
647
 
     * @param {String}  type The type of event, which is passed to the callback
648
 
     *                  when the event fires
649
 
     * @param o configuration object
650
 
     * @class Event.Custom
651
 
     * @constructor
652
 
     */
653
 
    Y.CustomEvent = function(type, o) {
654
 
 
655
 
        // if (arguments.length > 2) {
656
 
        // }
657
 
 
658
 
        o = o || {};
659
 
 
660
 
        this.id = Y.stamp(this);
661
 
 
662
 
        /**
663
 
         * The type of event, returned to subscribers when the event fires
664
 
         * @property type
665
 
         * @type string
666
 
         */
667
 
        this.type = type;
668
 
 
669
 
        /**
670
 
         * The context the the event will fire from by default.  Defaults to the YUI
671
 
         * instance.
672
 
         * @property context
673
 
         * @type object
674
 
         */
675
 
        this.context = Y;
676
 
 
677
 
 
678
 
        /**
679
 
         * If 0, this event does not broadcast.  If 1, the YUI instance is notified
680
 
         * every time this event fires.  If 2, the YUI instance and the YUI global
681
 
         * (if event is enabled on the global) are notified every time this event
682
 
         * fires.
683
 
         * @property broadcast
684
 
         * @type int
685
 
         */
686
 
        this.broadcast = 0;
687
 
 
688
 
        /**
689
 
         * By default all custom events are logged in the debug build, set silent
690
 
         * to true to disable debug outpu for this event.
691
 
         * @property silent
692
 
         * @type boolean
693
 
         */
694
 
 
695
 
        this.queuable = false;
696
 
 
697
 
        /**
698
 
         * The subscribers to this event
699
 
         * @property subscribers
700
 
         * @type Event.Subscriber{}
701
 
         */
702
 
        this.subscribers = {};
703
 
 
704
 
        /*
705
 
         * The publisher has configured this event
706
 
         * @property configured
707
 
         * @type boolean
708
 
         * @default true
709
 
         */
710
 
        // this.configured = true;
711
 
 
712
 
        /**
713
 
         * 'After' subscribers
714
 
         * @property afters
715
 
         * @type Event.Subscriber{}
716
 
         */
717
 
        this.afters = {};
718
 
 
719
 
        /**
720
 
         * This event has fired if true
721
 
         *
722
 
         * @property fired
723
 
         * @type boolean
724
 
         * @default false;
725
 
         */
726
 
        this.fired = false;
727
 
 
728
 
        /**
729
 
         * This event should only fire one time if true, and if
730
 
         * it has fired, any new subscribers should be notified
731
 
         * immediately.
732
 
         *
733
 
         * @property fireOnce
734
 
         * @type boolean
735
 
         * @default false;
736
 
         */
737
 
        this.fireOnce = false;
738
 
 
739
 
        /**
740
 
         * Flag for stopPropagation that is modified during fire()
741
 
         * 1 means to stop propagation to bubble targets.  2 means
742
 
         * to also stop additional subscribers on this target.
743
 
         * @property stopped
744
 
         * @type int
745
 
         */
746
 
        this.stopped = 0;
747
 
 
748
 
        /**
749
 
         * Flag for preventDefault that is modified during fire().
750
 
         * if it is not 0, the default behavior for this event
751
 
         * @property prevented
752
 
         * @type int
753
 
         */
754
 
        this.prevented = 0;
755
 
 
756
 
        /**
757
 
         * Specifies the host for this custom event.  This is used
758
 
         * to enable event bubbling
759
 
         * @property host
760
 
         * @type Event.Target
761
 
         */
762
 
        this.host = null;
763
 
 
764
 
        /**
765
 
         * The default function to execute after event listeners
766
 
         * have fire, but only if the default action was not
767
 
         * prevented.
768
 
         * @property defaultFn
769
 
         * @type Function
770
 
         */
771
 
        this.defaultFn = null;
772
 
 
773
 
        /**
774
 
         * The function to execute if a subscriber calls
775
 
         * stopPropagation or stopImmediatePropagation
776
 
         * @property stoppedFn
777
 
         * @type Function
778
 
         */
779
 
        this.stoppedFn = null;
780
 
 
781
 
        /**
782
 
         * The function to execute if a subscriber calls
783
 
         * preventDefault
784
 
         * @property preventedFn
785
 
         * @type Function
786
 
         */
787
 
        this.preventedFn = null;
788
 
 
789
 
        /**
790
 
         * Specifies whether or not this event's default function
791
 
         * can be cancelled by a subscriber by executing preventDefault() 
792
 
         * on the event facade 
793
 
         * @property preventable 
794
 
         * @type boolean 
795
 
         * @default true
796
 
         */
797
 
        this.preventable = true;
798
 
 
799
 
        /**
800
 
         * Specifies whether or not a subscriber can stop the event propagation
801
 
         * via stopPropagation(), stopImmediatePropagation(), or halt()
802
 
         * @property bubbles
803
 
         * @type boolean
804
 
         * @default true
805
 
         */
806
 
        this.bubbles = true;
807
 
 
808
 
        /**
809
 
         * Supports multiple options for listener signatures in order to
810
 
         * port YUI 2 apps.
811
 
         * @property signature
812
 
         * @type int
813
 
         * @default 9
814
 
         */
815
 
        this.signature = YUI3_SIGNATURE;
816
 
 
817
 
        /**
818
 
         * If set to true, the custom event will deliver an Event.Facade object
819
 
         * that is similar to a DOM event object.
820
 
         * @property emitFacade
821
 
         * @type boolean
822
 
         * @default false
823
 
         */
824
 
        this.emitFacade = false;
825
 
 
826
 
        this.applyConfig(o, true);
827
 
 
828
 
 
829
 
        // Only add subscribe events for events that are not generated by 
830
 
        // Event.Custom
831
 
        if (type !== onsubscribeType) {
832
 
 
833
 
            /**
834
 
             * Custom events provide a custom event that fires whenever there is
835
 
             * a new subscriber to the event.  This provides an opportunity to
836
 
             * handle the case where there is a non-repeating event that has
837
 
             * already fired has a new subscriber.  
838
 
             *
839
 
             * @event subscribeEvent
840
 
             * @type Event.Custom
841
 
             * @param {Function} fn The function to execute
842
 
             * @param {Object}   obj An object to be passed along when the event 
843
 
             *                       fires
844
 
             * @param {boolean|Object}  override If true, the obj passed in becomes 
845
 
             *                                   the execution context of the listener.
846
 
             *                                   if an object, that object becomes the
847
 
             *                                   the execution context.
848
 
             */
849
 
            this.subscribeEvent = new Y.CustomEvent(onsubscribeType, {
850
 
                    context: this,
851
 
                    silent: true
852
 
                });
853
 
        } 
854
 
 
855
 
    };
856
 
 
857
 
    Y.CustomEvent.prototype = {
858
 
 
859
 
        _YUI_EVENT: true,
860
 
 
861
 
        /**
862
 
         * Apply configuration properties.  Only applies the CONFIG whitelist
863
 
         * @method applyConfig
864
 
         * @param o hash of properties to apply
865
 
         * @param force {boolean} if true, properties that exist on the event 
866
 
         * will be overwritten.
867
 
         */
868
 
        applyConfig: function(o, force) {
869
 
            if (o) {
870
 
                Y.mix(this, o, force, CONFIGS);
871
 
            }
872
 
        },
873
 
 
874
 
        _subscribe: function(fn, obj, args, when) {
875
 
 
876
 
            if (!fn) {
877
 
                Y.fail("Invalid callback for CE: " + this.type);
878
 
            }
879
 
 
880
 
            var se = this.subscribeEvent;
881
 
            if (se) {
882
 
                se.fire.apply(se, args);
883
 
            }
884
 
 
885
 
            var s = new Y.Subscriber(fn, obj, args, when);
886
 
 
887
 
 
888
 
            if (this.fireOnce && this.fired) {
889
 
 
890
 
                // this._notify(s);
891
 
                // setTimeout(Y.bind(this._notify, this, s), 0);
892
 
                Y.later(0, this, this._notify, s);
893
 
            }
894
 
 
895
 
            if (when == AFTER) {
896
 
                this.afters[s.id] = s;
897
 
            } else {
898
 
                this.subscribers[s.id] = s;
899
 
            }
900
 
 
901
 
            return new Y.EventHandle(this, s);
902
 
 
903
 
        },
904
 
 
905
 
        /**
906
 
         * Listen for this event
907
 
         * @method subscribe
908
 
         * @param {Function} fn        The function to execute
909
 
         * @param {Object}   obj       An object to be passed along when the event fires
910
 
         * @param args* 1..n params to provide to the listener
911
 
         * @return {Event.Handle} unsubscribe handle
912
 
         */
913
 
        subscribe: function(fn, obj) {
914
 
            return this._subscribe(fn, obj, arguments, true);
915
 
        },
916
 
 
917
 
        /**
918
 
         * Listen for this event after the normal subscribers have been notified and
919
 
         * the default behavior has been applied.  If a normal subscriber prevents the 
920
 
         * default behavior, it also prevents after listeners from firing.
921
 
         * @method after
922
 
         * @param {Function} fn        The function to execute
923
 
         * @param {Object}   obj       An object to be passed along when the event fires
924
 
         * @param args* 1..n params to provide to the listener
925
 
         * @return {Event.Handle} unsubscribe handle
926
 
         */
927
 
        after: function(fn, obj) {
928
 
            return this._subscribe(fn, obj, arguments, AFTER);
929
 
        },
930
 
 
931
 
        /**
932
 
         * Unsubscribes subscribers.
933
 
         * @method unsubscribe
934
 
         * @param {Function} fn  The subscribed function to remove, if not supplied
935
 
         *                       all will be removed
936
 
         * @param {Object}   obj  The custom object passed to subscribe.  This is
937
 
         *                        optional, but if supplied will be used to
938
 
         *                        disambiguate multiple listeners that are the same
939
 
         *                        (e.g., you subscribe many object using a function
940
 
         *                        that lives on the prototype)
941
 
         * @return {boolean} True if the subscriber was found and detached.
942
 
         */
943
 
        unsubscribe: function(fn, obj) {
944
 
 
945
 
            // if arg[0] typeof unsubscribe handle
946
 
            if (fn && fn.detach) {
947
 
                return fn.detach();
948
 
            }
949
 
 
950
 
            if (!fn) {
951
 
                return this.unsubscribeAll();
952
 
            }
953
 
 
954
 
            var found = false, subs = this.subscribers;
955
 
            for (var i in subs) {
956
 
                if (subs.hasOwnProperty(i)) {
957
 
                    var s = subs[i];
958
 
                    if (s && s.contains(fn, obj)) {
959
 
                        this._delete(s);
960
 
                        found = true;
961
 
                    }
962
 
                }
963
 
            }
964
 
 
965
 
            return found;
966
 
        },
967
 
 
968
 
        _getFacade: function(args) {
969
 
 
970
 
            var ef = this._facade;
971
 
 
972
 
            if (!ef) {
973
 
                ef = new Y.Event.Facade(this, this.currentTarget);
974
 
            }
975
 
 
976
 
            // if the first argument is an object literal, apply the
977
 
            // properties to the event facade
978
 
            var o = args && args[0];
979
 
            if (Y.Lang.isObject(o, true) && !o._yuifacade) {
980
 
                Y.mix(ef, o, true);
981
 
            }
982
 
 
983
 
            // update the details field with the arguments
984
 
            ef.details = this.details;
985
 
            ef.target = this.target;
986
 
            ef.currentTarget = this.currentTarget;
987
 
            ef.stopped = 0;
988
 
            ef.prevented = 0;
989
 
 
990
 
            this._facade = ef;
991
 
 
992
 
            return this._facade;
993
 
        },
994
 
 
995
 
        /**
996
 
         * Notify a single subscriber
997
 
         * @method _notify
998
 
         * @param s {Event.Subscriber} the subscriber
999
 
         * @param args {Array} the arguments array to apply to the listener
1000
 
         * @private
1001
 
         */
1002
 
        _notify: function(s, args, ef) {
1003
 
 
1004
 
 
1005
 
            var ret, c, ct;
1006
 
 
1007
 
            // emit an Event.Facade if this is that sort of event
1008
 
            // if (this.emitFacade && (!args[0] || !args[0]._yuifacade)) {
1009
 
            if (this.emitFacade) {
1010
 
 
1011
 
                // @TODO object literal support to fire makes it possible for
1012
 
                // config info to be passed if we wish.
1013
 
                
1014
 
                if (!ef) {
1015
 
                    ef = this._getFacade(args);
1016
 
                    args[0] = ef;
1017
 
                }
1018
 
 
1019
 
            }
1020
 
 
1021
 
            // The default context should be the object/element that
1022
 
            // the listener was bound to.
1023
 
            ct = (args && Y.Lang.isObject(args[0]) && args[0].currentTarget);
1024
 
            ret = s.notify(ct || this.context, args, this);
1025
 
 
1026
 
            if (false === ret || this.stopped > 1) {
1027
 
                return false;
1028
 
            }
1029
 
 
1030
 
            return true;
1031
 
        },
1032
 
 
1033
 
        /**
1034
 
         * Logger abstraction to centralize the application of the silent flag
1035
 
         * @method log
1036
 
         * @param msg {string} message to log
1037
 
         * @param cat {string} log category
1038
 
         */
1039
 
        log: function(msg, cat) {
1040
 
            var es = Y.Env._eventstack, s =  es && es.logging;
1041
 
            // if (!s && !this.silent) {
1042
 
            if (!this.silent) {
1043
 
            }
1044
 
        },
1045
 
 
1046
 
        /**
1047
 
         * Notifies the subscribers.  The callback functions will be executed
1048
 
         * from the context specified when the event was created, and with the 
1049
 
         * following parameters:
1050
 
         *   <ul>
1051
 
         *   <li>The type of event</li>
1052
 
         *   <li>All of the arguments fire() was executed with as an array</li>
1053
 
         *   <li>The custom object (if any) that was passed into the subscribe() 
1054
 
         *       method</li>
1055
 
         *   </ul>
1056
 
         * @method fire 
1057
 
         * @param {Object*} arguments an arbitrary set of parameters to pass to 
1058
 
         *                            the handler.
1059
 
         * @return {boolean} false if one of the subscribers returned false, 
1060
 
         *                   true otherwise
1061
 
         */
1062
 
        fire: function() {
1063
 
 
1064
 
            var es = Y.Env._eventstack;
1065
 
 
1066
 
            if (es) {
1067
 
 
1068
 
                // var b = this.bubbles, h = this.host;
1069
 
                // if (b && h) {
1070
 
                //     b = (h._yuievt.targets.length);
1071
 
                // }
1072
 
 
1073
 
                // es.silent = (es.silent || this.silent);
1074
 
 
1075
 
                // queue this event if the current item in the queue bubbles
1076
 
                // if (b && this.queuable && this.type != es.next.type) {
1077
 
                if (this.queuable && this.type != es.next.type) {
1078
 
 
1079
 
 
1080
 
                    es.queue.push([this, arguments]);
1081
 
                    return true;
1082
 
                }
1083
 
 
1084
 
            } else {
1085
 
 
1086
 
                Y.Env._eventstack = {
1087
 
                   // id of the first event in the stack
1088
 
                   id: this.id,
1089
 
                   next: this,
1090
 
                   silent: this.silent,
1091
 
                   logging: (this.type === 'yui:log'),
1092
 
                   stopped: 0,
1093
 
                   prevented: 0,
1094
 
                   queue: []
1095
 
                };
1096
 
 
1097
 
                es = Y.Env._eventstack;
1098
 
            }
1099
 
 
1100
 
            var ret = true;
1101
 
 
1102
 
            if (this.fireOnce && this.fired) {
1103
 
 
1104
 
 
1105
 
            } else {
1106
 
 
1107
 
                // var subs = this.subscribers.slice(), len=subs.length,
1108
 
                var subs = Y.merge(this.subscribers), s,
1109
 
                           args=Y.Array(arguments, 0, true), i;
1110
 
 
1111
 
                this.stopped = 0;
1112
 
                this.prevented = 0;
1113
 
                this.target = this.target || this.host;
1114
 
 
1115
 
                this.currentTarget = this.host || this.currentTarget;
1116
 
 
1117
 
                this.fired = true;
1118
 
                this.details = args.slice(); // original arguments in the details
1119
 
 
1120
 
 
1121
 
                var hasSub = false;
1122
 
                es.lastLogState = es.logging;
1123
 
 
1124
 
 
1125
 
                var ef = null;
1126
 
                if (this.emitFacade) {
1127
 
 
1128
 
                    // this.fire({
1129
 
                    //   foo: 1
1130
 
                    //   bar: 2
1131
 
                    // }
1132
 
                    // this.fire({
1133
 
                    //   bar: 2
1134
 
                    // } // foo is still 1 unless we create a new facade
1135
 
                    this._facade = null;
1136
 
 
1137
 
                    ef = this._getFacade(args);
1138
 
                    args[0] = ef;
1139
 
                }
1140
 
 
1141
 
                for (i in subs) {
1142
 
                    if (subs.hasOwnProperty(i)) {
1143
 
 
1144
 
                        if (!hasSub) {
1145
 
                            es.logging = (es.logging || (this.type === 'yui:log'));
1146
 
                            hasSub = true;
1147
 
                        }
1148
 
 
1149
 
                        // stopImmediatePropagation
1150
 
                        if (this.stopped == 2) {
1151
 
                            break;
1152
 
                        }
1153
 
 
1154
 
                        s = subs[i];
1155
 
                        if (s && s.fn) {
1156
 
                            ret = this._notify(s, args, ef);
1157
 
                            if (false === ret) {
1158
 
                                this.stopped = 2;
1159
 
                            }
1160
 
                        }
1161
 
                    }
1162
 
                }
1163
 
 
1164
 
                es.logging = (es.lastLogState);
1165
 
 
1166
 
                // bubble if this is hosted in an event target and propagation has not been stopped
1167
 
                // @TODO check if we need to worry about defaultFn order
1168
 
                if (this.bubbles && this.host && !this.stopped) {
1169
 
                    es.stopped = 0;
1170
 
                    es.prevented = 0;
1171
 
                    ret = this.host.bubble(this);
1172
 
 
1173
 
                    this.stopped = Math.max(this.stopped, es.stopped);
1174
 
                    this.prevented = Math.max(this.prevented, es.prevented);
1175
 
                }
1176
 
 
1177
 
                // execute the default behavior if not prevented
1178
 
                // @TODO need context
1179
 
                if (this.defaultFn && !this.prevented) {
1180
 
                    this.defaultFn.apply(this.host || this, args);
1181
 
                }
1182
 
 
1183
 
                // process after listeners.  If the default behavior was
1184
 
                // prevented, the after events don't fire.
1185
 
                if (!this.prevented && this.stopped < 2) {
1186
 
                    subs = Y.merge(this.afters);
1187
 
                    for (i in subs) {
1188
 
                        if (subs.hasOwnProperty(i)) {
1189
 
 
1190
 
                            if (!hasSub) {
1191
 
                                es.logging = (es.logging || (this.type === 'yui:log'));
1192
 
                                hasSub = true;
1193
 
                            }
1194
 
 
1195
 
                            // stopImmediatePropagation
1196
 
                            if (this.stopped == 2) {
1197
 
                                break;
1198
 
                            }
1199
 
 
1200
 
                            s = subs[i];
1201
 
                            if (s && s.fn) {
1202
 
                                ret = this._notify(s, args, ef);
1203
 
                                if (false === ret) {
1204
 
                                    this.stopped = 2;
1205
 
                                }
1206
 
                            }
1207
 
                        }
1208
 
                    }
1209
 
                }
1210
 
            }
1211
 
 
1212
 
            if (es.id === this.id) {
1213
 
// console.log('clearing stack: ' + es.id + ', ' + this);
1214
 
 
1215
 
// reset propragation properties while processing the rest of the queue
1216
 
 
1217
 
// process queued events
1218
 
                var queue = es.queue;
1219
 
 
1220
 
                while (queue.length) {
1221
 
                    // q[0] = the event, q[1] = arguments to fire
1222
 
                    var q = queue.pop(), ce = q[0];
1223
 
 
1224
 
                    es.stopped = 0;
1225
 
                    es.prevented = 0;
1226
 
                    
1227
 
// set up stack to allow the next item to be processed
1228
 
                    es.next = ce;
1229
 
 
1230
 
                    ret = ce.fire.apply(ce, q[1]);
1231
 
                }
1232
 
 
1233
 
                Y.Env._eventstack = null;
1234
 
            } 
1235
 
 
1236
 
            return (ret !== false);
1237
 
        },
1238
 
 
1239
 
        /**
1240
 
         * Removes all listeners
1241
 
         * @method unsubscribeAll
1242
 
         * @return {int} The number of listeners unsubscribed
1243
 
         */
1244
 
        unsubscribeAll: function() {
1245
 
            var subs = this.subscribers, i;
1246
 
            for (i in subs) {
1247
 
                if (subs.hasOwnProperty(i)) {
1248
 
                    this._delete(subs[i]);
1249
 
                }
1250
 
            }
1251
 
 
1252
 
            this.subscribers={};
1253
 
 
1254
 
            return i;
1255
 
        },
1256
 
 
1257
 
        /**
1258
 
         * @method _delete
1259
 
         * @param subscriber object
1260
 
         * @private
1261
 
         */
1262
 
        _delete: function(s) {
1263
 
 
1264
 
            if (s) {
1265
 
                delete s.fn;
1266
 
                delete s.obj;
1267
 
                delete this.subscribers[s.id];
1268
 
                delete this.afters[s.id];
1269
 
            }
1270
 
 
1271
 
        },
1272
 
 
1273
 
        /**
1274
 
         * @method toString
1275
 
         */
1276
 
        toString: function() {
1277
 
             // return "{ CE '" + this.type + "' " + "id: " + this.id +
1278
 
                  // ", host: " + (this.host && Y.stamp(this.host) + " }");
1279
 
             return this.type;
1280
 
        },
1281
 
 
1282
 
        /**
1283
 
         * Stop propagation to bubble targets
1284
 
         * @method stopPropagation
1285
 
         */
1286
 
        stopPropagation: function() {
1287
 
            this.stopped = 1;
1288
 
            Y.Env._eventstack.stopped = 1;
1289
 
            if (this.stoppedFn) {
1290
 
                this.stoppedFn.call(this.host || this, this);
1291
 
            }
1292
 
        },
1293
 
 
1294
 
        /**
1295
 
         * Stops propagation to bubble targets, and prevents any remaining
1296
 
         * subscribers on the current target from executing.
1297
 
         * @method stopImmediatePropagation
1298
 
         */
1299
 
        stopImmediatePropagation: function() {
1300
 
            this.stopped = 2;
1301
 
            Y.Env._eventstack.stopped = 2;
1302
 
            if (this.stoppedFn) {
1303
 
                this.stoppedFn.call(this.host || this, this);
1304
 
            }
1305
 
        },
1306
 
 
1307
 
        /**
1308
 
         * Prevents the execution of this event's defaultFn
1309
 
         * @method preventDefault
1310
 
         */
1311
 
        preventDefault: function() {
1312
 
            if (this.preventable) {
1313
 
                this.prevented = 1;
1314
 
                Y.Env._eventstack.prevented = 1;
1315
 
            }
1316
 
            if (this.preventedFn) {
1317
 
                this.preventedFn.call(this.host || this, this);
1318
 
            }
1319
 
        }
1320
 
 
1321
 
    };
1322
 
 
1323
 
    /////////////////////////////////////////////////////////////////////
1324
 
 
1325
 
    /**
1326
 
     * Stores the subscriber information to be used when the event fires.
1327
 
     * @param {Function} fn       The wrapped function to execute
1328
 
     * @param {Object}   obj      An object to be passed along when the event fires
1329
 
     * @param {Array} args        subscribe() additional arguments
1330
 
     *
1331
 
     * @class Event.Subscriber
1332
 
     * @constructor
1333
 
     */
1334
 
    Y.Subscriber = function(fn, obj, args) {
1335
 
 
1336
 
        /**
1337
 
         * The callback that will be execute when the event fires
1338
 
         * This is wrapped by Y.bind if obj was supplied.
1339
 
         * @property fn
1340
 
         * @type Function
1341
 
         */
1342
 
        this.fn = fn;
1343
 
 
1344
 
        /**
1345
 
         * An optional custom object that will passed to the callback when
1346
 
         * the event fires
1347
 
         * @property obj
1348
 
         * @type Object
1349
 
         */
1350
 
        this.obj = obj;
1351
 
 
1352
 
        /**
1353
 
         * Unique subscriber id
1354
 
         * @property id
1355
 
         * @type String
1356
 
         */
1357
 
        this.id = Y.stamp(this);
1358
 
 
1359
 
        /**
1360
 
         * Optional additional arguments supplied to subscribe().  If present,
1361
 
         * these will be appended to the arguments supplied to fire()
1362
 
         * @property args
1363
 
         * @type Array
1364
 
         */
1365
 
        // this.args = args;
1366
 
 
1367
 
        /**
1368
 
         * }
1369
 
         * fn bound to obj with additional arguments applied via Y.bind
1370
 
         * @property wrappedFn
1371
 
         * @type Function
1372
 
         */
1373
 
        this.wrappedFn = fn;
1374
 
        
1375
 
        if (obj) {
1376
 
            /*
1377
 
            var a = (args) ? Y.Array(args) : [];
1378
 
            a.unshift(fn, obj);
1379
 
            // a.unshift(fn);
1380
 
            m = Y.bind.apply(Y, a);
1381
 
            */
1382
 
            this.wrappedFn = Y.bind.apply(Y, args);
1383
 
        }
1384
 
        
1385
 
 
1386
 
 
1387
 
    };
1388
 
 
1389
 
    Y.Subscriber.prototype = {
1390
 
 
1391
 
        /**
1392
 
         * Executes the subscriber.
1393
 
         * @method notify
1394
 
         * @param defaultContext The execution context if not overridden
1395
 
         * by the subscriber
1396
 
         * @param args {Array} Arguments array for the subscriber
1397
 
         * @param ce {Event.Custom} The custom event that sent the notification
1398
 
         */
1399
 
        notify: function(defaultContext, args, ce) {
1400
 
            var c = this.obj || defaultContext, ret = true,
1401
 
 
1402
 
                f = function() {
1403
 
                    switch (ce.signature) {
1404
 
                        case 0:
1405
 
                            ret = this.fn.call(c, ce.type, args, this.obj);
1406
 
                            break;
1407
 
                        case 1:
1408
 
                            ret = this.fn.call(c, args[0] || null, this.obj);
1409
 
                            break;
1410
 
                        default:
1411
 
                            ret = this.wrappedFn.apply(c, args || []);
1412
 
                    }
1413
 
                };
1414
 
 
1415
 
            // Ease debugging by only catching errors if we will not re-throw
1416
 
            // them.
1417
 
            if (Y.config.throwFail) {
1418
 
                f.call(this);
1419
 
            } else {
1420
 
                try {
1421
 
                    f.call(this);
1422
 
                } catch(e) {
1423
 
                    Y.fail(this + ' failed: ' + e.message, e);
1424
 
                }
1425
 
            }
1426
 
 
1427
 
            return ret;
1428
 
        },
1429
 
 
1430
 
        /**
1431
 
         * Returns true if the fn and obj match this objects properties.
1432
 
         * Used by the unsubscribe method to match the right subscriber.
1433
 
         *
1434
 
         * @method contains
1435
 
         * @param {Function} fn the function to execute
1436
 
         * @param {Object} obj an object to be passed along when the event fires
1437
 
         * @return {boolean} true if the supplied arguments match this 
1438
 
         *                   subscriber's signature.
1439
 
         */
1440
 
        contains: function(fn, obj) {
1441
 
            if (obj) {
1442
 
                return ((this.fn == fn) && this.obj == obj);
1443
 
            } else {
1444
 
                return (this.fn == fn);
1445
 
            }
1446
 
        },
1447
 
 
1448
 
        /**
1449
 
         * @method toString
1450
 
         */
1451
 
        toString: function() {
1452
 
            return "Subscriber " + this.id;
1453
 
        }
1454
 
    };
1455
 
 
1456
 
}, "3.0.0");
1457
 
/*
1458
 
 * Configures an object to be able to be targeted for events, and to publish events
1459
 
 * @submodule event-target
1460
 
 * @module event
1461
 
 */
1462
 
YUI.add("event-target", function(Y) {
1463
 
 
1464
 
    var SILENT = { 'yui:log': true };
1465
 
 
1466
 
    /**
1467
 
     * Event.Target is designed to be used with Y.augment to wrap 
1468
 
     * Event.Custom in an interface that allows events to be subscribed to 
1469
 
     * and fired by name.  This makes it possible for implementing code to
1470
 
     * subscribe to an event that either has not been created yet, or will
1471
 
     * not be created at all.
1472
 
     *
1473
 
     * @Class Event.Target
1474
 
     */
1475
 
    Y.EventTarget = function(opts) { 
1476
 
 
1477
 
        // console.log('Event.Target constructor executed: ' + this._yuid);
1478
 
 
1479
 
        var o = (Y.Lang.isObject(opts)) ? opts : {};
1480
 
 
1481
 
        this._yuievt = {
1482
 
 
1483
 
            events: {},
1484
 
 
1485
 
            targets: {},
1486
 
 
1487
 
            config: o,
1488
 
 
1489
 
            defaults: {
1490
 
                context: this, 
1491
 
                host: this,
1492
 
                emitFacade: o.emitFacade || false,
1493
 
                bubbles: ('bubbles' in o) ? o.bubbles : true
1494
 
            }
1495
 
            
1496
 
        };
1497
 
 
1498
 
    };
1499
 
 
1500
 
    var ET = Y.EventTarget;
1501
 
 
1502
 
 
1503
 
    ET.prototype = {
1504
 
 
1505
 
        /**
1506
 
         * Subscribe to a custom event hosted by this object
1507
 
         * @method subscribe
1508
 
         * @param type    {string}   The type of the event
1509
 
         * @param fn {Function} The callback
1510
 
         * @param context The execution context
1511
 
         * @param args* 1..n params to supply to the callback
1512
 
         */
1513
 
        subscribe: function(type, fn, context) {
1514
 
 
1515
 
            if (Y.Lang.isObject(type)) {
1516
 
 
1517
 
                var f = fn, c = context, args = Y.Array(arguments, 0, true),
1518
 
                    ret = {};
1519
 
 
1520
 
                Y.each(type, function(v, k) {
1521
 
 
1522
 
                    if (v) {
1523
 
                        f = v.fn || f;
1524
 
                        c = v.context || c;
1525
 
                    }
1526
 
 
1527
 
                    args[0] = k;
1528
 
                    args[1] = f;
1529
 
                    args[2] = c;
1530
 
 
1531
 
                    ret[k] = this.subscribe.apply(this, args); 
1532
 
 
1533
 
                }, this);
1534
 
 
1535
 
                return ret;
1536
 
 
1537
 
            }
1538
 
 
1539
 
            var ce = this._yuievt.events[type] || 
1540
 
                // this.publish(type, {
1541
 
                //     configured: false
1542
 
                // }),
1543
 
                this.publish(type),
1544
 
                a = Y.Array(arguments, 1, true);
1545
 
 
1546
 
            return ce.subscribe.apply(ce, a);
1547
 
 
1548
 
        },
1549
 
 
1550
 
        /**
1551
 
         * Unsubscribes one or more listeners the from the specified event
1552
 
         * @method unsubscribe
1553
 
         * @param type {string|Object}   Either the handle to the subscriber or the 
1554
 
         *                        type of event.  If the type
1555
 
         *                        is not specified, it will attempt to remove
1556
 
         *                        the listener from all hosted events.
1557
 
         * @param fn   {Function} The subscribed function to unsubscribe, if not
1558
 
         *                          supplied, all subscribers will be removed.
1559
 
         * @param context  {Object}   The custom object passed to subscribe.  This is
1560
 
         *                        optional, but if supplied will be used to
1561
 
         *                        disambiguate multiple listeners that are the same
1562
 
         *                        (e.g., you subscribe many object using a function
1563
 
         *                        that lives on the prototype)
1564
 
         * @return {boolean} true if the subscriber was found and detached.
1565
 
         */
1566
 
        unsubscribe: function(type, fn, context) {
1567
 
 
1568
 
            // If this is an event handle, use it to detach
1569
 
            if (Y.Lang.isObject(type) && type.detach) {
1570
 
                return type.detach();
1571
 
            }
1572
 
 
1573
 
            var evts = this._yuievt.events;
1574
 
 
1575
 
            if (type) {
1576
 
                var ce = evts[type];
1577
 
                if (ce) {
1578
 
                    return ce.unsubscribe(fn, context);
1579
 
                }
1580
 
            } else {
1581
 
                var ret = true;
1582
 
                for (var i in evts) {
1583
 
                    if (Y.Object.owns(evts, i)) {
1584
 
                        ret = ret && evts[i].unsubscribe(fn, context);
1585
 
                    }
1586
 
                }
1587
 
                return ret;
1588
 
            }
1589
 
 
1590
 
            return false;
1591
 
        },
1592
 
        
1593
 
        /**
1594
 
         * Removes all listeners from the specified event.  If the event type
1595
 
         * is not specified, all listeners from all hosted custom events will
1596
 
         * be removed.
1597
 
         * @method unsubscribeAll
1598
 
         * @param type {string}   The type, or name of the event
1599
 
         */
1600
 
        unsubscribeAll: function(type) {
1601
 
            return this.unsubscribe(type);
1602
 
        },
1603
 
 
1604
 
        /**
1605
 
         * Creates a new custom event of the specified type.  If a custom event
1606
 
         * by that name already exists, it will not be re-created.  In either
1607
 
         * case the custom event is returned. 
1608
 
         *
1609
 
         * @method publish
1610
 
         *
1611
 
         * @param type {string} the type, or name of the event
1612
 
         * @param opts {object} optional config params.  Valid properties are:
1613
 
         *
1614
 
         *  <ul>
1615
 
         *    <li>
1616
 
         *   'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
1617
 
         *    </li>
1618
 
         *    <li>
1619
 
         *   'bubbles': whether or not this event bubbles (true)
1620
 
         *    </li>
1621
 
         *    <li>
1622
 
         *   'context': the default execution context for the listeners (this)
1623
 
         *    </li>
1624
 
         *    <li>
1625
 
         *   'defaultFn': the default function to execute when this event fires if preventDefault was not called
1626
 
         *    </li>
1627
 
         *    <li>
1628
 
         *   'emitFacade': whether or not this event emits a facade (false)
1629
 
         *    </li>
1630
 
         *    <li>
1631
 
         *   'fireOnce': if an event is configured to fire once, new subscribers after
1632
 
         *   the fire will be notified immediately.
1633
 
         *    </li>
1634
 
         *    <li>
1635
 
         *   'preventable': whether or not preventDefault() has an effect (true)
1636
 
         *    </li>
1637
 
         *    <li>
1638
 
         *   'preventedFn': a function that is executed when preventDefault is called
1639
 
         *    </li>
1640
 
         *    <li>
1641
 
         *   'queuable': whether or not this event can be queued during bubbling (false)
1642
 
         *    </li>
1643
 
         *    <li>
1644
 
         *   'silent': if silent is true, debug messages are not provided for this event.
1645
 
         *    </li>
1646
 
         *    <li>
1647
 
         *   'stoppedFn': a function that is executed when stopPropagation is called
1648
 
         *    </li>
1649
 
         *    <li>
1650
 
         *   'type': the event type (valid option if not provided as the first parameter to publish)
1651
 
         *    </li>
1652
 
         *  </ul>
1653
 
         *
1654
 
         *  @return {Event.Custom} the custom event
1655
 
         *
1656
 
         */
1657
 
        publish: function(type, opts) {
1658
 
 
1659
 
            if (Y.Lang.isObject(type)) {
1660
 
                var ret = {};
1661
 
                Y.each(type, function(v, k) {
1662
 
                    ret[k] = this.publish(k, v || opts); 
1663
 
                }, this);
1664
 
 
1665
 
                return ret;
1666
 
            }
1667
 
 
1668
 
            var events = this._yuievt.events, ce = events[type];
1669
 
 
1670
 
            //if (ce && !ce.configured) {
1671
 
            if (ce) {
1672
 
// ce.log("publish applying config to published event: '"+type+"' exists", 'info', 'event');
1673
 
 
1674
 
                // This event could have been published
1675
 
                ce.applyConfig(opts, true);
1676
 
                // ce.configured = true;
1677
 
 
1678
 
            } else {
1679
 
                var o = opts || {};
1680
 
 
1681
 
                // apply defaults
1682
 
                Y.mix(o, this._yuievt.defaults);
1683
 
 
1684
 
                ce = new Y.CustomEvent(type, o);
1685
 
 
1686
 
                events[type] = ce;
1687
 
 
1688
 
                if (o.onSubscribeCallback) {
1689
 
                    ce.subscribeEvent.subscribe(o.onSubscribeCallback);
1690
 
                }
1691
 
 
1692
 
            }
1693
 
 
1694
 
            return events[type];
1695
 
        },
1696
 
 
1697
 
        /**
1698
 
         * Registers another Event.Target as a bubble target.  Bubble order
1699
 
         * is determined by the order registered.  Multiple targets can
1700
 
         * be specified.
1701
 
         * @method addTarget
1702
 
         * @param o {Event.Target} the target to add
1703
 
         */
1704
 
        addTarget: function(o) {
1705
 
            this._yuievt.targets[Y.stamp(o)] = o;
1706
 
            this._yuievt.hasTargets = true;
1707
 
        },
1708
 
 
1709
 
        /**
1710
 
         * Removes a bubble target
1711
 
         * @method removeTarget
1712
 
         * @param o {Event.Target} the target to remove
1713
 
         */
1714
 
        removeTarget: function(o) {
1715
 
            delete this._yuievt.targets[Y.stamp(o)];
1716
 
        },
1717
 
 
1718
 
       /**
1719
 
         * Fire a custom event by name.  The callback functions will be executed
1720
 
         * from the context specified when the event was created, and with the 
1721
 
         * following parameters.
1722
 
         *
1723
 
         * If the custom event object hasn't been created, then the event hasn't 
1724
 
         * been published and it has no subscribers.  For performance sake, we 
1725
 
         * immediate exit in this case.  This means the event won't bubble, so 
1726
 
         * if the intention is that a bubble target be notified, the event must 
1727
 
         * be published on this object first.
1728
 
         *
1729
 
         * @method fire
1730
 
         * @param type {String|Object} The type of the event, or an object that contains
1731
 
         * a 'type' property.
1732
 
         * @param arguments {Object*} an arbitrary set of parameters to pass to 
1733
 
         * the handler.
1734
 
         * @return {boolean} the return value from Event.Custom.fire
1735
 
         *                   
1736
 
         */
1737
 
        fire: function(type) {
1738
 
 
1739
 
            var typeIncluded = Y.Lang.isString(type),
1740
 
                t = (typeIncluded) ? type : (type && type.type);
1741
 
 
1742
 
            var ce = this.getEvent(t);
1743
 
 
1744
 
            // this event has not been published or subscribed to
1745
 
            if (!ce) {
1746
 
                
1747
 
                // if this object has bubble targets, we need to publish the
1748
 
                // event in order for it to bubble.
1749
 
                if (this._yuievt.hasTargets) {
1750
 
                    // ce = this.publish(t, {
1751
 
                    //     configured: false
1752
 
                    // });
1753
 
                    ce = this.publish(t);
1754
 
                    ce.details = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
1755
 
 
1756
 
                    return this.bubble(ce);
1757
 
                }
1758
 
 
1759
 
                // otherwise there is nothing to be done
1760
 
                return true;
1761
 
            }
1762
 
 
1763
 
            // Provide this object's subscribers the object they are listening to.
1764
 
            // ce.currentTarget = this;
1765
 
 
1766
 
            // This this the target unless target is current not null
1767
 
            // (set in bubble()).
1768
 
            // ce.target = ce.target || this;
1769
 
 
1770
 
            var a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
1771
 
            var ret = ce.fire.apply(ce, a);
1772
 
 
1773
 
            // clear target for next fire()
1774
 
            ce.target = null;
1775
 
 
1776
 
            return ret;
1777
 
        },
1778
 
 
1779
 
        /**
1780
 
         * Returns the custom event of the provided type has been created, a
1781
 
         * falsy value otherwise
1782
 
         * @method getEvent
1783
 
         * @param type {string} the type, or name of the event
1784
 
         * @return {Event.Custom} the custom event or null
1785
 
         */
1786
 
        getEvent: function(type) {
1787
 
            var e = this._yuievt.events;
1788
 
            return (e && type in e) ? e[type] : null;
1789
 
        },
1790
 
 
1791
 
        /**
1792
 
         * Propagate an event
1793
 
         * @method bubble
1794
 
         * @param evt {Event.Custom} the custom event to propagate
1795
 
         * @return {boolean} the aggregated return value from Event.Custom.fire
1796
 
         */
1797
 
        bubble: function(evt) {
1798
 
 
1799
 
            var targs = this._yuievt.targets, ret = true;
1800
 
 
1801
 
            if (!evt.stopped && targs) {
1802
 
 
1803
 
 
1804
 
                for (var i in targs) {
1805
 
                    if (targs.hasOwnProperty(i)) {
1806
 
 
1807
 
                        var t = targs[i], type = evt.type,
1808
 
                            ce = t.getEvent(type), targetProp = evt.target || this;
1809
 
                            
1810
 
                        // if this event was not published on the bubble target,
1811
 
                        // publish it with sensible default properties
1812
 
                        if (!ce) {
1813
 
 
1814
 
                            // publish the event on the bubble target using this event
1815
 
                            // for its configuration
1816
 
                            ce = t.publish(type, evt);
1817
 
                            // ce.configured = false;
1818
 
 
1819
 
                            // set the host and context appropriately
1820
 
                            ce.context = (evt.host === evt.context) ? t : evt.context;
1821
 
                            ce.host = t;
1822
 
 
1823
 
                            // clear handlers if specified on this event
1824
 
                            ce.defaultFn = null;
1825
 
                            ce.preventedFn = null;
1826
 
                            ce.stoppedFn = null;
1827
 
                        }
1828
 
 
1829
 
                        ce.target = targetProp;
1830
 
                        ce.currentTarget = t;
1831
 
 
1832
 
                        // ce.target = evt.target;
1833
 
 
1834
 
                        ret = ret && ce.fire.apply(ce, evt.details);
1835
 
 
1836
 
                        // stopPropagation() was called
1837
 
                        if (ce.stopped) {
1838
 
                            break;
1839
 
                        }
1840
 
                    }
1841
 
                }
1842
 
            }
1843
 
 
1844
 
            return ret;
1845
 
        },
1846
 
 
1847
 
        /**
1848
 
         * Subscribe to a custom event hosted by this object.  The
1849
 
         * supplied callback will execute after any listeners add
1850
 
         * via the subscribe method, and after the default function,
1851
 
         * if configured for the event, has executed.
1852
 
         * @method after
1853
 
         * @param type    {string}   The type of the event
1854
 
         * @param fn {Function} The callback
1855
 
         * @param context The execution context
1856
 
         * @param args* 1..n params to supply to the callback
1857
 
         */
1858
 
        after: function(type, fn) {
1859
 
            if (Y.Lang.isFunction(type)) {
1860
 
                return Y.Do.after.apply(Y.Do, arguments);
1861
 
            } else {
1862
 
                var ce = this._yuievt.events[type] || 
1863
 
                    // this.publish(type, {
1864
 
                    //     configured: false
1865
 
                    // }),
1866
 
                    this.publish(type),
1867
 
                    a = Y.Array(arguments, 1, true);
1868
 
 
1869
 
                return ce.after.apply(ce, a);
1870
 
            }
1871
 
        },
1872
 
 
1873
 
        before: function(type, fn) {
1874
 
            if (Y.Lang.isFunction(type)) {
1875
 
                return Y.Do.after.apply(Y.Do, arguments);
1876
 
            } else {
1877
 
                return this.subscribe.apply(this, arguments);
1878
 
            }
1879
 
        }
1880
 
 
1881
 
    };
1882
 
 
1883
 
    // make Y an event target
1884
 
    Y.mix(Y, ET.prototype, false, false, { 
1885
 
        bubbles: false 
1886
 
    });
1887
 
    ET.call(Y);
1888
 
 
1889
 
 
1890
 
}, "3.0.0");
1891
 
 
1892
 
/*
1893
 
 * DOMReady
1894
 
 * @submodule event-ready
1895
 
 * @module event
1896
 
 */
1897
 
 
1898
 
(function() {
1899
 
 
1900
 
var Env = YUI.Env, 
1901
 
    C = YUI.config, 
1902
 
    D = C.doc, 
1903
 
    POLL_INTERVAL = C.pollInterval || 20;
1904
 
 
1905
 
    if (!Env._ready) {
1906
 
 
1907
 
        Env.windowLoaded = false;
1908
 
 
1909
 
        var _ready = function(e) {
1910
 
            YUI.Env._ready();
1911
 
        };
1912
 
 
1913
 
        Env._ready = function() {
1914
 
            if (!Env.DOMReady) {
1915
 
                Env.DOMReady=true;
1916
 
 
1917
 
                // Remove the DOMContentLoaded (FF/Opera)
1918
 
                if (D.removeEventListener) {
1919
 
                    D.removeEventListener("DOMContentLoaded", _ready, false);
1920
 
                }
1921
 
            }
1922
 
        };
1923
 
 
1924
 
        // create custom event
1925
 
 
1926
 
        /////////////////////////////////////////////////////////////
1927
 
        // DOMReady
1928
 
        // based on work by: Dean Edwards/John Resig/Matthias Miller 
1929
 
 
1930
 
        // Internet Explorer: use the readyState of a defered script.
1931
 
        // This isolates what appears to be a safe moment to manipulate
1932
 
        // the DOM prior to when the document's readyState suggests
1933
 
        // it is safe to do so.
1934
 
        if (navigator.userAgent.match(/MSIE/)) {
1935
 
 
1936
 
            Env._dri = setInterval(function() {
1937
 
                try {
1938
 
                    // throws an error if doc is not ready
1939
 
                    document.documentElement.doScroll('left');
1940
 
                    clearInterval(Env._dri);
1941
 
                    Env._dri = null;
1942
 
                    _ready();
1943
 
                } catch (ex) { 
1944
 
                }
1945
 
            }, POLL_INTERVAL); 
1946
 
 
1947
 
        // FireFox and Opera: These browsers provide a event for this
1948
 
        // moment.  The latest WebKit releases now support this event.
1949
 
        } else {
1950
 
            D.addEventListener("DOMContentLoaded", _ready, false);
1951
 
        }
1952
 
 
1953
 
        /////////////////////////////////////////////////////////////
1954
 
    }
1955
 
 
1956
 
    YUI.add("event-ready", function(Y) {
1957
 
 
1958
 
        if (Y === YUI) {
1959
 
            return;
1960
 
        }
1961
 
 
1962
 
        Y.mix(Y.Env.eventAdaptors, {
1963
 
 
1964
 
            /**
1965
 
             * Executes the supplied callback when the DOM is first usable.  This
1966
 
             * will execute immediately if called after the DOMReady event has
1967
 
             * fired.   @todo the DOMContentReady event does not fire when the
1968
 
             * script is dynamically injected into the page.  This means the
1969
 
             * DOMReady custom event will never fire in FireFox or Opera when the
1970
 
             * library is injected.  It _will_ fire in Safari, and the IE 
1971
 
             * implementation would allow for us to fire it if the defered script
1972
 
             * is not available.  We want this to behave the same in all browsers.
1973
 
             * Is there a way to identify when the script has been injected 
1974
 
             * instead of included inline?  Is there a way to know whether the 
1975
 
             * window onload event has fired without having had a listener attached 
1976
 
             * to it when it did so?
1977
 
             *
1978
 
             * <p>The callback is a Event.Custom, so the signature is:</p>
1979
 
             * <p>type &lt;string&gt;, args &lt;array&gt;, customobject &lt;object&gt;</p>
1980
 
             * <p>For DOMReady events, there are no fire argments, so the
1981
 
             * signature is:</p>
1982
 
             * <p>"DOMReady", [], obj</p>
1983
 
             *
1984
 
             *
1985
 
             * @event domready
1986
 
             * @for YUI
1987
 
             *
1988
 
             * @param {function} fn what to execute when the element is found.
1989
 
             * @optional context execution context
1990
 
             * @optional args 1..n arguments to send to the listener
1991
 
             *
1992
 
             */
1993
 
            domready: {
1994
 
 
1995
 
            },
1996
 
 
1997
 
            /**
1998
 
             * Use domready event instead. @see domready
1999
 
             * @event event:ready
2000
 
             * @for YUI
2001
 
             * @deprecated use 'domready' instead
2002
 
             */
2003
 
            'event:ready': {
2004
 
 
2005
 
                on: function() {
2006
 
                    arguments[0] = 'domready';
2007
 
                    return Y.subscribe.apply(Y, arguments);
2008
 
                },
2009
 
 
2010
 
                detach: function() {
2011
 
                    arguments[0] = 'domready';
2012
 
                    return Y.unsubscribe.apply(Y, arguments);
2013
 
                }
2014
 
            }
2015
 
 
2016
 
        });
2017
 
 
2018
 
 
2019
 
        Y.publish('domready', {
2020
 
            fireOnce: true
2021
 
        });
2022
 
 
2023
 
        var yready = function() {
2024
 
            Y.fire('domready');
2025
 
        };
2026
 
 
2027
 
        if (Env.DOMReady) {
2028
 
            yready();
2029
 
        } else {
2030
 
            Y.before(yready, Env, "_ready");
2031
 
        }
2032
 
 
2033
 
    }, "3.0.0");
2034
 
 
2035
 
})();
2036
 
/*
2037
 
 * The YUI DOM event system
2038
 
 * @submodule event-dom
2039
 
 * @module event
2040
 
 */
2041
 
(function() {
2042
 
 
2043
 
    var add = function(el, type, fn, capture) {
2044
 
        if (el.addEventListener) {
2045
 
                el.addEventListener(type, fn, !!capture);
2046
 
        } else if (el.attachEvent) {
2047
 
                el.attachEvent("on" + type, fn);
2048
 
        } 
2049
 
    },
2050
 
 
2051
 
    remove = function(el, type, fn, capture) {
2052
 
        if (el.removeEventListener) {
2053
 
                el.removeEventListener(type, fn, !!capture);
2054
 
        } else if (el.detachEvent) {
2055
 
                el.detachEvent("on" + type, fn);
2056
 
        }
2057
 
    },
2058
 
 
2059
 
    onLoad = function() {
2060
 
        YUI.Env.windowLoaded = true;
2061
 
        remove(window, "load", onLoad);
2062
 
    },
2063
 
 
2064
 
    EVENT_READY = 'domready',
2065
 
 
2066
 
    COMPAT_ARG = '~yui|2|compat~',
2067
 
 
2068
 
    CAPTURE = "capture_";
2069
 
 
2070
 
add(window, "load", onLoad);
2071
 
 
2072
 
YUI.add("event-dom", function(Y) {
2073
 
 
2074
 
    /**
2075
 
     * The event utility provides functions to add and remove event listeners,
2076
 
     * event cleansing.  It also tries to automatically remove listeners it
2077
 
     * registers during the unload event.
2078
 
     *
2079
 
     * @class Event
2080
 
     * @static
2081
 
     */
2082
 
    Y.Event = function() {
2083
 
 
2084
 
        /**
2085
 
         * True after the onload event has fired
2086
 
         * @property loadComplete
2087
 
         * @type boolean
2088
 
         * @static
2089
 
         * @private
2090
 
         */
2091
 
        var loadComplete =  false;
2092
 
 
2093
 
        /**
2094
 
         * The number of times to poll after window.onload.  This number is
2095
 
         * increased if additional late-bound handlers are requested after
2096
 
         * the page load.
2097
 
         * @property _retryCount
2098
 
         * @static
2099
 
         * @private
2100
 
         */
2101
 
        var _retryCount = 0;
2102
 
 
2103
 
        /**
2104
 
         * onAvailable listeners
2105
 
         * @property _avail
2106
 
         * @static
2107
 
         * @private
2108
 
         */
2109
 
        var _avail = [];
2110
 
 
2111
 
        /**
2112
 
         * Custom event wrappers for DOM events.  Key is 
2113
 
         * 'event:' + Element uid stamp + event type
2114
 
         * @property _wrappers
2115
 
         * @type Y.Event.Custom
2116
 
         * @static
2117
 
         * @private
2118
 
         */
2119
 
        var _wrappers = {};
2120
 
 
2121
 
        var _windowLoadKey = null;
2122
 
 
2123
 
        /**
2124
 
         * Custom event wrapper map DOM events.  Key is 
2125
 
         * Element uid stamp.  Each item is a hash of custom event
2126
 
         * wrappers as provided in the _wrappers collection.  This
2127
 
         * provides the infrastructure for getListeners.
2128
 
         * @property _el_events
2129
 
         * @static
2130
 
         * @private
2131
 
         */
2132
 
        var _el_events = {};
2133
 
 
2134
 
        return {
2135
 
 
2136
 
            /**
2137
 
             * The number of times we should look for elements that are not
2138
 
             * in the DOM at the time the event is requested after the document
2139
 
             * has been loaded.  The default is 2000@amp;20 ms, so it will poll
2140
 
             * for 40 seconds or until all outstanding handlers are bound
2141
 
             * (whichever comes first).
2142
 
             * @property POLL_RETRYS
2143
 
             * @type int
2144
 
             * @static
2145
 
             * @final
2146
 
             */
2147
 
            POLL_RETRYS: 2000,
2148
 
 
2149
 
            /**
2150
 
             * The poll interval in milliseconds
2151
 
             * @property POLL_INTERVAL
2152
 
             * @type int
2153
 
             * @static
2154
 
             * @final
2155
 
             */
2156
 
            POLL_INTERVAL: 20,
2157
 
 
2158
 
            /**
2159
 
             * addListener/removeListener can throw errors in unexpected scenarios.
2160
 
             * These errors are suppressed, the method returns false, and this property
2161
 
             * is set
2162
 
             * @property lastError
2163
 
             * @static
2164
 
             * @type Error
2165
 
             */
2166
 
            lastError: null,
2167
 
 
2168
 
 
2169
 
            /**
2170
 
             * poll handle
2171
 
             * @property _interval
2172
 
             * @static
2173
 
             * @private
2174
 
             */
2175
 
            _interval: null,
2176
 
 
2177
 
            /**
2178
 
             * document readystate poll handle
2179
 
             * @property _dri
2180
 
             * @static
2181
 
             * @private
2182
 
             */
2183
 
             _dri: null,
2184
 
 
2185
 
            /**
2186
 
             * True when the document is initially usable
2187
 
             * @property DOMReady
2188
 
             * @type boolean
2189
 
             * @static
2190
 
             */
2191
 
            DOMReady: false,
2192
 
 
2193
 
            /**
2194
 
             * @method startInterval
2195
 
             * @static
2196
 
             * @private
2197
 
             */
2198
 
            startInterval: function() {
2199
 
                var E = Y.Event;
2200
 
 
2201
 
                if (!E._interval) {
2202
 
E._interval = setInterval(Y.bind(E._tryPreloadAttach, E), E.POLL_INTERVAL);
2203
 
                }
2204
 
            },
2205
 
 
2206
 
            /**
2207
 
             * Executes the supplied callback when the item with the supplied
2208
 
             * id is found.  This is meant to be used to execute behavior as
2209
 
             * soon as possible as the page loads.  If you use this after the
2210
 
             * initial page load it will poll for a fixed time for the element.
2211
 
             * The number of times it will poll and the frequency are
2212
 
             * configurable.  By default it will poll for 10 seconds.
2213
 
             *
2214
 
             * <p>The callback is executed with a single parameter:
2215
 
             * the custom object parameter, if provided.</p>
2216
 
             *
2217
 
             * @method onAvailable
2218
 
             *
2219
 
             * @param {string||string[]}   id the id of the element, or an array
2220
 
             * of ids to look for.
2221
 
             * @param {function} fn what to execute when the element is found.
2222
 
             * @param {object}   p_obj an optional object to be passed back as
2223
 
             *                   a parameter to fn.
2224
 
             * @param {boolean|object}  p_override If set to true, fn will execute
2225
 
             *                   in the context of p_obj, if set to an object it
2226
 
             *                   will execute in the context of that object
2227
 
             * @param checkContent {boolean} check child node readiness (onContentReady)
2228
 
             * @static
2229
 
             * @deprecated Use Y.on("available")
2230
 
             */
2231
 
            // @TODO fix arguments
2232
 
            onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
2233
 
 
2234
 
                var a = Y.Array(id);
2235
 
 
2236
 
 
2237
 
                for (var i=0; i<a.length; i=i+1) {
2238
 
                    _avail.push({ 
2239
 
                        id:         a[i], 
2240
 
                        fn:         fn, 
2241
 
                        obj:        p_obj, 
2242
 
                        override:   p_override, 
2243
 
                        checkReady: checkContent,
2244
 
                        compat:     compat 
2245
 
                    });
2246
 
                }
2247
 
                _retryCount = this.POLL_RETRYS;
2248
 
 
2249
 
                // We want the first test to be immediate, but async
2250
 
                setTimeout(Y.bind(Y.Event._tryPreloadAttach, Y.Event), 0);
2251
 
 
2252
 
                return new Y.EventHandle(); // @TODO by id needs a defered handle
2253
 
            },
2254
 
 
2255
 
            /**
2256
 
             * Works the same way as onAvailable, but additionally checks the
2257
 
             * state of sibling elements to determine if the content of the
2258
 
             * available element is safe to modify.
2259
 
             *
2260
 
             * <p>The callback is executed with a single parameter:
2261
 
             * the custom object parameter, if provided.</p>
2262
 
             *
2263
 
             * @method onContentReady
2264
 
             *
2265
 
             * @param {string}   id the id of the element to look for.
2266
 
             * @param {function} fn what to execute when the element is ready.
2267
 
             * @param {object}   p_obj an optional object to be passed back as
2268
 
             *                   a parameter to fn.
2269
 
             * @param {boolean|object}  p_override If set to true, fn will execute
2270
 
             *                   in the context of p_obj.  If an object, fn will
2271
 
             *                   exectute in the context of that object
2272
 
             *
2273
 
             * @static
2274
 
             * @deprecated Use Y.on("contentready")
2275
 
             */
2276
 
            // @TODO fix arguments
2277
 
            onContentReady: function(id, fn, p_obj, p_override, compat) {
2278
 
                return this.onAvailable(id, fn, p_obj, p_override, true, compat);
2279
 
            },
2280
 
 
2281
 
 
2282
 
            /**
2283
 
             * Appends an event handler
2284
 
             *
2285
 
             * @method attach
2286
 
             *
2287
 
             * @param {String}   type     The type of event to append
2288
 
             * @param {Function} fn        The method the event invokes
2289
 
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
2290
 
             *  reference, or a collection of ids and/or elements to assign the 
2291
 
             *  listener to.
2292
 
             * @param {Object}   obj    An arbitrary object that will be 
2293
 
             *                             passed as a parameter to the handler
2294
 
             * @param {Boolean|object}  args 1..n ar
2295
 
             * @return {Boolean} True if the action was successful or defered,
2296
 
             *                        false if one or more of the elements 
2297
 
             *                        could not have the listener attached,
2298
 
             *                        or if the operation throws an exception.
2299
 
             * @static
2300
 
             */
2301
 
            attach: function(type, fn, el, obj) {
2302
 
 
2303
 
                // var a=Y.Array(arguments, 1, true), override=a[3], E=Y.Event, aa=Y.Array(arguments, 0, true);
2304
 
 
2305
 
                var args=Y.Array(arguments, 0, true), 
2306
 
                    trimmedArgs=args.slice(1),
2307
 
                    compat, E=Y.Event, capture = false;
2308
 
 
2309
 
                if (type.indexOf(CAPTURE) > -1) {
2310
 
                    type = type.substr(CAPTURE.length);
2311
 
                    capture = true;
2312
 
                }
2313
 
 
2314
 
                if (trimmedArgs[trimmedArgs.length-1] === COMPAT_ARG) {
2315
 
                    compat = true;
2316
 
                    trimmedArgs.pop();
2317
 
                }
2318
 
 
2319
 
                if (!fn || !fn.call) {
2320
 
// throw new TypeError(type + " attach call failed, callback undefined");
2321
 
                    return false;
2322
 
                }
2323
 
 
2324
 
                // The el argument can be an array of elements or element ids.
2325
 
                if (this._isValidCollection(el)) {
2326
 
 
2327
 
 
2328
 
                    var handles=[], i, l;
2329
 
                    
2330
 
                    Y.each(el, function(v, k) {
2331
 
                        args[2] = v;
2332
 
                        handles.push(E.attach.apply(E, args));
2333
 
                    });
2334
 
 
2335
 
                    return handles;
2336
 
 
2337
 
 
2338
 
                } else if (Y.Lang.isString(el)) {
2339
 
 
2340
 
                    var oEl = (compat) ? Y.DOM.byId(el) : Y.all(el);
2341
 
 
2342
 
                    // If the el argument is a string, we assume it is 
2343
 
                    // actually the id of the element.  If the page is loaded
2344
 
                    // we convert el to the actual element, otherwise we 
2345
 
                    // defer attaching the event until onload event fires
2346
 
 
2347
 
                    // check to see if we need to delay hooking up the event 
2348
 
                    // until after the page loads.
2349
 
 
2350
 
                    // Node collection
2351
 
                    // if (oEl && oEl.size && oEl.size() > 0) {
2352
 
                    //
2353
 
 
2354
 
                    /*
2355
 
                    if (oEl) {
2356
 
                        el = oEl;
2357
 
                    */
2358
 
 
2359
 
                    if (oEl && (oEl instanceof Y.Node)) {
2360
 
                        var size = oEl.size();
2361
 
                        if (size > 1) {
2362
 
                            // args[0] = oEl;
2363
 
                            args[2] = oEl;
2364
 
                            return E.attach.apply(E, args);
2365
 
                        } else {
2366
 
                            el = oEl.item(0);
2367
 
                            // el = oEl;
2368
 
                        }
2369
 
 
2370
 
                    // HTMLElement
2371
 
                    // } else if (compat && oEl) {
2372
 
                    } else if (oEl) {
2373
 
                        el = oEl;
2374
 
 
2375
 
                    // Not found = defer adding the event until the element is available
2376
 
                    } else {
2377
 
 
2378
 
 
2379
 
                        return this.onAvailable(el, function() {
2380
 
                            E.attach.apply(E, args);
2381
 
                        }, E, true, false, compat);
2382
 
                    }
2383
 
                }
2384
 
 
2385
 
                // Element should be an html element or an array if we get here.
2386
 
                if (!el) {
2387
 
                    return false;
2388
 
                }
2389
 
 
2390
 
                // the custom event key is the uid for the element + type
2391
 
 
2392
 
                var ek = Y.stamp(el), key = 'event:' + ek + type,
2393
 
                    cewrapper = _wrappers[key];
2394
 
 
2395
 
 
2396
 
                if (!cewrapper) {
2397
 
                    // create CE wrapper
2398
 
                    cewrapper = Y.publish(key, {
2399
 
                        silent: true,
2400
 
                        // host: this,
2401
 
                        bubbles: false
2402
 
                    });
2403
 
 
2404
 
                    // cache the dom event details in the custom event
2405
 
                    // for later removeListener calls
2406
 
                    cewrapper.el = el;
2407
 
                    cewrapper.type = type;
2408
 
                    cewrapper.fn = function(e) {
2409
 
                        cewrapper.fire(E.getEvent(e, el, compat));
2410
 
                    };
2411
 
 
2412
 
                    if (el == Y.config.win && type == "load") {
2413
 
                        // window load happens once
2414
 
                        cewrapper.fireOnce = true;
2415
 
                        _windowLoadKey = key;
2416
 
 
2417
 
                        // if the load is complete, fire immediately.
2418
 
                        // all subscribers, including the current one
2419
 
                        // will be notified.
2420
 
                        if (YUI.Env.windowLoaded) {
2421
 
                            cewrapper.fire();
2422
 
                        }
2423
 
                    }
2424
 
 
2425
 
                    _wrappers[key] = cewrapper;
2426
 
                    _el_events[ek] = _el_events[ek] || {};
2427
 
                    _el_events[ek][key] = cewrapper;
2428
 
 
2429
 
                    // var capture = (Y.lang.isObject(obj) && obj.capture);
2430
 
                    // attach a listener that fires the custom event
2431
 
 
2432
 
                    add(el, type, cewrapper.fn, capture);
2433
 
                }
2434
 
 
2435
 
                // switched from obj to trimmedArgs[2] to deal with appened compat param
2436
 
                var context = trimmedArgs[2] || ((compat) ? el : Y.get(el));
2437
 
                
2438
 
                // set the context as the second arg to subscribe
2439
 
                trimmedArgs[1] = context;
2440
 
 
2441
 
                // remove the 'obj' param
2442
 
                trimmedArgs.splice(2, 1);
2443
 
 
2444
 
                // set context to the Node if not specified
2445
 
                return cewrapper.subscribe.apply(cewrapper, trimmedArgs);
2446
 
 
2447
 
            },
2448
 
 
2449
 
            /**
2450
 
             * Removes an event listener.  Supports the signature the event was bound
2451
 
             * with, but the preferred way to remove listeners is using the handle
2452
 
             * that is returned when using Y.on
2453
 
             *
2454
 
             * @method detach
2455
 
             *
2456
 
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
2457
 
             *  reference, or a collection of ids and/or elements to remove
2458
 
             *  the listener from.
2459
 
             * @param {String} type the type of event to remove.
2460
 
             * @param {Function} fn the method the event invokes.  If fn is
2461
 
             *  undefined, then all event handlers for the type of event are *  removed.
2462
 
             * @return {boolean} true if the unbind was successful, false *  otherwise.
2463
 
             * @static
2464
 
             */
2465
 
            detach: function(type, fn, el, obj) {
2466
 
 
2467
 
                var args=Y.Array(arguments, 0, true), compat;
2468
 
 
2469
 
                if (args[args.length-1] === COMPAT_ARG) {
2470
 
                    compat = true;
2471
 
                    // args.pop();
2472
 
                }
2473
 
 
2474
 
                if (type && type.detach) {
2475
 
                    return type.detach();
2476
 
                }
2477
 
 
2478
 
                var i, len, li;
2479
 
 
2480
 
                // The el argument can be a string
2481
 
                if (typeof el == "string") {
2482
 
 
2483
 
                    el = (compat) ? Y.DOM.byId(el) : Y.all(el);
2484
 
 
2485
 
                // The el argument can be an array of elements or element ids.
2486
 
                } else if ( this._isValidCollection(el)) {
2487
 
 
2488
 
                    var ok = true;
2489
 
                    for (i=0, len=el.length; i<len; ++i) {
2490
 
 
2491
 
                        args[2] = el[i];
2492
 
 
2493
 
                        // ok = ( this.detach(el[i], type, fn) && ok );
2494
 
                        ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
2495
 
                    }
2496
 
 
2497
 
                    return ok;
2498
 
 
2499
 
                }
2500
 
 
2501
 
                if (!fn || !fn.call) {
2502
 
                    return this.purgeElement(el, false, type);
2503
 
                }
2504
 
 
2505
 
                var id = 'event:' + Y.stamp(el) + type, 
2506
 
                    ce = _wrappers[id];
2507
 
                if (ce) {
2508
 
                    return ce.unsubscribe(fn);
2509
 
                } else {
2510
 
                    return false;
2511
 
                }
2512
 
 
2513
 
            },
2514
 
 
2515
 
            /**
2516
 
             * Finds the event in the window object, the caller's arguments, or
2517
 
             * in the arguments of another method in the callstack.  This is
2518
 
             * executed automatically for events registered through the event
2519
 
             * manager, so the implementer should not normally need to execute
2520
 
             * this function at all.
2521
 
             * @method getEvent
2522
 
             * @param {Event} e the event parameter from the handler
2523
 
             * @param {HTMLElement} el the element the listener was attached to
2524
 
             * @return {Event} the event 
2525
 
             * @static
2526
 
             */
2527
 
            getEvent: function(e, el, noFacade) {
2528
 
                var ev = e || window.event;
2529
 
 
2530
 
                return (noFacade) ? ev : 
2531
 
                    new Y.Event.Facade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
2532
 
            },
2533
 
 
2534
 
            /**
2535
 
             * Generates an unique ID for the element if it does not already 
2536
 
             * have one.
2537
 
             * @method generateId
2538
 
             * @param el the element to create the id for
2539
 
             * @return {string} the resulting id of the element
2540
 
             * @static
2541
 
             */
2542
 
            generateId: function(el) {
2543
 
                var id = el.id;
2544
 
 
2545
 
                if (!id) {
2546
 
                    id = Y.stamp(el);
2547
 
                    el.id = id;
2548
 
                }
2549
 
 
2550
 
                return id;
2551
 
            },
2552
 
 
2553
 
            /**
2554
 
             * We want to be able to use getElementsByTagName as a collection
2555
 
             * to attach a group of events to.  Unfortunately, different 
2556
 
             * browsers return different types of collections.  This function
2557
 
             * tests to determine if the object is array-like.  It will also 
2558
 
             * fail if the object is an array, but is empty.
2559
 
             * @method _isValidCollection
2560
 
             * @param o the object to test
2561
 
             * @return {boolean} true if the object is array-like and populated
2562
 
             * @static
2563
 
             * @private
2564
 
             */
2565
 
            _isValidCollection: function(o) {
2566
 
                try {
2567
 
                     
2568
 
                    // if (o instanceof Y.Node) {
2569
 
                        // o.tagName ="adsf";
2570
 
                    // }
2571
 
 
2572
 
                    return ( o                     && // o is something
2573
 
                             typeof o !== "string" && // o is not a string
2574
 
                             // o.length  && // o is indexed
2575
 
                             (o.length && ((!o.size) || (o.size() > 1)))  && // o is indexed
2576
 
                             !o.tagName            && // o is not an HTML element
2577
 
                             !o.alert              && // o is not a window
2578
 
                             (o.item || typeof o[0] !== "undefined") );
2579
 
                } catch(ex) {
2580
 
                    return false;
2581
 
                }
2582
 
 
2583
 
            },
2584
 
 
2585
 
            /**
2586
 
             * hook up any deferred listeners
2587
 
             * @method _load
2588
 
             * @static
2589
 
             * @private
2590
 
             */
2591
 
            _load: function(e) {
2592
 
 
2593
 
                if (!loadComplete) {
2594
 
 
2595
 
 
2596
 
                    loadComplete = true;
2597
 
 
2598
 
                    // Just in case DOMReady did not go off for some reason
2599
 
                    // E._ready();
2600
 
                    if (Y.fire) {
2601
 
                        Y.fire(EVENT_READY);
2602
 
                    }
2603
 
 
2604
 
                    // Available elements may not have been detected before the
2605
 
                    // window load event fires. Try to find them now so that the
2606
 
                    // the user is more likely to get the onAvailable notifications
2607
 
                    // before the window load notification
2608
 
                    Y.Event._tryPreloadAttach();
2609
 
 
2610
 
                }
2611
 
            },
2612
 
 
2613
 
            /**
2614
 
             * Polling function that runs before the onload event fires, 
2615
 
             * attempting to attach to DOM Nodes as soon as they are 
2616
 
             * available
2617
 
             * @method _tryPreloadAttach
2618
 
             * @static
2619
 
             * @private
2620
 
             */
2621
 
            _tryPreloadAttach: function() {
2622
 
 
2623
 
                if (this.locked) {
2624
 
                    return;
2625
 
                }
2626
 
 
2627
 
                if (Y.UA.ie && !YUI.Env.DOMReady) {
2628
 
                    // Hold off if DOMReady has not fired and check current
2629
 
                    // readyState to protect against the IE operation aborted
2630
 
                    // issue.
2631
 
                    this.startInterval();
2632
 
                    return;
2633
 
                }
2634
 
 
2635
 
                this.locked = true;
2636
 
 
2637
 
 
2638
 
                // keep trying until after the page is loaded.  We need to 
2639
 
                // check the page load state prior to trying to bind the 
2640
 
                // elements so that we can be certain all elements have been 
2641
 
                // tested appropriately
2642
 
                var tryAgain = !loadComplete;
2643
 
                if (!tryAgain) {
2644
 
                    tryAgain = (_retryCount > 0);
2645
 
                }
2646
 
 
2647
 
                // onAvailable
2648
 
                var notAvail = [];
2649
 
 
2650
 
                var executeItem = function (el, item) {
2651
 
                    var context, ov = item.override;
2652
 
 
2653
 
                    if (item.compat) {
2654
 
 
2655
 
                        if (item.override) {
2656
 
                            if (ov === true) {
2657
 
                                context = item.obj;
2658
 
                            } else {
2659
 
                                context = ov;
2660
 
                            }
2661
 
                        } else {
2662
 
                            context = el;
2663
 
                        }
2664
 
 
2665
 
                        item.fn.call(context, item.obj);
2666
 
 
2667
 
                    } else {
2668
 
                        context = item.obj || Y.get(el);
2669
 
                        item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
2670
 
                    }
2671
 
 
2672
 
                };
2673
 
 
2674
 
                var i, len, item, el;
2675
 
 
2676
 
                // onAvailable
2677
 
                for (i=0,len=_avail.length; i<len; ++i) {
2678
 
                    item = _avail[i];
2679
 
                    if (item && !item.checkReady) {
2680
 
 
2681
 
                        el = (item.compat) ? Y.DOM.byId(item.id) : Y.get(item.id);
2682
 
 
2683
 
                        if (el) {
2684
 
                            executeItem(el, item);
2685
 
                            _avail[i] = null;
2686
 
                        } else {
2687
 
                            notAvail.push(item);
2688
 
                        }
2689
 
                    }
2690
 
                }
2691
 
 
2692
 
                // onContentReady
2693
 
                for (i=0,len=_avail.length; i<len; ++i) {
2694
 
                    item = _avail[i];
2695
 
                    if (item && item.checkReady) {
2696
 
 
2697
 
                        el = (item.compat) ? Y.DOM.byId(item.id) : Y.get(item.id);
2698
 
 
2699
 
                        if (el) {
2700
 
                            // The element is available, but not necessarily ready
2701
 
                            // @todo should we test parentNode.nextSibling?
2702
 
                            if (loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
2703
 
                                executeItem(el, item);
2704
 
                                _avail[i] = null;
2705
 
                            }
2706
 
                        } else {
2707
 
                            notAvail.push(item);
2708
 
                        }
2709
 
                    }
2710
 
                }
2711
 
 
2712
 
                _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
2713
 
 
2714
 
                if (tryAgain) {
2715
 
                    // we may need to strip the nulled out items here
2716
 
                    this.startInterval();
2717
 
                } else {
2718
 
                    clearInterval(this._interval);
2719
 
                    this._interval = null;
2720
 
                }
2721
 
 
2722
 
                this.locked = false;
2723
 
 
2724
 
                return;
2725
 
 
2726
 
            },
2727
 
 
2728
 
            /**
2729
 
             * Removes all listeners attached to the given element via addListener.
2730
 
             * Optionally, the node's children can also be purged.
2731
 
             * Optionally, you can specify a specific type of event to remove.
2732
 
             * @method purgeElement
2733
 
             * @param {HTMLElement} el the element to purge
2734
 
             * @param {boolean} recurse recursively purge this element's children
2735
 
             * as well.  Use with caution.
2736
 
             * @param {string} type optional type of listener to purge. If
2737
 
             * left out, all listeners will be removed
2738
 
             * @static
2739
 
             */
2740
 
            purgeElement: function(el, recurse, type) {
2741
 
                var oEl = (Y.Lang.isString(el)) ? Y.get(el) : el,
2742
 
                    id = Y.stamp(oEl);
2743
 
                var lis = this.getListeners(oEl, type), i, len;
2744
 
                if (lis) {
2745
 
                    for (i=0,len=lis.length; i<len ; ++i) {
2746
 
                        lis[i].unsubscribeAll();
2747
 
                    }
2748
 
                }
2749
 
 
2750
 
                if (recurse && oEl && oEl.childNodes) {
2751
 
                    for (i=0,len=oEl.childNodes.length; i<len ; ++i) {
2752
 
                        this.purgeElement(oEl.childNodes[i], recurse, type);
2753
 
                    }
2754
 
                }
2755
 
            },
2756
 
 
2757
 
            /**
2758
 
             * Returns all listeners attached to the given element via addListener.
2759
 
             * Optionally, you can specify a specific type of event to return.
2760
 
             * @method getListeners
2761
 
             * @param el {HTMLElement|string} the element or element id to inspect 
2762
 
             * @param type {string} optional type of listener to return. If
2763
 
             * left out, all listeners will be returned
2764
 
             * @return {Y.Custom.Event} the custom event wrapper for the DOM event(s)
2765
 
             * @static
2766
 
             */           
2767
 
            getListeners: function(el, type) {
2768
 
                var ek = Y.stamp(el), evts = _el_events[ek];
2769
 
 
2770
 
                if (!evts) {
2771
 
                    return null;
2772
 
                }
2773
 
 
2774
 
                var results=[] , key = (type) ? 'event:' + type : null;
2775
 
 
2776
 
                if (key) {
2777
 
                    if (evts[key]) {
2778
 
                        results.push(evts[key]);
2779
 
                    }
2780
 
                } else {
2781
 
                    Y.each(evts, function(v, k) {
2782
 
                        results.push(v);
2783
 
                    });
2784
 
                }
2785
 
 
2786
 
                return (results.length) ? results : null;
2787
 
            },
2788
 
 
2789
 
            /**
2790
 
             * Removes all listeners registered by pe.event.  Called 
2791
 
             * automatically during the unload event.
2792
 
             * @method _unload
2793
 
             * @static
2794
 
             * @private
2795
 
             */
2796
 
            _unload: function(e) {
2797
 
 
2798
 
                var E = Y.Event;
2799
 
 
2800
 
                Y.each(_wrappers, function(v, k) {
2801
 
                    v.unsubscribeAll();
2802
 
                    remove(v.el, v.type, v.fn);
2803
 
                    delete _wrappers[k];
2804
 
                });
2805
 
 
2806
 
                remove(window, "load", E._load);
2807
 
                remove(window, "unload", E._unload);
2808
 
            },
2809
 
 
2810
 
            
2811
 
            /**
2812
 
             * Adds a DOM event directly without the caching, cleanup, context adj, etc
2813
 
             *
2814
 
             * @method nativeAdd
2815
 
             * @param {HTMLElement} el      the element to bind the handler to
2816
 
             * @param {string}      type   the type of event handler
2817
 
             * @param {function}    fn      the callback to invoke
2818
 
             * @param {boolen}      capture capture or bubble phase
2819
 
             * @static
2820
 
             * @private
2821
 
             */
2822
 
            nativeAdd: add,
2823
 
 
2824
 
            /**
2825
 
             * Basic remove listener
2826
 
             *
2827
 
             * @method nativeRemove
2828
 
             * @param {HTMLElement} el      the element to bind the handler to
2829
 
             * @param {string}      type   the type of event handler
2830
 
             * @param {function}    fn      the callback to invoke
2831
 
             * @param {boolen}      capture capture or bubble phase
2832
 
             * @static
2833
 
             * @private
2834
 
             */
2835
 
            nativeRemove: remove
2836
 
        };
2837
 
 
2838
 
    }();
2839
 
 
2840
 
    var E = Y.Event;
2841
 
 
2842
 
    // Process onAvailable/onContentReady items when when the DOM is ready in IE
2843
 
    if (Y.UA.ie && Y.on) {
2844
 
        Y.on(EVENT_READY, E._tryPreloadAttach, E, true);
2845
 
    }
2846
 
 
2847
 
    E.Custom = Y.CustomEvent;
2848
 
    E.Subscriber = Y.Subscriber;
2849
 
    E.Target = Y.EventTarget;
2850
 
 
2851
 
    add(window, "load", E._load);
2852
 
    add(window, "unload", E._unload);
2853
 
 
2854
 
    E._tryPreloadAttach();
2855
 
 
2856
 
}, "3.0.0");
2857
 
 
2858
 
})();
2859
 
/*
2860
 
 * A wrapper for DOM events and Custom Events
2861
 
 * @submodule event-facade
2862
 
 * @module event
2863
 
 *
2864
 
 * @TODO constants? LEFTBUTTON, MIDDLEBUTTON, RIGHTBUTTON, keys
2865
 
 */
2866
 
YUI.add("event-facade", function(Y) {
2867
 
 
2868
 
 
2869
 
    var whitelist = {
2870
 
        "altKey"          : 1,
2871
 
        // "button"          : 1, // we supply
2872
 
        // "bubbles"         : 1, // needed?
2873
 
        // "cancelable"      : 1, // needed? 
2874
 
        // "charCode"        : 1, // we supply
2875
 
        "cancelBubble"    : 1,
2876
 
        // "currentTarget"   : 1, // we supply
2877
 
        "ctrlKey"         : 1,
2878
 
        "clientX"         : 1, // needed?
2879
 
        "clientY"         : 1, // needed?
2880
 
        "detail"          : 1, // not fully implemented
2881
 
        // "fromElement"     : 1,
2882
 
        "keyCode"         : 1,
2883
 
        // "height"          : 1, // needed?
2884
 
        // "initEvent"       : 1, // need the init events?
2885
 
        // "initMouseEvent"  : 1,
2886
 
        // "initUIEvent"     : 1,
2887
 
        // "layerX"          : 1, // needed?
2888
 
        // "layerY"          : 1, // needed?
2889
 
        "metaKey"         : 1,
2890
 
        // "modifiers"       : 1, // needed?
2891
 
        // "offsetX"         : 1, // needed?
2892
 
        // "offsetY"         : 1, // needed?
2893
 
        // "preventDefault"  : 1, // we supply
2894
 
        // "reason"          : 1, // IE proprietary
2895
 
        // "relatedTarget"   : 1,
2896
 
        // "returnValue"     : 1, // needed?
2897
 
        "shiftKey"        : 1,
2898
 
        // "srcUrn"          : 1, // IE proprietary
2899
 
        // "srcElement"      : 1,
2900
 
        // "srcFilter"       : 1, IE proprietary
2901
 
        // "stopPropagation" : 1, // we supply
2902
 
        // "target"          : 1,
2903
 
        // "timeStamp"       : 1, // needed?
2904
 
        // "toElement"       : 1,
2905
 
        "type"            : 1,
2906
 
        // "view"            : 1,
2907
 
        // "which"           : 1, // we supply
2908
 
        // "width"           : 1, // needed?
2909
 
        "x"               : 1,
2910
 
        "y"               : 1
2911
 
    };
2912
 
 
2913
 
    var ua = Y.UA,
2914
 
 
2915
 
        /**
2916
 
         * webkit key remapping required for Safari < 3.1
2917
 
         * @property webkitKeymap
2918
 
         * @private
2919
 
         */
2920
 
        webkitKeymap = {
2921
 
            63232: 38, // up
2922
 
            63233: 40, // down
2923
 
            63234: 37, // left
2924
 
            63235: 39, // right
2925
 
            63276: 33, // page up
2926
 
            63277: 34, // page down
2927
 
            25: 9      // SHIFT-TAB (Safari provides a different key code in
2928
 
                       // this case, even though the shiftKey modifier is set)
2929
 
        },
2930
 
 
2931
 
        /**
2932
 
         * Returns a wrapped node.  Intended to be used on event targets,
2933
 
         * so it will return the node's parent if the target is a text
2934
 
         * node
2935
 
         * @method resolve
2936
 
         * @private
2937
 
         */
2938
 
        resolve = function(n) {
2939
 
 
2940
 
            if (!n) {
2941
 
                return null;
2942
 
            }
2943
 
 
2944
 
            try {
2945
 
                if (ua.webkit && 3 == n.nodeType) {
2946
 
                    n = n.parentNode;
2947
 
                } 
2948
 
            } catch(ex) { }
2949
 
 
2950
 
            return Y.Node.get(n);
2951
 
        };
2952
 
 
2953
 
 
2954
 
    // provide a single event with browser abstractions resolved
2955
 
    //
2956
 
    // include all properties for both browers?
2957
 
    // include only DOM2 spec properties?
2958
 
    // provide browser-specific facade?
2959
 
 
2960
 
    /**
2961
 
     * Wraps a DOM event, properties requiring browser abstraction are
2962
 
     * fixed here.  Provids a security layer when required.
2963
 
     * @class Event.Facade
2964
 
     * @param ev {Event} the DOM event
2965
 
     * @param currentTarget {HTMLElement} the element the listener was attached to
2966
 
     * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
2967
 
     */
2968
 
    Y.Event.Facade = function(ev, currentTarget, wrapper, details) {
2969
 
 
2970
 
        // @TODO the document should be the target's owner document
2971
 
 
2972
 
        var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
2973
 
            x = e.pageX, y = e.pageY, isCE = (ev._YUI_EVENT);
2974
 
 
2975
 
        // copy all primitives ... this is slow in FF
2976
 
        // for (var i in e) {
2977
 
        for (var i in whitelist) {
2978
 
            // if (!Y.Lang.isObject(e[i])) {
2979
 
            if (whitelist.hasOwnProperty(i)) {
2980
 
                this[i] = e[i];
2981
 
            }
2982
 
        }
2983
 
 
2984
 
        //////////////////////////////////////////////////////
2985
 
 
2986
 
        if (!x && 0 !== x) {
2987
 
            x = e.clientX || 0;
2988
 
            y = e.clientY || 0;
2989
 
 
2990
 
            if (ua.ie) {
2991
 
                x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
2992
 
                y += Math.max(d.documentElement.scrollTop, b.scrollTop);
2993
 
            }
2994
 
        }
2995
 
 
2996
 
        this._yuifacade = true;
2997
 
 
2998
 
        /**
2999
 
         * The X location of the event on the page (including scroll)
3000
 
         * @property pageX
3001
 
         * @type int
3002
 
         */
3003
 
        this.pageX = x;
3004
 
 
3005
 
        /**
3006
 
         * The Y location of the event on the page (including scroll)
3007
 
         * @property pageY
3008
 
         * @type int
3009
 
         */
3010
 
        this.pageY = y;
3011
 
 
3012
 
        //////////////////////////////////////////////////////
3013
 
 
3014
 
        /**
3015
 
         * The keyCode for key events.  Uses charCode if keyCode is not available
3016
 
         * @property keyCode
3017
 
         * @type int
3018
 
         */
3019
 
        var c = e.keyCode || e.charCode || 0;
3020
 
 
3021
 
        if (ua.webkit && (c in webkitKeymap)) {
3022
 
            c = webkitKeymap[c];
3023
 
        }
3024
 
 
3025
 
        /**
3026
 
         * The keyCode for key events.  Uses charCode if keyCode is not available
3027
 
         * @property keyCode
3028
 
         * @type int
3029
 
         */
3030
 
        this.keyCode = c;
3031
 
 
3032
 
        /**
3033
 
         * The charCode for key events.  Same as keyCode
3034
 
         * @property charCode
3035
 
         * @type int
3036
 
         */
3037
 
        this.charCode = c;
3038
 
 
3039
 
        //////////////////////////////////////////////////////
3040
 
 
3041
 
        /**
3042
 
         * The button that was pushed.
3043
 
         * @property button
3044
 
         * @type int
3045
 
         */
3046
 
        this.button = e.which || e.button;
3047
 
 
3048
 
        /**
3049
 
         * The button that was pushed.  Same as button.
3050
 
         * @property which
3051
 
         * @type int
3052
 
         */
3053
 
        this.which = this.button;
3054
 
 
3055
 
        /**
3056
 
         * The event details.  Currently supported for Custom
3057
 
         * Events only, where it contains the arguments that
3058
 
         * were passed to fire().
3059
 
         * @property details
3060
 
         * @type Array
3061
 
         */
3062
 
        this.details = details;
3063
 
 
3064
 
        //////////////////////////////////////////////////////
3065
 
 
3066
 
        /**
3067
 
         * Timestamp for the event
3068
 
         * @property time
3069
 
         * @type Date
3070
 
         */
3071
 
        this.time = e.time || new Date().getTime();
3072
 
 
3073
 
        //////////////////////////////////////////////////////
3074
 
        
3075
 
        /**
3076
 
         * Node reference for the targeted element
3077
 
         * @propery target
3078
 
         * @type Node
3079
 
         */
3080
 
        this.target = (isCE) ? e.target : resolve(e.target || e.srcElement);
3081
 
 
3082
 
        /**
3083
 
         * Node reference for the element that the listener was attached to.
3084
 
         * @propery currentTarget
3085
 
         * @type Node
3086
 
         */
3087
 
        this.currentTarget = (isCE) ? ot :  resolve(ot);
3088
 
 
3089
 
        var t = e.relatedTarget;
3090
 
        if (!t) {
3091
 
            if (e.type == "mouseout") {
3092
 
                t = e.toElement;
3093
 
            } else if (e.type == "mouseover") {
3094
 
                t = e.fromElement;
3095
 
            }
3096
 
        }
3097
 
 
3098
 
        /**
3099
 
         * Node reference to the relatedTarget
3100
 
         * @propery relatedTarget
3101
 
         * @type Node
3102
 
         */
3103
 
        this.relatedTarget = (isCE) ? t : resolve(t);
3104
 
        
3105
 
        //////////////////////////////////////////////////////
3106
 
        // methods
3107
 
 
3108
 
        /**
3109
 
         * Stops the propagation to the next bubble target
3110
 
         * @method stopPropagation
3111
 
         */
3112
 
        this.stopPropagation = function() {
3113
 
            if (e.stopPropagation) {
3114
 
                e.stopPropagation();
3115
 
            } else {
3116
 
                e.cancelBubble = true;
3117
 
            }
3118
 
            if (wrapper) {
3119
 
                wrapper.stopPropagation();
3120
 
            }
3121
 
        };
3122
 
 
3123
 
        /**
3124
 
         * Stops the propagation to the next bubble target and
3125
 
         * prevents any additional listeners from being exectued
3126
 
         * on the current target.
3127
 
         * @method stopImmediatePropagation
3128
 
         */
3129
 
        this.stopImmediatePropagation = function() {
3130
 
 
3131
 
            if (e.stopImmediatePropagation) {
3132
 
                e.stopImmediatePropagation();
3133
 
            } else {
3134
 
                this.stopPropagation();
3135
 
            }
3136
 
 
3137
 
            if (wrapper) {
3138
 
                wrapper.stopImmediatePropagation();
3139
 
            }
3140
 
 
3141
 
        };
3142
 
 
3143
 
        /**
3144
 
         * Prevents the event's default behavior
3145
 
         * @method preventDefault
3146
 
         */
3147
 
        this.preventDefault = function() {
3148
 
            if (e.preventDefault) {
3149
 
                e.preventDefault();
3150
 
            } else {
3151
 
                e.returnValue = false;
3152
 
            }
3153
 
            if (wrapper) {
3154
 
                wrapper.preventDefault();
3155
 
            }
3156
 
        };
3157
 
 
3158
 
        /**
3159
 
         * Stops the event propagation and prevents the default
3160
 
         * event behavior.
3161
 
         * @method halt
3162
 
         * @param immediate {boolean} if true additional listeners
3163
 
         * on the current target will not be executed
3164
 
         */
3165
 
        this.halt = function(immediate) {
3166
 
            if (immediate) {
3167
 
                this.stopImmediatePropagation();
3168
 
            } else {
3169
 
                this.stopPropagation();
3170
 
            }
3171
 
            this.preventDefault();
3172
 
        };
3173
 
 
3174
 
    };
3175
 
 
3176
 
}, "3.0.0");
3177
 
/*
3178
 
 * Functionality to simulate events.
3179
 
 * @submodule event-simulate
3180
 
 * @module event
3181
 
 */
3182
 
YUI.add("event-simulate", function(Y) {
3183
 
 
3184
 
    //shortcuts
3185
 
    var L   = Y.Lang,
3186
 
        array       = Y.Array,
3187
 
        isFunction  = L.isFunction,
3188
 
        isString    = L.isString,
3189
 
        isBoolean   = L.isBoolean,
3190
 
        isObject    = L.isObject,
3191
 
        isNumber    = L.isNumber,
3192
 
        
3193
 
        //mouse events supported
3194
 
        mouseEvents = [
3195
 
        
3196
 
            /**
3197
 
             * Simulates a click on a particular element.
3198
 
             * @param {HTMLElement} target The element to click on.
3199
 
             * @param {Object} options Additional event options (use DOM standard names).
3200
 
             * @method click
3201
 
             * @static   
3202
 
             * @for Event
3203
 
             */        
3204
 
            "click", 
3205
 
            
3206
 
            /**
3207
 
             * Simulates a double click on a particular element.
3208
 
             * @param {HTMLElement} target The element to double click on.
3209
 
             * @param {Object} options Additional event options (use DOM standard names).
3210
 
             * @method dblclick
3211
 
             * @static
3212
 
             */            
3213
 
            "dblclick", 
3214
 
            
3215
 
            /**
3216
 
             * Simulates a mouseover event on a particular element. Use "relatedTarget"
3217
 
             * on the options object to specify where the mouse moved from.
3218
 
             * Quirks: Firefox less than 2.0 doesn't set relatedTarget properly, so
3219
 
             * fromElement is assigned in its place. IE doesn't allow fromElement to be
3220
 
             * be assigned, so relatedTarget is assigned in its place. Both of these
3221
 
             * concessions allow YAHOO.util.Event.getRelatedTarget() to work correctly
3222
 
             * in both browsers.
3223
 
             * @param {HTMLElement} target The element to act on.
3224
 
             * @param {Object} options Additional event options (use DOM standard names).
3225
 
             * @method mouseover
3226
 
             * @static
3227
 
             */             
3228
 
            "mouseover", 
3229
 
            
3230
 
            /**
3231
 
             * Simulates a mouseout event on a particular element. Use "relatedTarget"
3232
 
             * on the options object to specify where the mouse moved to.
3233
 
             * Quirks: Firefox less than 2.0 doesn't set relatedTarget properly, so
3234
 
             * toElement is assigned in its place. IE doesn't allow toElement to be
3235
 
             * be assigned, so relatedTarget is assigned in its place. Both of these
3236
 
             * concessions allow YAHOO.util.Event.getRelatedTarget() to work correctly
3237
 
             * in both browsers.
3238
 
             * @param {HTMLElement} target The element to act on.
3239
 
             * @param {Object} options Additional event options (use DOM standard names).
3240
 
             * @method mouseout
3241
 
             * @static
3242
 
             */            
3243
 
            "mouseout", 
3244
 
            
3245
 
            /**
3246
 
             * Simulates a mousedown on a particular element.
3247
 
             * @param {HTMLElement} target The element to act on.
3248
 
             * @param {Object} options Additional event options (use DOM standard names).
3249
 
             * @method mousedown
3250
 
             * @static
3251
 
             */            
3252
 
            "mousedown", 
3253
 
            
3254
 
            /**
3255
 
             * Simulates a mouseup on a particular element.
3256
 
             * @param {HTMLElement} target The element to act on.
3257
 
             * @param {Object} options Additional event options (use DOM standard names).
3258
 
             * @method mouseup
3259
 
             * @static
3260
 
             */            
3261
 
            "mouseup", 
3262
 
            
3263
 
            /**
3264
 
             * Simulates a mousemove on a particular element.
3265
 
             * @param {HTMLElement} target The element to act on.
3266
 
             * @param {Object} options Additional event options (use DOM standard names).
3267
 
             * @method mousemove
3268
 
             * @static
3269
 
             */           
3270
 
            "mousemove"
3271
 
        ],
3272
 
        
3273
 
        //key events supported
3274
 
        keyEvents   = [
3275
 
        
3276
 
            /**
3277
 
             * Simulates a keydown event on a particular element.
3278
 
             * @param {HTMLElement} target The element to act on.
3279
 
             * @param {Object} options Additional event options (use DOM standard names).
3280
 
             * @method keydown
3281
 
             * @static
3282
 
             */        
3283
 
            "keydown", 
3284
 
            
3285
 
            /**
3286
 
             * Simulates a keyup event on a particular element.
3287
 
             * @param {HTMLElement} target The element to act on.
3288
 
             * @param {Object} options Additional event options (use DOM standard names).
3289
 
             * @method keyup
3290
 
             * @static
3291
 
             */            
3292
 
            "keyup", 
3293
 
            
3294
 
            /**
3295
 
             * Simulates a keypress on a particular element.
3296
 
             * @param {HTMLElement} target The element to act on.
3297
 
             * @param {Object} options Additional event options (use DOM standard names).
3298
 
             * @method keypress
3299
 
             * @static
3300
 
             */            
3301
 
            "keypress"
3302
 
        ];
3303
 
 
3304
 
    /**
3305
 
     * Note: Intentionally not for YUIDoc generation.
3306
 
     * Simulates a key event using the given event information to populate
3307
 
     * the generated event object. This method does browser-equalizing
3308
 
     * calculations to account for differences in the DOM and IE event models
3309
 
     * as well as different browser quirks. Note: keydown causes Safari 2.x to
3310
 
     * crash.
3311
 
     * @method simulateKeyEvent
3312
 
     * @private
3313
 
     * @static
3314
 
     * @param {HTMLElement} target The target of the given event.
3315
 
     * @param {String} type The type of event to fire. This can be any one of
3316
 
     *      the following: keyup, keydown, and keypress.
3317
 
     * @param {Boolean} bubbles (Optional) Indicates if the event can be
3318
 
     *      bubbled up. DOM Level 3 specifies that all key events bubble by
3319
 
     *      default. The default is true.
3320
 
     * @param {Boolean} cancelable (Optional) Indicates if the event can be
3321
 
     *      canceled using preventDefault(). DOM Level 3 specifies that all
3322
 
     *      key events can be cancelled. The default 
3323
 
     *      is true.
3324
 
     * @param {Window} view (Optional) The view containing the target. This is
3325
 
     *      typically the window object. The default is window.
3326
 
     * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
3327
 
     *      is pressed while the event is firing. The default is false.
3328
 
     * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
3329
 
     *      is pressed while the event is firing. The default is false.
3330
 
     * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
3331
 
     *      is pressed while the event is firing. The default is false.
3332
 
     * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
3333
 
     *      is pressed while the event is firing. The default is false.
3334
 
     * @param {int} keyCode (Optional) The code for the key that is in use. 
3335
 
     *      The default is 0.
3336
 
     * @param {int} charCode (Optional) The Unicode code for the character
3337
 
     *      associated with the key being used. The default is 0.
3338
 
     */
3339
 
    function simulateKeyEvent(target /*:HTMLElement*/, type /*:String*/, 
3340
 
                                 bubbles /*:Boolean*/,  cancelable /*:Boolean*/,    
3341
 
                                 view /*:Window*/,
3342
 
                                 ctrlKey /*:Boolean*/,    altKey /*:Boolean*/, 
3343
 
                                 shiftKey /*:Boolean*/,   metaKey /*:Boolean*/, 
3344
 
                                 keyCode /*:int*/,        charCode /*:int*/) /*:Void*/                             
3345
 
    {
3346
 
        //check target    
3347
 
        if (!target){
3348
 
            Y.fail("simulateKeyEvent(): Invalid target.");
3349
 
        }
3350
 
        
3351
 
        //check event type
3352
 
        if (isString(type)){
3353
 
            type = type.toLowerCase();
3354
 
            switch(type){
3355
 
                case "textevent": //DOM Level 3
3356
 
                    type = "keypress";
3357
 
                    /*falls through*/
3358
 
                case "keyup":
3359
 
                case "keydown":
3360
 
                case "keypress":
3361
 
                    break;
3362
 
                default:
3363
 
                    Y.fail("simulateKeyEvent(): Event type '" + type + "' not supported.");
3364
 
            }
3365
 
        } else {
3366
 
            Y.fail("simulateKeyEvent(): Event type must be a string.");
3367
 
        }
3368
 
        
3369
 
        //setup default values
3370
 
        if (!isBoolean(bubbles)){
3371
 
            bubbles = true; //all key events bubble
3372
 
        }
3373
 
        if (!isBoolean(cancelable)){
3374
 
            cancelable = true; //all key events can be cancelled
3375
 
        }
3376
 
        if (!isObject(view)){
3377
 
            view = window; //view is typically window
3378
 
        }
3379
 
        if (!isBoolean(ctrlKey)){
3380
 
            ctrlKey = false;
3381
 
        }
3382
 
        if (!isBoolean(altKey)){
3383
 
            altKey = false;
3384
 
        }
3385
 
        if (!isBoolean(shiftKey)){
3386
 
            shiftKey = false;
3387
 
        }
3388
 
        if (!isBoolean(metaKey)){
3389
 
            metaKey = false;
3390
 
        }
3391
 
        if (!isNumber(keyCode)){
3392
 
            keyCode = 0;
3393
 
        }
3394
 
        if (!isNumber(charCode)){
3395
 
            charCode = 0; 
3396
 
        }
3397
 
 
3398
 
        //try to create a mouse event
3399
 
        var customEvent /*:MouseEvent*/ = null;
3400
 
            
3401
 
        //check for DOM-compliant browsers first
3402
 
        if (isFunction(document.createEvent)){
3403
 
        
3404
 
            try {
3405
 
                
3406
 
                //try to create key event
3407
 
                customEvent = document.createEvent("KeyEvents");
3408
 
                
3409
 
                /*
3410
 
                 * Interesting problem: Firefox implemented a non-standard
3411
 
                 * version of initKeyEvent() based on DOM Level 2 specs.
3412
 
                 * Key event was removed from DOM Level 2 and re-introduced
3413
 
                 * in DOM Level 3 with a different interface. Firefox is the
3414
 
                 * only browser with any implementation of Key Events, so for
3415
 
                 * now, assume it's Firefox if the above line doesn't error.
3416
 
                 */
3417
 
                //TODO: Decipher between Firefox's implementation and a correct one.
3418
 
                customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey,
3419
 
                    altKey, shiftKey, metaKey, keyCode, charCode);       
3420
 
                
3421
 
            } catch (ex /*:Error*/){
3422
 
 
3423
 
                /*
3424
 
                 * If it got here, that means key events aren't officially supported. 
3425
 
                 * Safari/WebKit is a real problem now. WebKit 522 won't let you
3426
 
                 * set keyCode, charCode, or other properties if you use a
3427
 
                 * UIEvent, so we first must try to create a generic event. The
3428
 
                 * fun part is that this will throw an error on Safari 2.x. The
3429
 
                 * end result is that we need another try...catch statement just to
3430
 
                 * deal with this mess.
3431
 
                 */
3432
 
                try {
3433
 
 
3434
 
                    //try to create generic event - will fail in Safari 2.x
3435
 
                    customEvent = document.createEvent("Events");
3436
 
 
3437
 
                } catch (uierror /*:Error*/){
3438
 
 
3439
 
                    //the above failed, so create a UIEvent for Safari 2.x
3440
 
                    customEvent = document.createEvent("UIEvents");
3441
 
 
3442
 
                } finally {
3443
 
 
3444
 
                    customEvent.initEvent(type, bubbles, cancelable);
3445
 
    
3446
 
                    //initialize
3447
 
                    customEvent.view = view;
3448
 
                    customEvent.altKey = altKey;
3449
 
                    customEvent.ctrlKey = ctrlKey;
3450
 
                    customEvent.shiftKey = shiftKey;
3451
 
                    customEvent.metaKey = metaKey;
3452
 
                    customEvent.keyCode = keyCode;
3453
 
                    customEvent.charCode = charCode;
3454
 
          
3455
 
                }          
3456
 
             
3457
 
            }
3458
 
            
3459
 
            //fire the event
3460
 
            target.dispatchEvent(customEvent);
3461
 
 
3462
 
        } else if (isObject(document.createEventObject)){ //IE
3463
 
        
3464
 
            //create an IE event object
3465
 
            customEvent = document.createEventObject();
3466
 
            
3467
 
            //assign available properties
3468
 
            customEvent.bubbles = bubbles;
3469
 
            customEvent.cancelable = cancelable;
3470
 
            customEvent.view = view;
3471
 
            customEvent.ctrlKey = ctrlKey;
3472
 
            customEvent.altKey = altKey;
3473
 
            customEvent.shiftKey = shiftKey;
3474
 
            customEvent.metaKey = metaKey;
3475
 
            
3476
 
            /*
3477
 
             * IE doesn't support charCode explicitly. CharCode should
3478
 
             * take precedence over any keyCode value for accurate
3479
 
             * representation.
3480
 
             */
3481
 
            customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
3482
 
            
3483
 
            //fire the event
3484
 
            target.fireEvent("on" + type, customEvent);  
3485
 
                    
3486
 
        } else {
3487
 
            Y.fail("simulateKeyEvent(): No event simulation framework present.");
3488
 
        }
3489
 
    }
3490
 
 
3491
 
    /*
3492
 
     * Note: Intentionally not for YUIDoc generation.
3493
 
     * Simulates a mouse event using the given event information to populate
3494
 
     * the generated event object. This method does browser-equalizing
3495
 
     * calculations to account for differences in the DOM and IE event models
3496
 
     * as well as different browser quirks.
3497
 
     * @method simulateMouseEvent
3498
 
     * @private
3499
 
     * @static
3500
 
     * @param {HTMLElement} target The target of the given event.
3501
 
     * @param {String} type The type of event to fire. This can be any one of
3502
 
     *      the following: click, dblclick, mousedown, mouseup, mouseout,
3503
 
     *      mouseover, and mousemove.
3504
 
     * @param {Boolean} bubbles (Optional) Indicates if the event can be
3505
 
     *      bubbled up. DOM Level 2 specifies that all mouse events bubble by
3506
 
     *      default. The default is true.
3507
 
     * @param {Boolean} cancelable (Optional) Indicates if the event can be
3508
 
     *      canceled using preventDefault(). DOM Level 2 specifies that all
3509
 
     *      mouse events except mousemove can be cancelled. The default 
3510
 
     *      is true for all events except mousemove, for which the default 
3511
 
     *      is false.
3512
 
     * @param {Window} view (Optional) The view containing the target. This is
3513
 
     *      typically the window object. The default is window.
3514
 
     * @param {int} detail (Optional) The number of times the mouse button has
3515
 
     *      been used. The default value is 1.
3516
 
     * @param {int} screenX (Optional) The x-coordinate on the screen at which
3517
 
     *      point the event occured. The default is 0.
3518
 
     * @param {int} screenY (Optional) The y-coordinate on the screen at which
3519
 
     *      point the event occured. The default is 0.
3520
 
     * @param {int} clientX (Optional) The x-coordinate on the client at which
3521
 
     *      point the event occured. The default is 0.
3522
 
     * @param {int} clientY (Optional) The y-coordinate on the client at which
3523
 
     *      point the event occured. The default is 0.
3524
 
     * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
3525
 
     *      is pressed while the event is firing. The default is false.
3526
 
     * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
3527
 
     *      is pressed while the event is firing. The default is false.
3528
 
     * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
3529
 
     *      is pressed while the event is firing. The default is false.
3530
 
     * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
3531
 
     *      is pressed while the event is firing. The default is false.
3532
 
     * @param {int} button (Optional) The button being pressed while the event
3533
 
     *      is executing. The value should be 0 for the primary mouse button
3534
 
     *      (typically the left button), 1 for the terciary mouse button
3535
 
     *      (typically the middle button), and 2 for the secondary mouse button
3536
 
     *      (typically the right button). The default is 0.
3537
 
     * @param {HTMLElement} relatedTarget (Optional) For mouseout events,
3538
 
     *      this is the element that the mouse has moved to. For mouseover
3539
 
     *      events, this is the element that the mouse has moved from. This
3540
 
     *      argument is ignored for all other events. The default is null.
3541
 
     */
3542
 
    function simulateMouseEvent(target /*:HTMLElement*/, type /*:String*/, 
3543
 
                                   bubbles /*:Boolean*/,  cancelable /*:Boolean*/,    
3544
 
                                   view /*:Window*/,        detail /*:int*/, 
3545
 
                                   screenX /*:int*/,        screenY /*:int*/, 
3546
 
                                   clientX /*:int*/,        clientY /*:int*/,       
3547
 
                                   ctrlKey /*:Boolean*/,    altKey /*:Boolean*/, 
3548
 
                                   shiftKey /*:Boolean*/,   metaKey /*:Boolean*/, 
3549
 
                                   button /*:int*/,         relatedTarget /*:HTMLElement*/) /*:Void*/
3550
 
    {
3551
 
        
3552
 
        //check target   
3553
 
        if (!target){
3554
 
            Y.fail("simulateMouseEvent(): Invalid target.");
3555
 
        }
3556
 
        
3557
 
        //check event type
3558
 
        if (isString(type)){
3559
 
            type = type.toLowerCase();
3560
 
            
3561
 
            //make sure it's a supported mouse event
3562
 
            if (array.indexOf(mouseEvents, type) == -1){
3563
 
                Y.fail("simulateMouseEvent(): Event type '" + type + "' not supported.");
3564
 
            }
3565
 
        } else {
3566
 
            Y.fail("simulateMouseEvent(): Event type must be a string.");
3567
 
        }
3568
 
        
3569
 
        //setup default values
3570
 
        if (!isBoolean(bubbles)){
3571
 
            bubbles = true; //all mouse events bubble
3572
 
        }
3573
 
        if (!isBoolean(cancelable)){
3574
 
            cancelable = (type != "mousemove"); //mousemove is the only one that can't be cancelled
3575
 
        }
3576
 
        if (!isObject(view)){
3577
 
            view = window; //view is typically window
3578
 
        }
3579
 
        if (!isNumber(detail)){
3580
 
            detail = 1;  //number of mouse clicks must be at least one
3581
 
        }
3582
 
        if (!isNumber(screenX)){
3583
 
            screenX = 0; 
3584
 
        }
3585
 
        if (!isNumber(screenY)){
3586
 
            screenY = 0; 
3587
 
        }
3588
 
        if (!isNumber(clientX)){
3589
 
            clientX = 0; 
3590
 
        }
3591
 
        if (!isNumber(clientY)){
3592
 
            clientY = 0; 
3593
 
        }
3594
 
        if (!isBoolean(ctrlKey)){
3595
 
            ctrlKey = false;
3596
 
        }
3597
 
        if (!isBoolean(altKey)){
3598
 
            altKey = false;
3599
 
        }
3600
 
        if (!isBoolean(shiftKey)){
3601
 
            shiftKey = false;
3602
 
        }
3603
 
        if (!isBoolean(metaKey)){
3604
 
            metaKey = false;
3605
 
        }
3606
 
        if (!isNumber(button)){
3607
 
            button = 0; 
3608
 
        }
3609
 
 
3610
 
        //try to create a mouse event
3611
 
        var customEvent /*:MouseEvent*/ = null;
3612
 
            
3613
 
        //check for DOM-compliant browsers first
3614
 
        if (isFunction(document.createEvent)){
3615
 
        
3616
 
            customEvent = document.createEvent("MouseEvents");
3617
 
        
3618
 
            //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
3619
 
            if (customEvent.initMouseEvent){
3620
 
                customEvent.initMouseEvent(type, bubbles, cancelable, view, detail,
3621
 
                                     screenX, screenY, clientX, clientY, 
3622
 
                                     ctrlKey, altKey, shiftKey, metaKey, 
3623
 
                                     button, relatedTarget);
3624
 
            } else { //Safari
3625
 
            
3626
 
                //the closest thing available in Safari 2.x is UIEvents
3627
 
                customEvent = document.createEvent("UIEvents");
3628
 
                customEvent.initEvent(type, bubbles, cancelable);
3629
 
                customEvent.view = view;
3630
 
                customEvent.detail = detail;
3631
 
                customEvent.screenX = screenX;
3632
 
                customEvent.screenY = screenY;
3633
 
                customEvent.clientX = clientX;
3634
 
                customEvent.clientY = clientY;
3635
 
                customEvent.ctrlKey = ctrlKey;
3636
 
                customEvent.altKey = altKey;
3637
 
                customEvent.metaKey = metaKey;
3638
 
                customEvent.shiftKey = shiftKey;
3639
 
                customEvent.button = button;
3640
 
                customEvent.relatedTarget = relatedTarget;
3641
 
            }
3642
 
            
3643
 
            /*
3644
 
             * Check to see if relatedTarget has been assigned. Firefox
3645
 
             * versions less than 2.0 don't allow it to be assigned via
3646
 
             * initMouseEvent() and the property is readonly after event
3647
 
             * creation, so in order to keep YAHOO.util.getRelatedTarget()
3648
 
             * working, assign to the IE proprietary toElement property
3649
 
             * for mouseout event and fromElement property for mouseover
3650
 
             * event.
3651
 
             */
3652
 
            if (relatedTarget && !customEvent.relatedTarget){
3653
 
                if (type == "mouseout"){
3654
 
                    customEvent.toElement = relatedTarget;
3655
 
                } else if (type == "mouseover"){
3656
 
                    customEvent.fromElement = relatedTarget;
3657
 
                }
3658
 
            }
3659
 
            
3660
 
            //fire the event
3661
 
            target.dispatchEvent(customEvent);
3662
 
 
3663
 
        } else if (isObject(document.createEventObject)){ //IE
3664
 
        
3665
 
            //create an IE event object
3666
 
            customEvent = document.createEventObject();
3667
 
            
3668
 
            //assign available properties
3669
 
            customEvent.bubbles = bubbles;
3670
 
            customEvent.cancelable = cancelable;
3671
 
            customEvent.view = view;
3672
 
            customEvent.detail = detail;
3673
 
            customEvent.screenX = screenX;
3674
 
            customEvent.screenY = screenY;
3675
 
            customEvent.clientX = clientX;
3676
 
            customEvent.clientY = clientY;
3677
 
            customEvent.ctrlKey = ctrlKey;
3678
 
            customEvent.altKey = altKey;
3679
 
            customEvent.metaKey = metaKey;
3680
 
            customEvent.shiftKey = shiftKey;
3681
 
 
3682
 
            //fix button property for IE's wacky implementation
3683
 
            switch(button){
3684
 
                case 0:
3685
 
                    customEvent.button = 1;
3686
 
                    break;
3687
 
                case 1:
3688
 
                    customEvent.button = 4;
3689
 
                    break;
3690
 
                case 2:
3691
 
                    //leave as is
3692
 
                    break;
3693
 
                default:
3694
 
                    customEvent.button = 0;                    
3695
 
            }    
3696
 
 
3697
 
            /*
3698
 
             * Have to use relatedTarget because IE won't allow assignment
3699
 
             * to toElement or fromElement on generic events. This keeps
3700
 
             * YAHOO.util.customEvent.getRelatedTarget() functional.
3701
 
             */
3702
 
            customEvent.relatedTarget = relatedTarget;
3703
 
            
3704
 
            //fire the event
3705
 
            target.fireEvent("on" + type, customEvent);
3706
 
                    
3707
 
        } else {
3708
 
            Y.fail("simulateMouseEvent(): No event simulation framework present.");
3709
 
        }
3710
 
    }
3711
 
    
3712
 
    //add mouse event methods
3713
 
    array.each(mouseEvents, function(type){
3714
 
        Y.Event[type] = function(target, options){
3715
 
            options = options || {};
3716
 
            simulateMouseEvent(target, type, options.bubbles,
3717
 
                options.cancelable, options.view, options.detail, options.screenX,        
3718
 
                options.screenY, options.clientX, options.clientY, options.ctrlKey,
3719
 
                options.altKey, options.shiftKey, options.metaKey, options.button,         
3720
 
                options.relatedTarget);        
3721
 
        };
3722
 
    });
3723
 
 
3724
 
    //add key event methods
3725
 
    array.each(keyEvents, function(type){
3726
 
        Y.Event[type] = function(target, options){
3727
 
            options = options || {};
3728
 
            simulateKeyEvent(target, type, options.bubbles,
3729
 
                options.cancelable, options.view, options.ctrlKey,
3730
 
                options.altKey, options.shiftKey, options.metaKey, 
3731
 
                options.keyCode, options.charCode);       
3732
 
        };
3733
 
    });
3734
 
    
3735
 
    /**
3736
 
     * Simulates the event with the given name on a target.
3737
 
     * @param {HTMLElement} target The DOM element that's the target of the event.
3738
 
     * @param {String} type The type of event to simulate (i.e., "click").
3739
 
     * @param {Object} options (Optional) Extra options to copy onto the event object.
3740
 
     * @return {void}
3741
 
     * @method simulate
3742
 
     * @static
3743
 
     */
3744
 
    Y.Event.simulate = function(target, type, options){
3745
 
        if (isFunction(Y.Event[type])){
3746
 
            Y.Event[type](target, options);
3747
 
        }
3748
 
    };
3749
 
    
3750
 
    /*
3751
 
     * TODO: focus(), blur(), submit()
3752
 
     */
3753
 
 
3754
 
}, "3.0.0pr2", { requires: ["lang","event-dom"] });