Build: update Sizzle

Fixes gh-2042
Fixes gh-1969
Closes gh-1709
This commit is contained in:
Timmy Willison 2015-04-13 11:30:18 -04:00
parent 062b5267d0
commit 3a0dd5a3d3
5 changed files with 237 additions and 159 deletions

View File

@ -1,5 +1,4 @@
Copyright 2008, 2014 jQuery Foundation and other contributors, Copyright jQuery Foundation and other contributors, https://jquery.org/
https://jquery.org/
This software consists of voluntary contributions made by many This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history individuals. For exact contribution history, see the revision history

View File

@ -1,12 +1,12 @@
/*! /*!
* Sizzle CSS Selector Engine v2.1.1 * Sizzle CSS Selector Engine v2.2.0
* http://sizzlejs.com/ * http://sizzlejs.com/
* *
* Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors * Copyright jQuery Foundation and other contributors
* Released under the MIT license * Released under the MIT license
* http://jquery.org/license * http://jquery.org/license
* *
* Date: 2014-12-15 * Date: 2015-04-10
*/ */
(function( window ) { (function( window ) {
@ -191,104 +191,128 @@ try {
} }
function Sizzle( selector, context, results, seed ) { function Sizzle( selector, context, results, seed ) {
var match, elem, m, nodeType, var m, i, elem, nid, match, groups, newSelector,
// QSA vars newContext = context && context.ownerDocument,
i, groups, old, nid, newContext, newSelector;
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { // nodeType defaults to 9, since context defaults to document
setDocument( context ); nodeType = context ? context.nodeType : 9;
}
context = context || document;
results = results || []; results = results || [];
if ( !selector || typeof selector !== "string" ) { // Return early from calls with invalid selector or context
if ( typeof selector !== "string" || !selector ||
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
return results; return results;
} }
if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 && nodeType !== 11 ) { // Try to shortcut find operations (as opposed to filters) in HTML documents
return []; if ( !seed ) {
}
if ( documentIsHTML && !seed ) { if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
setDocument( context );
}
context = context || document;
if ( documentIsHTML ) {
// If the selector is sufficiently simple, try using a "get*By*" DOM method
// (excepting DocumentFragment context, where the methods don't exist)
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
// ID selector
if ( (m = match[1]) ) {
// Document context
if ( nodeType === 9 ) {
if ( (elem = context.getElementById( m )) ) {
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( elem.id === m ) {
results.push( elem );
return results;
}
} else {
return results;
}
// Element context
} else {
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( newContext && (elem = newContext.getElementById( m )) &&
contains( context, elem ) &&
elem.id === m ) {
// Try to shortcut find operations when possible (e.g., not under DocumentFragment)
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
// Speed-up: Sizzle("#ID")
if ( (m = match[1]) ) {
if ( nodeType === 9 ) {
elem = context.getElementById( m );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document (jQuery #6963)
if ( elem && elem.parentNode ) {
// Handle the case where IE, Opera, and Webkit return items
// by name instead of ID
if ( elem.id === m ) {
results.push( elem ); results.push( elem );
return results; return results;
} }
} else {
return results;
} }
} else {
// Context is not a document
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
contains( context, elem ) && elem.id === m ) {
results.push( elem );
return results;
}
}
// Speed-up: Sizzle("TAG") // Type selector
} else if ( match[2] ) { } else if ( match[2] ) {
push.apply( results, context.getElementsByTagName( selector ) ); push.apply( results, context.getElementsByTagName( selector ) );
return results;
// Speed-up: Sizzle(".CLASS")
} else if ( (m = match[3]) && support.getElementsByClassName ) {
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
}
// QSA path
if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
nid = old = expando;
newContext = context;
newSelector = nodeType !== 1 && selector;
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
groups = tokenize( selector );
if ( (old = context.getAttribute("id")) ) {
nid = old.replace( rescape, "\\$&" );
} else {
context.setAttribute( "id", nid );
}
nid = "[id='" + nid + "'] ";
i = groups.length;
while ( i-- ) {
groups[i] = nid + toSelector( groups[i] );
}
newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
newSelector = groups.join(",");
}
if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results; return results;
} catch(qsaError) {
} finally { // Class selector
if ( !old ) { } else if ( (m = match[3]) && support.getElementsByClassName &&
context.removeAttribute("id"); context.getElementsByClassName ) {
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
}
// Take advantage of querySelectorAll
if ( support.qsa &&
!compilerCache[ selector + " " ] &&
(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
if ( nodeType !== 1 ) {
newContext = context;
newSelector = selector;
// qSA looks outside Element context, which is not what we want
// Thanks to Andrew Dupont for this workaround technique
// Support: IE <=8
// Exclude object elements
} else if ( context.nodeName.toLowerCase() !== "object" ) {
// Capture the context ID, setting it first if necessary
if ( (nid = context.getAttribute( "id" )) ) {
nid = nid.replace( rescape, "\\$&" );
} else {
context.setAttribute( "id", (nid = expando) );
}
// Prefix every selector in the list
groups = tokenize( selector );
i = groups.length;
while ( i-- ) {
groups[i] = "[id='" + nid + "'] " + toSelector( groups[i] );
}
newSelector = groups.join( "," );
// Expand context for sibling selectors
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
context;
}
if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch ( qsaError ) {
} finally {
if ( nid === expando ) {
context.removeAttribute( "id" );
}
} }
} }
} }
@ -301,7 +325,7 @@ function Sizzle( selector, context, results, seed ) {
/** /**
* Create key-value caches of limited size * Create key-value caches of limited size
* @returns {Function(string, Object)} Returns the Object data after storing it on itself with * @returns {function(string, object)} Returns the Object data after storing it on itself with
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
* deleting the oldest entry * deleting the oldest entry
*/ */
@ -469,33 +493,30 @@ setDocument = Sizzle.setDocument = function( node ) {
var hasCompare, parent, var hasCompare, parent,
doc = node ? node.ownerDocument || node : preferredDoc; doc = node ? node.ownerDocument || node : preferredDoc;
// If no document and documentElement is available, return // Return early if doc is invalid or already selected
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
return document; return document;
} }
// Set our document // Update global variables
document = doc; document = doc;
docElem = doc.documentElement; docElem = document.documentElement;
parent = doc.defaultView; documentIsHTML = !isXML( document );
// Support: IE>8 // Support: IE 9 - 11
// If iframe document is assigned to "document" variable and if iframe has been reloaded, // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 // Limit the fix to IE with document.documentMode and IE >=9 with document.defaultView
// IE6-8 do not support the defaultView property so parent will be undefined if ( document.documentMode && (parent = document.defaultView) && parent.top !== parent ) {
if ( parent && parent !== parent.top ) { // Support: IE 11
// IE11 does not have attachEvent, so all must suffer
if ( parent.addEventListener ) { if ( parent.addEventListener ) {
parent.addEventListener( "unload", unloadHandler, false ); parent.addEventListener( "unload", unloadHandler, false );
// Support: IE 9 - 10 only
} else if ( parent.attachEvent ) { } else if ( parent.attachEvent ) {
parent.attachEvent( "onunload", unloadHandler ); parent.attachEvent( "onunload", unloadHandler );
} }
} }
/* Support tests
---------------------------------------------------------------------- */
documentIsHTML = !isXML( doc );
/* Attributes /* Attributes
---------------------------------------------------------------------- */ ---------------------------------------------------------------------- */
@ -512,12 +533,12 @@ setDocument = Sizzle.setDocument = function( node ) {
// Check if getElementsByTagName("*") returns only elements // Check if getElementsByTagName("*") returns only elements
support.getElementsByTagName = assert(function( div ) { support.getElementsByTagName = assert(function( div ) {
div.appendChild( doc.createComment("") ); div.appendChild( document.createComment("") );
return !div.getElementsByTagName("*").length; return !div.getElementsByTagName("*").length;
}); });
// Support: IE<9 // Support: IE<9
support.getElementsByClassName = rnative.test( doc.getElementsByClassName ); support.getElementsByClassName = rnative.test( document.getElementsByClassName );
// Support: IE<10 // Support: IE<10
// Check if getElementById returns elements by name // Check if getElementById returns elements by name
@ -525,7 +546,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// so use a roundabout getElementsByName test // so use a roundabout getElementsByName test
support.getById = assert(function( div ) { support.getById = assert(function( div ) {
docElem.appendChild( div ).id = expando; docElem.appendChild( div ).id = expando;
return !doc.getElementsByName || !doc.getElementsByName( expando ).length; return !document.getElementsByName || !document.getElementsByName( expando ).length;
}); });
// ID find and filter // ID find and filter
@ -533,9 +554,7 @@ setDocument = Sizzle.setDocument = function( node ) {
Expr.find["ID"] = function( id, context ) { Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var m = context.getElementById( id ); var m = context.getElementById( id );
// Check parentNode to catch when Blackberry 4.6 returns return m ? [ m ] : [];
// nodes that are no longer in the document #6963
return m && m.parentNode ? [ m ] : [];
} }
}; };
Expr.filter["ID"] = function( id ) { Expr.filter["ID"] = function( id ) {
@ -552,7 +571,8 @@ setDocument = Sizzle.setDocument = function( node ) {
Expr.filter["ID"] = function( id ) { Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape ); var attrId = id.replace( runescape, funescape );
return function( elem ) { return function( elem ) {
var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); var node = typeof elem.getAttributeNode !== "undefined" &&
elem.getAttributeNode("id");
return node && node.value === attrId; return node && node.value === attrId;
}; };
}; };
@ -592,7 +612,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// Class // Class
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
if ( documentIsHTML ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
return context.getElementsByClassName( className ); return context.getElementsByClassName( className );
} }
}; };
@ -612,7 +632,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// See http://bugs.jquery.com/ticket/13378 // See http://bugs.jquery.com/ticket/13378
rbuggyQSA = []; rbuggyQSA = [];
if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
// Build QSA regex // Build QSA regex
// Regex strategy adopted from Diego Perini // Regex strategy adopted from Diego Perini
assert(function( div ) { assert(function( div ) {
@ -622,7 +642,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// since its presence should be enough // since its presence should be enough
// http://bugs.jquery.com/ticket/12359 // http://bugs.jquery.com/ticket/12359
docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" + docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
"<select id='" + expando + "-\f]' msallowcapture=''>" + "<select id='" + expando + "-\r\\' msallowcapture=''>" +
"<option selected=''></option></select>"; "<option selected=''></option></select>";
// Support: IE8, Opera 11-12.16 // Support: IE8, Opera 11-12.16
@ -639,7 +659,7 @@ setDocument = Sizzle.setDocument = function( node ) {
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
} }
// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
rbuggyQSA.push("~="); rbuggyQSA.push("~=");
} }
@ -662,7 +682,7 @@ setDocument = Sizzle.setDocument = function( node ) {
assert(function( div ) { assert(function( div ) {
// Support: Windows 8 Native Apps // Support: Windows 8 Native Apps
// The type and name attributes are restricted during .innerHTML assignment // The type and name attributes are restricted during .innerHTML assignment
var input = doc.createElement("input"); var input = document.createElement("input");
input.setAttribute( "type", "hidden" ); input.setAttribute( "type", "hidden" );
div.appendChild( input ).setAttribute( "name", "D" ); div.appendChild( input ).setAttribute( "name", "D" );
@ -710,7 +730,7 @@ setDocument = Sizzle.setDocument = function( node ) {
hasCompare = rnative.test( docElem.compareDocumentPosition ); hasCompare = rnative.test( docElem.compareDocumentPosition );
// Element contains another // Element contains another
// Purposefully does not implement inclusive descendent // Purposefully self-exclusive
// As in, an element does not contain itself // As in, an element does not contain itself
contains = hasCompare || rnative.test( docElem.contains ) ? contains = hasCompare || rnative.test( docElem.contains ) ?
function( a, b ) { function( a, b ) {
@ -764,10 +784,10 @@ setDocument = Sizzle.setDocument = function( node ) {
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
// Choose the first element that is related to our preferred document // Choose the first element that is related to our preferred document
if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
return -1; return -1;
} }
if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
return 1; return 1;
} }
@ -795,8 +815,8 @@ setDocument = Sizzle.setDocument = function( node ) {
// Parentless nodes are either documents or disconnected // Parentless nodes are either documents or disconnected
if ( !aup || !bup ) { if ( !aup || !bup ) {
return a === doc ? -1 : return a === document ? -1 :
b === doc ? 1 : b === document ? 1 :
aup ? -1 : aup ? -1 :
bup ? 1 : bup ? 1 :
sortInput ? sortInput ?
@ -833,7 +853,7 @@ setDocument = Sizzle.setDocument = function( node ) {
0; 0;
}; };
return doc; return document;
}; };
Sizzle.matches = function( expr, elements ) { Sizzle.matches = function( expr, elements ) {
@ -850,6 +870,7 @@ Sizzle.matchesSelector = function( elem, expr ) {
expr = expr.replace( rattributeQuotes, "='$1']" ); expr = expr.replace( rattributeQuotes, "='$1']" );
if ( support.matchesSelector && documentIsHTML && if ( support.matchesSelector && documentIsHTML &&
!compilerCache[ expr + " " ] &&
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
@ -1123,11 +1144,12 @@ Expr = Sizzle.selectors = {
} : } :
function( elem, context, xml ) { function( elem, context, xml ) {
var cache, outerCache, node, diff, nodeIndex, start, var cache, uniqueCache, outerCache, node, nodeIndex, start,
dir = simple !== forward ? "nextSibling" : "previousSibling", dir = simple !== forward ? "nextSibling" : "previousSibling",
parent = elem.parentNode, parent = elem.parentNode,
name = ofType && elem.nodeName.toLowerCase(), name = ofType && elem.nodeName.toLowerCase(),
useCache = !xml && !ofType; useCache = !xml && !ofType,
diff = false;
if ( parent ) { if ( parent ) {
@ -1136,7 +1158,10 @@ Expr = Sizzle.selectors = {
while ( dir ) { while ( dir ) {
node = elem; node = elem;
while ( (node = node[ dir ]) ) { while ( (node = node[ dir ]) ) {
if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { if ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) {
return false; return false;
} }
} }
@ -1150,11 +1175,21 @@ Expr = Sizzle.selectors = {
// non-xml :nth-child(...) stores cache data on `parent` // non-xml :nth-child(...) stores cache data on `parent`
if ( forward && useCache ) { if ( forward && useCache ) {
// Seek `elem` from a previously-cached index // Seek `elem` from a previously-cached index
outerCache = parent[ expando ] || (parent[ expando ] = {});
cache = outerCache[ type ] || []; // ...in a gzip-friendly way
nodeIndex = cache[0] === dirruns && cache[1]; node = parent;
diff = cache[0] === dirruns && cache[2]; outerCache = node[ expando ] || (node[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
cache = uniqueCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex && cache[ 2 ];
node = nodeIndex && parent.childNodes[ nodeIndex ]; node = nodeIndex && parent.childNodes[ nodeIndex ];
while ( (node = ++nodeIndex && node && node[ dir ] || while ( (node = ++nodeIndex && node && node[ dir ] ||
@ -1164,29 +1199,55 @@ Expr = Sizzle.selectors = {
// When found, cache indexes on `parent` and break // When found, cache indexes on `parent` and break
if ( node.nodeType === 1 && ++diff && node === elem ) { if ( node.nodeType === 1 && ++diff && node === elem ) {
outerCache[ type ] = [ dirruns, nodeIndex, diff ]; uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
break; break;
} }
} }
// Use previously-cached element index if available
} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
diff = cache[1];
// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
} else { } else {
// Use the same loop as above to seek `elem` from the start // Use previously-cached element index if available
while ( (node = ++nodeIndex && node && node[ dir ] || if ( useCache ) {
(diff = nodeIndex = 0) || start.pop()) ) { // ...in a gzip-friendly way
node = elem;
outerCache = node[ expando ] || (node[ expando ] = {});
if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Support: IE <9 only
// Cache the index of each encountered element // Defend against cloned attroperties (jQuery gh-1709)
if ( useCache ) { uniqueCache = outerCache[ node.uniqueID ] ||
(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; (outerCache[ node.uniqueID ] = {});
}
if ( node === elem ) { cache = uniqueCache[ type ] || [];
break; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex;
}
// xml :nth-child(...)
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
if ( diff === false ) {
// Use the same loop as above to seek `elem` from the start
while ( (node = ++nodeIndex && node && node[ dir ] ||
(diff = nodeIndex = 0) || start.pop()) ) {
if ( ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) &&
++diff ) {
// Cache the index of each encountered element
if ( useCache ) {
outerCache = node[ expando ] || (node[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
uniqueCache[ type ] = [ dirruns, diff ];
}
if ( node === elem ) {
break;
}
} }
} }
} }
@ -1548,10 +1609,10 @@ function addCombinator( matcher, combinator, base ) {
// Check against all ancestor/preceding elements // Check against all ancestor/preceding elements
function( elem, context, xml ) { function( elem, context, xml ) {
var oldCache, outerCache, var oldCache, uniqueCache, outerCache,
newCache = [ dirruns, doneName ]; newCache = [ dirruns, doneName ];
// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
if ( xml ) { if ( xml ) {
while ( (elem = elem[ dir ]) ) { while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) { if ( elem.nodeType === 1 || checkNonElements ) {
@ -1564,14 +1625,19 @@ function addCombinator( matcher, combinator, base ) {
while ( (elem = elem[ dir ]) ) { while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) { if ( elem.nodeType === 1 || checkNonElements ) {
outerCache = elem[ expando ] || (elem[ expando ] = {}); outerCache = elem[ expando ] || (elem[ expando ] = {});
if ( (oldCache = outerCache[ dir ]) &&
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
if ( (oldCache = uniqueCache[ dir ]) &&
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
// Assign to newCache so results back-propagate to previous elements // Assign to newCache so results back-propagate to previous elements
return (newCache[ 2 ] = oldCache[ 2 ]); return (newCache[ 2 ] = oldCache[ 2 ]);
} else { } else {
// Reuse newcache so results back-propagate to previous elements // Reuse newcache so results back-propagate to previous elements
outerCache[ dir ] = newCache; uniqueCache[ dir ] = newCache;
// A match means we're done; a fail means we have to keep checking // A match means we're done; a fail means we have to keep checking
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
@ -1796,18 +1862,21 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
len = elems.length; len = elems.length;
if ( outermost ) { if ( outermost ) {
outermostContext = context !== document && context; outermostContext = context === document || context || outermost;
} }
// Add elements passing elementMatchers directly to results // Add elements passing elementMatchers directly to results
// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
// Support: IE<9, Safari // Support: IE<9, Safari
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
for ( ; i !== len && (elem = elems[i]) != null; i++ ) { for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
if ( byElement && elem ) { if ( byElement && elem ) {
j = 0; j = 0;
if ( !context && elem.ownerDocument !== document ) {
setDocument( elem );
xml = !documentIsHTML;
}
while ( (matcher = elementMatchers[j++]) ) { while ( (matcher = elementMatchers[j++]) ) {
if ( matcher( elem, context, xml ) ) { if ( matcher( elem, context || document, xml) ) {
results.push( elem ); results.push( elem );
break; break;
} }
@ -1831,8 +1900,17 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
} }
} }
// Apply set filters to unmatched elements // `i` is now the count of elements visited above, and adding it to `matchedCount`
// makes the latter nonnegative.
matchedCount += i; matchedCount += i;
// Apply set filters to unmatched elements
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
// no element matchers and no seed.
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
// numerically zero.
if ( bySet && i !== matchedCount ) { if ( bySet && i !== matchedCount ) {
j = 0; j = 0;
while ( (matcher = setMatchers[j++]) ) { while ( (matcher = setMatchers[j++]) ) {
@ -1924,10 +2002,11 @@ select = Sizzle.select = function( selector, context, results, seed ) {
results = results || []; results = results || [];
// Try to minimize operations if there is no seed and only one group // Try to minimize operations if there is only one selector in the list and no seed
// (the latter of which guarantees us context)
if ( match.length === 1 ) { if ( match.length === 1 ) {
// Take a shortcut and set the context if the root selector is an ID // Reduce context if the leading compound selector is an ID
tokens = match[0] = match[0].slice( 0 ); tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML && support.getById && context.nodeType === 9 && documentIsHTML &&
@ -1982,7 +2061,7 @@ select = Sizzle.select = function( selector, context, results, seed ) {
context, context,
!documentIsHTML, !documentIsHTML,
results, results,
rsibling.test( selector ) && testContext( context.parentNode ) || context !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
); );
return results; return results;
}; };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -51,7 +51,7 @@
"qunitjs": "1.17.1", "qunitjs": "1.17.1",
"requirejs": "2.1.15", "requirejs": "2.1.15",
"sinon": "1.10.3", "sinon": "1.10.3",
"sizzle": "2.1.1", "sizzle": "2.2.0",
"testswarm": "1.1.0" "testswarm": "1.1.0"
}, },
"scripts": { "scripts": {