Make sure non-left-click events don't bubble. Fixes #3861.
[jquery.git] / src / event.js
index 64b202d..5271460 100644 (file)
@@ -26,7 +26,7 @@ jQuery.event = {
 
                // Make sure that the function being executed has a unique ID
                if ( !handler.guid ) {
-                       handler.guid = this.guid++;
+                       handler.guid = jQuery.guid++;
                }
 
                // if data is passed, bind to handler
@@ -35,7 +35,7 @@ jQuery.event = {
                        var fn = handler;
 
                        // Create unique handler function, wrapped around original handler
-                       handler = this.proxy( fn );
+                       handler = jQuery.proxy( fn );
 
                        // Store data in unique handler
                        handler.data = data;
@@ -57,6 +57,12 @@ jQuery.event = {
                        handle = jQuery.data( elem, "handle", eventHandle );
                }
 
+               // If no handle is found then we must be trying to bind to one of the
+               // banned noData elements
+               if ( !handle ) {
+                       return;
+               }
+
                // Add elem as a property of the handle function
                // This is to prevent a memory leak with non-native
                // event in IE.
@@ -114,7 +120,6 @@ jQuery.event = {
                elem = null;
        },
 
-       guid: 1,
        global: {},
 
        // Detach an event or set of events from an element
@@ -405,23 +410,11 @@ jQuery.event = {
                return event;
        },
 
-       proxy: function( fn, proxy, thisObject ) {
-               if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
-                       thisObject = proxy;
-                       proxy = undefined;
-               }
-
-               // FIXME: Should proxy be redefined to be applied with thisObject if defined?
-               proxy = proxy || function() {
-                       return fn.apply( thisObject !== undefined ? thisObject : this, arguments );
-               };
+       // Deprecated, use jQuery.guid instead
+       guid: 1E8,
 
-               // 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++;
-
-               // So proxy can be declared as an argument
-               return proxy;
-       },
+       // Deprecated, use jQuery.proxy instead
+       proxy: jQuery.proxy,
 
        special: {
                ready: {
@@ -435,6 +428,8 @@ jQuery.event = {
                                jQuery.extend( proxy, data || {} );
 
                                proxy.guid += data.selector + data.live; 
+                               data.liveProxy = proxy;
+
                                jQuery.event.add( this, data.live, liveHandler, data ); 
                                
                        },
@@ -617,6 +612,9 @@ jQuery.event.special.submit = {
                                        return trigger( "submit", this, arguments );
                                }
                        });
+
+               } else {
+                       return false;
                }
        },
 
@@ -672,9 +670,9 @@ function testChange( e ) {
                        jQuery.data( elem, "_change_data", val );
                }
 
-               if ( elem.type !== "select" && (data != null || val) ) {
+               if ( data != null || val ) {
                        e.type = "change";
-                       return jQuery.event.trigger( e, arguments[1], this );
+                       return jQuery.event.trigger( e, arguments[1], elem );
                }
 }
 
@@ -759,7 +757,7 @@ if ( document.addEventListener ) {
 }
 
 jQuery.each(["bind", "one"], function( i, name ) {
-       jQuery.fn[ name ] = function( type, data, fn, thisObject ) {
+       jQuery.fn[ name ] = function( type, data, fn ) {
                // Handle object literals
                if ( typeof type === "object" ) {
                        for ( var key in type ) {
@@ -769,17 +767,17 @@ jQuery.each(["bind", "one"], function( i, name ) {
                }
                
                if ( jQuery.isFunction( data ) ) {
-                       thisObject = fn;
                        fn = data;
                        data = undefined;
                }
-               fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
-               var handler = name === "one" ? jQuery.event.proxy( fn, function( event ) {
+
+               var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
                        jQuery( this ).unbind( event, handler );
                        return fn.apply( this, arguments );
                }) : fn;
+
                return type === "unload" && name !== "one" ?
-                       this.one( type, data, fn, thisObject ) :
+                       this.one( type, data, fn ) :
                        this.each(function() {
                                jQuery.event.add( this, type, handler, data );
                        });
@@ -822,10 +820,10 @@ jQuery.fn.extend({
 
                // link all the functions, so any of them can unbind this click handler
                while ( i < args.length ) {
-                       jQuery.event.proxy( fn, args[ i++ ] );
+                       jQuery.proxy( fn, args[ i++ ] );
                }
 
-               return this.click( jQuery.event.proxy( fn, function( event ) {
+               return this.click( jQuery.proxy( fn, function( event ) {
                        // Figure out which function to execute
                        var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
                        jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
@@ -842,17 +840,16 @@ jQuery.fn.extend({
                return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
        },
 
-       live: function( type, data, fn, thisObject ) {
+       live: function( type, data, fn ) {
                if ( jQuery.isFunction( data ) ) {
-                       if ( fn !== undefined ) {
-                               thisObject = fn;
-                       }
                        fn = data;
                        data = undefined;
                }
+
                jQuery( this.context ).bind( liveConvert( type, this.selector ), {
                        data: data, selector: this.selector, live: type
-               }, fn, thisObject );
+               }, fn );
+
                return this;
        },
 
@@ -864,9 +861,14 @@ jQuery.fn.extend({
 
 function liveHandler( event ) {
        var stop = true, elems = [], selectors = [], args = arguments,
-               related, match, fn, elem, j, i, data,
+               related, match, fn, elem, j, i, l, data,
                live = jQuery.extend({}, jQuery.data( this, "events" ).live);
 
+       // Make sure we avoid non-left-click bubbling in Firefox (#3861)
+       if ( event.button && event.type === "click" ) {
+               return;
+       }
+
        for ( j in live ) {
                fn = live[j];
                if ( fn.live === event.type ||
@@ -920,7 +922,7 @@ function liveConvert( type, selector ) {
        return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
 }
 
-jQuery.each( ("blur focus load resize scroll unload click dblclick " +
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
        "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
 
@@ -929,8 +931,8 @@ jQuery.each( ("blur focus load resize scroll unload click dblclick " +
                return fn ? this.bind( name, fn ) : this.trigger( name );
        };
 
-       if ( jQuery.fnAttr ) {
-               jQuery.fnAttr[ name ] = true;
+       if ( jQuery.attrFn ) {
+               jQuery.attrFn[ name ] = true;
        }
 });