X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fevent.js;h=fdf61baef005f29daf9d59e1304e472d6b44ff61;hb=a78557472ce1c2cdf7db01a13fcc8591f3fdcfb0;hp=97565a84aae0a84ae2cef56368a7605d29aee858;hpb=c7a14f13916ca8ed22f9bb6fe40fa104b370211f;p=jquery.git diff --git a/src/event.js b/src/event.js index 97565a8..fdf61ba 100644 --- a/src/event.js +++ b/src/event.js @@ -26,10 +26,7 @@ jQuery.event = { var fn = handler; // Create unique handler function, wrapped around original handler - handler = this.proxy( fn, function() { - // Pass arguments and context to original handler - return fn.apply(this, arguments); - }); + handler = this.proxy( fn ); // Store data in unique handler handler.data = data; @@ -128,10 +125,10 @@ jQuery.event = { // remove all handlers for the given type else - for ( handler in events[type] ) + for ( var handle in events[type] ) // Handle the removal of namespaced events - if ( namespace.test(events[type][handler].type) ) - delete events[type][handler]; + if ( namespace.test(events[type][handle].type) ) + delete events[type][handle]; if ( jQuery.event.specialAll[type] ) jQuery.event.specialAll[type].teardown.call(elem, namespaces); @@ -163,98 +160,78 @@ jQuery.event = { } }, - trigger: function( event, data, elem, extra) { + // bubbling is internal + trigger: function( event, data, elem, bubbling ) { // Event object or event type var type = event.type || event; - event = typeof event === "object" ? - // jQuery.Event object - event[expando] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); - - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } - - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - // Only trigger if we've ever bound an event for it - if ( this.global[type] ) - jQuery.each( jQuery.cache, function(){ - if ( this.events && this.events[type] ) - jQuery.event.trigger( event, data, this.handle.elem ); - }); + if( !bubbling ){ + event = typeof event === "object" ? + // jQuery.Event object + event[expando] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + // Only trigger if we've ever bound an event for it + if ( this.global[type] ) + jQuery.each( jQuery.cache, function(){ + if ( this.events && this.events[type] ) + jQuery.event.trigger( event, data, this.handle.elem ); + }); + } - // Handle triggering a single element - } else { + // Handle triggering a single element // don't do events on text and comment nodes - if ( elem.nodeType == 3 || elem.nodeType == 8 ) + if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 ) return undefined; - + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + // Clone the incoming data, if any data = jQuery.makeArray(data); - - // AT_TARGET phase (not bubbling) - if( !event.target ){ - // Clean up in case it is reused - event.result = undefined; - event.target = elem; - } - - // Fix for custom events - event.currentTarget = elem; - data.unshift( event ); + } - var fn = jQuery.isFunction( elem[ type ] ); - - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery.data(elem, "handle"); - if ( handle ) - handle.apply( elem, data ); - - // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links) - if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false ) - event.result = false; - - // Extra functions don't get the custom event object - data.shift(); + event.currentTarget = elem; - // Handle triggering of extra function - if ( extra && jQuery.isFunction( extra ) ) { - // call the extra function and tack the current return value on the end for possible inspection - var ret = extra.apply( elem, event.result == null ? data : data.concat( event.result ) ); - // if anything is returned, give it precedence and have it overwrite the previous value - if ( ret !== undefined ) - event.result = ret; - } + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery.data(elem, "handle"); + if ( handle ) + handle.apply( elem, data ); - // Trigger the native events (except for clicks on links) - if ( event.target === elem && fn && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) { - this.triggered = true; - try { - elem[ type ](); - // prevent IE from throwing an error for some hidden elements - } catch (e) {} - } + // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links) + if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false ) + event.result = false; - if ( !event.isPropagationStopped() ) { - var parent = elem.parentNode || elem.ownerDocument; - if ( parent ) - jQuery.event.trigger(event, data, parent); - } + // Trigger the native events (except for clicks on links) + if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) { + this.triggered = true; + try { + elem[ type ](); + // prevent IE from throwing an error for some hidden elements + } catch (e) {} + } - // Clean up, in case the event object is reused - event.target = null; + this.triggered = false; - this.triggered = false; + if ( !event.isPropagationStopped() ) { + var parent = elem.parentNode || elem.ownerDocument; + if ( parent ) + jQuery.event.trigger(event, data, parent, true); } }, @@ -354,6 +331,7 @@ jQuery.event = { }, proxy: function( fn, proxy ){ + proxy = proxy || function(){ return fn.apply(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++; // So proxy can be declared as an argument @@ -382,7 +360,7 @@ jQuery.event = { remove++; }); - if ( remove <= 1 ) + if ( remove < 1 ) jQuery.event.remove( this, namespaces[0], liveHandler ); } } @@ -399,13 +377,13 @@ jQuery.Event = function( src ){ if( src && src.type ){ this.originalEvent = src; this.type = src.type; - this.timeStamp = src.timeStamp; // Event type }else this.type = src; - if( !this.timeStamp ) - this.timeStamp = now(); + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = now(); // Mark it as fixed this[expando] = true; @@ -508,18 +486,18 @@ jQuery.fn.extend({ }); }, - trigger: function( type, data, fn ) { + trigger: function( type, data ) { return this.each(function(){ - jQuery.event.trigger( type, data, this, fn ); + jQuery.event.trigger( type, data, this ); }); }, - triggerHandler: function( type, data, fn ) { + triggerHandler: function( type, data ) { if( this[0] ){ var event = jQuery.Event(type); event.preventDefault(); event.stopPropagation(); - jQuery.event.trigger( event, data, this[0], fn ); + jQuery.event.trigger( event, data, this[0] ); return event.result; } }, @@ -566,32 +544,43 @@ jQuery.fn.extend({ }, live: function( type, fn ){ - jQuery(document).bind( liveConvert(type, this.selector), this.selector, fn ); + var proxy = jQuery.event.proxy( fn ); + proxy.guid += this.selector + type; + + jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy ); + return this; }, die: function( type, fn ){ - jQuery(document).unbind( liveConvert(type, this.selector), fn ); + jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null ); return this; } }); function liveHandler( event ){ var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"), - stop = true; + stop = true, + elems = []; jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){ if ( check.test(fn.type) ) { var elem = jQuery(event.target).closest(fn.data)[0]; - if ( elem && fn.call(elem, event, fn.data) === false ) - stop = false; + if ( elem ) + elems.push({ elem: elem, fn: fn }); } }); + + jQuery.each(elems, function(){ + if ( this.fn.call(this.elem, event, this.fn.data) === false ) + stop = false; + }); + return stop; } function liveConvert(type, selector){ - return ["live", type, selector.replace(/\./g, "_")].join("."); + return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join("."); } jQuery.extend({ @@ -648,7 +637,7 @@ function bindReady(){ // If IE and not an iframe // continually check to see if the document is ready - if ( document.documentElement.doScroll && !window.frameElement ) (function(){ + if ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){ if ( jQuery.isReady ) return; try {