Skip to content

Commit 1c8aec9

Browse files
committed
Maintain original sort order in detached node sorting in Webkit. Fixes jQuery #13331. gibson rules. Close gh-187.
1 parent e1baee5 commit 1c8aec9

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

sizzle.js

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ var i,
1212
getText,
1313
isXML,
1414
compile,
15-
hasDuplicate,
1615
outermostContext,
1716

1817
// Local document vars
@@ -25,6 +24,8 @@ var i,
2524
matches,
2625
contains,
2726
sortOrder,
27+
hasDuplicate,
28+
sortInput,
2829

2930
// Instance-specific data
3031
expando = "sizzle" + -(new Date()),
@@ -392,6 +393,16 @@ setDocument = Sizzle.setDocument = function( node ) {
392393
return pass;
393394
});
394395

396+
// Support: Webkit
397+
// Detached nodes confoundingly follow *each other*
398+
support.sortDetached = assert(function( div1 ) {
399+
return assert(function( div2 ) {
400+
return div1.compareDocumentPosition &&
401+
// Should return 1, but Webkit returns 4 (following)
402+
!!(div1.compareDocumentPosition( div2 ) & 1);
403+
});
404+
});
405+
395406
// IE6/7 return modified attributes
396407
Expr.attrHandle = assert(function( div ) {
397408
div.innerHTML = "<a href='#'></a>";
@@ -588,26 +599,42 @@ setDocument = Sizzle.setDocument = function( node ) {
588599
// Document order sorting
589600
sortOrder = docElem.compareDocumentPosition ?
590601
function( a, b ) {
591-
var compare;
592602

603+
// Flag for duplicate removal
593604
if ( a === b ) {
594605
hasDuplicate = true;
595606
return 0;
596607
}
597608

598-
if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
599-
if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
600-
if ( a === doc || contains( preferredDoc, a ) ) {
609+
var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
610+
611+
if ( compare ) {
612+
// Disconnected nodes
613+
if ( compare & 1 ||
614+
// Support: Opera, Firefox
615+
// Results can't be trusted for document fragment children
616+
a.parentNode && a.parentNode.nodeType === 11 ||
617+
// Support: Webkit
618+
(sortInput && b.compareDocumentPosition( a ) === compare) ) {
619+
620+
// Choose the first element that is related to our preferred document
621+
if ( a === doc || contains(preferredDoc, a) ) {
601622
return -1;
602623
}
603-
if ( b === doc || contains( preferredDoc, b ) ) {
624+
if ( b === doc || contains(preferredDoc, b) ) {
604625
return 1;
605626
}
606-
return 0;
627+
628+
// Maintain original order
629+
return sortInput ?
630+
( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
631+
0;
607632
}
633+
608634
return compare & 4 ? -1 : 1;
609635
}
610636

637+
// Not directly comparable, sort on existence of method
611638
return a.compareDocumentPosition ? -1 : 1;
612639
} :
613640
function( a, b ) {
@@ -744,6 +771,8 @@ Sizzle.uniqueSort = function( results ) {
744771

745772
// Unless we *know* we can detect duplicates, assume their presence
746773
hasDuplicate = !support.detectDuplicates;
774+
// Save the original sort order if necessary
775+
sortInput = !support.sortDetached && results.slice( 0 );
747776
results.sort( sortOrder );
748777

749778
if ( hasDuplicate ) {

test/unit/utilities.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ if ( jQuery("<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1' wi
4444
}
4545

4646
test("Sizzle.uniqueSort", function() {
47-
expect( 12 );
47+
expect( 14 );
4848

4949
function Arrayish( arr ) {
5050
var i = this.length = arr.length;
@@ -59,15 +59,18 @@ test("Sizzle.uniqueSort", function() {
5959
};
6060

6161
var i, tests,
62+
detached = [],
6263
body = document.body,
6364
fixture = document.getElementById("qunit-fixture"),
6465
detached1 = document.createElement("p"),
6566
detached2 = document.createElement("ul"),
6667
detachedChild = detached1.appendChild( document.createElement("a") ),
6768
detachedGrandchild = detachedChild.appendChild( document.createElement("b") );
6869

69-
for ( i = 0; i < 4; i++ ) {
70-
detached2.appendChild( document.createElement("li") ).id = "i" + i;
70+
for ( i = 0; i < 12; i++ ) {
71+
detached.push( document.createElement("li") );
72+
detached[i].id = "detached" + i;
73+
detached2.appendChild( document.createElement("li") ).id = "detachedChild" + i;
7174
}
7275

7376
tests = {
@@ -87,7 +90,11 @@ test("Sizzle.uniqueSort", function() {
8790
input: [ body, fixture, fixture, body ],
8891
expected: [ body, fixture ]
8992
},
90-
"Detached elements": {
93+
"Detached": {
94+
input: detached.slice( 0 ),
95+
expected: detached.slice( 0 )
96+
},
97+
"Detached children": {
9198
input: [
9299
detached2.childNodes[0],
93100
detached2.childNodes[1],

0 commit comments

Comments
 (0)