Project

General

Profile

« Previous | Next » 

Revision 1289

Added by kweitzel over 14 years ago

Branch 2.8.1 merged back into Trunk

View differences:

event.js
1 1
/*
2
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 3
Code licensed under the BSD License:
4 4
http://developer.yahoo.net/yui/license.txt
5
version: 2.4.1
5
version: 2.8.0r4
6 6
*/
7 7

  
8 8
/**
......
11 11
 *
12 12
 * @param {String}  type The type of event, which is passed to the callback
13 13
 *                  when the event fires
14
 * @param {Object}  oScope The context the event will fire from.  "this" will
14
 * @param {Object}  context The context the event will fire from.  "this" will
15 15
 *                  refer to this object in the callback.  Default value: 
16 16
 *                  the window object.  The listener can override this.
17 17
 * @param {boolean} silent pass true to prevent the event from writing to
......
20 20
 *                  will receive. YAHOO.util.CustomEvent.LIST or 
21 21
 *                  YAHOO.util.CustomEvent.FLAT.  The default is
22 22
 *                  YAHOO.util.CustomEvent.LIST.
23
 * @param fireOnce {boolean} If configured to fire once, the custom event 
24
 * will only notify subscribers a single time regardless of how many times 
25
 * the event is fired.  In addition, new subscribers will be notified 
26
 * immediately if the event has already been fired.
23 27
 * @namespace YAHOO.util
24 28
 * @class CustomEvent
25 29
 * @constructor
26 30
 */
