Selector: update Sizzle

(cherry-picked from a74ad04bc9)
This commit is contained in:
Michał Gołębiowski 2014-02-05 15:10:22 +01:00
parent 2f202b034f
commit e70d0d749b
5 changed files with 93 additions and 63 deletions

View File

@ -13,7 +13,7 @@
"bower.json"
],
"dependencies": {
"sizzle": "1.10.16"
"sizzle": "1.10.18"
},
"devDependencies": {
"requirejs": "2.1.10",

View File

@ -1,12 +1,12 @@
/*!
* Sizzle CSS Selector Engine v1.10.16
* Sizzle CSS Selector Engine v1.10.18
* http://sizzlejs.com/
*
* Copyright 2013 jQuery Foundation, Inc. and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2014-01-13
* Date: 2014-02-05
*/
(function( window ) {
@ -16,6 +16,7 @@ var i,
getText,
isXML,
compile,
select,
outermostContext,
sortInput,
hasDuplicate,
@ -137,7 +138,7 @@ var i,
funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox
// Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ?
escaped :
@ -1570,6 +1571,15 @@ function elementMatcher( matchers ) {
matchers[0];
}
function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results );
}
return results;
}
function condense( unmatched, map, filter, context, xml ) {
var elem,
newUnmatched = [],
@ -1838,7 +1848,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
superMatcher;
}
compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
var i,
setMatchers = [],
elementMatchers = [],
@ -1846,12 +1856,12 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
if ( !cached ) {
// Generate a function of recursive functions that can be used to check each element
if ( !group ) {
group = tokenize( selector );
if ( !match ) {
match = tokenize( selector );
}
i = group.length;
i = match.length;
while ( i-- ) {
cached = matcherFromTokens( group[i] );
cached = matcherFromTokens( match[i] );
if ( cached[ expando ] ) {
setMatchers.push( cached );
} else {
@ -1861,74 +1871,83 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
// Cache the compiled function
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
// Save selector and tokenization
cached.selector = selector;
}
return cached;
};
function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results );
}
return results;
}
function select( selector, context, results, seed ) {
/**
* A low-level selection function that works with Sizzle's compiled
* selector functions
* @param {String|Function} selector A selector or a pre-compiled
* selector function built with Sizzle.compile
* @param {Element} context
* @param {Array} [results]
* @param {Array} [seed] A set of elements to match against
*/
select = Sizzle.select = function( selector, context, results, seed ) {
var i, tokens, token, type, find,
match = tokenize( selector );
compiled = typeof selector === "function" && selector,
match = !seed && tokenize( (selector = compiled.selector || selector) );
if ( !seed ) {
// Try to minimize operations if there is only one group
if ( match.length === 1 ) {
results = results || [];
// Take a shortcut and set the context if the root selector is an ID
tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML &&
Expr.relative[ tokens[1].type ] ) {
// Try to minimize operations if there is no seed and only one group
if ( match.length === 1 ) {
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
if ( !context ) {
return results;
}
selector = selector.slice( tokens.shift().value.length );
// Take a shortcut and set the context if the root selector is an ID
tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML &&
Expr.relative[ tokens[1].type ] ) {
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
if ( !context ) {
return results;
// Precompiled matchers will still verify ancestry, so step up a level
} else if ( compiled ) {
context = context.parentNode;
}
// Fetch a seed set for right-to-left matching
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
while ( i-- ) {
token = tokens[i];
selector = selector.slice( tokens.shift().value.length );
}
// Abort if we hit a combinator
if ( Expr.relative[ (type = token.type) ] ) {
break;
}
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
// Fetch a seed set for right-to-left matching
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
while ( i-- ) {
token = tokens[i];
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
}
// Abort if we hit a combinator
if ( Expr.relative[ (type = token.type) ] ) {
break;
}
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
break;
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
}
break;
}
}
}
}
// Compile and execute a filtering function
// Compile and execute a filtering function if one is not provided
// Provide `match` to avoid retokenization if we modified the selector above
compile( selector, match )(
( compiled || compile( selector, match ) )(
seed,
context,
!documentIsHTML,
@ -1936,7 +1955,7 @@ function select( selector, context, results, seed ) {
rsibling.test( selector ) && testContext( context.parentNode ) || context
);
return results;
}
};
// One-time assignments

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -162,7 +162,7 @@ test("broken", function() {
var attrbad,
broken = function( name, selector ) {
raises(function() {
throws(function() {
// Setting context to null here somehow avoids QUnit's window.error handling
// making the e & e.message correct
// For whatever reason, without this,
@ -1055,7 +1055,7 @@ test("pseudo - :lang", function() {
anchor.lang = "ara\\b";
deepEqual( Sizzle( ":lang(ara\\b)", foo ), [], ":lang respects backslashes" );
deepEqual( Sizzle( ":lang(ara\\\\b)", foo ), [ anchor ], ":lang respects escaped backslashes" );
raises(function() {
throws(function() {
Sizzle.call( null, "dl:lang(c++)" );
}, function( e ) {
return e.message.indexOf("Syntax error") >= 0;
@ -1136,3 +1136,14 @@ test("matchesSelector", function() {
ok( Sizzle.matchesSelector( el, "* > *" ), "child combinator (matching)" );
ok( !Sizzle.matchesSelector( disconnected, "* > *" ), "child combinator (not matching)" );
});
test("select() with pre-compiled function", function() {
expect( 6 );
jQuery.each([ "#qunit-fixture #first", "ol#listWithTabIndex > li[tabindex]", "#liveSpan1" ],
function( i, selector ) {
var compiled = Sizzle.compile( selector );
equal( Sizzle.select( compiled, document ).length, 1, "Should match using a compiled selector function" );
equal( Sizzle.select( compiled, Sizzle( "#first")[0] ).length, 0, "Should not match with different context" );
});
});