Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('yui2-event', function(Y) {
2
    var YAHOO    = Y.YUI2;
3
    /*
4
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
5
Code licensed under the BSD License:
6
http://developer.yahoo.com/yui/license.html
7
version: 2.9.0
8
*/
9
 
10
/**
11
 * The CustomEvent class lets you define events for your application
12
 * that can be subscribed to by one or more independent component.
13
 *
14
 * @param {String}  type The type of event, which is passed to the callback
15
 *                  when the event fires
16
 * @param {Object}  context The context the event will fire from.  "this" will
17
 *                  refer to this object in the callback.  Default value:
18
 *                  the window object.  The listener can override this.
19
 * @param {boolean} silent pass true to prevent the event from writing to
20
 *                  the debugsystem
21
 * @param {int}     signature the signature that the custom event subscriber
22
 *                  will receive. YAHOO.util.CustomEvent.LIST or
23
 *                  YAHOO.util.CustomEvent.FLAT.  The default is
24
 *                  YAHOO.util.CustomEvent.LIST.
25
 * @param fireOnce {boolean} If configured to fire once, the custom event
26
 * will only notify subscribers a single time regardless of how many times
27
 * the event is fired.  In addition, new subscribers will be notified
28
 * immediately if the event has already been fired.
29
 * @namespace YAHOO.util
30
 * @class CustomEvent
31
 * @constructor
32
 */
33
YAHOO.util.CustomEvent = function(type, context, silent, signature, fireOnce) {
34
 
35
    /**
36
     * The type of event, returned to subscribers when the event fires
37
     * @property type
38
     * @type string
39
     */
40
    this.type = type;
41
 
42
    /**
43
     * The context the event will fire from by default. Defaults to the window obj.
44
     * @property scope
45
     * @type object
46
     */
47
    this.scope = context || window;
48
 
49
    /**
50
     * By default all custom events are logged in the debug build. Set silent to true
51
     * to disable debug output for this event.
52
     * @property silent
53
     * @type boolean
54
     */
55
    this.silent = silent;
56
 
57
    /**
58
     * If configured to fire once, the custom event will only notify subscribers
59
     * a single time regardless of how many times the event is fired.  In addition,
60
     * new subscribers will be notified immediately if the event has already been
61
     * fired.
62
     * @property fireOnce
63
     * @type boolean
64
     * @default false
65
     */
66
    this.fireOnce = fireOnce;
67
 
68
    /**
69
     * Indicates whether or not this event has ever been fired.
70
     * @property fired
71
     * @type boolean
72
     * @default false
73
     */
74
    this.fired = false;
75
 
76
    /**
77
     * For fireOnce events the arguments the event was fired with are stored
78
     * so that new subscribers get the proper payload.
79
     * @property firedWith
80
     * @type Array
81
     */
82
    this.firedWith = null;
83
 
84
    /**
85
     * Custom events support two styles of arguments provided to the event
86
     * subscribers.
87
     * <ul>
88
     * <li>YAHOO.util.CustomEvent.LIST:
89
     *   <ul>
90
     *   <li>param1: event name</li>
91
     *   <li>param2: array of arguments sent to fire</li>
92
     *   <li>param3: <optional> a custom object supplied by the subscriber</li>
93
     *   </ul>
94
     * </li>
95
     * <li>YAHOO.util.CustomEvent.FLAT
96
     *   <ul>
97
     *   <li>param1: the first argument passed to fire.  If you need to
98
     *           pass multiple parameters, use and array or object literal</li>
99
     *   <li>param2: <optional> a custom object supplied by the subscriber</li>
100
     *   </ul>
101
     * </li>
102
     * </ul>
103
     *   @property signature
104
     *   @type int
105
     */
106
    this.signature = signature || YAHOO.util.CustomEvent.LIST;
107
 
108
    /**
109
     * The subscribers to this event
110
     * @property subscribers
111
     * @type Subscriber[]
112
     */
113
    this.subscribers = [];
114
 
115
    if (!this.silent) {
116
    }
117
 
118
    var onsubscribeType = "_YUICEOnSubscribe";
119
 
120
    // Only add subscribe events for events that are not generated by
121
    // CustomEvent
122
    if (type !== onsubscribeType) {
123
 
124
        /**
125
         * Custom events provide a custom event that fires whenever there is
126
         * a new subscriber to the event.  This provides an opportunity to
127
         * handle the case where there is a non-repeating event that has
128
         * already fired has a new subscriber.
129
         *
130
         * @event subscribeEvent
131
         * @type YAHOO.util.CustomEvent
132
         * @param fn {Function} The function to execute
133
         * @param obj <Object> An object to be passed along when the event fires.
134
         * Defaults to the custom event.
135
         * @param override <boolean|Object> If true, the obj passed in becomes the
136
         * execution context of the listener. If an object, that object becomes
137
         * the execution context. Defaults to the custom event.
138
         */
139
        this.subscribeEvent =
140
                new YAHOO.util.CustomEvent(onsubscribeType, this, true);
141
 
142
    }
143
 
144
 
145
    /**
146
     * In order to make it possible to execute the rest of the subscriber
147
     * stack when one thows an exception, the subscribers exceptions are
148
     * caught.  The most recent exception is stored in this property
149
     * @property lastError
150
     * @type Error
151
     */
152
    this.lastError = null;
153
};
154
 
155
/**
156
 * Subscriber listener sigature constant.  The LIST type returns three
157
 * parameters: the event type, the array of args passed to fire, and
158
 * the optional custom object
159
 * @property YAHOO.util.CustomEvent.LIST
160
 * @static
161
 * @type int
162
 */
163
YAHOO.util.CustomEvent.LIST = 0;
164
 
165
/**
166
 * Subscriber listener sigature constant.  The FLAT type returns two
167
 * parameters: the first argument passed to fire and the optional
168
 * custom object
169
 * @property YAHOO.util.CustomEvent.FLAT
170
 * @static
171
 * @type int
172
 */
173
YAHOO.util.CustomEvent.FLAT = 1;
174
 
175
YAHOO.util.CustomEvent.prototype = {
176
 
177
    /**
178
     * Subscribes the caller to this event
179
     * @method subscribe
180
     * @param {Function} fn        The function to execute
181
     * @param {Object}   obj       An object to be passed along when the event
182
     * fires.
183
     * @param {boolean|Object} overrideContext If true, the obj passed in
184
     * becomes the execution.
185
     * context of the listener. If an object, that object becomes the execution
186
     * context.
187
     */
188
    subscribe: function(fn, obj, overrideContext) {
189
 
190
        if (!fn) {
191
throw new Error("Invalid callback for subscriber to '" + this.type + "'");
192
        }
193
 
194
        if (this.subscribeEvent) {
195
            this.subscribeEvent.fire(fn, obj, overrideContext);
196
        }
197
 
198
        var s = new YAHOO.util.Subscriber(fn, obj, overrideContext);
199
 
200
        if (this.fireOnce && this.fired) {
201
            this.notify(s, this.firedWith);
202
        } else {
203
            this.subscribers.push(s);
204
        }
205
    },
206
 
207
    /**
208
     * Unsubscribes subscribers.
209
     * @method unsubscribe
210
     * @param {Function} fn  The subscribed function to remove, if not supplied
211
     *                       all will be removed
212
     * @param {Object}   obj  The custom object passed to subscribe.  This is
213
     *                        optional, but if supplied will be used to
214
     *                        disambiguate multiple listeners that are the same
215
     *                        (e.g., you subscribe many object using a function
216
     *                        that lives on the prototype)
217
     * @return {boolean} True if the subscriber was found and detached.
218
     */
219
    unsubscribe: function(fn, obj) {
220
 
221
        if (!fn) {
222
            return this.unsubscribeAll();
223
        }
224
 
225
        var found = false;
226
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
227
            var s = this.subscribers[i];
228
            if (s && s.contains(fn, obj)) {
229
                this._delete(i);
230
                found = true;
231
            }
232
        }
233
 
234
        return found;
235
    },
236
 
237
    /**
238
     * Notifies the subscribers.  The callback functions will be executed
239
     * from the context specified when the event was created, and with the
240
     * following parameters:
241
     *   <ul>
242
     *   <li>The type of event</li>
243
     *   <li>All of the arguments fire() was executed with as an array</li>
244
     *   <li>The custom object (if any) that was passed into the subscribe()
245
     *       method</li>
246
     *   </ul>
247
     * @method fire
248
     * @param {Object*} arguments an arbitrary set of parameters to pass to
249
     *                            the handler.
250
     * @return {boolean} false if one of the subscribers returned false,
251
     *                   true otherwise
252
     */
253
    fire: function() {
254
 
255
        this.lastError = null;
256
 
257
        var errors = [],
258
            len=this.subscribers.length;
259
 
260
 
261
        var args=[].slice.call(arguments, 0), ret=true, i, rebuild=false;
262
 
263
        if (this.fireOnce) {
264
            if (this.fired) {
265
                return true;
266
            } else {
267
                this.firedWith = args;
268
            }
269
        }
270
 
271
        this.fired = true;
272
 
273
        if (!len && this.silent) {
274
            return true;
275
        }
276
 
277
        if (!this.silent) {
278
        }
279
 
280
        // make a copy of the subscribers so that there are
281
        // no index problems if one subscriber removes another.
282
        var subs = this.subscribers.slice();
283
 
284
        for (i=0; i<len; ++i) {
285
            var s = subs[i];
286
            if (!s || !s.fn) {
287
                rebuild=true;
288
            } else {
289
 
290
                ret = this.notify(s, args);
291
 
292
                if (false === ret) {
293
                    if (!this.silent) {
294
                    }
295
 
296
                    break;
297
                }
298
            }
299
        }
300
 
301
        return (ret !== false);
302
    },
303
 
304
    notify: function(s, args) {
305
 
306
        var ret, param=null, scope = s.getScope(this.scope),
307
                 throwErrors = YAHOO.util.Event.throwErrors;
308
 
309
        if (!this.silent) {
310
        }
311
 
312
        if (this.signature == YAHOO.util.CustomEvent.FLAT) {
313
 
314
            if (args.length > 0) {
315
                param = args[0];
316
            }
317
 
318
            try {
319
                ret = s.fn.call(scope, param, s.obj);
320
            } catch(e) {
321
                this.lastError = e;
322
                // errors.push(e);
323
                if (throwErrors) {
324
                    throw e;
325
                }
326
            }
327
        } else {
328
            try {
329
                ret = s.fn.call(scope, this.type, args, s.obj);
330
            } catch(ex) {
331
                this.lastError = ex;
332
                if (throwErrors) {
333
                    throw ex;
334
                }
335
            }
336
        }
337
 
338
        return ret;
339
    },
340
 
341
    /**
342
     * Removes all listeners
343
     * @method unsubscribeAll
344
     * @return {int} The number of listeners unsubscribed
345
     */
346
    unsubscribeAll: function() {
347
        var l = this.subscribers.length, i;
348
        for (i=l-1; i>-1; i--) {
349
            this._delete(i);
350
        }
351
 
352
        this.subscribers=[];
353
 
354
        return l;
355
    },
356
 
357
    /**
358
     * @method _delete
359
     * @private
360
     */
361
    _delete: function(index) {
362
        var s = this.subscribers[index];
363
        if (s) {
364
            delete s.fn;
365
            delete s.obj;
366
        }
367
 
368
        // this.subscribers[index]=null;
369
        this.subscribers.splice(index, 1);
370
    },
371
 
372
    /**
373
     * @method toString
374
     */
375
    toString: function() {
376
         return "CustomEvent: " + "'" + this.type  + "', " +
377
             "context: " + this.scope;
378
 
379
    }
380
};
381
 
382
/////////////////////////////////////////////////////////////////////
383
 
384
/**
385
 * Stores the subscriber information to be used when the event fires.
386
 * @param {Function} fn       The function to execute
387
 * @param {Object}   obj      An object to be passed along when the event fires
388
 * @param {boolean}  overrideContext If true, the obj passed in becomes the execution
389
 *                            context of the listener
390
 * @class Subscriber
391
 * @constructor
392
 */
393
YAHOO.util.Subscriber = function(fn, obj, overrideContext) {
394
 
395
    /**
396
     * The callback that will be execute when the event fires
397
     * @property fn
398
     * @type function
399
     */
400
    this.fn = fn;
401
 
402
    /**
403
     * An optional custom object that will passed to the callback when
404
     * the event fires
405
     * @property obj
406
     * @type object
407
     */
408
    this.obj = YAHOO.lang.isUndefined(obj) ? null : obj;
409
 
410
    /**
411
     * The default execution context for the event listener is defined when the
412
     * event is created (usually the object which contains the event).
413
     * By setting overrideContext to true, the execution context becomes the custom
414
     * object passed in by the subscriber.  If overrideContext is an object, that
415
     * object becomes the context.
416
     * @property overrideContext
417
     * @type boolean|object
418
     */
419
    this.overrideContext = overrideContext;
420
 
421
};
422
 
423
/**
424
 * Returns the execution context for this listener.  If overrideContext was set to true
425
 * the custom obj will be the context.  If overrideContext is an object, that is the
426
 * context, otherwise the default context will be used.
427
 * @method getScope
428
 * @param {Object} defaultScope the context to use if this listener does not
429
 *                              override it.
430
 */
431
YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
432
    if (this.overrideContext) {
433
        if (this.overrideContext === true) {
434
            return this.obj;
435
        } else {
436
            return this.overrideContext;
437
        }
438
    }
439
    return defaultScope;
440
};
441
 
