Project

General

Profile

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