No reason to limit the initial change data store to just radio elements. Fixes #5851.
[jquery.git] / src / event.js
index 3e3f834..efefe57 100644 (file)
@@ -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.
@@ -65,19 +71,28 @@ jQuery.event = {
                // Handle multiple events separated by a space
                // jQuery(...).bind("mouseover mouseout", fn);
                types = types.split( /\s+/ );
-               var type, i=0;
+
+               var type, i = 0;
+
                while ( (type = types[ i++ ]) ) {
                        // Namespaced event handlers
                        var namespaces = type.split(".");
                        type = namespaces.shift();
+
+                       if ( i > 1 ) {
+                               handler = jQuery.proxy( handler );
+
+                               if ( data !== undefined ) {
+                                       handler.data = data;
+                               }
+                       }
+
                        handler.type = namespaces.slice(0).sort().join(".");
 
                        // Get the current list of functions bound to this event
                        var handlers = events[ type ],
                                special = this.special[ type ] || {};
 
-                       
-
                        // Init the event handler queue
                        if ( !handlers ) {
                                handlers = events[ type ] = {};
@@ -99,6 +114,8 @@ jQuery.event = {
                                var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); 
                                if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { 
                                        modifiedHandler.guid = modifiedHandler.guid || handler.guid; 
+                                       modifiedHandler.data = modifiedHandler.data || handler.data; 
+                                       modifiedHandler.type = modifiedHandler.type || handler.type; 
                                        handler = modifiedHandler; 
                                } 
                        } 
@@ -264,36 +281,48 @@ jQuery.event = {
                        handle.apply( elem, data );
                }
 
-               var nativeFn, nativeHandler;
+               var parent = elem.parentNode || elem.ownerDocument;
+
+               // Trigger an inline bound script
                try {
                        if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
-                               nativeFn = elem[ type ];
-                               nativeHandler = elem[ "on" + type ];
+                               if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
+                                       event.result = false;
+                               }
                        }
+
                // prevent IE from throwing an error for some elements with some event types, see #3533
                } catch (e) {}
 
-               var isClick = jQuery.nodeName(elem, "a") && type === "click";
+               if ( !event.isPropagationStopped() && parent ) {
+                       jQuery.event.trigger( event, data, parent, true );
 
-               // Trigger the native events (except for clicks on links)
-               if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !isClick ) {
-                       this.triggered = true;
-                       try {
-                               elem[ type ]();
-                       // prevent IE from throwing an error for some hidden elements
-                       } catch (e) {}
+               } else if ( !event.isDefaultPrevented() ) {
+                       var target = event.target, old,
+                               isClick = jQuery.nodeName(target, "a") && type === "click";
 
-               // Handle triggering native .onfoo handlers
-               } else if ( nativeHandler && elem[ "on" + type ].apply( elem, data ) === false ) {
-                       event.result = false;
-               }
+                       if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
+                               try {
+                                       if ( target[ type ] ) {
+                                               // Make sure that we don't accidentally re-trigger the onFOO events
+                                               old = target[ "on" + type ];
 
-               this.triggered = false;
+                                               if ( old ) {
+                                                       target[ "on" + type ] = null;
+                                               }
 
-               if ( !event.isPropagationStopped() ) {
-                       var parent = elem.parentNode || elem.ownerDocument;
-                       if ( parent ) {
-                               jQuery.event.trigger( event, data, parent, true );
+                                               this.triggered = true;
+                                               target[ type ]();
+                                       }
+
+                               // prevent IE from throwing an error for some elements with some event types, see #3533
+                               } catch (e) {}
+
+                               if ( old ) {
+                                       target[ "on" + type ] = old;
+                               }
+
+                               this.triggered = false;
                        }
                }
        },
@@ -404,13 +433,17 @@ jQuery.event = {
                return event;
        },
 