442
/**
443
 * Returns true if the fn and obj match this objects properties.
444
 * Used by the unsubscribe method to match the right subscriber.
445
 *
446
 * @method contains
447
 * @param {Function} fn the function to execute
448
 * @param {Object} obj an object to be passed along when the event fires
449
 * @return {boolean} true if the supplied arguments match this
450
 *                   subscriber's signature.
451
 */
452
YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
453
    if (obj) {
454
        return (this.fn == fn && this.obj == obj);
455
    } else {
456
        return (this.fn == fn);
457
    }
458
};
459
 
460
/**
461
 * @method toString
462
 */
463
YAHOO.util.Subscriber.prototype.toString = function() {
464
    return "Subscriber { obj: " + this.obj  +
465
           ", overrideContext: " +  (this.overrideContext || "no") + " }";
466
};
467
 
468
/**
469
 * The Event Utility provides utilities for managing DOM Events and tools
470
 * for building event systems
471
 *
472
 * @module event
473
 * @title Event Utility
474
 * @namespace YAHOO.util
475
 * @requires yahoo
476
 */
477
 
478
// The first instance of Event will win if it is loaded more than once.
479
// @TODO this needs to be changed so that only the state data that needs to
480
// be preserved is kept, while methods are overwritten/added as needed.
481
// This means that the module pattern can't be used.
482
if (!YAHOO.util.Event) {
483
 
484
/**
485
 * The event utility provides functions to add and remove event listeners,
486
 * event cleansing.  It also tries to automatically remove listeners it
487
 * registers during the unload event.
488
 *
489
 * @class Event
490
 * @static
491
 */
492
    YAHOO.util.Event = function() {
493
 
494
        /**
495
         * True after the onload event has fired
496
         * @property loadComplete
497
         * @type boolean
498
         * @static
499
         * @private
500
         */
501
        var loadComplete =  false,
502
 
503
        /**
504
         * Cache of wrapped listeners
505
         * @property listeners
506
         * @type array
507
         * @static
508
         * @private
509
         */
510
        listeners = [],
511
 
512
 
513
        /**
514
         * User-defined unload function that will be fired before all events
515
         * are detached
516
         * @property unloadListeners
517
         * @type array
518
         * @static
519
         * @private
520
         */
521
        unloadListeners = [],
522
 
523
        /**
524
         * The number of times to poll after window.onload.  This number is
525
         * increased if additional late-bound handlers are requested after
526
         * the page load.
527
         * @property retryCount
528
         * @static
529
         * @private
530
         */
531
        retryCount = 0,
532
 
533
        /**
534
         * onAvailable listeners
535
         * @property onAvailStack
536
         * @static
537
         * @private
538
         */
539
        onAvailStack = [],
540
 
541
        /**
542
         * Counter for auto id generation
543
         * @property counter
544
         * @static
545
         * @private
546
         */
547
        counter = 0,
548
 
549
        /**
550
         * Normalized keycodes for webkit/safari
551
         * @property webkitKeymap
552
         * @type {int: int}
553
         * @private
554
         * @static
555
         * @final
556
         */
557
         webkitKeymap = {
558
            63232: 38, // up
559
            63233: 40, // down
560
            63234: 37, // left
561
            63235: 39, // right
562
            63276: 33, // page up
563
            63277: 34, // page down
564
            25: 9      // SHIFT-TAB (Safari provides a different key code in
565
                       // this case, even though the shiftKey modifier is set)
566
        },
567
 
568
        isIE = YAHOO.env.ua.ie,
569
 
570
        // String constants used by the addFocusListener and removeFocusListener methods
571
 
572
        FOCUSIN = "focusin",
573
        FOCUSOUT = "focusout";
574
 
575
        return {
576
 
577
            /**
578
             * The number of times we should look for elements that are not
579
             * in the DOM at the time the event is requested after the document
580
             * has been loaded.  The default is 500@amp;40 ms, so it will poll
581
             * for 20 seconds or until all outstanding handlers are bound
582
             * (whichever comes first).
583
             * @property POLL_RETRYS
584
             * @type int
585
             * @static
586
             * @final
587
             */
588
            POLL_RETRYS: 500,
589
 
590
            /**
591
             * The poll interval in milliseconds
592
             * @property POLL_INTERVAL
593
             * @type int
594
             * @static
595
             * @final
596
             */
597
            POLL_INTERVAL: 40,
598
 
599
            /**
600
             * Element to bind, int constant
601
             * @property EL
602
             * @type int
603
             * @static
604
             * @final
605
             */
606
            EL: 0,
607
 
608
            /**
609
             * Type of event, int constant
610
             * @property TYPE
611
             * @type int
612
             * @static
613
             * @final
614
             */
615
            TYPE: 1,
616
 
617
            /**
618
             * Function to execute, int constant
619
             * @property FN
620
             * @type int
621
             * @static
622
             * @final
623
             */
624
            FN: 2,
625
 
626
            /**
627
             * Function wrapped for context correction and cleanup, int constant
628
             * @property WFN
629
             * @type int
630
             * @static
631
             * @final
632
             */
633
            WFN: 3,
634
 
635
            /**
636
             * Object passed in by the user that will be returned as a
637
             * parameter to the callback, int constant.  Specific to
638
             * unload listeners
639
             * @property OBJ
640
             * @type int
641
             * @static
642
             * @final
643
             */
644
            UNLOAD_OBJ: 3,
645
 
646
            /**
647
             * Adjusted context, either the element we are registering the event
648
             * on or the custom object passed in by the listener, int constant
649
             * @property ADJ_SCOPE
650
             * @type int
651
             * @static
652
             * @final
653
             */
654
            ADJ_SCOPE: 4,
655
 
656
            /**
657
             * The original obj passed into addListener
658
             * @property OBJ
659
             * @type int
660
             * @static
661
             * @final
662
             */
663
            OBJ: 5,
664
 
665
            /**
666
             * The original context parameter passed into addListener
667
             * @property OVERRIDE
668
             * @type int
669
             * @static
670
             * @final
671
             */
672
            OVERRIDE: 6,
673
 
674
            /**
675
             * The original capture parameter passed into addListener
676
             * @property CAPTURE
677
             * @type int
678
             * @static
679
             * @final
680
             */
681
            CAPTURE: 7,
682
 
683
            /**
684
             * addListener/removeListener can throw errors in unexpected scenarios.
685
             * These errors are suppressed, the method returns false, and this property
686
             * is set
687
             * @property lastError
688
             * @static
689
             * @type Error
690
             */
691
            lastError: null,
692
 
693
            /**
694
             * Safari detection
695
             * @property isSafari
696
             * @private
697
             * @static
698
             * @deprecated use YAHOO.env.ua.webkit
699
             */
700
            isSafari: YAHOO.env.ua.webkit,
701
 
702
            /**
703
             * webkit version
704
             * @property webkit
705
             * @type string
706
             * @private
707
             * @static
708
             * @deprecated use YAHOO.env.ua.webkit
709
             */
710
            webkit: YAHOO.env.ua.webkit,
711
 
712
            /**
713
             * IE detection
714
             * @property isIE
715
             * @private
716
             * @static
717
             * @deprecated use YAHOO.env.ua.ie
718
             */
719
            isIE: isIE,
720
 
721
            /**
722
             * poll handle
723
             * @property _interval
724
             * @static
725
             * @private
726
             */
727
            _interval: null,
728
 
729
            /**
730
             * document readystate poll handle
731
             * @property _dri
732
             * @static
733
             * @private
734
             */
735
             _dri: null,
736
 
737
 
738
            /**
739
             * Map of special event types
740
             * @property _specialTypes
741
             * @static
742
             * @private
743
             */
744
            _specialTypes: {
745
                focusin: (isIE ? "focusin" : "focus"),
746
                focusout: (isIE ? "focusout" : "blur")
747
            },
748
 
749
 
750
            /**
751
             * True when the document is initially usable
752
             * @property DOMReady
753
             * @type boolean
754
             * @static
755
             */
756
            DOMReady: false,
757
 
758
            /**
759
             * Errors thrown by subscribers of custom events are caught
760
             * and the error message is written to the debug console.  If
761
             * this property is set to true, it will also re-throw the
762
             * error.
763
             * @property throwErrors
764
             * @type boolean
765
             * @default false
766
             */
767
            throwErrors: false,
768
 
769
 
770
            /**
771
             * @method startInterval
772
             * @static
773
             * @private
774
             */
775
            startInterval: function() {
776
                if (!this._interval) {
777
                    // var self = this;
778
                    // var callback = function() { self._tryPreloadAttach(); };
779
                    // this._interval = setInterval(callback, this.POLL_INTERVAL);
780
                    this._interval = YAHOO.lang.later(this.POLL_INTERVAL, this, this._tryPreloadAttach, null, true);
781
                }
782
            },
783
 
784
            /**
785
             * Executes the supplied callback when the item with the supplied
786
             * id is found.  This is meant to be used to execute behavior as
787
             * soon as possible as the page loads.  If you use this after the
788
             * initial page load it will poll for a fixed time for the element.
789
             * The number of times it will poll and the frequency are
790
             * configurable.  By default it will poll for 10 seconds.
791
             *
792
             * <p>The callback is executed with a single parameter:
793
             * the custom object parameter, if provided.</p>
794
             *
795
             * @method onAvailable
796
             *
797
             * @param {string||string[]}   id the id of the element, or an array
798
             * of ids to look for.
799
             * @param {function} fn what to execute when the element is found.
800
             * @param {object}   obj an optional object to be passed back as
801
             *                   a parameter to fn.
802
             * @param {boolean|object}  overrideContext If set to true, fn will execute
803
             *                   in the context of obj, if set to an object it
804
             *                   will execute in the context of that object
805
             * @param checkContent {boolean} check child node readiness (onContentReady)
806
             * @static
807
             */
808
            onAvailable: function(id, fn, obj, overrideContext, checkContent) {
809
 
810
                var a = (YAHOO.lang.isString(id)) ? [id] : id;
811
 
812
                for (var i=0; i<a.length; i=i+1) {
813
                    onAvailStack.push({id:         a[i],
814
                                       fn:         fn,
815
                                       obj:        obj,
816
                                       overrideContext:   overrideContext,
817
                                       checkReady: checkContent });
818
                }
819
 
820
                retryCount = this.POLL_RETRYS;
821
 
822
                this.startInterval();
823
            },
824
 
825
            /**
826
             * Works the same way as onAvailable, but additionally checks the
827
             * state of sibling elements to determine if the content of the
828
             * available element is safe to modify.
829
             *
830
             * <p>The callback is executed with a single parameter:
831
             * the custom object parameter, if provided.</p>
832
             *
833
             * @method onContentReady
834
             *
835
             * @param {string}   id the id of the element to look for.
836
             * @param {function} fn what to execute when the element is ready.
837
             * @param {object}   obj an optional object to be passed back as
838
             *                   a parameter to fn.
839
             * @param {boolean|object}  overrideContext If set to true, fn will execute
840
             *                   in the context of obj.  If an object, fn will
841
             *                   exectute in the context of that object
842
             *
843
             * @static
844
             */
845
            onContentReady: function(id, fn, obj, overrideContext) {
846
                this.onAvailable(id, fn, obj, overrideContext, true);
847
            },
848
 
849
            /**
850
             * Executes the supplied callback when the DOM is first usable.  This
851
             * will execute immediately if called after the DOMReady event has
852
             * fired.   @todo the DOMContentReady event does not fire when the
853
             * script is dynamically injected into the page.  This means the
854
             * DOMReady custom event will never fire in FireFox or Opera when the
855
             * library is injected.  It _will_ fire in Safari, and the IE
856
             * implementation would allow for us to fire it if the defered script
857
             * is not available.  We want this to behave the same in all browsers.
858
             * Is there a way to identify when the script has been injected
859
             * instead of included inline?  Is there a way to know whether the
860
             * window onload event has fired without having had a listener attached
861
             * to it when it did so?
862
             *
863
             * <p>The callback is a CustomEvent, so the signature is:</p>
864
             * <p>type &lt;string&gt;, args &lt;array&gt;, customobject &lt;object&gt;</p>
865
             * <p>For DOMReady events, there are no fire argments, so the
866
             * signature is:</p>
867
             * <p>"DOMReady", [], obj</p>
868
             *
869
             *
870
             * @method onDOMReady
871
             *
872
             * @param {function} fn what to execute when the element is found.
873
             * @param {object}   obj an optional object to be passed back as
874
             *                   a parameter to fn.
875
             * @param {boolean|object}  overrideContext If set to true, fn will execute
876
             *                   in the context of obj, if set to an object it
877
             *                   will execute in the context of that object
878
             *
879
             * @static
880
             */
881
            // onDOMReady: function(fn, obj, overrideContext) {
882
            onDOMReady: function() {
883
                this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent, arguments);
884
            },
885
 
886
 
887
            /**
888
             * Appends an event handler
889
             *
890
             * @method _addListener
891
             *
892
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
893
             *  reference, or a collection of ids and/or elements to assign the
894
             *  listener to.
895
             * @param {String}   sType     The type of event to append
896
             * @param {Function} fn        The method the event invokes
897
             * @param {Object}   obj    An arbitrary object that will be
898
             *                             passed as a parameter to the handler
899
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
900
             *                             the execution context of the listener. If an
901
             *                             object, this object becomes the execution
902
             *                             context.
903
             * @param {boolen}      capture capture or bubble phase
904
             * @return {Boolean} True if the action was successful or defered,
905
             *                        false if one or more of the elements
906
             *                        could not have the listener attached,
907
             *                        or if the operation throws an exception.
908
             * @private
909
             * @static
910
             */
911
            _addListener: function(el, sType, fn, obj, overrideContext, bCapture) {
912
 
913
                if (!fn || !fn.call) {
914
                    return false;
915
                }
916
 
917
                // The el argument can be an array of elements or element ids.
918
                if ( this._isValidCollection(el)) {
919
                    var ok = true;
920
                    for (var i=0,len=el.length; i<len; ++i) {
921
                        ok = this.on(el[i],
922
                                       sType,
923
                                       fn,
924
                                       obj,
925
                                       overrideContext) && ok;
926
                    }
927
                    return ok;
928
 
929
                } else if (YAHOO.lang.isString(el)) {
930
                    var oEl = this.getEl(el);
931
                    // If the el argument is a string, we assume it is
932
                    // actually the id of the element.  If the page is loaded
933
                    // we convert el to the actual element, otherwise we
934
                    // defer attaching the event until onload event fires
935
 
936
                    // check to see if we need to delay hooking up the event
937
                    // until after the page loads.
938
                    if (oEl) {
939
                        el = oEl;
940
                    } else {
941
                        // defer adding the event until the element is available
942
                        this.onAvailable(el, function() {
943
                           YAHOO.util.Event._addListener(el, sType, fn, obj, overrideContext, bCapture);
944
                        });
945
 
946
                        return true;
947
                    }
948
                }
949
 
950
                // Element should be an html element or an array if we get
951
                // here.
952
                if (!el) {
953
                    return false;
954
                }
955
 
956
                // we need to make sure we fire registered unload events
957
                // prior to automatically unhooking them.  So we hang on to
958
                // these instead of attaching them to the window and fire the
959
                // handles explicitly during our one unload event.
960
                if ("unload" == sType && obj !== this) {
961
                    unloadListeners[unloadListeners.length] =
962
                            [el, sType, fn, obj, overrideContext];
963
                    return true;
964
                }
965
 
966
 
967
                // if the user chooses to override the context, we use the custom
968
                // object passed in, otherwise the executing context will be the
969
                // HTML element that the event is registered on
970
                var context = el;
971
                if (overrideContext) {
972
                    if (overrideContext === true) {
973
                        context = obj;
974
                    } else {
975
                        context = overrideContext;
976
                    }
977
                }
978
 
979
                // wrap the function so we can return the obj object when
980
                // the event fires;
981
                var wrappedFn = function(e) {
982
                        return fn.call(context, YAHOO.util.Event.getEvent(e, el),
983
                                obj);
984
                    };
985
 
986
                var li = [el, sType, fn, wrappedFn, context, obj, overrideContext, bCapture];
987
                var index = listeners.length;
988
                // cache the listener so we can try to automatically unload
989
                listeners[index] = li;
990
 
991
                try {
992
                    this._simpleAdd(el, sType, wrappedFn, bCapture);
993
                } catch(ex) {
994
                    // handle an error trying to attach an event.  If it fails
995
                    // we need to clean up the cache
996
                    this.lastError = ex;
997
                    this.removeListener(el, sType, fn);
998
                    return false;
999
                }
1000
 
1001
                return true;
1002
 
1003
            },
1004
 
1005
            /**
1006
             * Checks to see if the type requested is a special type
1007
             * (as defined by the _specialTypes hash), and (if so) returns
1008
             * the special type name.
1009
             *
1010
             * @method _getType
1011
             *
1012
             * @param {String}   sType     The type to look up
1013
             * @private
1014
             */
1015
            _getType: function (type) {
1016
 
1017
                return this._specialTypes[type] || type;
1018
 
1019
            },
1020
 
1021
 
1022
            /**
1023
             * Appends an event handler
1024
             *
1025
             * @method addListener
1026
             *
1027
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1028
             *  reference, or a collection of ids and/or elements to assign the
1029
             *  listener to.
1030
             * @param {String}   sType     The type of event to append
1031
             * @param {Function} fn        The method the event invokes
1032
             * @param {Object}   obj    An arbitrary object that will be
1033
             *                             passed as a parameter to the handler
1034
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1035
             *                             the execution context of the listener. If an
1036
             *                             object, this object becomes the execution
1037
             *                             context.
1038
             * @return {Boolean} True if the action was successful or defered,
1039
             *                        false if one or more of the elements
1040
             *                        could not have the listener attached,
1041
             *                        or if the operation throws an exception.
1042
             * @static
1043
             */
1044
            addListener: function (el, sType, fn, obj, overrideContext) {
1045
 
1046
                var capture = ((sType == FOCUSIN || sType == FOCUSOUT) && !YAHOO.env.ua.ie) ? true : false;
1047
 
1048
                return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
1049
 
1050
            },
1051
 
1052
 
1053
            /**
1054
             * Attaches a focusin event listener to the specified element for
1055
             * the purpose of listening for the focus event on the element's
1056
             * descendants.
1057
             * @method addFocusListener
1058
             *
1059
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1060
             *  reference, or a collection of ids and/or elements to assign the
1061
             *  listener to.
1062
             * @param {Function} fn        The method the event invokes
1063
             * @param {Object}   obj    An arbitrary object that will be
1064
             *                             passed as a parameter to the handler
1065
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1066
             *                             the execution context of the listener. If an
1067
             *                             object, this object becomes the execution
1068
             *                             context.
1069
             * @return {Boolean} True if the action was successful or defered,
1070
             *                        false if one or more of the elements
1071
             *                        could not have the listener attached,
1072
             *                        or if the operation throws an exception.
1073
             * @static
1074
            * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
1075
             */
1076
            addFocusListener: function (el, fn, obj, overrideContext) {
1077
                return this.on(el, FOCUSIN, fn, obj, overrideContext);
1078
            },
1079
 
1080
 
1081
            /**
1082
             * Removes a focusin event listener to the specified element for
1083
             * the purpose of listening for the focus event on the element's
1084
             * descendants.
1085
             *
1086
             * @method removeFocusListener
1087
             *
1088
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1089
             *  reference, or a collection of ids and/or elements to remove
1090
             *  the listener from.
1091
             * @param {Function} fn the method the event invokes.  If fn is
1092
             *  undefined, then all event handlers for the type of event are
1093
             *  removed.
1094
             * @return {boolean} true if the unbind was successful, false
1095
             *  otherwise.
1096
             * @static
1097
             * @deprecated use YAHOO.util.Event.removeListener and specify "focusin" as the event type.
1098
             */
1099
            removeFocusListener: function (el, fn) {
1100
                return this.removeListener(el, FOCUSIN, fn);
1101
            },
1102
 
1103
            /**
1104
             * Attaches a focusout event listener to the specified element for
1105
             * the purpose of listening for the blur event on the element's
1106
             * descendants.
1107
             *
1108
             * @method addBlurListener
1109
             *
1110
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1111
             *  reference, or a collection of ids and/or elements to assign the
1112
             *  listener to.
1113
             * @param {Function} fn        The method the event invokes
1114
             * @param {Object}   obj    An arbitrary object that will be
1115
             *                             passed as a parameter to the handler
1116
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1117
             *                             the execution context of the listener. If an
1118
             *                             object, this object becomes the execution
1119
             *                             context.
1120
             * @return {Boolean} True if the action was successful or defered,
1121
             *                        false if one or more of the elements
1122
             *                        could not have the listener attached,
1123
             *                        or if the operation throws an exception.
1124
             * @static
1125
             * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
1126
             */
1127
            addBlurListener: function (el, fn, obj, overrideContext) {
1128
                return this.on(el, FOCUSOUT, fn, obj, overrideContext);
1129
            },
1130
 
1131
            /**
1132
             * Removes a focusout event listener to the specified element for
1133
             * the purpose of listening for the blur event on the element's
1134
             * descendants.
1135
             *
1136
             * @method removeBlurListener
1137
             *
1138
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1139
             *  reference, or a collection of ids and/or elements to remove
1140
             *  the listener from.
1141
             * @param {Function} fn the method the event invokes.  If fn is
1142
             *  undefined, then all event handlers for the type of event are
1143
             *  removed.
1144
             * @return {boolean} true if the unbind was successful, false
1145
             *  otherwise.
1146
             * @static
1147
             * @deprecated use YAHOO.util.Event.removeListener and specify "focusout" as the event type.
1148
             */
1149
            removeBlurListener: function (el, fn) {
1150
                return this.removeListener(el, FOCUSOUT, fn);
1151
            },
1152
 
1153
            /**
1154
             * Removes an event listener
1155
             *
1156
             * @method removeListener
1157
             *
1158
             * @param {String|HTMLElement|Array|NodeList} el An id, an element
1159
             *  reference, or a collection of ids and/or elements to remove
1160
             *  the listener from.
1161
             * @param {String} sType the type of event to remove.
1162
             * @param {Function} fn the method the event invokes.  If fn is
1163
             *  undefined, then all event handlers for the type of event are
1164
             *  removed.
1165
             * @return {boolean} true if the unbind was successful, false
1166
             *  otherwise.
1167
             * @static
1168
             */
1169
            removeListener: function(el, sType, fn) {
1170
                var i, len, li;
1171
 
1172
                sType = this._getType(sType);
1173
 
1174
                // The el argument can be a string
1175
                if (typeof el == "string") {
1176
                    el = this.getEl(el);
1177
                // The el argument can be an array of elements or element ids.
1178
                } else if ( this._isValidCollection(el)) {
1179
                    var ok = true;
1180
                    for (i=el.length-1; i>-1; i--) {
1181
                        ok = ( this.removeListener(el[i], sType, fn) && ok );
1182
                    }
1183
                    return ok;
1184
                }
1185
 
1186
                if (!fn || !fn.call) {
1187
                    //return false;
1188
                    return this.purgeElement(el, false, sType);
1189
                }
1190
 
1191
                if ("unload" == sType) {
1192
 
1193
                    for (i=unloadListeners.length-1; i>-1; i--) {
1194
                        li = unloadListeners[i];
1195
                        if (li &&
1196
                            li[0] == el &&
1197
                            li[1] == sType &&
1198
                            li[2] == fn) {
1199
                                unloadListeners.splice(i, 1);
1200
                                // unloadListeners[i]=null;
1201
                                return true;
1202
                        }
1203
                    }
1204
 
1205
                    return false;
1206
                }
1207
 
1208
                var cacheItem = null;
1209
 
1210
                // The index is a hidden parameter; needed to remove it from
1211
                // the method signature because it was tempting users to
1212
                // try and take advantage of it, which is not possible.
1213
                var index = arguments[3];
1214
 
1215
                if ("undefined" === typeof index) {
1216
                    index = this._getCacheIndex(listeners, el, sType, fn);
1217
                }
1218
 
1219
                if (index >= 0) {
1220
                    cacheItem = listeners[index];
1221
                }
1222
 
1223
                if (!el || !cacheItem) {
1224
                    return false;
1225
                }
1226
 
1227
 
1228
                var bCapture = cacheItem[this.CAPTURE] === true ? true : false;
1229
 
1230
                try {
1231
                    this._simpleRemove(el, sType, cacheItem[this.WFN], bCapture);
1232
                } catch(ex) {
1233
                    this.lastError = ex;
1234
                    return false;
1235
                }
1236
 
1237
                // removed the wrapped handler
1238
                delete listeners[index][this.WFN];
1239
                delete listeners[index][this.FN];
1240
                listeners.splice(index, 1);
1241
                // listeners[index]=null;
1242
 
1243
                return true;
1244
 
1245
            },
1246
 
1247
            /**
1248
             * Returns the event's target element.  Safari sometimes provides
1249
             * a text node, and this is automatically resolved to the text
1250
             * node's parent so that it behaves like other browsers.
1251
             * @method getTarget
1252
             * @param {Event} ev the event
1253
             * @param {boolean} resolveTextNode when set to true the target's
1254
             *                  parent will be returned if the target is a
1255
             *                  text node.  @deprecated, the text node is
1256
             *                  now resolved automatically
1257
             * @return {HTMLElement} the event's target
1258
             * @static
1259
             */
1260
            getTarget: function(ev, resolveTextNode) {
1261
                var t = ev.target || ev.srcElement;
1262
                return this.resolveTextNode(t);
1263
            },
1264
 
1265
            /**
1266
             * In some cases, some browsers will return a text node inside
1267
             * the actual element that was targeted.  This normalizes the
1268
             * return value for getTarget and getRelatedTarget.
1269
             *
1270
             * If accessing a property of the node throws an error, this is
1271
             * probably the anonymous div wrapper Gecko adds inside text
1272
             * nodes.  This likely will only occur when attempting to access
1273
             * the relatedTarget.  In this case, we now return null because
1274
             * the anonymous div is completely useless and we do not know
1275
             * what the related target was because we can't even get to
1276
             * the element's parent node.
1277
             *
1278
             * @method resolveTextNode
1279
             * @param {HTMLElement} node node to resolve
1280
             * @return {HTMLElement} the normized node
1281
             * @static
1282
             */
1283
            resolveTextNode: function(n) {
1284
                try {
1285
                    if (n && 3 == n.nodeType) {
1286
                        return n.parentNode;
1287
                    }
1288
                } catch(e) {
1289
                    return null;
1290
                }
1291
 
1292
                return n;
1293
            },
1294
 
1295
            /**
1296
             * Returns the event's pageX
1297
             * @method getPageX
1298
             * @param {Event} ev the event
1299
             * @return {int} the event's pageX
1300
             * @static
1301
             */
1302
            getPageX: function(ev) {
1303
                var x = ev.pageX;
1304
                if (!x && 0 !== x) {
1305
                    x = ev.clientX || 0;
1306
 
1307
                    if ( this.isIE ) {
1308
                        x += this._getScrollLeft();
1309
                    }
1310
                }
1311
 
1312
                return x;
1313
            },
1314
 
1315
            /**
1316
             * Returns the event's pageY
1317
             * @method getPageY
1318
             * @param {Event} ev the event
1319
             * @return {int} the event's pageY
1320
             * @static
1321
             */
1322
            getPageY: function(ev) {
1323
                var y = ev.pageY;
1324
                if (!y && 0 !== y) {
1325
                    y = ev.clientY || 0;
1326
 
1327
                    if ( this.isIE ) {
1328
                        y += this._getScrollTop();
1329
                    }
1330
                }
1331
 
1332
 
1333
                return y;
1334
            },
1335
 
1336
            /**
1337
             * Returns the pageX and pageY properties as an indexed array.
1338
             * @method getXY
1339
             * @param {Event} ev the event
1340
             * @return {[x, y]} the pageX and pageY properties of the event
1341
             * @static
1342
             */
1343
            getXY: function(ev) {
1344
                return [this.getPageX(ev), this.getPageY(ev)];
1345
            },
1346
 
1347
            /**
1348
             * Returns the event's related target
1349
             * @method getRelatedTarget
1350
             * @param {Event} ev the event
1351
             * @return {HTMLElement} the event's relatedTarget
1352
             * @static
1353
             */
1354
            getRelatedTarget: function(ev) {
1355
                var t = ev.relatedTarget;
1356
                if (!t) {
1357
                    if (ev.type == "mouseout") {
1358
                        t = ev.toElement;
1359
                    } else if (ev.type == "mouseover") {
1360
                        t = ev.fromElement;
1361
                    }
1362
                }
1363
 
1364
                return this.resolveTextNode(t);
1365
            },
1366
 
1367
            /**
1368
             * Returns the time of the event.  If the time is not included, the
1369
             * event is modified using the current time.
1370
             * @method getTime
1371
             * @param {Event} ev the event
1372
             * @return {Date} the time of the event
1373
             * @static
1374
             */
1375
            getTime: function(ev) {
1376
                if (!ev.time) {
1377
                    var t = new Date().getTime();
1378
                    try {
1379
                        ev.time = t;
1380
                    } catch(ex) {
1381
                        this.lastError = ex;
1382
                        return t;
1383
                    }
1384
                }
1385
 
1386
                return ev.time;
1387
            },
1388
 
1389
            /**
1390
             * Convenience method for stopPropagation + preventDefault
1391
             * @method stopEvent
1392
             * @param {Event} ev the event
1393
             * @static
1394
             */
1395
            stopEvent: function(ev) {
1396
                this.stopPropagation(ev);
1397
                this.preventDefault(ev);
1398
            },
1399
 
1400
            /**
1401
             * Stops event propagation
1402
             * @method stopPropagation
1403
             * @param {Event} ev the event
1404
             * @static
1405
             */
1406
            stopPropagation: function(ev) {
1407
                if (ev.stopPropagation) {
1408
                    ev.stopPropagation();
1409
                } else {
1410
                    ev.cancelBubble = true;
1411
                }
1412
            },
1413
 
1414
            /**
1415
             * Prevents the default behavior of the event
1416
             * @method preventDefault
1417
             * @param {Event} ev the event
1418
             * @static
1419
             */
1420
            preventDefault: function(ev) {
1421
                if (ev.preventDefault) {
1422
                    ev.preventDefault();
1423
                } else {
1424
                    ev.returnValue = false;
1425
                }
1426
            },
1427
 
1428
            /**
1429
             * Finds the event in the window object, the caller's arguments, or
1430
             * in the arguments of another method in the callstack.  This is
1431
             * executed automatically for events registered through the event
1432
             * manager, so the implementer should not normally need to execute
1433
             * this function at all.
1434
             * @method getEvent
1435
             * @param {Event} e the event parameter from the handler
1436
             * @param {HTMLElement} boundEl the element the listener is attached to
1437
             * @return {Event} the event
1438
             * @static
1439
             */
1440
            getEvent: function(e, boundEl) {
1441
                var ev = e || window.event;
1442
 
1443
                if (!ev) {
1444
                    var c = this.getEvent.caller;
1445
                    while (c) {
1446
                        ev = c.arguments[0];
1447
                        if (ev && Event == ev.constructor) {
1448
                            break;
1449
                        }
1450
                        c = c.caller;
1451
                    }
1452
                }
1453
 
1454
                return ev;
1455
            },
1456
 
1457
            /**
1458
             * Returns the charcode for an event
1459
             * @method getCharCode
1460
             * @param {Event} ev the event
1461
             * @return {int} the event's charCode
1462
             * @static
1463
             */
1464
            getCharCode: function(ev) {
1465
                var code = ev.keyCode || ev.charCode || 0;
1466
 
1467
                // webkit key normalization
1468
                if (YAHOO.env.ua.webkit && (code in webkitKeymap)) {
1469
                    code = webkitKeymap[code];
1470
                }
1471
                return code;
1472
            },
1473
 
1474
            /**
1475
             * Locating the saved event handler data by function ref
1476
             *
1477
             * @method _getCacheIndex
1478
             * @static
1479
             * @private
1480
             */
1481
            _getCacheIndex: function(a, el, sType, fn) {
1482
                for (var i=0, l=a.length; i<l; i=i+1) {
1483
                    var li = a[i];
1484
                    if ( li                 &&
1485
                         li[this.FN] == fn  &&
1486
                         li[this.EL] == el  &&
1487
                         li[this.TYPE] == sType ) {
1488
                        return i;
1489
                    }
1490
                }
1491
 
1492
                return -1;
1493
            },
1494
 
1495
            /**
1496
             * Generates an unique ID for the element if it does not already
1497
             * have one.
1498
             * @method generateId
1499
             * @param el the element to create the id for
1500
             * @return {string} the resulting id of the element
1501
             * @static
1502
             */
1503
            generateId: function(el) {
1504
                var id = el.id;
1505
 
1506
                if (!id) {
1507
                    id = "yuievtautoid-" + counter;
1508
                    ++counter;
1509
                    el.id = id;
1510
                }
1511
 
1512
                return id;
1513
            },
1514
 
1515
 
1516
            /**
1517
             * We want to be able to use getElementsByTagName as a collection
1518
             * to attach a group of events to.  Unfortunately, different
1519
             * browsers return different types of collections.  This function
1520
             * tests to determine if the object is array-like.  It will also
1521
             * fail if the object is an array, but is empty.
1522
             * @method _isValidCollection
1523
             * @param o the object to test
1524
             * @return {boolean} true if the object is array-like and populated
1525
             * @static
1526
             * @private
1527
             */
1528
            _isValidCollection: function(o) {
1529
                try {
1530
                    return ( o                     && // o is something
1531
                             typeof o !== "string" && // o is not a string
1532
                             o.length              && // o is indexed
1533
                             !o.tagName            && // o is not an HTML element
1534
                             !o.alert              && // o is not a window
1535
                             typeof o[0] !== "undefined" );
1536
                } catch(ex) {
1537
                    return false;
1538
                }
1539
 
1540
            },
1541
 
1542
            /**
1543
             * @private
1544
             * @property elCache
1545
             * DOM element cache
1546
             * @static
1547
             * @deprecated Elements are not cached due to issues that arise when
1548
             * elements are removed and re-added
1549
             */
1550
            elCache: {},
1551
 
1552
            /**
1553
             * We cache elements bound by id because when the unload event
1554
             * fires, we can no longer use document.getElementById
1555
             * @method getEl
1556
             * @static
1557
             * @private
1558
             * @deprecated Elements are not cached any longer
1559
             */
1560
            getEl: function(id) {
1561
                return (typeof id === "string") ? document.getElementById(id) : id;
1562
            },
1563
 
1564
            /**
1565
             * Clears the element cache
1566
             * @deprecated Elements are not cached any longer
1567
             * @method clearCache
1568
             * @static
1569
             * @private
1570
             */
1571
            clearCache: function() { },
1572
 
1573
            /**
1574
             * Custom event the fires when the dom is initially usable
1575
             * @event DOMReadyEvent
1576
             */
1577
            DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", YAHOO, 0, 0, 1),
1578
 
1579
            /**
1580
             * hook up any deferred listeners
1581
             * @method _load
1582
             * @static
1583
             * @private
1584
             */
1585
            _load: function(e) {
1586
 
1587
                if (!loadComplete) {
1588
                    loadComplete = true;
1589
                    var EU = YAHOO.util.Event;
1590
 
1591
                    // Just in case DOMReady did not go off for some reason
1592
                    EU._ready();
1593
 
1594
                    // Available elements may not have been detected before the
1595
                    // window load event fires. Try to find them now so that the
1596
                    // the user is more likely to get the onAvailable notifications
1597
                    // before the window load notification
1598
                    EU._tryPreloadAttach();
1599
 
1600
                }
1601
            },
1602
 
1603
            /**
1604
             * Fires the DOMReady event listeners the first time the document is
1605
             * usable.
1606
             * @method _ready
1607
             * @static
1608
             * @private
1609
             */
1610
            _ready: function(e) {
1611
                var EU = YAHOO.util.Event;
1612
                if (!EU.DOMReady) {
1613
                    EU.DOMReady=true;
1614
 
1615
                    // Fire the content ready custom event
1616
                    EU.DOMReadyEvent.fire();
1617
 
1618
                    // Remove the DOMContentLoaded (FF/Opera)
1619
                    EU._simpleRemove(document, "DOMContentLoaded", EU._ready);
1620
                }
1621
            },
1622
 
1623
            /**
1624
             * Polling function that runs before the onload event fires,
1625
             * attempting to attach to DOM Nodes as soon as they are
1626
             * available
1627
             * @method _tryPreloadAttach
1628
             * @static
1629
             * @private
1630
             */
1631
            _tryPreloadAttach: function() {
1632
 
1633
                if (onAvailStack.length === 0) {
1634
                    retryCount = 0;
1635
                    if (this._interval) {
1636
                        // clearInterval(this._interval);
1637
                        this._interval.cancel();
1638
                        this._interval = null;
1639
                    }
1640
                    return;
1641
                }
1642
 
1643
                if (this.locked) {
1644
                    return;
1645
                }
1646
 
1647
                if (this.isIE) {
1648
                    // Hold off if DOMReady has not fired and check current
1649
                    // readyState to protect against the IE operation aborted
1650
                    // issue.
1651
                    if (!this.DOMReady) {
1652
                        this.startInterval();
1653
                        return;
1654
                    }
1655
                }
1656
 
1657
                this.locked = true;
1658
 
1659
 
1660
                // keep trying until after the page is loaded.  We need to
1661
                // check the page load state prior to trying to bind the
1662
                // elements so that we can be certain all elements have been
1663
                // tested appropriately
1664
                var tryAgain = !loadComplete;
1665
                if (!tryAgain) {
1666
                    tryAgain = (retryCount > 0 && onAvailStack.length > 0);
1667
                }
1668
 
1669
                // onAvailable
1670
                var notAvail = [];
1671
 
1672
                var executeItem = function (el, item) {
1673
                    var context = el;
1674
                    if (item.overrideContext) {
1675
                        if (item.overrideContext === true) {
1676
                            context = item.obj;
1677
                        } else {
1678
                            context = item.overrideContext;
1679
                        }
1680
                    }
1681
                    item.fn.call(context, item.obj);
1682
                };
1683
 
1684
                var i, len, item, el, ready=[];
1685
 
1686
                // onAvailable onContentReady
1687
                for (i=0, len=onAvailStack.length; i<len; i=i+1) {
1688
                    item = onAvailStack[i];
1689
                    if (item) {
1690
                        el = this.getEl(item.id);
1691
                        if (el) {
1692
                            if (item.checkReady) {
1693
                                if (loadComplete || el.nextSibling || !tryAgain) {
1694
                                    ready.push(item);
1695
                                    onAvailStack[i] = null;
1696
                                }
1697
                            } else {
1698
                                executeItem(el, item);
1699
                                onAvailStack[i] = null;
1700
                            }
1701
                        } else {
1702
                            notAvail.push(item);
1703
                        }
1704
                    }
1705
                }
1706
 
1707
                // make sure onContentReady fires after onAvailable
1708
                for (i=0, len=ready.length; i<len; i=i+1) {
1709
                    item = ready[i];
1710
                    executeItem(this.getEl(item.id), item);
1711
                }
1712
 
1713
 
1714
                retryCount--;
1715
 
1716
                if (tryAgain) {
1717
                    for (i=onAvailStack.length-1; i>-1; i--) {
1718
                        item = onAvailStack[i];
1719
                        if (!item || !item.id) {
1720
                            onAvailStack.splice(i, 1);
1721
                        }
1722
                    }
1723
 
1724
                    this.startInterval();
1725
                } else {
1726
                    if (this._interval) {
1727
                        // clearInterval(this._interval);
1728
                        this._interval.cancel();
1729
                        this._interval = null;
1730
                    }
1731
                }
1732
 
1733
                this.locked = false;
1734
 
1735
            },
1736
 
1737
            /**
1738
             * Removes all listeners attached to the given element via addListener.
1739
             * Optionally, the node's children can also be purged.
1740
             * Optionally, you can specify a specific type of event to remove.
1741
             * @method purgeElement
1742
             * @param {HTMLElement} el the element to purge
1743
             * @param {boolean} recurse recursively purge this element's children
1744
             * as well.  Use with caution.
1745
             * @param {string} sType optional type of listener to purge. If
1746
             * left out, all listeners will be removed
1747
             * @static
1748
             */
1749
            purgeElement: function(el, recurse, sType) {
1750
                var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1751
                var elListeners = this.getListeners(oEl, sType), i, len;
1752
                if (elListeners) {
1753
                    for (i=elListeners.length-1; i>-1; i--) {
1754
                        var l = elListeners[i];
1755
                        this.removeListener(oEl, l.type, l.fn);
1756
                    }
1757
                }
1758
 
1759
                if (recurse && oEl && oEl.childNodes) {
1760
                    for (i=0,len=oEl.childNodes.length; i<len ; ++i) {
1761
                        this.purgeElement(oEl.childNodes[i], recurse, sType);
1762
                    }
1763
                }
1764
            },
1765
 
1766
            /**
1767
             * Returns all listeners attached to the given element via addListener.
1768
             * Optionally, you can specify a specific type of event to return.
1769
             * @method getListeners
1770
             * @param el {HTMLElement|string} the element or element id to inspect
1771
             * @param sType {string} optional type of listener to return. If
1772
             * left out, all listeners will be returned
1773
             * @return {Object} the listener. Contains the following fields:
1774
             * &nbsp;&nbsp;type:   (string)   the type of event
1775
             * &nbsp;&nbsp;fn:     (function) the callback supplied to addListener
1776
             * &nbsp;&nbsp;obj:    (object)   the custom object supplied to addListener
1777
             * &nbsp;&nbsp;adjust: (boolean|object)  whether or not to adjust the default context
1778
             * &nbsp;&nbsp;scope: (boolean)  the derived context based on the adjust parameter
1779
             * &nbsp;&nbsp;index:  (int)      its position in the Event util listener cache
1780
             * @static
1781
             */
1782
            getListeners: function(el, sType) {
1783
                var results=[], searchLists;
1784
                if (!sType) {
1785
                    searchLists = [listeners, unloadListeners];
1786
                } else if (sType === "unload") {
1787
                    searchLists = [unloadListeners];
1788
                } else {
1789
                    sType = this._getType(sType);
1790
                    searchLists = [listeners];
1791
                }
1792
 
1793
                var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1794
 
1795
                for (var j=0;j<searchLists.length; j=j+1) {
1796
                    var searchList = searchLists[j];
1797
                    if (searchList) {
1798
                        for (var i=0,len=searchList.length; i<len ; ++i) {
1799
                            var l = searchList[i];
1800
                            if ( l  && l[this.EL] === oEl &&
1801
                                    (!sType || sType === l[this.TYPE]) ) {
1802
                                results.push({
1803
                                    type:   l[this.TYPE],
1804
                                    fn:     l[this.FN],
1805
                                    obj:    l[this.OBJ],
1806
                                    adjust: l[this.OVERRIDE],
1807
                                    scope:  l[this.ADJ_SCOPE],
1808
                                    index:  i
1809
                                });
1810
                            }
1811
                        }
1812
                    }
1813
                }
1814
 
1815
                return (results.length) ? results : null;
1816
            },
1817
 
1818
            /**
1819
             * Removes all listeners registered by pe.event.  Called
1820
             * automatically during the unload event.
1821
             * @method _unload
1822
             * @static
1823
             * @private
1824
             */
1825
            _unload: function(e) {
1826
 
1827
                var EU = YAHOO.util.Event, i, j, l, len, index,
1828
                         ul = unloadListeners.slice(), context;
1829
 
1830
                // execute and clear stored unload listeners
1831
                for (i=0, len=unloadListeners.length; i<len; ++i) {
1832
                    l = ul[i];
1833
                    if (l) {
1834
                        try {
1835
                            context = window;
1836
                            if (l[EU.ADJ_SCOPE]) {
1837
                                if (l[EU.ADJ_SCOPE] === true) {
1838
                                    context = l[EU.UNLOAD_OBJ];
1839
                                } else {
1840
                                    context = l[EU.ADJ_SCOPE];
1841
                                }
1842
                            }
1843
                            l[EU.FN].call(context, EU.getEvent(e, l[EU.EL]), l[EU.UNLOAD_OBJ] );
1844
                        } catch(e1) {}
1845
                        ul[i] = null;
1846
                    }
1847
                }
1848
 
1849
                l = null;
1850
                context = null;
1851
                unloadListeners = null;
1852
 
1853
                // Remove listeners to handle IE memory leaks
1854
                // 2.5.0 listeners are removed for all browsers again.  FireFox preserves
1855
                // at least some listeners between page refreshes, potentially causing
1856
                // errors during page load (mouseover listeners firing before they
1857
                // should if the user moves the mouse at the correct moment).
1858
                if (listeners) {
1859
                    for (j=listeners.length-1; j>-1; j--) {
1860
                        l = listeners[j];
1861
                        if (l) {
1862
                            try {
1863
                                EU.removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN], j);
1864
                            } catch(e2) {}
1865
                        }
1866
                    }
1867
                    l=null;
1868
                }
1869
 
1870
                try {
1871
                    EU._simpleRemove(window, "unload", EU._unload);
1872
                    EU._simpleRemove(window, "load", EU._load);
1873
                } catch(e3) {}
1874
 
1875
            },
