Fixed bubbling of live events (if an inner element handles an event first - and stops...
authorJohn Resig <jeresig@gmail.com>
Mon, 9 Feb 2009 23:29:57 +0000 (23:29 +0000)
committerJohn Resig <jeresig@gmail.com>
Mon, 9 Feb 2009 23:29:57 +0000 (23:29 +0000)
src/core.js
src/event.js
test/index.html
test/unit/event.js
test/unit/selector.js

index 3a9eaa7..ac8ec6b 100644 (file)
@@ -346,14 +346,18 @@ jQuery.fn = jQuery.prototype = {
        },
 
        closest: function( selector ) {
-               var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null;
+               var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
+                       closer = 0;
 
                return this.map(function(){
                        var cur = this;
                        while ( cur && cur.ownerDocument ) {
-                               if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) )
+                               if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
+                                       jQuery.data(cur, "closest", closer);
                                        return cur;
+                               }
                                cur = cur.parentNode;
+                               closer++;
                        }
                });
        },
index a621eb9..e707015 100644 (file)
@@ -571,9 +571,13 @@ function liveHandler( event ){
                }
        });
 
+       elems.sort(function(a,b) {
+               return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
+       });
+       
        jQuery.each(elems, function(){
                if ( this.fn.call(this.elem, event, this.fn.data) === false )
-                       stop = false;
+                       return (stop = false);
        });
 
        return stop;
index 89244d7..2c3545f 100644 (file)
@@ -213,6 +213,11 @@ Z</textarea>
                        <span>...</span><a id="linkWithNoHrefWithTabIndex" tabindex="1">Eat some funyuns</a><span>...</span>
                        <span>...</span><a id="linkWithNoHrefWithNegativeTabIndex" tabindex="-1">Eat some funyuns</a><span>...</span>
                </div>
+               
+               <div id="liveHandlerOrder">
+                       <span id="liveSpan1"><a href="#" id="liveLink1"></a></span>
+                       <span id="liveSpan2"><a href="#" id="liveLink2"></a></span>
+               </div>
        </div>
        </dl>
        
index 4d2b0aa..1da9b59 100644 (file)
@@ -474,7 +474,7 @@ test("toggle(Function, Function, ...)", function() {
 });
 
 test(".live()/.die()", function() {
-       expect(42);
+       expect(46);
 
        var submit = 0, div = 0, livea = 0, liveb = 0;
 
@@ -611,6 +611,29 @@ test(".live()/.die()", function() {
        
        // Cleanup
        jQuery("#nothiddendivchild").die("click");
+
+       // Verify that .live() ocurs and cancel buble in the same order as
+       // we would expect .bind() and .click() without delegation
+       var lived = 0, livee = 0;
+       
+       // bind one pair in one order
+       jQuery('span#liveSpan1 a').live('click', function(){ lived++; return false; });
+       jQuery('span#liveSpan1').live('click', function(){      livee++; });
+
+       jQuery('span#liveSpan1 a').click();
+       equals( lived, 1, "Verify that only one first handler occurred." );
+       equals( livee, 0, "Verify that second handler don't." );
+
+       // and one pair in inverse
+       jQuery('#liveHandlerOrder span#liveSpan2').live('click', function(){    livee++; });
+       jQuery('#liveHandlerOrder span#liveSpan2 a').live('click', function(){ lived++; return false; });
+
+       jQuery('span#liveSpan2 a').click();
+       equals( lived, 2, "Verify that only one first handler occurred." );
+       equals( livee, 0, "Verify that second handler don't." );
+       
+       // Cleanup
+       jQuery("span#liveSpan1 a, span#liveSpan1, span#liveSpan2 a, span#liveSpan2").die("click");
 });
 
 /*
index 924f41d..f7c3912 100644 (file)
@@ -189,7 +189,7 @@ test("child and adjacent", function() {
        reset();
        
        t( "Last Child", "p:last-child", ["sap"] );
-       t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon"] );
+       t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon","liveLink1","liveLink2"] );
        
        t( "Nth-child", "#main form#form > *:nth-child(2)", ["text1"] );
        t( "Nth-child", "#main form#form > :nth-child(2)", ["text1"] );
@@ -278,7 +278,7 @@ test("pseudo (:) selectors", function() {
        expect(53);
        t( "First Child", "p:first-child", ["firstp","sndp"] );
        t( "Last Child", "p:last-child", ["sap"] );
-       t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
+       t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2","liveLink1","liveLink2"] );
        t( "Empty", "ul:empty", ["firstUL"] );
        t( "Enabled UI Element", "#form input:not([type=hidden]):enabled", ["text1","radio1","radio2","check1","check2","hidden2","name"] );
        t( "Disabled UI Element", "#form input:disabled", ["text2"] );
@@ -290,7 +290,7 @@ test("pseudo (:) selectors", function() {
        t( "Text Contains", "a:contains('Google Groups (Link)')", ["groups"] );
        t( "Text Contains", "a:contains('(Link)')", ["groups"] );
 
-       t( "Element Preceded By", "p ~ div", ["foo","fx-queue","fx-tests", "moretests","tabindex-tests"] );
+       t( "Element Preceded By", "p ~ div", ["foo","fx-queue","fx-tests", "moretests","tabindex-tests", "liveHandlerOrder"] );
        t( "Not", "a.blog:not(.link)", ["mark"] );
        t( "Not - multiple", "#form option:not(:contains('Nothing'),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e"] );
        //t( "Not - complex", "#form option:not([id^='opt']:nth-child(-n+3))", [ "option1a", "option1d", "option2d", "option3d", "option3e"] );