X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fevent.js;h=58f7a3190f959732709a88c353617a1a983a8225;hb=390186b902c4c1ac13e23754d33ed4d8b3d5fa38;hp=64b202d1aeb57295c89d305e08afd7a25f92fd9d;hpb=40ce7f98301e4ff0d912f91025af0fd7b82107bd;p=jquery.git diff --git a/src/event.js b/src/event.js index 64b202d..58f7a31 100644 --- a/src/event.js +++ b/src/event.js @@ -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. @@ -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; } } @@ -114,7 +131,6 @@ jQuery.event = { elem = null; }, - guid: 1, global: {}, // Detach an event or set of events from an element @@ -265,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 ]; + + if ( old ) { + target[ "on" + type ] = null; + } + + this.triggered = true; + target[ type ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} - this.triggered = false; + if ( old ) { + target[ "on" + type ] = old; + } - if ( !event.isPropagationStopped() ) { - var parent = elem.parentNode || elem.ownerDocument; - if ( parent ) { - jQuery.event.trigger( event, data, parent, true ); + this.triggered = false; } } }, @@ -405,23 +433,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 ); - }; - - // 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++; + // Deprecated, use jQuery.guid instead + guid: 1E8, - // So proxy can be declared as an argument - return proxy; - }, + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, special: { ready: { @@ -435,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 ); }, @@ -617,6 +635,9 @@ jQuery.event.special.submit = { return trigger( "submit", this, arguments ); } }); + + } else { + return false; } }, @@ -663,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 ); } } @@ -759,7 +780,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 +790,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 +843,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 ); @@ -840,33 +861,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, thisObject ) { 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 ); - return this; - }, - die: function( type, fn ) { - jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); + types = (types || "").split( /\s+/ ); + + 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 ); + + } 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 || @@ -917,10 +957,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 ) { @@ -929,8 +969,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; } });