X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fevent.js;h=76b1dfb20102c9a0ec2780d3bc2249bcb7b963d9;hb=9ebb2fc654d51244618e208705e2258fe733058f;hp=8d737bf4bb3e84b7e1c81c00dc4a8089da0928ec;hpb=3a9c827bf86657a0d007f66c9920d4c2b1726961;p=jquery.git diff --git a/src/event.js b/src/event.js index 8d737bf..76b1dfb 100644 --- a/src/event.js +++ b/src/event.js @@ -57,7 +57,7 @@ jQuery.event = { // Namespaced event handlers var namespaces = type.split("."); type = namespaces.shift(); - handler.type = namespaces.slice().sort().join("."); + handler.type = namespaces.slice(0).sort().join("."); // Get the current list of functions bound to this event var handlers = events[ type ], @@ -133,7 +133,7 @@ jQuery.event = { var namespaces = type.split("."); type = namespaces.shift(); var all = !namespaces.length, - namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"), + namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join(".*\\.") + "(\\.|$)"), special = this.special[ type ] || {}; if ( events[ type ] ) { @@ -190,9 +190,10 @@ jQuery.event = { }, // bubbling is internal - trigger: function( event, data, elem, bubbling ) { + trigger: function( event, data, elem /*, bubbling */ ) { // Event object or event type - var type = event.type || event; + var type = event.type || event, + bubbling = arguments[3]; if ( !bubbling ) { event = typeof event === "object" ? @@ -246,16 +247,22 @@ jQuery.event = { handle.apply( elem, data ); } + var nativeFn, nativeHandler; + try { + nativeFn = elem[ type ]; + nativeHandler = elem[ "on" + type ]; + // prevent IE from throwing an error for some elements with some event types, see #3533 + } 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 ) { + if ( (!nativeFn || (jQuery.nodeName(elem, 'a') && type === "click")) && nativeHandler && nativeHandler.apply( elem, data ) === false ) { event.result = false; } // Trigger the native events (except for clicks on links) - if ( !bubbling && elem[ type ] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) { + if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) { this.triggered = true; try { - elem[ type ](); + nativeFn(); // prevent IE from throwing an error for some hidden elements } catch (e) {} } @@ -284,7 +291,7 @@ jQuery.event = { // Cache this now, all = true means, any handler all = !namespaces.length && !event.exclusive; - var namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"); + var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join(".*\\.") + "(\\.|$)"); handlers = ( jQuery.data(this, "events") || {} )[ event.type ]; @@ -367,15 +374,20 @@ jQuery.event = { // Add which for click: 1 == left; 2 == middle; 3 == right // Note: button is not normalized, so don't use it - if ( !event.which && event.button ) { + if ( !event.which && event.button !== undefined ) { event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); } return event; }, - proxy: function( fn, proxy ) { - proxy = proxy || function() { return fn.apply( this, arguments ); }; + 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++; // So proxy can be declared as an argument @@ -396,8 +408,20 @@ jQuery.event = { jQuery.event.add( this, data.live, liveHandler ); }, - teardown: function( namespaces ) { - jQuery.event.remove( this, namespaces[0], liveHandler ); + remove: function( namespaces ) { + if ( namespaces.length ) { + var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)"); + + jQuery.each( (jQuery.data(this, "events").live || {}), function() { + if ( name.test(this.type) ) { + remove++; + } + }); + + if ( remove < 1 ) { + jQuery.event.remove( this, namespaces[0], liveHandler ); + } + } } } } @@ -494,9 +518,10 @@ var withinElement = function( event ) { } }; +// Create mouseenter and mouseleave events jQuery.each({ - mouseover: 'mouseenter', - mouseout: 'mouseleave' + mouseover: "mouseenter", + mouseout: "mouseleave" }, function( orig, fix ) { jQuery.event.special[ fix ] = { setup: function(){ @@ -508,24 +533,91 @@ jQuery.each({ }; }); +// Create "bubbling" focus and blur events +jQuery.each({ + focus: "focusin", + blur: "focusout" +}, function( orig, fix ){ + var event = jQuery.event, + special = event.special, + handle = event.handle; + + function ieHandler() { + arguments[0].type = orig; + return handle.apply(this, arguments); + } + + special[orig] = { + setup:function() { + if ( this.addEventListener ) + this.addEventListener( orig, handle, true ); + else + jQuery.event.add( this, fix, ieHandler ); + }, + teardown:function() { + if ( this.removeEventListener ) + this.removeEventListener( orig, handle, true ); + else + jQuery.event.remove( this, fix, ieHandler ); + } + }; +}); + jQuery.fn.extend({ - bind: function( type, data, fn ) { - return type === "unload" ? this.one(type, data, fn) : this.each(function() { - jQuery.event.add( this, type, fn || data, fn && data ); + // TODO: make bind(), unbind() and one() DRY! + bind: function( type, data, fn, thisObject ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this.bind(key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + thisObject = fn; + fn = data; + data = undefined; + } + fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject ); + return type === "unload" ? this.one(type, data, fn, thisObject) : this.each(function() { + jQuery.event.add( this, type, fn, data ); }); }, - one: function( type, data, fn ) { - var one = jQuery.event.proxy( fn || data, function( event ) { + one: function( type, data, fn, thisObject ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this.one(key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + thisObject = fn; + fn = data; + data = undefined; + } + fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject ); + var one = jQuery.event.proxy( fn, function( event ) { jQuery( this ).unbind( event, one ); - return (fn || data).apply( this, arguments ); + return fn.apply( this, arguments ); }); return this.each(function() { - jQuery.event.add( this, type, one, fn && data ); + jQuery.event.add( this, type, one, data ); }); }, unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + return this; + } + return this.each(function() { jQuery.event.remove( this, type, fn ); }); @@ -569,7 +661,7 @@ jQuery.fn.extend({ }, hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut ); + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); }, ready: function( fn ) { @@ -590,10 +682,17 @@ jQuery.fn.extend({ return this; }, - live: function( type, data, fn ) { + 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: fn && data, selector: this.selector, live: type - }, fn || data ); + data: data, selector: this.selector, live: type + }, fn, thisObject ); return this; }, @@ -621,7 +720,7 @@ function liveHandler( event ) { jQuery.each(elems, function() { event.currentTarget = this.elem; - event.data = this.fn.data + event.data = this.fn.data; if ( this.fn.apply( this.elem, args ) === false ) { return (stop = false); } @@ -668,6 +767,12 @@ function bindReady() { if ( readyBound ) return; readyBound = true; + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + return jQuery.ready(); + } + // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback @@ -718,16 +823,15 @@ jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + // Handle event binding jQuery.fn[ name ] = function( fn ) { - return fn ? this.bind (name, fn ) : this.trigger( name ); + return fn ? this.bind( name, fn ) : this.trigger( name ); }; }); // Prevent memory leaks in IE -// And prevent errors on refresh with events like mouseover in other browsers // Window isn't included so as not to unbind existing unload events // More info: // - http://isaacschlueter.com/2006/10/msie-memory-leaks/ -// - https://bugzilla.mozilla.org/show_bug.cgi?id=252542 +/*@cc_on jQuery( window ).bind( 'unload', function() { for ( var id in jQuery.cache ) { // Skip the window @@ -736,3 +840,4 @@ jQuery( window ).bind( 'unload', function() { } } }); +@*/