1876
 
1877
            /**
1878
             * Returns scrollLeft
1879
             * @method _getScrollLeft
1880
             * @static
1881
             * @private
1882
             */
1883
            _getScrollLeft: function() {
1884
                return this._getScroll()[1];
1885
            },
1886
 
1887
            /**
1888
             * Returns scrollTop
1889
             * @method _getScrollTop
1890
             * @static
1891
             * @private
1892
             */
1893
            _getScrollTop: function() {
1894
                return this._getScroll()[0];
1895
            },
1896
 
1897
            /**
1898
             * Returns the scrollTop and scrollLeft.  Used to calculate the
1899
             * pageX and pageY in Internet Explorer
1900
             * @method _getScroll
1901
             * @static
1902
             * @private
1903
             */
1904
            _getScroll: function() {
1905
                var dd = document.documentElement, db = document.body;
1906
                if (dd && (dd.scrollTop || dd.scrollLeft)) {
1907
                    return [dd.scrollTop, dd.scrollLeft];
1908
                } else if (db) {
1909
                    return [db.scrollTop, db.scrollLeft];
1910
                } else {
1911
                    return [0, 0];
1912
                }
1913
            },
1914
 
1915
            /**
1916
             * Used by old versions of CustomEvent, restored for backwards
1917
             * compatibility
1918
             * @method regCE
1919
             * @private
1920
             * @static
1921
             * @deprecated still here for backwards compatibility
1922
             */
