Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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