Skip to content

Commit a268f52

Browse files
gibson042timmywil
authored andcommitted
Traversing: Never let .closest() match positional selectors
Fixes gh-2796 Close gh-2818
1 parent 0e2f8f9 commit a268f52

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

src/traversing.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,24 @@ jQuery.fn.extend( {
3939
i = 0,
4040
l = this.length,
4141
matched = [],
42-
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
43-
jQuery( selectors, context || this.context ) :
44-
0;
42+
targets = typeof selectors !== "string" && jQuery( selectors );
4543

46-
for ( ; i < l; i++ ) {
47-
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
44+
// Positional selectors never match, since there's no _selection_ context
45+
if ( !rneedsContext.test( selectors ) ) {
46+
for ( ; i < l; i++ ) {
47+
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
4848

49-
// Always skip document fragments
50-
if ( cur.nodeType < 11 && ( pos ?
51-
pos.index( cur ) > -1 :
49+
// Always skip document fragments
50+
if ( cur.nodeType < 11 && ( targets ?
51+
targets.index( cur ) > -1 :
5252

53-
// Don't pass non-elements to Sizzle
54-
cur.nodeType === 1 &&
55-
jQuery.find.matchesSelector( cur, selectors ) ) ) {
53+
// Don't pass non-elements to Sizzle
54+
cur.nodeType === 1 &&
55+
jQuery.find.matchesSelector( cur, selectors ) ) ) {
5656

57-
matched.push( cur );
58-
break;
57+
matched.push( cur );
58+
break;
59+
}
5960
}
6061
}
6162
}

test/unit/traversing.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ QUnit[ jQuery.find.compile ? "test" : "skip" ]( "filter() with positional select
323323
} );
324324

325325
QUnit.test( "closest()", function( assert ) {
326-
assert.expect( 13 );
326+
assert.expect( 14 );
327327

328328
var jq;
329329

@@ -344,6 +344,12 @@ QUnit.test( "closest()", function( assert ) {
344344
// Test on disconnected node
345345
assert.equal( jQuery( "<div><p></p></div>" ).find( "p" ).closest( "table" ).length, 0, "Make sure disconnected closest work." );
346346

347+
assert.deepEqual(
348+
jQuery( "#firstp" ).closest( q( "qunit-fixture" ) ).get(),
349+
q( "qunit-fixture" ),
350+
"Non-string match target"
351+
);
352+
347353
// Bug #7369
348354
assert.equal( jQuery( "<div foo='bar'></div>" ).closest( "[foo]" ).length, 1, "Disconnected nodes with attribute selector" );
349355
assert.equal( jQuery( "<div>text</div>" ).closest( "[lang]" ).length, 0, "Disconnected nodes with text and non-existent attribute selector" );
@@ -355,10 +361,17 @@ QUnit.test( "closest()", function( assert ) {
355361
} );
356362

357363
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "closest() with positional selectors", function( assert ) {
358-
assert.expect( 2 );
364+
assert.expect( 3 );
359365

360-
assert.deepEqual( jQuery( "#qunit-fixture" ).closest( "div:first" ).get(), [], "closest(div:first)" );
361-
assert.deepEqual( jQuery( "#qunit-fixture div" ).closest( "body:first div:last" ).get(), q( "fx-tests" ), "closest(body:first div:last)" );
366+
assert.deepEqual( jQuery( "#qunit-fixture" ).closest( "div:first" ).get(), [],
367+
"closest(div:first)" );
368+
assert.deepEqual( jQuery( "#qunit-fixture div" ).closest( "body:first div:last" ).get(), [],
369+
"closest(body:first div:last)" );
370+
assert.deepEqual(
371+
jQuery( "#qunit-fixture div" ).closest( "body:first div:last", document ).get(),
372+
[],
373+
"closest(body:first div:last, document)"
374+
);
362375
} );
363376

364377
QUnit.test( "closest(jQuery)", function( assert ) {

0 commit comments

Comments
 (0)