27
YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {
31
YAHOO.util.CustomEvent = function(type, context, silent, signature, fireOnce) {
28 32

  
29 33
    /**
30 34
     * The type of event, returned to subscribers when the event fires
......
34 38
    this.type = type;
35 39

  
36 40
    /**
37
     * The scope the the event will fire from by default.  Defaults to the window 
38
     * obj
41
     * The context the event will fire from by default. Defaults to the window obj.
39 42
     * @property scope
40 43
     * @type object
41 44
     */
42
    this.scope = oScope || window;
45
    this.scope = context || window;
43 46

  
44 47
    /**
45
     * By default all custom events are logged in the debug build, set silent
46
     * to true to disable debug outpu for this event.
48
     * By default all custom events are logged in the debug build. Set silent to true 
49
     * to disable debug output for this event.
47 50
     * @property silent
48 51
     * @type boolean
49 52
     */
50 53
    this.silent = silent;
51 54

  
52 55
    /**
56
     * If configured to fire once, the custom event will only notify subscribers
57
     * a single time regardless of how many times the event is fired.  In addition,
58
     * new subscribers will be notified immediately if the event has already been
59
     * fired.
60
     * @property fireOnce
61
     * @type boolean
62
     * @default false
63
     */
64
    this.fireOnce = fireOnce;
65

  
66
    /**
67
     * Indicates whether or not this event has ever been fired.
68
     * @property fired
69
     * @type boolean
70
     * @default false
71
     */
72
    this.fired = false;
73

  
74
    /**
75
     * For fireOnce events the arguments the event was fired with are stored
76
     * so that new subscribers get the proper payload.
77
     * @property firedWith
78
     * @type Array
79
     */
80
    this.firedWith = null;
81

  
82
    /**
53 83
     * Custom events support two styles of arguments provided to the event
54 84
     * subscribers.  
55 85
     * <ul>
......
97 127
         *
98 128
         * @event subscribeEvent
99 129
         * @type YAHOO.util.CustomEvent
100
         * @param {Function} fn The function to execute
101
         * @param {Object}   obj An object to be passed along when the event 
102
         *                       fires
103
         * @param {boolean|Object}  override If true, the obj passed in becomes 
104
         *                                   the execution scope of the listener.
105
         *                                   if an object, that object becomes the
106
         *                                   the execution scope.
130
         * @param fn {Function} The function to execute
131
         * @param obj <Object> An object to be passed along when the event fires. 
132
         * Defaults to the custom event.
133
         * @param override <boolean|Object> If true, the obj passed in becomes the 
134
         * execution context of the listener. If an object, that object becomes 
135
         * the execution context. Defaults to the custom event.
107 136
         */
108 137
        this.subscribeEvent = 
109 138
                new YAHOO.util.CustomEvent(onsubscribeType, this, true);
......
147 176
     * Subscribes the caller to this event
148 177
     * @method subscribe
149 178
     * @param {Function} fn        The function to execute
150
     * @param {Object}   obj       An object to be passed along when the event 
151
     *                             fires
152
     * @param {boolean|Object}  override If true, the obj passed in becomes 
153
     *                                   the execution scope of the listener.
154
     *                                   if an object, that object becomes the
155
     *                                   the execution scope.
179
     * @param {Object}   obj       An object to be passed along when the event fires.
180
     * overrideContext <boolean|Object> If true, the obj passed in becomes the execution 
181
     * context of the listener. If an object, that object becomes the execution context.
156 182
     */
157
    subscribe: function(fn, obj, override) {
183
    subscribe: function(fn, obj, overrideContext) {
158 184

  
159 185
        if (!fn) {
160 186
throw new Error("Invalid callback for subscriber to '" + this.type + "'");
161 187
        }
162 188

  
163 189
        if (this.subscribeEvent) {
164
            this.subscribeEvent.fire(fn, obj, override);
190
            this.subscribeEvent.fire(fn, obj, overrideContext);
165 191
        }
166 192

  
167
        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );
193
        var s = new YAHOO.util.Subscriber(fn, obj, overrideContext);
194

  
195
        if (this.fireOnce && this.fired) {
196
            this.notify(s, this.firedWith);
197
        } else {
198
            this.subscribers.push(s);
199
        }
168 200
    },
169 201

  
170 202
    /**
......
199 231

  
200 232
    /**
201 233
     * Notifies the subscribers.  The callback functions will be executed
202
     * from the scope specified when the event was created, and with the 
234
     * from the context specified when the event was created, and with the 
203 235
     * following parameters:
204 236
     *   <ul>
205 237
     *   <li>The type of event</li>
......
214 246
     *                   true otherwise
215 247
     */
216 248
    fire: function() {
217
        var len=this.subscribers.length;
218
        if (!len && this.silent) {
219
            return true;
249

  
250
        this.lastError = null;
251

  
252
        var errors = [],
253
            len=this.subscribers.length;
254

  
255

  
256
        var args=[].slice.call(arguments, 0), ret=true, i, rebuild=false;
257

  
258
        if (this.fireOnce) {
259
            if (this.fired) {
260
                return true;
261
            } else {
262
                this.firedWith = args;
263
            }
220 264
        }
221 265

  
222
        var args=[], ret=true, i, rebuild=false;
266
        this.fired = true;
223 267

  
224
        for (i=0; i<arguments.length; ++i) {
225
            args.push(arguments[i]);
268
        if (!len && this.silent) {
269
            return true;
226 270
        }
227 271

  
228 272
        if (!this.silent) {
229 273
        }
230 274

  
275
        // make a copy of the subscribers so that there are
276
        // no index problems if one subscriber removes another.
277
        var subs = this.subscribers.slice();
278

  
231 279
        for (i=0; i<len; ++i) {
232
            var s = this.subscribers[i];
280
            var s = subs[i];
233 281
            if (!s) {
234 282
                rebuild=true;
235 283
            } else {
236
                if (!this.silent) {
237
                }
238 284

  
239
                var scope = s.getScope(this.scope);
285
                ret = this.notify(s, args);
240 286

  
241
                if (this.signature == YAHOO.util.CustomEvent.FLAT) {
242
                    var param = null;
243
                    if (args.length > 0) {
244
                        param = args[0];
245
                    }
246

  
247
                    try {
248
                        ret = s.fn.call(scope, param, s.obj);
249
                    } catch(e) {
250
                        this.lastError = e;
251
                    }
252
                } else {
253
                    try {
254
                        ret = s.fn.call(scope, this.type, args, s.obj);
255
                    } catch(ex) {
256
                        this.lastError = ex;
257
                    }
258
                }
259 287
                if (false === ret) {
260 288
                    if (!this.silent) {
261 289
                    }
262 290

  
263
                    //break;
264
                    return false;
291
                    break;
265 292
                }
266 293
            }
267 294
        }
268 295

  
269
        if (rebuild) {
270
            var newlist=[],subs=this.subscribers;
271
            for (i=0,len=subs.length; i<len; i=i+1) {
272
                newlist.push(subs[i]);
296
        return (ret !== false);
297
    },
298

  
299
    notify: function(s, args) {
300

  
301
        var ret, param=null, scope = s.getScope(this.scope),
302
                 throwErrors = YAHOO.util.Event.throwErrors;
303

  
304
        if (!this.silent) {
305
        }
306

  
307
        if (this.signature == YAHOO.util.CustomEvent.FLAT) {
308

  
309
            if (args.length > 0) {
310
                param = args[0];
273 311
            }
274 312

  
275
            this.subscribers=newlist;
313
            try {
314
                ret = s.fn.call(scope, param, s.obj);
315
            } catch(e) {
316
                this.lastError = e;
317
                // errors.push(e);
318
                if (throwErrors) {
319
                    throw e;
320
                }
321
            }
322
        } else {
323
            try {
324
                ret = s.fn.call(scope, this.type, args, s.obj);
325
            } catch(ex) {
326
                this.lastError = ex;
327
                if (throwErrors) {
328
                    throw ex;
329
                }
330
            }
276 331
        }
277 332

  
278
        return true;
333
        return ret;
279 334
    },
280 335

  
281 336
    /**
......
284 339
     * @return {int} The number of listeners unsubscribed
285 340
     */
286 341
    unsubscribeAll: function() {
287
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
288
            this._delete(len - 1 - i);
342
        var l = this.subscribers.length, i;
343
        for (i=l-1; i>-1; i--) {
344
            this._delete(i);
289 345
        }
290 346

  
291 347
        this.subscribers=[];
292 348

  
293
        return i;
349
        return l;
294 350
    },
295 351

  
296 352
    /**
......
304 360
            delete s.obj;
305 361
        }
306 362

  
307
        this.subscribers[index]=null;
363
        // this.subscribers[index]=null;
364
        this.subscribers.splice(index, 1);
308 365
    },
309 366

  
310 367
    /**
......
312 369
     */
313 370
    toString: function() {
314 371
         return "CustomEvent: " + "'" + this.type  + "', " + 
315
             "scope: " + this.scope;
372
             "context: " + this.scope;
316 373

  
317 374
    }
318 375
};
......
323 380
 * Stores the subscriber information to be used when the event fires.
324 381
 * @param {Function} fn       The function to execute
325 382
 * @param {Object}   obj      An object to be passed along when the event fires
326
 * @param {boolean}  override If true, the obj passed in becomes the execution
327
 *                            scope of the listener
383
 * @param {boolean}  overrideContext If true, the obj passed in becomes the execution
384
 *                            context of the listener
328 385
 * @class Subscriber
329 386
 * @constructor
330 387
 */
331
YAHOO.util.Subscriber = function(fn, obj, override) {
388
YAHOO.util.Subscriber = function(fn, obj, overrideContext) {
332 389

  
333 390
    /**
334 391
     * The callback that will be execute when the event fires
......
346 403
    this.obj = YAHOO.lang.isUndefined(obj) ? null : obj;
347 404

  
348 405
    /**
349
     * The default execution scope for the event listener is defined when the
406
     * The default execution context for the event listener is defined when the
350 407
     * event is created (usually the object which contains the event).
351
     * By setting override to true, the execution scope becomes the custom
352
     * object passed in by the subscriber.  If override is an object, that 
353
     * object becomes the scope.
354
     * @property override
408
     * By setting overrideContext to true, the execution context becomes the custom
409
     * object passed in by the subscriber.  If overrideContext is an object, that 
410
     * object becomes the context.
411
     * @property overrideContext
355 412
     * @type boolean|object
356 413
     */
357
    this.override = override;
414
    this.overrideContext = overrideContext;
358 415

  
359 416
};
360 417

  
361 418
/**
362
 * Returns the execution scope for this listener.  If override was set to true
363
 * the custom obj will be the scope.  If override is an object, that is the
364
 * scope, otherwise the default scope will be used.
419
 * Returns the execution context for this listener.  If overrideContext was set to true
420
 * the custom obj will be the context.  If overrideContext is an object, that is the
421
 * context, otherwise the default context will be used.
365 422
 * @method getScope
366
 * @param {Object} defaultScope the scope to use if this listener does not
423
 * @param {Object} defaultScope the context to use if this listener does not
367 424
 *                              override it.
368 425
 */
369 426
YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
370
    if (this.override) {
371
        if (this.override === true) {
427
    if (this.overrideContext) {
428
        if (this.overrideContext === true) {
372 429
            return this.obj;
373 430
        } else {
374
            return this.override;
431
            return this.overrideContext;
375 432
        }
376 433
    }
377 434
    return defaultScope;
......
400 457
 */
401 458
YAHOO.util.Subscriber.prototype.toString = function() {
402 459
    return "Subscriber { obj: " + this.obj  + 
403
           ", override: " +  (this.override || "no") + " }";
460
           ", overrideContext: " +  (this.overrideContext || "no") + " }";
404 461
};
405 462

  
406 463
/**
......
436 493
         * @static
437 494
         * @private
438 495
         */
439
        var loadComplete =  false;
496
        var loadComplete =  false,
440 497

  
441 498
        /**
442 499
         * Cache of wrapped listeners
......
445 502
         * @static
446 503
         * @private
447 504
         */
448
        var listeners = [];
505
        listeners = [],
449 506

  
507

  
450 508
        /**
451 509
         * User-defined unload function that will be fired before all events
452 510
         * are detached
......
455 513
         * @static
456 514
         * @private
457 515
         */
458
        var unloadListeners = [];
516
        unloadListeners = [],
459 517

  
460 518
        /**
461
         * Cache of DOM0 event handlers to work around issues with DOM2 events
462
         * in Safari
463
         * @property legacyEvents
464
         * @static
465
         * @private
466
         */
467
        var legacyEvents = [];
468

  
469
        /**
470
         * Listener stack for DOM0 events
471
         * @property legacyHandlers
472
         * @static
473
         * @private
474
         */
475
        var legacyHandlers = [];
476

  
477
        /**
478 519
         * The number of times to poll after window.onload.  This number is
479 520
         * increased if additional late-bound handlers are requested after
480 521
         * the page load.
......
482 523
         * @static
483 524
         * @private
484 525
         */
485
        var retryCount = 0;
526
        retryCount = 0,
486 527

  
487 528
        /**
488 529
         * onAvailable listeners
......
490 531
         * @static
491 532
         * @private
492 533
         */
493
        var onAvailStack = [];
534
        onAvailStack = [],
494 535

  
495 536
        /**
496
         * Lookup table for legacy events
497
         * @property legacyMap
498
         * @static
499
         * @private
500
         */
501
        var legacyMap = [];
502

  
503
        /**
504 537
         * Counter for auto id generation
505 538
         * @property counter
506 539
         * @static
507 540
         * @private
508 541
         */
509
        var counter = 0;
542
        counter = 0,
510 543
        
511 544
        /**
512 545
         * Normalized keycodes for webkit/safari
......
516 549
         * @static
517 550
         * @final
518 551
         */
519
        var webkitKeymap = {
552
         webkitKeymap = {
520 553
            63232: 38, // up
521 554
            63233: 40, // down
522 555
            63234: 37, // left
......
525 558
            63277: 34, // page down
526 559
            25: 9      // SHIFT-TAB (Safari provides a different key code in
527 560
                       // this case, even though the shiftKey modifier is set)
528
        };
561
        },
529 562

  
563
		isIE = YAHOO.env.ua.ie,
564

  
565
        // String constants used by the addFocusListener and removeFocusListener methods
566
		
567
       	FOCUSIN = "focusin",
568
       	FOCUSOUT = "focusout";
569

  
530 570
        return {
531 571

  
532 572
            /**
533 573
             * The number of times we should look for elements that are not
534 574
             * in the DOM at the time the event is requested after the document
535
             * has been loaded.  The default is 4000@amp;10 ms, so it will poll
536
             * for 40 seconds or until all outstanding handlers are bound
575
             * has been loaded.  The default is 500@amp;40 ms, so it will poll
576
             * for 20 seconds or until all outstanding handlers are bound
537 577
             * (whichever comes first).
538 578
             * @property POLL_RETRYS
539 579
             * @type int
540 580
             * @static
541 581
             * @final
542 582
             */
543
            POLL_RETRYS: 4000,
583
            POLL_RETRYS: 500,
544 584

  
545 585
            /**
546 586
             * The poll interval in milliseconds
......
549 589
             * @static
550 590
             * @final
551 591
             */
552
            POLL_INTERVAL: 10,
592
            POLL_INTERVAL: 40,
553 593

  
554 594
            /**
555 595
             * Element to bind, int constant
......
579 619
            FN: 2,
580 620

  
581 621
            /**
582
             * Function wrapped for scope correction and cleanup, int constant
622
             * Function wrapped for context correction and cleanup, int constant
583 623
             * @property WFN
584 624
             * @type int
585 625
             * @static
......
599 639
            UNLOAD_OBJ: 3,
600 640

  
601 641
            /**
602
             * Adjusted scope, either the element we are registering the event
642
             * Adjusted context, either the element we are registering the event
603 643
             * on or the custom object passed in by the listener, int constant
604 644
             * @property ADJ_SCOPE
605 645
             * @type int
......
618 658
            OBJ: 5,
619 659

  
620 660
            /**
621
             * The original scope parameter passed into addListener
661
             * The original context parameter passed into addListener
622 662
             * @property OVERRIDE
623 663
             * @type int
624 664
             * @static
......
627 667
            OVERRIDE: 6,
628 668

  
629 669
            /**
670
             * The original capture parameter passed into addListener
671
             * @property CAPTURE
672
             * @type int
673
             * @static
674
             * @final
675
             */
676
			CAPTURE: 7,
677

  
678
            /**
630 679
             * addListener/removeListener can throw errors in unexpected scenarios.
631 680
             * These errors are suppressed, the method returns false, and this property
632 681
             * is set
......
662 711
             * @static
663 712
             * @deprecated use YAHOO.env.ua.ie
664 713
             */
665
            isIE: YAHOO.env.ua.ie,
714
            isIE: isIE,
666 715

  
667 716
            /**
668 717
             * poll handle
......
680 729
             */
681 730
             _dri: null,
682 731

  
732

  
683 733
            /**
734
             * Map of special event types
735
             * @property _specialTypes
736
             * @static
737
             * @private
738
             */
739
			_specialTypes: {
740
				focusin: (isIE ? "focusin" : "focus"),
741
				focusout: (isIE ? "focusout" : "blur")
742
			},
743

  
744

  
745
            /**
684 746
             * True when the document is initially usable
685 747
             * @property DOMReady
686 748
             * @type boolean
......
689 751
            DOMReady: false,
690 752

  
691 753
            /**
754
             * Errors thrown by subscribers of custom events are caught
755
             * and the error message is written to the debug console.  If
756
             * this property is set to true, it will also re-throw the
757
             * error.
758
             * @property throwErrors
759
             * @type boolean
760
             * @default false
761
             */
762
            throwErrors: false,
763

  
764

  
765
            /**
692 766
             * @method startInterval
693 767
             * @static
694 768
             * @private
695 769
             */
696 770
            startInterval: function() {
697 771
                if (!this._interval) {
698
                    var self = this;
699
                    var callback = function() { self._tryPreloadAttach(); };
700
                    this._interval = setInterval(callback, this.POLL_INTERVAL);
772
                    // var self = this;
773
                    // var callback = function() { self._tryPreloadAttach(); };
774
                    // this._interval = setInterval(callback, this.POLL_INTERVAL);
775
                    this._interval = YAHOO.lang.later(this.POLL_INTERVAL, this, this._tryPreloadAttach, null, true);
701 776
                }
702 777
            },
703 778

  
......
714 789
             *
715 790
             * @method onAvailable
716 791
             *
717
             * @param {string||string[]}   p_id the id of the element, or an array
792
             * @param {string||string[]}   id the id of the element, or an array
718 793
             * of ids to look for.
719
             * @param {function} p_fn what to execute when the element is found.
720
             * @param {object}   p_obj an optional object to be passed back as
721
             *                   a parameter to p_fn.
722
             * @param {boolean|object}  p_override If set to true, p_fn will execute
723
             *                   in the scope of p_obj, if set to an object it
724
             *                   will execute in the scope of that object
794
             * @param {function} fn what to execute when the element is found.
795
             * @param {object}   obj an optional object to be passed back as
796
             *                   a parameter to fn.
797
             * @param {boolean|object}  overrideContext If set to true, fn will execute
798
             *                   in the context of obj, if set to an object it
799
             *                   will execute in the context of that object
725 800
             * @param checkContent {boolean} check child node readiness (onContentReady)
726 801
             * @static
727 802
             */
728
            onAvailable: function(p_id, p_fn, p_obj, p_override, checkContent) {
803
            onAvailable: function(id, fn, obj, overrideContext, checkContent) {
729 804

  
730
                var a = (YAHOO.lang.isString(p_id)) ? [p_id] : p_id;
805
                var a = (YAHOO.lang.isString(id)) ? [id] : id;
731 806

  
732 807
                for (var i=0; i<a.length; i=i+1) {
733 808
                    onAvailStack.push({id:         a[i], 
734
                                       fn:         p_fn, 
735
                                       obj:        p_obj, 
736
                                       override:   p_override, 
809
                                       fn:         fn, 
810
                                       obj:        obj, 
811
                                       overrideContext:   overrideContext, 
737 812
                                       checkReady: checkContent });
738 813
                }
814

  
739 815
                retryCount = this.POLL_RETRYS;
816

  
740 817
                this.startInterval();
741 818
            },
742 819

  
......
750 827
             *
751 828
             * @method onContentReady
752 829
             *
753
             * @param {string}   p_id the id of the element to look for.
754
             * @param {function} p_fn what to execute when the element is ready.
755
             * @param {object}   p_obj an optional object to be passed back as
756
             *                   a parameter to p_fn.
757
             * @param {boolean|object}  p_override If set to true, p_fn will execute
758
             *                   in the scope of p_obj.  If an object, p_fn will
759
             *                   exectute in the scope of that object
830
             * @param {string}   id the id of the element to look for.
831
             * @param {function} fn what to execute when the element is ready.
832
             * @param {object}   obj an optional object to be passed back as
833
             *                   a parameter to fn.
834
             * @param {boolean|object}  overrideContext If set to true, fn will execute
835
             *                   in the context of obj.  If an object, fn will
836
             *                   exectute in the context of that object
760 837
             *
761 838
             * @static
762 839
             */
763
            onContentReady: function(p_id, p_fn, p_obj, p_override) {
764
                this.onAvailable(p_id, p_fn, p_obj, p_override, true);
840
            onContentReady: function(id, fn, obj, overrideContext) {
841
                this.onAvailable(id, fn, obj, overrideContext, true);
765 842
            },
766 843

  
767 844
            /**
......
787 864
             *
788 865
             * @method onDOMReady
789 866
             *
790
             * @param {function} p_fn what to execute when the element is found.
791
             * @param {object}   p_obj an optional object to be passed back as
792
             *                   a parameter to p_fn.
793
             * @param {boolean|object}  p_scope If set to true, p_fn will execute
794
             *                   in the scope of p_obj, if set to an object it
795
             *                   will execute in the scope of that object
867
             * @param {function} fn what to execute when the element is found.
868
             * @param {object}   obj an optional object to be passed back as
869
             *                   a parameter to fn.
870
             * @param {boolean|object}  overrideContext If set to true, fn will execute
871
             *                   in the context of obj, if set to an object it
872
             *                   will execute in the context of that object
796 873
             *
797 874
             * @static
798 875
             */
799
            onDOMReady: function(p_fn, p_obj, p_override) {
800
                if (this.DOMReady) {
801
                    setTimeout(function() {
802
                        var s = window;
803
                        if (p_override) {
804
                            if (p_override === true) {
805
                                s = p_obj;
806
                            } else {
807
                                s = p_override;
808
                            }
809
                        }
810
                        p_fn.call(s, "DOMReady", [], p_obj);
811
                    }, 0);
812
                } else {
813
                    this.DOMReadyEvent.subscribe(p_fn, p_obj, p_override);
814
                }
876
            // onDOMReady: function(fn, obj, overrideContext) {
877
            onDOMReady: function() {
878
                this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent, arguments);
815 879
            },
816 880

  
881

  
817 882
            /**
818 883
             * Appends an event handler
819 884
             *
820
             * @method addListener
885
             * @method _addListener
821 886
             *
822 887
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
823 888
             *  reference, or a collection of ids and/or elements to assign the 
......
826 891
             * @param {Function} fn        The method the event invokes
827 892
             * @param {Object}   obj    An arbitrary object that will be 
828 893
             *                             passed as a parameter to the handler
829
             * @param {Boolean|object}  override  If true, the obj passed in becomes
830
             *                             the execution scope of the listener. If an
894
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
895
             *                             the execution context of the listener. If an
831 896
             *                             object, this object becomes the execution
832
             *                             scope.
897
             *                             context.
898
             * @param {boolen}      capture capture or bubble phase
833 899
             * @return {Boolean} True if the action was successful or defered,
834 900
             *                        false if one or more of the elements 
835 901
             *                        could not have the listener attached,
836 902
             *                        or if the operation throws an exception.
903
             * @private
837 904
             * @static
838 905
             */
839
            addListener: function(el, sType, fn, obj, override) {
906
            _addListener: function(el, sType, fn, obj, overrideContext, bCapture) {
840 907

  
841 908
                if (!fn || !fn.call) {
842
// throw new TypeError(sType + " addListener call failed, callback undefined");
843 909
                    return false;
844 910
                }
845 911

  
......
851 917
                                       sType, 
852 918
                                       fn, 
853 919
                                       obj, 
854
                                       override) && ok;
920
                                       overrideContext) && ok;
855 921
                    }
856 922
                    return ok;
857 923

  
......
869 935
                    } else {
870 936
                        // defer adding the event until the element is available
871 937
                        this.onAvailable(el, function() {
872
                           YAHOO.util.Event.on(el, sType, fn, obj, override);
938
                           YAHOO.util.Event._addListener(el, sType, fn, obj, overrideContext, bCapture);
873 939
                        });
874 940

  
875 941
                        return true;
......
888 954
                // handles explicitly during our one unload event.
889 955
                if ("unload" == sType && obj !== this) {
890 956
                    unloadListeners[unloadListeners.length] =
891
                            [el, sType, fn, obj, override];
957
                            [el, sType, fn, obj, overrideContext];
892 958
                    return true;
893 959
                }
894 960

  
895 961

  
896
                // if the user chooses to override the scope, we use the custom
897
                // object passed in, otherwise the executing scope will be the
962
                // if the user chooses to override the context, we use the custom
963
                // object passed in, otherwise the executing context will be the
898 964
                // HTML element that the event is registered on
899
                var scope = el;
900
                if (override) {
901
                    if (override === true) {
902
                        scope = obj;
965
                var context = el;
966
                if (overrideContext) {
967
                    if (overrideContext === true) {
968
                        context = obj;
903 969
                    } else {
904
                        scope = override;
970
                        context = overrideContext;
905 971
                    }
906 972
                }
907 973

  
908 974
                // wrap the function so we can return the obj object when
909 975
                // the event fires;
910 976
                var wrappedFn = function(e) {
911
                        return fn.call(scope, YAHOO.util.Event.getEvent(e, el), 
977
                        return fn.call(context, YAHOO.util.Event.getEvent(e, el), 
912 978
                                obj);
913 979
                    };
914 980

  
915
                var li = [el, sType, fn, wrappedFn, scope, obj, override];
981
                var li = [el, sType, fn, wrappedFn, context, obj, overrideContext, bCapture];
916 982
                var index = listeners.length;
917 983
                // cache the listener so we can try to automatically unload
918 984
                listeners[index] = li;
919 985

  
920
                if (this.useLegacyEvent(el, sType)) {
921
                    var legacyIndex = this.getLegacyIndex(el, sType);
986
                try {
987
                    this._simpleAdd(el, sType, wrappedFn, bCapture);
988
                } catch(ex) {
989
                    // handle an error trying to attach an event.  If it fails
990
                    // we need to clean up the cache
991
                    this.lastError = ex;
992
                    this.removeListener(el, sType, fn);
993
                    return false;
994
                }
922 995

  
923
                    // Add a new dom0 wrapper if one is not detected for this
924
                    // element
925
                    if ( legacyIndex == -1 || 
926
                                el != legacyEvents[legacyIndex][0] ) {
996
                return true;
997
                
998
            },
927 999

  
928
                        legacyIndex = legacyEvents.length;
929
                        legacyMap[el.id + sType] = legacyIndex;
1000
            /**
1001
             * Checks to see if the type requested is a special type 
1002
			 * (as defined by the _specialTypes hash), and (if so) returns 
1003
			 * the special type name.
1004
             *
1005
             * @method _getType
1006
             *
1007
             * @param {String}   sType     The type to look up
1008
             * @private
1009
             */
1010
			_getType: function (type) {
1011
			
1012
				return this._specialTypes[type] || type;
1013
				
1014
			},
930 1015

  
931
                        // cache the signature for the DOM0 event, and 
932
                        // include the existing handler for the event, if any
933
                        legacyEvents[legacyIndex] = 
934
                            [el, sType, el["on" + sType]];
935
                        legacyHandlers[legacyIndex] = [];
936 1016

  
937
                        el["on" + sType] = 
938
                            function(e) {
939
                                YAHOO.util.Event.fireLegacyEvent(
940
                                    YAHOO.util.Event.getEvent(e), legacyIndex);
941
                            };
942
                    }
1017
            /**
1018
             * Appends an event handler
1019
             *
1020
             * @method addListener
1021
             *
1022
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1023
             *  reference, or a collection of ids and/or elements to assign the 
1024
             *  listener to.
1025
             * @param {String}   sType     The type of event to append
1026
             * @param {Function} fn        The method the event invokes
1027
             * @param {Object}   obj    An arbitrary object that will be 
1028
             *                             passed as a parameter to the handler
1029
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1030
             *                             the execution context of the listener. If an
1031
             *                             object, this object becomes the execution
1032
             *                             context.
1033
             * @return {Boolean} True if the action was successful or defered,
1034
             *                        false if one or more of the elements 
1035
             *                        could not have the listener attached,
1036
             *                        or if the operation throws an exception.
1037
             * @static
1038
             */
1039
            addListener: function (el, sType, fn, obj, overrideContext) {
943 1040

  
944
                    // add a reference to the wrapped listener to our custom
945
                    // stack of events
946
                    //legacyHandlers[legacyIndex].push(index);
947
                    legacyHandlers[legacyIndex].push(li);
1041
				var capture = ((sType == FOCUSIN || sType == FOCUSOUT) && !YAHOO.env.ua.ie) ? true : false;
948 1042

  
949
                } else {
950
                    try {
951
                        this._simpleAdd(el, sType, wrappedFn, false);
952
                    } catch(ex) {
953
                        // handle an error trying to attach an event.  If it fails
954
                        // we need to clean up the cache
955
                        this.lastError = ex;
956
                        this.removeListener(el, sType, fn);
957
                        return false;
958
                    }
959
                }
1043
                return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
960 1044

  
961
                return true;
962
                
963
            },
1045
        	},
964 1046

  
1047

  
965 1048
            /**
966
             * When using legacy events, the handler is routed to this object
967
             * so we can fire our custom listener stack.
968
             * @method fireLegacyEvent
1049
             * Attaches a focusin event listener to the specified element for 
1050
 			 * the purpose of listening for the focus event on the element's 
1051
             * descendants.
1052
             * @method addFocusListener
1053
             *
1054
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1055
             *  reference, or a collection of ids and/or elements to assign the 
1056
             *  listener to.
1057
             * @param {Function} fn        The method the event invokes
1058
             * @param {Object}   obj    An arbitrary object that will be 
1059
             *                             passed as a parameter to the handler
1060
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1061
             *                             the execution context of the listener. If an
1062
             *                             object, this object becomes the execution
1063
             *                             context.
1064
             * @return {Boolean} True if the action was successful or defered,
1065
             *                        false if one or more of the elements 
1066
             *                        could not have the listener attached,
1067
             *                        or if the operation throws an exception.
969 1068
             * @static
970
             * @private
1069
			* @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
971 1070
             */
972
            fireLegacyEvent: function(e, legacyIndex) {
973
                var ok=true,le,lh,li,scope,ret;
974
                
975
                lh = legacyHandlers[legacyIndex];
976
                for (var i=0,len=lh.length; i<len; ++i) {
977
                    li = lh[i];
978
                    if ( li && li[this.WFN] ) {
979
                        scope = li[this.ADJ_SCOPE];
980
                        ret = li[this.WFN].call(scope, e);
981
                        ok = (ok && ret);
982
                    }
983
                }
1071
            addFocusListener: function (el, fn, obj, overrideContext) {
1072
                return this.on(el, FOCUSIN, fn, obj, overrideContext);
1073
            },          
984 1074

  
985
                // Fire the original handler if we replaced one.  We fire this
986
                // after the other events to keep stopPropagation/preventDefault
987
                // that happened in the DOM0 handler from touching our DOM2
988
                // substitute
989
                le = legacyEvents[legacyIndex];
990
                if (le && le[2]) {
991
                    le[2](e);
992
                }
993
                
994
                return ok;
995
            },
996 1075

  
997 1076
            /**
998
             * Returns the legacy event index that matches the supplied 
999
             * signature
1000
             * @method getLegacyIndex
1077
             * Removes a focusin event listener to the specified element for 
1078
			 * the purpose of listening for the focus event on the element's 
1079
             * descendants.
1080
             *
1081
             * @method removeFocusListener
1082
             *
1083
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1084
             *  reference, or a collection of ids and/or elements to remove
1085
             *  the listener from.
1086
             * @param {Function} fn the method the event invokes.  If fn is
1087
             *  undefined, then all event handlers for the type of event are 
1088
             *  removed.
1089
             * @return {boolean} true if the unbind was successful, false 
1090
             *  otherwise.
1001 1091
             * @static
1002
             * @private
1092
         	 * @deprecated use YAHOO.util.Event.removeListener and specify "focusin" as the event type.
1003 1093
             */
1004
            getLegacyIndex: function(el, sType) {
1005
                var key = this.generateId(el) + sType;
1006
                if (typeof legacyMap[key] == "undefined") { 
1007
                    return -1;
1008
                } else {
1009
                    return legacyMap[key];
1010
                }
1094
            removeFocusListener: function (el, fn) { 
1095
                return this.removeListener(el, FOCUSIN, fn);
1011 1096
            },
1012 1097

  
1013 1098
            /**
1014
             * Logic that determines when we should automatically use legacy
1015
             * events instead of DOM2 events.  Currently this is limited to old
1016
             * Safari browsers with a broken preventDefault
1017
             * @method useLegacyEvent
1099
             * Attaches a focusout event listener to the specified element for 
1100
			 * the purpose of listening for the blur event on the element's 
1101
			 * descendants.
1102
             *
1103
             * @method addBlurListener
1104
             *
1105
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1106
             *  reference, or a collection of ids and/or elements to assign the 
1107
             *  listener to.
1108
             * @param {Function} fn        The method the event invokes
1109
             * @param {Object}   obj    An arbitrary object that will be 
1110
             *                             passed as a parameter to the handler
1111
             * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1112
             *                             the execution context of the listener. If an
1113
             *                             object, this object becomes the execution
1114
             *                             context.
1115
             * @return {Boolean} True if the action was successful or defered,
1116
             *                        false if one or more of the elements 
1117
             *                        could not have the listener attached,
1118
             *                        or if the operation throws an exception.
1018 1119
             * @static
1019
             * @private
1120
         	 * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
1020 1121
             */
1021
            useLegacyEvent: function(el, sType) {
1022
                if (this.webkit && ("click"==sType || "dblclick"==sType)) {
1023
                    var v = parseInt(this.webkit, 10);
1024
                    if (!isNaN(v) && v<418) {
1025
                        return true;
1026
                    }
1027
                }
1028
                return false;
1122
            addBlurListener: function (el, fn, obj, overrideContext) {
1123
                return this.on(el, FOCUSOUT, fn, obj, overrideContext);
1124
            },          
1125

  
1126
            /**
1127
             * Removes a focusout event listener to the specified element for 
1128
			 * the purpose of listening for the blur event on the element's 
1129
			 * descendants.
1130
             *
1131
             * @method removeBlurListener
1132
             *
1133
             * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1134
             *  reference, or a collection of ids and/or elements to remove
1135
             *  the listener from.
1136
             * @param {Function} fn the method the event invokes.  If fn is
1137
             *  undefined, then all event handlers for the type of event are 
1138
             *  removed.
1139
             * @return {boolean} true if the unbind was successful, false 
1140
             *  otherwise.
1141
             * @static
1142
         	 * @deprecated use YAHOO.util.Event.removeListener and specify "focusout" as the event type.
1143
             */
1144
            removeBlurListener: function (el, fn) { 
1145
                return this.removeListener(el, FOCUSOUT, fn);
1029 1146
            },
1030
                    
1147

  
1031 1148
            /**
1032 1149
             * Removes an event listener
1033 1150
             *
......
1047 1164
            removeListener: function(el, sType, fn) {
1048 1165
                var i, len, li;
1049 1166

  
1167
				sType = this._getType(sType);
1168

  
1050 1169
                // The el argument can be a string
1051 1170
                if (typeof el == "string") {
1052 1171
                    el = this.getEl(el);
1053 1172
                // The el argument can be an array of elements or element ids.
1054 1173
                } else if ( this._isValidCollection(el)) {
1055 1174
                    var ok = true;
1056
                    for (i=0,len=el.length; i<len; ++i) {
1175
                    for (i=el.length-1; i>-1; i--) {
1057 1176
                        ok = ( this.removeListener(el[i], sType, fn) && ok );
1058 1177
                    }
1059 1178
                    return ok;
......
1066 1185

  
1067 1186
                if ("unload" == sType) {
1068 1187

  
1069
                    for (i=0, len=unloadListeners.length; i<len; i++) {
1188
                    for (i=unloadListeners.length-1; i>-1; i--) {
1070 1189
                        li = unloadListeners[i];
1071 1190
                        if (li && 
1072 1191
                            li[0] == el && 
1073 1192
                            li[1] == sType && 
1074 1193
                            li[2] == fn) {
1075
                                //unloadListeners.splice(i, 1);
1076
                                unloadListeners[i]=null;
1194
                                unloadListeners.splice(i, 1);
1195
                                // unloadListeners[i]=null;
1077 1196
                                return true;
1078 1197
                        }
1079 1198
                    }
......
1089 1208
                var index = arguments[3];
1090 1209
  
1091 1210
                if ("undefined" === typeof index) {
1092
                    index = this._getCacheIndex(el, sType, fn);
1211
                    index = this._getCacheIndex(listeners, el, sType, fn);
1093 1212
                }
1094 1213

  
1095 1214
                if (index >= 0) {
......
1101 1220
                }
1102 1221

  
1103 1222

  
1104
                if (this.useLegacyEvent(el, sType)) {
1105
                    var legacyIndex = this.getLegacyIndex(el, sType);
1106
                    var llist = legacyHandlers[legacyIndex];
1107
                    if (llist) {
1108
                        for (i=0, len=llist.length; i<len; ++i) {
1109
                            li = llist[i];
1110
                            if (li && 
1111
                                li[this.EL] == el && 
1112
                                li[this.TYPE] == sType && 
1113
                                li[this.FN] == fn) {
1114
                                    //llist.splice(i, 1);
1115
                                    llist[i]=null;
1116
                                    break;
1117
                            }
1118
                        }
1119
                    }
1223
				var bCapture = cacheItem[this.CAPTURE] === true ? true : false;
1120 1224

  
1121
                } else {
1122
                    try {
1123
                        this._simpleRemove(el, sType, cacheItem[this.WFN], false);
1124
                    } catch(ex) {
1125
                        this.lastError = ex;
1126
                        return false;
1127
                    }
1225
                try {
1226
                    this._simpleRemove(el, sType, cacheItem[this.WFN], bCapture);
1227
                } catch(ex) {
1228
                    this.lastError = ex;
1229
                    return false;
1128 1230
                }
1129 1231

  
1130 1232
                // removed the wrapped handler
1131 1233
                delete listeners[index][this.WFN];
1132 1234
                delete listeners[index][this.FN];
1133
                //listeners.splice(index, 1);
1134
                listeners[index]=null;
1235
                listeners.splice(index, 1);
1236
                // listeners[index]=null;
1135 1237

  
1136 1238
                return true;
1137 1239

  
......
1164 1266
             * @return {HTMLElement} the normized node
1165 1267
             * @static
1166 1268
             */
1167
            resolveTextNode: function(node) {
1168
                if (node && 3 == node.nodeType) {
1169
                    return node.parentNode;
1170
                } else {
1171
                    return node;
1172
                }
1269
            resolveTextNode: function(n) {
1270
                try {
1271
                    if (n && 3 == n.nodeType) {
1272
                        return n.parentNode;
1273
                    }
1274
                } catch(e) { }
1275

  
1276
                return n;
1173 1277
            },
1174 1278

  
1175 1279
            /**
......
1331 1435
                    }
1332 1436
                }
1333 1437

  
1334
                // IE events that target non-browser objects (e.g., VML
1335
                // canvas) will sometimes throw errors when you try to
1336
                // inspect the properties of the event target.  We try to
1337
                // detect this condition, and provide a dummy target (the bound
1338
                // element) to eliminate spurious errors.  
1339

  
1340
                // the implementation caused unexpected results in some 
1341
                // implementations, so this has been rolled back for now
1342
                /* 
1343
                if (ev && this.isIE) {
1344

  
1345
                    try {
1346

  
1347
                        var el = ev.srcElement;
1348

  
1349
                    } catch(ex) {
1350

  
1351
                         
1352
                        ev.target = boundEl;
1353
                    }
1354

  
1355
                }
1356
                */
1357

  
1358 1438
                return ev;
1359 1439
            },
1360 1440

  
......
1368 1448
            getCharCode: function(ev) {
1369 1449
                var code = ev.keyCode || ev.charCode || 0;
1370 1450

  
1371
                // webkit normalization
1451
                // webkit key normalization
1372 1452
                if (YAHOO.env.ua.webkit && (code in webkitKeymap)) {
1373 1453
                    code = webkitKeymap[code];
1374 1454
                }
......
1382 1462
             * @static
1383 1463
             * @private
1384 1464
             */
1385
            _getCacheIndex: function(el, sType, fn) {
1386
                for (var i=0,len=listeners.length; i<len; ++i) {
1387
                    var li = listeners[i];
1465
            _getCacheIndex: function(a, el, sType, fn) {
1466
                for (var i=0, l=a.length; i<l; i=i+1) {
1467
                    var li = a[i];
1388 1468
                    if ( li                 && 
1389 1469
                         li[this.FN] == fn  && 
1390 1470
                         li[this.EL] == el  && 
......
1478 1558
             * Custom event the fires when the dom is initially usable
1479 1559
             * @event DOMReadyEvent
1480 1560
             */
1481
            DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", this),
1561
            DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", YAHOO, 0, 0, 1),
1482 1562

  
1483 1563
            /**
1484 1564
             * hook up any deferred listeners
......
1501 1581
                    // before the window load notification
1502 1582
                    EU._tryPreloadAttach();
1503 1583

  
1504
                    // Remove the listener to assist with the IE memory issue, but not
1505
                    // for other browsers because FF 1.0x does not like it.
1506
                    //if (this.isIE) {
1507
                        //EU._simpleRemove(window, "load", EU._load);
1508
                    //}
1509 1584
                }
1510 1585
            },
1511 1586

  
......
1539 1614
             */
1540 1615
            _tryPreloadAttach: function() {
1541 1616

  
1617
                if (onAvailStack.length === 0) {
1618
                    retryCount = 0;
1619
                    if (this._interval) {
1620
                        // clearInterval(this._interval);
1621
                        this._interval.cancel();
1622
                        this._interval = null;
1623
                    } 
1624
                    return;
1625
                }
1626

  
1542 1627
                if (this.locked) {
1543
                    return false;
1628
                    return;
1544 1629
                }
1545 1630

  
1546 1631
                if (this.isIE) {
1547 1632
                    // Hold off if DOMReady has not fired and check current
1548 1633
                    // readyState to protect against the IE operation aborted
1549 1634
                    // issue.
1550
                    //if (!this.DOMReady || "complete" !== document.readyState) {
1551 1635
                    if (!this.DOMReady) {
1552 1636
                        this.startInterval();
1553
                        return false;
1637
                        return;
1554 1638
                    }
1555 1639
                }
1556 1640

  
......
1563 1647
                // tested appropriately
1564 1648
                var tryAgain = !loadComplete;
1565 1649
                if (!tryAgain) {
1566
                    tryAgain = (retryCount > 0);
1650
                    tryAgain = (retryCount > 0 && onAvailStack.length > 0);
1567 1651
                }
1568 1652

  
1569 1653
                // onAvailable
1570 1654
                var notAvail = [];
1571 1655

  
1572 1656
                var executeItem = function (el, item) {
1573
                    var scope = el;
1574
                    if (item.override) {
1575
                        if (item.override === true) {
1576
                            scope = item.obj;
1657
                    var context = el;
1658
                    if (item.overrideContext) {
1659
                        if (item.overrideContext === true) {
1660
                            context = item.obj;
1577 1661
                        } else {
1578
                            scope = item.override;
1662
                            context = item.overrideContext;
1579 1663
                        }
1580 1664
                    }
1581
                    item.fn.call(scope, item.obj);
1665
                    item.fn.call(context, item.obj);
1582 1666
                };
1583 1667

  
1584
                var i,len,item,el;
1668
                var i, len, item, el, ready=[];
1585 1669

  
1586
                // onAvailable
1587
                for (i=0,len=onAvailStack.length; i<len; ++i) {
1670
                // onAvailable onContentReady
1671
                for (i=0, len=onAvailStack.length; i<len; i=i+1) {
1588 1672
                    item = onAvailStack[i];
1589
                    if (item && !item.checkReady) {
1673
                    if (item) {
1590 1674
                        el = this.getEl(item.id);
1591 1675
                        if (el) {
1592
                            executeItem(el, item);
1593
                            onAvailStack[i] = null;
1594
                        } else {
1595
                            notAvail.push(item);
1596
                        }
1597
                    }
1598
                }
1599

  
1600
                // onContentReady
1601
                for (i=0,len=onAvailStack.length; i<len; ++i) {
1602
                    item = onAvailStack[i];
1603
                    if (item && item.checkReady) {
1604
                        el = this.getEl(item.id);
1605

  
1606
                        if (el) {
1607
                            // The element is available, but not necessarily ready
1608
                            // @todo should we test parentNode.nextSibling?
1609
                            if (loadComplete || el.nextSibling) {
1676
                            if (item.checkReady) {
1677
                                if (loadComplete || el.nextSibling || !tryAgain) {
1678
                                    ready.push(item);
1679
                                    onAvailStack[i] = null;
1680
                                }
1681
                            } else {
1610 1682
                                executeItem(el, item);
1611 1683
                                onAvailStack[i] = null;
1612 1684
                            }
......
1615 1687
                        }
1616 1688
                    }
1617 1689
                }
1690
                
1691
                // make sure onContentReady fires after onAvailable
1692
                for (i=0, len=ready.length; i<len; i=i+1) {
1693
                    item = ready[i];
1694
                    executeItem(this.getEl(item.id), item);
1695
                }
1618 1696

  
1619
                retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
1620 1697

  
1698
                retryCount--;
1699

  
1621 1700
                if (tryAgain) {
1622
                    // we may need to strip the nulled out items here
1701
                    for (i=onAvailStack.length-1; i>-1; i--) {
1702
                        item = onAvailStack[i];
1703
                        if (!item || !item.id) {
1704
                            onAvailStack.splice(i, 1);
1705
                        }
1706
                    }
1707

  
1623 1708
                    this.startInterval();
1624 1709
                } else {
1625
                    clearInterval(this._interval);
1626
                    this._interval = null;
1710
                    if (this._interval) {
1711
                        // clearInterval(this._interval);
1712
                        this._interval.cancel();
1713
                        this._interval = null;
1714
                    }
1627 1715
                }
1628 1716

  
1629 1717
                this.locked = false;
1630 1718

  
1631
                return true;
1632

  
1633 1719
            },
1634 1720

  
1635 1721
            /**
......
1648 1734
                var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1649 1735
                var elListeners = this.getListeners(oEl, sType), i, len;
1650 1736
                if (elListeners) {
1651
                    for (i=0,len=elListeners.length; i<len ; ++i) {
1737
                    for (i=elListeners.length-1; i>-1; i--) {
1652 1738
                        var l = elListeners[i];
1653
                        // can't use the index on the changing collection
1654
                        this.removeListener(oEl, l.type, l.fn, l.index);
1655
                        //this.removeListener(oEl, l.type, l.fn);
1739
                        this.removeListener(oEl, l.type, l.fn);
1656 1740
                    }
1657 1741
                }
1658 1742

  
......
1674 1758
             * &nbsp;&nbsp;type:   (string)   the type of event
1675 1759
             * &nbsp;&nbsp;fn:     (function) the callback supplied to addListener
1676 1760
             * &nbsp;&nbsp;obj:    (object)   the custom object supplied to addListener
1677
             * &nbsp;&nbsp;adjust: (boolean|object)  whether or not to adjust the default scope
1678
             * &nbsp;&nbsp;scope: (boolean)  the derived scope based on the adjust parameter
1761
             * &nbsp;&nbsp;adjust: (boolean|object)  whether or not to adjust the default context
1762
             * &nbsp;&nbsp;scope: (boolean)  the derived context based on the adjust parameter
1679 1763
             * &nbsp;&nbsp;index:  (int)      its position in the Event util listener cache
1680 1764
             * @static
1681 1765
             */           
......
1686 1770
                } else if (sType === "unload") {
1687 1771
                    searchLists = [unloadListeners];
1688 1772
                } else {
1773
					sType = this._getType(sType);
1689 1774
                    searchLists = [listeners];
1690 1775
                }
1691 1776

  
......
1693 1778

  
1694 1779
                for (var j=0;j<searchLists.length; j=j+1) {
1695 1780
                    var searchList = searchLists[j];
1696
                    if (searchList && searchList.length > 0) {
1781
                    if (searchList) {
1697 1782
                        for (var i=0,len=searchList.length; i<len ; ++i) {
1698 1783
                            var l = searchList[i];
1699 1784
                            if ( l  && l[this.EL] === oEl && 
......
1723 1808
             */
1724 1809
            _unload: function(e) {
1725 1810

  
1726
                var EU = YAHOO.util.Event, i, j, l, len, index;
1811
                var EU = YAHOO.util.Event, i, j, l, len, index,
1812
                         ul = unloadListeners.slice(), context;
1727 1813

  
1728 1814
                // execute and clear stored unload listeners
1729
                for (i=0,len=unloadListeners.length; i<len; ++i) {
1730
                    l = unloadListeners[i];
1815
                for (i=0, len=unloadListeners.length; i<len; ++i) {
1816
                    l = ul[i];
1731 1817
                    if (l) {
1732
                        var scope = window;
1818
                        context = window;
1733 1819
                        if (l[EU.ADJ_SCOPE]) {
1734 1820
                            if (l[EU.ADJ_SCOPE] === true) {
1735
                                scope = l[EU.UNLOAD_OBJ];
1821
                                context = l[EU.UNLOAD_OBJ];
1736 1822
                            } else {
1737
                                scope = l[EU.ADJ_SCOPE];
1823
                                context = l[EU.ADJ_SCOPE];
1738 1824
                            }
1739 1825
                        }
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff