jquery testrunner: reset global events after each run, speeds up a test run for ajax...
[jquery.git] / src / event.js
index 0cf6c58..8e52081 100644 (file)
@@ -13,7 +13,7 @@ jQuery.event = {
 
                // For whatever reason, IE has trouble passing the window object
                // around, causing it to be cloned in the process
-               if ( jQuery.browser.msie && elem.setInterval != undefined )
+               if ( jQuery.browser.msie && elem.setInterval )
                        elem = window;
 
                // Make sure that the function being executed has a unique ID
@@ -26,10 +26,10 @@ jQuery.event = {
                        var fn = handler; 
 
                        // Create unique handler function, wrapped around original handler 
-                       handler = function() { 
+                       handler = this.proxy( fn, function() { 
                                // Pass arguments and context to original handler 
                                return fn.apply(this, arguments); 
-                       };
+                       });
 
                        // Store data in unique handler 
                        handler.data = data;
@@ -51,39 +51,39 @@ jQuery.event = {
                // event in IE.
                handle.elem = elem;
                        
-                       // Handle multiple events seperated by a space
-                       // jQuery(...).bind("mouseover mouseout", fn);
-                       jQuery.each(types.split(/\s+/), function(index, type) {
-                               // Namespaced event handlers
-                               var parts = type.split(".");
-                               type = parts[0];
-                               handler.type = parts[1];
-
-                               // Get the current list of functions bound to this event
-                               var handlers = events[type];
-
-                               // Init the event handler queue
-                               if (!handlers) {
-                                       handlers = events[type] = {};
-               
-                                       // Check for a special event handler
-                                       // Only use addEventListener/attachEvent if the special
-                                       // events handler returns false
-                                       if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
-                                               // Bind the global event handler to the element
-                                               if (elem.addEventListener)
-                                                       elem.addEventListener(type, handle, false);
-                                               else if (elem.attachEvent)
-                                                       elem.attachEvent("on" + type, handle);
-                                       }
+               // Handle multiple events separated by a space
+               // jQuery(...).bind("mouseover mouseout", fn);
+               jQuery.each(types.split(/\s+/), function(index, type) {
+                       // Namespaced event handlers
+                       var parts = type.split(".");
+                       type = parts[0];
+                       handler.type = parts[1];
+
+                       // Get the current list of functions bound to this event
+                       var handlers = events[type];
+
+                       // Init the event handler queue
+                       if (!handlers) {
+                               handlers = events[type] = {};
+       
+                               // Check for a special event handler
+                               // Only use addEventListener/attachEvent if the special
+                               // events handler returns false
+                               if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+                                       // Bind the global event handler to the element
+                                       if (elem.addEventListener)
+                                               elem.addEventListener(type, handle, false);
+                                       else if (elem.attachEvent)
+                                               elem.attachEvent("on" + type, handle);
                                }
+                       }
 
-                               // Add the function to the element's handler list
-                               handlers[handler.guid] = handler;
+                       // Add the function to the element's handler list
+                       handlers[handler.guid] = handler;
 
-                               // Keep track of which events have been used, for global triggering
-                               jQuery.event.global[type] = true;
-                       });
+                       // Keep track of which events have been used, for global triggering
+                       jQuery.event.global[type] = true;
+               });
                
                // Nullify elem to prevent memory leaks in IE
                elem = null;
@@ -190,7 +190,7 @@ jQuery.event = {
                                        target: elem, 
                                        preventDefault: function(){}, 
                                        stopPropagation: function(){}, 
-                                       timeStamp: +new Date
+                                       timeStamp: now()
                                });
                                data[0][expando] = true; // no need to fix fake event
                        }
@@ -309,7 +309,7 @@ jQuery.event = {
                };
                
                // Fix timeStamp
-               event.timeStamp = event.timeStamp || +new Date;
+               event.timeStamp = event.timeStamp || now();
                
                // Fix target property, if necessary
                if ( !event.target )
@@ -346,6 +346,12 @@ jQuery.event = {
                return event;
        },
        
+       proxy: function( fn, proxy ){
+               // Set the guid of unique handler to the same of original handler, so it can be removed 
+               proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
+               return proxy;//so proxy can be declared as an argument
+       },
+       
        special: {
                ready: {
                        setup: function() {
@@ -374,7 +380,7 @@ jQuery.event = {
                                // If we actually just moused on to a sub-element, ignore it
                                if ( withinElement(event, this) ) return true;
                                // Execute the right handlers by setting the event type to mouseenter
-                               arguments[0].type = "mouseenter";
+                               event.type = "mouseenter";
                                return jQuery.event.handle.apply(this, arguments);
                        }
                },
@@ -396,7 +402,7 @@ jQuery.event = {
                                // If we actually just moused on to a sub-element, ignore it
                                if ( withinElement(event, this) ) return true;
                                // Execute the right handlers by setting the event type to mouseleave
-                               arguments[0].type = "mouseleave";
+                               event.type = "mouseleave";
                                return jQuery.event.handle.apply(this, arguments);
                        }
                }
@@ -411,11 +417,12 @@ jQuery.fn.extend({
        },
        
        one: function( type, data, fn ) {
+               var one = jQuery.event.proxy( fn || data, function(event) {
+                       jQuery(this).unbind(event, one);
+                       return (fn || data).apply( this, arguments );
+               });
                return this.each(function(){
-                       jQuery.event.add( this, type, function(event) {
-                               jQuery(this).unbind(event);
-                               return (fn || data).apply( this, arguments);
-                       }, fn && data);
+                       jQuery.event.add( this, type, one, fn && data);
                });
        },
 
@@ -432,25 +439,27 @@ jQuery.fn.extend({
        },
 
        triggerHandler: function( type, data, fn ) {
-               if ( this[0] )
-                       return jQuery.event.trigger( type, data, this[0], false, fn );
-               return undefined;
+               return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
        },
 
-       toggle: function() {
+       toggle: function( fn ) {
                // Save reference to arguments for access in closure
-               var args = arguments;
+               var args = arguments, i = 1;
+
+               // link all the functions, so any of them can unbind this click handler
+               while( i < args.length )
+                       jQuery.event.proxy( fn, args[i++] );
 
-               return this.click(function(event) {
+               return this.click( jQuery.event.proxy( fn, function(event) {
                        // Figure out which function to execute
-                       this.lastToggle = 0 == this.lastToggle ? 1 : 0;
+                       this.lastToggle = ( this.lastToggle || 0 ) % i;
                        
                        // Make sure that clicks stop
                        event.preventDefault();
                        
                        // and execute the function
-                       return args[this.lastToggle].apply( this, arguments ) || false;
-               });
+                       return args[ this.lastToggle++ ].apply( this, arguments ) || false;
+               }));
        },
 
        hover: function(fnOver, fnOut) {