1923
            regCE: function() {},
1924
 
1925
            /**
1926
             * Adds a DOM event directly without the caching, cleanup, context adj, etc
1927
             *
1928
             * @method _simpleAdd
1929
             * @param {HTMLElement} el      the element to bind the handler to
1930
             * @param {string}      sType   the type of event handler
1931
             * @param {function}    fn      the callback to invoke
1932
             * @param {boolen}      capture capture or bubble phase
1933
             * @static
1934
             * @private
1935
             */
1936
            _simpleAdd: function () {
1937
                if (window.addEventListener) {
1938
                    return function(el, sType, fn, capture) {
1939
                        el.addEventListener(sType, fn, (capture));
1940
                    };
1941
                } else if (window.attachEvent) {
1942
                    return function(el, sType, fn, capture) {
1943
                        el.attachEvent("on" + sType, fn);
1944
                    };
1945
                } else {
1946
                    return function(){};
1947
                }
1948
            }(),
1949
 
1950
            /**
1951
             * Basic remove listener
1952
             *
1953
             * @method _simpleRemove
1954
             * @param {HTMLElement} el      the element to bind the handler to
1955
             * @param {string}      sType   the type of event handler
1956
             * @param {function}    fn      the callback to invoke
1957
             * @param {boolen}      capture capture or bubble phase
1958
             * @static
1959
             * @private
1960
             */
1961
            _simpleRemove: function() {
1962
                if (window.removeEventListener) {
1963
                    return function (el, sType, fn, capture) {
1964
                        el.removeEventListener(sType, fn, (capture));
1965
                    };
1966
                } else if (window.detachEvent) {
1967
                    return function (el, sType, fn) {
1968
                        el.detachEvent("on" + sType, fn);
1969
                    };
1970
                } else {
1971
                    return function(){};
1972
                }
1973
            }()
1974
        };
1975
 
1976
    }();
1977
 
1978
    (function() {
1979
        var EU = YAHOO.util.Event;
1980
 
1981
        /**
1982
         * Appends an event handler.  This is an alias for <code>addListener</code>
1983
         *
1984
         * @method on
1985
         *
1986
         * @param {String|HTMLElement|Array|NodeList} el An id, an element
1987
         *  reference, or a collection of ids and/or elements to assign the
1988
         *  listener to.
1989
         * @param {String}   sType     The type of event to append
1990
         * @param {Function} fn        The method the event invokes
1991
         * @param {Object}   obj    An arbitrary object that will be
1992
         *                             passed as a parameter to the handler
1993
         * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1994
         *                             the execution context of the listener. If an
1995
         *                             object, this object becomes the execution
1996
         *                             context.
1997
         * @return {Boolean} True if the action was successful or defered,
1998
         *                        false if one or more of the elements
1999
         *                        could not have the listener attached,
2000
         *                        or if the operation throws an exception.
2001
         * @static
2002
         */
2003
        EU.on = EU.addListener;
2004
 
2005
        /**
2006
         * YAHOO.util.Event.onFocus is an alias for addFocusListener
2007
         * @method onFocus
2008
         * @see addFocusListener
2009
         * @static
2010
         * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
2011
         */
2012
        EU.onFocus = EU.addFocusListener;
2013
 
2014
        /**
2015
         * YAHOO.util.Event.onBlur is an alias for addBlurListener
2016
         * @method onBlur
2017
         * @see addBlurListener
2018
         * @static
2019
         * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
2020
         */
2021
        EU.onBlur = EU.addBlurListener;
2022
 
2023
/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
2024
 
2025
        // Internet Explorer: use the readyState of a defered script.
2026
        // This isolates what appears to be a safe moment to manipulate
2027
        // the DOM prior to when the document's readyState suggests
2028
        // it is safe to do so.
2029
        if (EU.isIE) {
2030
            if (self !== self.top) {
2031
                document.onreadystatechange = function() {
2032
                    if (document.readyState == 'complete') {
2033
                        document.onreadystatechange = null;
2034
                        EU._ready();
2035
                    }
2036
                };
2037
            } else {
2038
 
2039
                // Process onAvailable/onContentReady items when the
2040
                // DOM is ready.
2041
                YAHOO.util.Event.onDOMReady(
2042
                        YAHOO.util.Event._tryPreloadAttach,
2043
                        YAHOO.util.Event, true);
2044
 
2045
                var n = document.createElement('p');
2046
 
2047
                EU._dri = setInterval(function() {
2048
                    try {
2049
                        // throws an error if doc is not ready
2050
                        n.doScroll('left');
2051
                        clearInterval(EU._dri);
2052
                        EU._dri = null;
2053
                        EU._ready();
2054
                        n = null;
2055
                    } catch (ex) {
2056
                    }
2057
                }, EU.POLL_INTERVAL);
2058
            }
2059
 
2060
        // The document's readyState in Safari currently will
2061
        // change to loaded/complete before images are loaded.
2062
        } else if (EU.webkit && EU.webkit < 525) {
2063
 
2064
            EU._dri = setInterval(function() {
2065
                var rs=document.readyState;
2066
                if ("loaded" == rs || "complete" == rs) {
2067
                    clearInterval(EU._dri);
2068
                    EU._dri = null;
2069
                    EU._ready();
2070
                }
2071
            }, EU.POLL_INTERVAL);
2072
 
2073
        // FireFox and Opera: These browsers provide a event for this
2074
        // moment.  The latest WebKit releases now support this event.
2075
        } else {
2076
 
2077
            EU._simpleAdd(document, "DOMContentLoaded", EU._ready);
2078
 
2079
        }
2080
        /////////////////////////////////////////////////////////////
2081
 
2082
 
2083
        EU._simpleAdd(window, "load", EU._load);
2084
        EU._simpleAdd(window, "unload", EU._unload);
2085
        EU._tryPreloadAttach();
2086
    })();
2087
 
2088
}
2089
/**
2090
 * EventProvider is designed to be used with YAHOO.augment to wrap
2091
 * CustomEvents in an interface that allows events to be subscribed to
2092
 * and fired by name.  This makes it possible for implementing code to
2093
 * subscribe to an event that either has not been created yet, or will
2094
 * not be created at all.
2095
 *
2096
 * @Class EventProvider
2097
 */
2098
YAHOO.util.EventProvider = function() { };
2099
 
2100
YAHOO.util.EventProvider.prototype = {
2101
 
2102
    /**
2103
     * Private storage of custom events
2104
     * @property __yui_events
2105
     * @type Object[]
2106
     * @private
2107
     */
2108
    __yui_events: null,
2109
 
2110
    /**
2111
     * Private storage of custom event subscribers
2112
     * @property __yui_subscribers
2113
     * @type Object[]
2114
     * @private
2115
     */
2116
    __yui_subscribers: null,
2117
 
2118
    /**
2119
     * Subscribe to a CustomEvent by event type
2120
     *
2121
     * @method subscribe
2122
     * @param p_type     {string}   the type, or name of the event
2123
     * @param p_fn       {function} the function to exectute when the event fires
2124
     * @param p_obj      {Object}   An object to be passed along when the event
2125
     *                              fires
2126
     * @param overrideContext {boolean}  If true, the obj passed in becomes the
2127
     *                              execution scope of the listener
2128
     */
2129
    subscribe: function(p_type, p_fn, p_obj, overrideContext) {
2130
 
2131
        this.__yui_events = this.__yui_events || {};
2132
        var ce = this.__yui_events[p_type];
2133
 
2134
        if (ce) {
2135
            ce.subscribe(p_fn, p_obj, overrideContext);
2136
        } else {
2137
            this.__yui_subscribers = this.__yui_subscribers || {};
2138
            var subs = this.__yui_subscribers;
2139
            if (!subs[p_type]) {
2140
                subs[p_type] = [];
2141
            }
2142
            subs[p_type].push(
2143
                { fn: p_fn, obj: p_obj, overrideContext: overrideContext } );
2144
        }
2145
    },
2146
 
2147
    /**
2148
     * Unsubscribes one or more listeners the from the specified event
2149
     * @method unsubscribe
2150
     * @param p_type {string}   The type, or name of the event.  If the type
2151
     *                          is not specified, it will attempt to remove
2152
     *                          the listener from all hosted events.
2153
     * @param p_fn   {Function} The subscribed function to unsubscribe, if not
2154
     *                          supplied, all subscribers will be removed.
2155
     * @param p_obj  {Object}   The custom object passed to subscribe.  This is
2156
     *                        optional, but if supplied will be used to
2157
     *                        disambiguate multiple listeners that are the same
2158
     *                        (e.g., you subscribe many object using a function
2159
     *                        that lives on the prototype)
2160
     * @return {boolean} true if the subscriber was found and detached.
2161
     */
2162
    unsubscribe: function(p_type, p_fn, p_obj) {
2163
        this.__yui_events = this.__yui_events || {};
2164
        var evts = this.__yui_events;
2165
        if (p_type) {
2166
            var ce = evts[p_type];
2167
            if (ce) {
2168
                return ce.unsubscribe(p_fn, p_obj);
2169
            }
2170
        } else {
2171
            var ret = true;
2172
            for (var i in evts) {
2173
                if (YAHOO.lang.hasOwnProperty(evts, i)) {
2174
                    ret = ret && evts[i].unsubscribe(p_fn, p_obj);
2175
                }
2176
            }
2177
            return ret;
2178
        }
2179
 
2180
        return false;
2181
    },
2182
 
2183
    /**
2184
     * Removes all listeners from the specified event.  If the event type
2185
     * is not specified, all listeners from all hosted custom events will
2186
     * be removed.
2187
     * @method unsubscribeAll
2188
     * @param p_type {string}   The type, or name of the event
2189
     */
2190
    unsubscribeAll: function(p_type) {
2191
        return this.unsubscribe(p_type);
2192
    },
2193
 
2194
    /**
2195
     * Creates a new custom event of the specified type.  If a custom event
2196
     * by that name already exists, it will not be re-created.  In either
2197
     * case the custom event is returned.
2198
     *
2199
     * @method createEvent
2200
     *
2201
     * @param p_type {string} the type, or name of the event
2202
     * @param p_config {object} optional config params.  Valid properties are:
2203
     *
2204
     *  <ul>
2205
     *    <li>
2206
     *      scope: defines the default execution scope.  If not defined
2207
     *      the default scope will be this instance.
2208
     *    </li>
2209
     *    <li>
2210
     *      silent: if true, the custom event will not generate log messages.
2211
     *      This is false by default.
2212
     *    </li>
2213
     *    <li>
2214
     *      fireOnce: if true, the custom event will only notify subscribers
2215
     *      once regardless of the number of times the event is fired.  In
2216
     *      addition, new subscribers will be executed immediately if the
2217
     *      event has already fired.
2218
     *      This is false by default.
2219
     *    </li>
2220
     *    <li>
2221
     *      onSubscribeCallback: specifies a callback to execute when the
2222
     *      event has a new subscriber.  This will fire immediately for
2223
     *      each queued subscriber if any exist prior to the creation of
2224
     *      the event.
2225
     *    </li>
2226
     *  </ul>
2227
     *
2228
     *  @return {CustomEvent} the custom event
2229
     *
2230
     */
2231
    createEvent: function(p_type, p_config) {
2232
 
2233
        this.__yui_events = this.__yui_events || {};
2234
        var opts = p_config || {},
2235
            events = this.__yui_events, ce;
2236
 
2237
        if (events[p_type]) {
2238
        } else {
2239
 
2240
            ce = new YAHOO.util.CustomEvent(p_type, opts.scope || this, opts.silent,
2241
                         YAHOO.util.CustomEvent.FLAT, opts.fireOnce);
2242
 
2243
            events[p_type] = ce;
2244
 
2245
            if (opts.onSubscribeCallback) {
2246
                ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
2247
            }
2248
 
2249
            this.__yui_subscribers = this.__yui_subscribers || {};
2250
            var qs = this.__yui_subscribers[p_type];
2251
 
2252
            if (qs) {
2253
                for (var i=0; i<qs.length; ++i) {
2254
                    ce.subscribe(qs[i].fn, qs[i].obj, qs[i].overrideContext);
2255
                }
2256
            }
2257
        }
2258
 
2259
        return events[p_type];
2260
    },
2261
 
2262
 
2263
   /**
2264
     * Fire a custom event by name.  The callback functions will be executed
2265
     * from the scope specified when the event was created, and with the
2266
     * following parameters:
2267
     *   <ul>
2268
     *   <li>The first argument fire() was executed with</li>
2269
     *   <li>The custom object (if any) that was passed into the subscribe()
2270
     *       method</li>
2271
     *   </ul>
2272
     * @method fireEvent
2273
     * @param p_type    {string}  the type, or name of the event
2274
     * @param arguments {Object*} an arbitrary set of parameters to pass to
2275
     *                            the handler.
2276
     * @return {boolean} the return value from CustomEvent.fire
2277
     *
2278
     */
2279
    fireEvent: function(p_type) {
2280
 
2281
        this.__yui_events = this.__yui_events || {};
2282
        var ce = this.__yui_events[p_type];
2283
 
2284
        if (!ce) {
2285
            return null;
2286
        }
2287
 
2288
        var args = [];
2289
        for (var i=1; i<arguments.length; ++i) {
2290
            args.push(arguments[i]);
2291
        }
2292
        return ce.fire.apply(ce, args);
2293
    },
2294
 
2295
    /**
2296
     * Returns true if the custom event of the provided type has been created
2297
     * with createEvent.
2298
     * @method hasEvent
2299
     * @param type {string} the type, or name of the event
2300
     */
2301
    hasEvent: function(type) {
2302
        if (this.__yui_events) {
2303
            if (this.__yui_events[type]) {
2304
                return true;
2305
            }
2306
        }
2307
        return false;
2308
    }
2309
 
2310
};
2311
 
