From 20bdde0176d94c0629a343680c35490c49ffdc77 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Fri, 14 Sep 2012 00:36:50 -0400 Subject: [PATCH] Fix jQuery #12337: harden position caching against DOM manipulation --- sizzle.js | 35 ++++++++++++++++------------------- test/unit/selector.js | 9 +++++---- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/sizzle.js b/sizzle.js index ac01c043..688e9660 100644 --- a/sizzle.js +++ b/sizzle.js @@ -611,37 +611,34 @@ Expr = Sizzle.selectors = { var doneName = done++; return function( elem ) { - var parent, diff, - count = 0, - node = elem; + var node, diff, + childkey = doneName + "." + dirruns + ".", + parent = elem.parentNode, + sizset = elem.sizset; if ( first === 1 && last === 0 ) { return true; } - parent = elem.parentNode; - - if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { + if ( typeof sizset === "string" && sizset.indexOf( childkey ) === 0 ) { + diff = sizset.substr( childkey.length ); + } else if ( parent ) { + diff = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { - node.sizset = ++count; - if ( node === elem ) { + node.sizset = childkey + (++diff); + if ( elem === node ) { break; } } } - - parent[ expando ] = doneName; } - diff = elem.sizset - last; + diff -= last; - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } + return first === 0 ? + diff === 0 : + diff % first === 0 && diff / first >= 0; }; } @@ -1096,8 +1093,8 @@ function addCombinator( matcher, combinator, context, xml ) { } : function( elem ) { var cache, - dirkey = doneName + "." + dirruns, - cachedkey = dirkey + "." + cachedruns; + dirkey = doneName + "." + dirruns + ".", + cachedkey = dirkey + cachedruns; while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 ) { if ( (cache = elem[ expando ]) === cachedkey ) { diff --git a/test/unit/selector.js b/test/unit/selector.js index cd2b1178..0a6c3334 100644 --- a/test/unit/selector.js +++ b/test/unit/selector.js @@ -512,7 +512,7 @@ test("attributes", function() { }); test("pseudo - child", function() { - expect( 41 ); + expect( 42 ); t( "First Child", "#qunit-fixture p:first-child", ["firstp","sndp"] ); t( "First Child (case-insensitive)", "#qunit-fixture p:FIRST-CHILD", ["firstp","sndp"] ); t( "Last Child", "p:last-child", ["sap"] ); @@ -528,10 +528,11 @@ test("pseudo - child", function() { t( "Not Nth Child", "#qunit-fixture p:not(:nth-child(1))", ["ap","en","sap","first"] ); // Verify that the child position isn't being cached improperly - jQuery("p:first-child").after("
"); - jQuery("p:first-child").before("
").next().remove(); + var firstChildren = jQuery("p:first-child").before("
"); - t( "First Child", "p:first-child", [] ); + t( "No longer First Child", "p:nth-child(1)", [] ); + firstChildren.prev().remove(); + t( "Restored First Child", "p:nth-child(1)", ["firstp","sndp"] ); QUnit.reset();