From 5267824aa36f0fcecb944a4daf0b99d6e01460fd Mon Sep 17 00:00:00 2001 From: jeresig Date: Mon, 8 Feb 2010 23:28:15 -0500 Subject: [PATCH 1/6] Updated formatting for the change/submit special event logic. Also switched the function declarations to statements. Thanks to Garrett for the recommendation. --- src/event.js | 167 ++++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 83 deletions(-) diff --git a/src/event.js b/src/event.js index 2fda802545..6fe8a5b15b 100644 --- a/src/event.js +++ b/src/event.js @@ -652,64 +652,66 @@ jQuery.each({ // submit delegation if ( !jQuery.support.submitBubbles ) { -jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - return trigger( "submit", this, arguments ); - } - }); + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + return trigger( "submit", this, arguments ); + } + }); - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - return trigger( "submit", this, arguments ); - } - }); + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + return trigger( "submit", this, arguments ); + } + }); - } else { - return false; - } - }, + } else { + return false; + } + }, - teardown: function( namespaces ) { - jQuery.event.remove( this, "click.specialSubmit" ); - jQuery.event.remove( this, "keypress.specialSubmit" ); - } -}; + teardown: function( namespaces ) { + jQuery.event.remove( this, "click.specialSubmit" ); + jQuery.event.remove( this, "keypress.specialSubmit" ); + } + }; } // change delegation, happens here so we have bind. if ( !jQuery.support.changeBubbles ) { -var formElems = /textarea|input|select/i; + var formElems = /textarea|input|select/i, -function getVal( elem ) { - var type = elem.type, val = elem.value; + changeFilters, - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; + getVal = function( elem ) { + var type = elem.type, val = elem.value; - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; - return val; -} + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, -function testChange( e ) { + testChange = function testChange( e ) { var elem = e.target, data, val; if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { @@ -732,60 +734,59 @@ function testChange( e ) { e.type = "change"; return jQuery.event.trigger( e, arguments[1], elem ); } -} + }; -jQuery.event.special.change = { - filters: { - focusout: testChange, + jQuery.event.special.change = { + filters: { + focusout: testChange, - click: function( e ) { - var elem = e.target, type = elem.type; + click: function( e ) { + var elem = e.target, type = elem.type; - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - return testChange.call( this, e ); - } - }, + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + return testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + return testChange.call( this, e ); + } + }, - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - return testChange.call( this, e ); + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information/focus[in] is not needed anymore + beforeactivate: function( e ) { + var elem = e.target; + jQuery.data( elem, "_change_data", getVal(elem) ); } }, - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information/focus[in] is not needed anymore - beforeactivate: function( e ) { - var elem = e.target; - jQuery.data( elem, "_change_data", getVal(elem) ); - } - }, + setup: function( data, namespaces ) { + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } - setup: function( data, namespaces ) { - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } + return formElems.test( this.nodeName ); + }, - return formElems.test( this.nodeName ); - }, + teardown: function( namespaces ) { + for ( var type in changeFilters ) { + jQuery.event.remove( this, type + ".specialChange", changeFilters[type] ); + } - teardown: function( namespaces ) { - for ( var type in changeFilters ) { - jQuery.event.remove( this, type + ".specialChange", changeFilters[type] ); + return formElems.test( this.nodeName ); } + }; - return formElems.test( this.nodeName ); - } -}; - -var changeFilters = jQuery.event.special.change.filters; - + changeFilters = jQuery.event.special.change.filters; } function trigger( type, elem, args ) { From 35c379075c9feaa7cf82b4cf4c50a790e35b4d5f Mon Sep 17 00:00:00 2001 From: jeresig Date: Wed, 10 Feb 2010 15:56:53 -0500 Subject: [PATCH 2/6] Simplify the special change/submit event removal logic, per Scott's suggestion in 5267824aa36f0fcecb944a4daf0b99d6e01460fd. --- src/event.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/event.js b/src/event.js index 6fe8a5b15b..2e510eabf2 100644 --- a/src/event.js +++ b/src/event.js @@ -677,8 +677,7 @@ if ( !jQuery.support.submitBubbles ) { }, teardown: function( namespaces ) { - jQuery.event.remove( this, "click.specialSubmit" ); - jQuery.event.remove( this, "keypress.specialSubmit" ); + jQuery.event.remove( this, ".specialSubmit" ); } }; @@ -778,9 +777,7 @@ if ( !jQuery.support.changeBubbles ) { }, teardown: function( namespaces ) { - for ( var type in changeFilters ) { - jQuery.event.remove( this, type + ".specialChange", changeFilters[type] ); - } + jQuery.event.remove( this, ".specialChange" ); return formElems.test( this.nodeName ); } From d3d497f900a559ca254d09470db532064eeacc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ira=C3=AA=20Carvalho?= Date: Wed, 10 Feb 2010 16:40:48 -0500 Subject: [PATCH 3/6] Ignore potential error codes from Github in doing a clone. Fixes #6049. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1854c866a0..2c0a9faa2f 100644 --- a/Makefile +++ b/Makefile @@ -43,8 +43,8 @@ init: @@echo "Grabbing external dependencies..." @@if test ! -d test/qunit/.git; then git clone git://github.com/jquery/qunit.git test/qunit; fi @@if test ! -d src/sizzle/.git; then git clone git://github.com/jeresig/sizzle.git src/sizzle; fi - @@cd src/sizzle && git pull origin master > /dev/null 2>&1 - @@cd test/qunit && git pull origin master > /dev/null 2>&1 + - @@cd src/sizzle && git pull origin master > /dev/null 2>&1 + - @@cd test/qunit && git pull origin master > /dev/null 2>&1 jquery: ${DIST_DIR} selector ${JQ} jq: ${DIST_DIR} ${JQ} From 639f4931b0409a8eb83aaf89a03b6b52f674663e Mon Sep 17 00:00:00 2001 From: John Resig Date: Thu, 11 Feb 2010 01:23:13 -0500 Subject: [PATCH 4/6] No reason to expose the temporary _load method. --- src/ajax.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 3c19ad6c70..7b15a1d80f 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -6,15 +6,15 @@ var jsc = now(), rquery = /\?/, rts = /(\?|&)_=.*?(&|$)/, rurl = /^(\w+:)?\/\/([^\/?#]+)/, - r20 = /%20/g; + r20 = /%20/g, -jQuery.fn.extend({ - // Keep a copy of the old load - _load: jQuery.fn.load, + // Keep a copy of the old load method + _load = jQuery.fn.load; +jQuery.fn.extend({ load: function( url, params, callback ) { if ( typeof url !== "string" ) { - return this._load( url ); + return _load.call( this, url ); // Don't do a request if no elements are being requested } else if ( !this.length ) { From 021b809acecc4e94613375b3182c86722470fe9b Mon Sep 17 00:00:00 2001 From: John Resig Date: Thu, 11 Feb 2010 01:42:51 -0500 Subject: [PATCH 5/6] Make sure that the teardown is called after all the handlers of a type are removed. Fixes #6065. --- src/event.js | 2 +- test/unit/event.js | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/event.js b/src/event.js index 2e510eabf2..e15a2ea639 100644 --- a/src/event.js +++ b/src/event.js @@ -221,7 +221,7 @@ jQuery.event = { } // remove generic event handler if no more handlers exist - if ( jQuery.isEmptyObject( events[ type ] ) ) { + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { removeEvent( elem, type, elemData.handle ); } diff --git a/test/unit/event.js b/test/unit/event.js index e85c4bd9d5..33329c3117 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -72,7 +72,7 @@ test("bind(), multiple events at once and namespaces", function() { }); test("bind(), namespace with special add", function() { - expect(18); + expect(19); var div = jQuery("
").bind("test", function(e) { ok( true, "Test event fired." ); @@ -87,7 +87,9 @@ test("bind(), namespace with special add", function() { equals( e.target, div[0], "And that the target is correct." ); }, setup: function(){}, - teardown: function(){}, + teardown: function(){ + ok(true, "Teardown called."); + }, add: function( handleObj ) { var handler = handleObj.handler; handleObj.handler = function(e) { @@ -116,6 +118,8 @@ test("bind(), namespace with special add", function() { // Should trigger 2 div.trigger("test.b"); + + div.unbind("test"); }); test("bind(), no data", function() { From 5d36fe3210787009e15e05ad602525d0c2823b5c Mon Sep 17 00:00:00 2001 From: jeresig Date: Thu, 11 Feb 2010 16:50:26 -0500 Subject: [PATCH 6/6] Make sure that live mouseenter/mouseleave work properly. Fixes #6077. --- src/event.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/event.js b/src/event.js index e15a2ea639..986322f793 100644 --- a/src/event.js +++ b/src/event.js @@ -917,9 +917,16 @@ jQuery.fn.extend({ } }); +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + jQuery.each(["live", "die"], function( i, name ) { jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, + var type, i = 0, match, namespaces, preType, selector = origSelector || this.selector, context = origSelector ? this : jQuery( this.context ); @@ -939,18 +946,19 @@ jQuery.each(["live", "die"], function( i, name ) { type = type.replace( rnamespaces, "" ); } - type = type === "focus" ? "focusin" : // focus --> focusin - type === "blur" ? "focusout" : // blur --> focusout - type === "hover" ? types.push("mouseleave" + namespaces) && "mouseenter" : // hover support - type; + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } - type += namespaces; + preType = type; + type = (liveMap[ type ] || type) + namespaces; if ( name === "live" ) { // bind live handler context.each(function(){ jQuery.event.add( this, liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn } ); + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); }); } else { @@ -999,7 +1007,7 @@ function liveHandler( event ) { related = null; // Those two events require additional checking - if ( handleObj.origType === "mouseenter" || handleObj.origType === "mouseleave" ) { + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; }