2312
(function() {
2313
 
2314
    var Event = YAHOO.util.Event, Lang = YAHOO.lang;
2315
 
2316
/**
2317
* KeyListener is a utility that provides an easy interface for listening for
2318
* keydown/keyup events fired against DOM elements.
2319
* @namespace YAHOO.util
2320
* @class KeyListener
2321
* @constructor
2322
* @param {HTMLElement} attachTo The element or element ID to which the key
2323
*                               event should be attached
2324
* @param {String}      attachTo The element or element ID to which the key
2325
*                               event should be attached
2326
* @param {Object}      keyData  The object literal representing the key(s)
2327
*                               to detect. Possible attributes are
2328
*                               shift(boolean), alt(boolean), ctrl(boolean)
2329
*                               and keys(either an int or an array of ints
2330
*                               representing keycodes).
2331
* @param {Function}    handler  The CustomEvent handler to fire when the
2332
*                               key event is detected
2333
* @param {Object}      handler  An object literal representing the handler.
2334
* @param {String}      event    Optional. The event (keydown or keyup) to
2335
*                               listen for. Defaults automatically to keydown.
2336
*
2337
* @knownissue the "keypress" event is completely broken in Safari 2.x and below.
2338
*             the workaround is use "keydown" for key listening.  However, if
2339
*             it is desired to prevent the default behavior of the keystroke,
2340
*             that can only be done on the keypress event.  This makes key
2341
*             handling quite ugly.
2342
* @knownissue keydown is also broken in Safari 2.x and below for the ESC key.
2343
*             There currently is no workaround other than choosing another
2344
*             key to listen for.
2345
*/
2346
YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
2347
    if (!attachTo) {
2348
    } else if (!keyData) {
2349
    } else if (!handler) {
2350
    }
2351
 
2352
    if (!event) {
2353
        event = YAHOO.util.KeyListener.KEYDOWN;
2354
    }
2355
 
2356
    /**
2357
    * The CustomEvent fired internally when a key is pressed
2358
    * @event keyEvent
2359
    * @private
2360
    * @param {Object} keyData The object literal representing the key(s) to
2361
    *                         detect. Possible attributes are shift(boolean),
2362
    *                         alt(boolean), ctrl(boolean) and keys(either an
2363
    *                         int or an array of ints representing keycodes).
2364
    */
2365
    var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
2366
 
2367
    /**
2368
    * The CustomEvent fired when the KeyListener is enabled via the enable()
2369
    * function
2370
    * @event enabledEvent
2371
    * @param {Object} keyData The object literal representing the key(s) to
2372
    *                         detect. Possible attributes are shift(boolean),
2373
    *                         alt(boolean), ctrl(boolean) and keys(either an
2374
    *                         int or an array of ints representing keycodes).
2375
    */
2376
    this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
2377
 
2378
    /**
2379
    * The CustomEvent fired when the KeyListener is disabled via the
2380
    * disable() function
2381
    * @event disabledEvent
2382
    * @param {Object} keyData The object literal representing the key(s) to
2383
    *                         detect. Possible attributes are shift(boolean),
2384
    *                         alt(boolean), ctrl(boolean) and keys(either an
2385
    *                         int or an array of ints representing keycodes).
2386
    */
2387
    this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
2388
 
2389
    if (Lang.isString(attachTo)) {
2390
        attachTo = document.getElementById(attachTo); // No Dom util
2391
    }
2392
 
2393
    if (Lang.isFunction(handler)) {
2394
        keyEvent.subscribe(handler);
2395
    } else {
2396
        keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
2397
    }
2398
 
2399
    /**
2400
    * Handles the key event when a key is pressed.
2401
    * @method handleKeyPress
2402
    * @param {DOMEvent} e   The keypress DOM event
2403
    * @param {Object}   obj The DOM event scope object
2404
    * @private
2405
    */
2406
    function handleKeyPress(e, obj) {
2407
        if (! keyData.shift) {
2408
            keyData.shift = false;
2409
        }
2410
        if (! keyData.alt) {
2411
            keyData.alt = false;
2412
        }
2413
        if (! keyData.ctrl) {
2414
            keyData.ctrl = false;
2415
        }
2416
 
2417
        // check held down modifying keys first
2418
        if (e.shiftKey == keyData.shift &&
2419
            e.altKey   == keyData.alt &&
2420
            e.ctrlKey  == keyData.ctrl) { // if we pass this, all modifiers match
2421
 
2422
            var dataItem, keys = keyData.keys, key;
2423
 
2424
            if (YAHOO.lang.isArray(keys)) {
2425
                for (var i=0;i<keys.length;i++) {
2426
                    dataItem = keys[i];
2427
                    key = Event.getCharCode(e);
2428
 
2429
                    if (dataItem == key) {
2430
                        keyEvent.fire(key, e);
2431
                        break;
2432
                    }
2433
                }
2434
            } else {
2435
                key = Event.getCharCode(e);
2436
                if (keys == key ) {
2437
                    keyEvent.fire(key, e);
2438
                }
2439
            }
2440
        }
2441
    }
2442
 
2443
    /**
2444
    * Enables the KeyListener by attaching the DOM event listeners to the
2445
    * target DOM element
2446
    * @method enable
2447
    */
2448
    this.enable = function() {
2449
        if (! this.enabled) {
2450
            Event.on(attachTo, event, handleKeyPress);
2451
            this.enabledEvent.fire(keyData);
2452
        }
2453
        /**
2454
        * Boolean indicating the enabled/disabled state of the Tooltip
2455
        * @property enabled
2456
        * @type Boolean
2457
        */
2458
        this.enabled = true;
2459
    };
2460
 
2461
    /**
2462
    * Disables the KeyListener by removing the DOM event listeners from the
2463
    * target DOM element
2464
    * @method disable
2465
    */
2466
    this.disable = function() {
2467
        if (this.enabled) {
2468
            Event.removeListener(attachTo, event, handleKeyPress);
2469
            this.disabledEvent.fire(keyData);
2470
        }
2471
        this.enabled = false;
2472
    };
2473
 
2474
    /**
2475
    * Returns a String representation of the object.
2476
    * @method toString
2477
    * @return {String}  The string representation of the KeyListener
2478
    */
2479
    this.toString = function() {
2480
        return "KeyListener [" + keyData.keys + "] " + attachTo.tagName +
2481
                (attachTo.id ? "[" + attachTo.id + "]" : "");
2482
    };
2483
 
2484
};
2485
 
2486
var KeyListener = YAHOO.util.KeyListener;
2487
 
2488
/**
2489
 * Constant representing the DOM "keydown" event.
2490
 * @property YAHOO.util.KeyListener.KEYDOWN
2491
 * @static
2492
 * @final
2493
 * @type String
2494
 */
2495
KeyListener.KEYDOWN = "keydown";
2496
 
2497
/**
2498
 * Constant representing the DOM "keyup" event.
2499
 * @property YAHOO.util.KeyListener.KEYUP
2500
 * @static
2501
 * @final
2502
 * @type String
2503
 */
2504
KeyListener.KEYUP = "keyup";
2505
 
2506
/**
2507
 * keycode constants for a subset of the special keys
2508
 * @property KEY
2509
 * @static
2510
 * @final
2511
 */
2512
KeyListener.KEY = {
2513
    ALT          : 18,
2514
    BACK_SPACE   : 8,
2515
    CAPS_LOCK    : 20,
2516
    CONTROL      : 17,
2517
    DELETE       : 46,
2518
    DOWN         : 40,
2519
    END          : 35,
2520
    ENTER        : 13,
2521
    ESCAPE       : 27,
2522
    HOME         : 36,
2523
    LEFT         : 37,
2524
    META         : 224,
2525
    NUM_LOCK     : 144,
2526
    PAGE_DOWN    : 34,
2527
    PAGE_UP      : 33,
2528
    PAUSE        : 19,
2529
    PRINTSCREEN  : 44,
2530
    RIGHT        : 39,
2531
    SCROLL_LOCK  : 145,
2532
    SHIFT        : 16,
2533
    SPACE        : 32,
2534
    TAB          : 9,
2535
    UP           : 38
2536
};
2537
 
2538
})();
2539
YAHOO.register("event", YAHOO.util.Event, {version: "2.9.0", build: "2800"});
2540
 
2541
    YAHOO.util.Event.generateId = function(el) {
2542
        if (!el.id) {
2543
            el.id = Y.guid();
2544
        }
2545
        return el.id;
2546
    };
2547
    YAHOO.util.Event._load();
2548
}, '2.9.0' ,{"requires": ["yui2-yahoo"]});