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" "bower.json"
], ],
"dependencies": { "dependencies": {
"sizzle": "1.10.16" "sizzle": "1.10.18"
}, },
"devDependencies": { "devDependencies": {
"requirejs": "2.1.10", "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/ * http://sizzlejs.com/
* *
* Copyright 2013 jQuery Foundation, Inc. and other contributors * Copyright 2013 jQuery Foundation, Inc. and other contributors
* Released under the MIT license * Released under the MIT license
* http://jquery.org/license * http://jquery.org/license
* *
* Date: 2014-01-13 * Date: 2014-02-05
*/ */
(function( window ) { (function( window ) {
@ -16,6 +16,7 @@ var i,
getText, getText,
isXML, isXML,
compile, compile,
select,
outermostContext, outermostContext,
sortInput, sortInput,
hasDuplicate, hasDuplicate,
@ -137,7 +138,7 @@ var i,
funescape = function( _, escaped, escapedWhitespace ) { funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000; var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint // NaN means non-codepoint
// Support: Firefox // Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x" // Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ? return high !== high || escapedWhitespace ?
escaped : escaped :
@ -1570,6 +1571,15 @@ function elementMatcher( matchers ) {
matchers[0]; 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 ) { function condense( unmatched, map, filter, context, xml ) {
var elem, var elem,
newUnmatched = [], newUnmatched = [],
@ -1838,7 +1848,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
superMatcher; superMatcher;
} }
compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
var i, var i,
setMatchers = [], setMatchers = [],
elementMatchers = [], elementMatchers = [],
@ -1846,12 +1856,12 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
if ( !cached ) { if ( !cached ) {
// Generate a function of recursive functions that can be used to check each element // Generate a function of recursive functions that can be used to check each element
if ( !group ) { if ( !match ) {
group = tokenize( selector ); match = tokenize( selector );
} }
i = group.length; i = match.length;
while ( i-- ) { while ( i-- ) {
cached = matcherFromTokens( group[i] ); cached = matcherFromTokens( match[i] );
if ( cached[ expando ] ) { if ( cached[ expando ] ) {
setMatchers.push( cached ); setMatchers.push( cached );
} else { } else {
@ -1861,74 +1871,83 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
// Cache the compiled function // Cache the compiled function
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
// Save selector and tokenization
cached.selector = selector;
} }
return cached; return cached;
}; };
function multipleContexts( selector, contexts, results ) { /**
var i = 0, * A low-level selection function that works with Sizzle's compiled
len = contexts.length; * selector functions
for ( ; i < len; i++ ) { * @param {String|Function} selector A selector or a pre-compiled
Sizzle( selector, contexts[i], results ); * selector function built with Sizzle.compile
} * @param {Element} context
return results; * @param {Array} [results]
} * @param {Array} [seed] A set of elements to match against
*/
function select( selector, context, results, seed ) { select = Sizzle.select = function( selector, context, results, seed ) {
var i, tokens, token, type, find, var i, tokens, token, type, find,
match = tokenize( selector ); compiled = typeof selector === "function" && selector,
match = !seed && tokenize( (selector = compiled.selector || selector) );
if ( !seed ) { results = results || [];
// Try to minimize operations if there is only one group
if ( match.length === 1 ) {
// Take a shortcut and set the context if the root selector is an ID // Try to minimize operations if there is no seed and only one group
tokens = match[0] = match[0].slice( 0 ); if ( match.length === 1 ) {
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]; // Take a shortcut and set the context if the root selector is an ID
if ( !context ) { tokens = match[0] = match[0].slice( 0 );
return results; if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
} support.getById && context.nodeType === 9 && documentIsHTML &&
selector = selector.slice( tokens.shift().value.length ); 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 selector = selector.slice( tokens.shift().value.length );
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; }
while ( i-- ) {
token = tokens[i];
// Abort if we hit a combinator // Fetch a seed set for right-to-left matching
if ( Expr.relative[ (type = token.type) ] ) { i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
break; while ( i-- ) {
} token = tokens[i];
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
)) ) {
// If seed is empty or no tokens remain, we can return early // Abort if we hit a combinator
tokens.splice( i, 1 ); if ( Expr.relative[ (type = token.type) ] ) {
selector = seed.length && toSelector( tokens ); break;
if ( !selector ) { }
push.apply( results, seed ); if ( (find = Expr.find[ type ]) ) {
return results; // 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 // Provide `match` to avoid retokenization if we modified the selector above
compile( selector, match )( ( compiled || compile( selector, match ) )(
seed, seed,
context, context,
!documentIsHTML, !documentIsHTML,
@ -1936,7 +1955,7 @@ function select( selector, context, results, seed ) {
rsibling.test( selector ) && testContext( context.parentNode ) || context rsibling.test( selector ) && testContext( context.parentNode ) || context
); );
return results; return results;
} };
// One-time assignments // 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, var attrbad,
broken = function( name, selector ) { broken = function( name, selector ) {
raises(function() { throws(function() {
// Setting context to null here somehow avoids QUnit's window.error handling // Setting context to null here somehow avoids QUnit's window.error handling
// making the e & e.message correct // making the e & e.message correct
// For whatever reason, without this, // For whatever reason, without this,
@ -1055,7 +1055,7 @@ test("pseudo - :lang", function() {
anchor.lang = "ara\\b"; anchor.lang = "ara\\b";
deepEqual( Sizzle( ":lang(ara\\b)", foo ), [], ":lang respects backslashes" ); deepEqual( Sizzle( ":lang(ara\\b)", foo ), [], ":lang respects backslashes" );
deepEqual( Sizzle( ":lang(ara\\\\b)", foo ), [ anchor ], ":lang respects escaped backslashes" ); deepEqual( Sizzle( ":lang(ara\\\\b)", foo ), [ anchor ], ":lang respects escaped backslashes" );
raises(function() { throws(function() {
Sizzle.call( null, "dl:lang(c++)" ); Sizzle.call( null, "dl:lang(c++)" );
}, function( e ) { }, function( e ) {
return e.message.indexOf("Syntax error") >= 0; return e.message.indexOf("Syntax error") >= 0;
@ -1136,3 +1136,14 @@ test("matchesSelector", function() {
ok( Sizzle.matchesSelector( el, "* > *" ), "child combinator (matching)" ); ok( Sizzle.matchesSelector( el, "* > *" ), "child combinator (matching)" );
ok( !Sizzle.matchesSelector( disconnected, "* > *" ), "child combinator (not 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" );
});
});