+       // Deprecated, use jQuery.guid instead
+       guid: 1E8,
+
+       // Deprecated, use jQuery.proxy instead
        proxy: jQuery.proxy,
 
        special: {
                ready: {
                        // Make sure the ready event is setup
                        setup: jQuery.bindReady,
-                       teardown: function() {}
+                       teardown: jQuery.noop
                },
 
                live: {
@@ -418,6 +451,8 @@ jQuery.event = {
                                jQuery.extend( proxy, data || {} );
 
                                proxy.guid += data.selector + data.live; 
+                               data.liveProxy = proxy;
+
                                jQuery.event.add( this, data.live, liveHandler, data ); 
                                
                        },
@@ -600,6 +635,9 @@ jQuery.event.special.submit = {
                                        return trigger( "submit", this, arguments );
                                }
                        });
+
+               } else {
+                       return false;
                }
        },
 
@@ -646,18 +684,18 @@ function testChange( e ) {
                data = jQuery.data( elem, "_change_data" );
                val = getVal(elem);
 
-               if ( val === data ) {
-                       return;
-               }
-
                // the current data will be also retrieved by beforeactivate
                if ( e.type !== "focusout" || elem.type !== "radio" ) {
                        jQuery.data( elem, "_change_data", val );
                }
+               
+               if ( data === undefined || val === data ) {
+                       return;
+               }
 
-               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 );
                }
 }
 
@@ -690,10 +728,7 @@ jQuery.event.special.change = {
                // information/focus[in] is not needed anymore
                beforeactivate: function( e ) {
                        var elem = e.target;
-
-                       if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
-                               jQuery.data( elem, "_change_data", getVal(elem) );
-                       }
+                       jQuery.data( elem, "_change_data", getVal(elem) );
                }
        },
        setup: function( data, namespaces, fn ) {
@@ -752,7 +787,6 @@ jQuery.each(["bind", "one"], function( i, name ) {
                }
                
                if ( jQuery.isFunction( data ) ) {
-                       thisObject = fn;
                        fn = data;
                        data = undefined;
                }
@@ -762,9 +796,11 @@ jQuery.each(["bind", "one"], function( i, name ) {
                        return fn.apply( this, arguments );
                }) : fn;
 
-               return type === "unload" ? this.one(type, data, handler) : this.each(function() {
-                       jQuery.event.add( this, type, handler, data );
-               });
+               return type === "unload" && name !== "one" ?
+                       this.one( type, data, fn ) :
+                       this.each(function() {
+                               jQuery.event.add( this, type, handler, data );
+                       });
        };
 });
 
@@ -822,32 +858,52 @@ jQuery.fn.extend({
 
        hover: function( fnOver, fnOut ) {
                return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-       },
+       }
+});
+
+jQuery.each(["live", "die"], function( i, name ) {
+       jQuery.fn[ name ] = function( types, data, fn ) {
+               var type, i = 0;
 
-       live: function( type, data, fn ) {
                if ( jQuery.isFunction( data ) ) {
                        fn = data;
                        data = undefined;
                }
 
-               jQuery( this.context ).bind( liveConvert( type, this.selector ), {
-                       data: data, selector: this.selector, live: type
-               }, fn );
+               types = (types || "").split( /\s+/ );
 
-               return this;
-       },
+               while ( (type = types[ i++ ]) != null ) {
+                       type = type === "focus" ? "focusin" : // focus --> focusin
+                                       type === "blur" ? "focusout" : // blur --> focusout
+                                       type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
+                                       type;
+                       
+                       if ( name === "live" ) {
+                               // bind live handler
+                               jQuery( this.context ).bind( liveConvert( type, this.selector ), {
+                                       data: data, selector: this.selector, live: type
+                               }, fn );
 
-       die: function( type, fn ) {
-               jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
+                       } else {
+                               // unbind live handler
+                               jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
+                       }
+               }
+               
                return this;
        }
 });
 
 function liveHandler( event ) {
-       var stop = true, elems = [], selectors = [], args = arguments,
-               related, match, fn, elem, j, i, data,
+       var stop, elems = [], selectors = [], args = arguments,
+               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 ||
@@ -898,10 +954,10 @@ function liveHandler( event ) {
 }
 
 function liveConvert( type, selector ) {
-       return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
+       return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
 }
 
-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 ) {
 
@@ -910,8 +966,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;
        }
 });