4 * Copyright, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://www.tinymce.com/license
8 * Contributing: http://www.tinymce.com/contributing
13 /*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */
16 * Sizzle CSS Selector Engine
17 * Copyright, The Dojo Foundation
18 * Released under the MIT, BSD, and GPL Licenses.
19 * More information: http://sizzlejs.com/
21 define("tinymce/dom/Sizzle", [], function() {
32 // Local document vars
42 // Instance-specific data
43 expando = "sizzle" + -(new Date()),
44 preferredDoc = window.document,
48 classCache = createCache(),
49 tokenCache = createCache(),
50 compilerCache = createCache(),
52 sortOrder = function() { return 0; },
54 // General-purpose constants
55 strundefined = typeof undefined,
56 MAX_NEGATIVE = 1 << 31,
61 push_native = arr.push,
64 // Use a stripped-down indexOf if we can't use a native one
65 indexOf = arr.indexOf || function( elem ) {
68 for ( ; i < len; i++ ) {
69 if ( this[i] === elem ) {
77 // Regular expressions
79 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
80 whitespace = "[\\x20\\t\\r\\n\\f]",
81 // http://www.w3.org/TR/css3-syntax/#characters
82 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
84 // Loosely modeled on CSS identifier characters
85 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
86 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
87 identifier = characterEncoding.replace( "w", "w#" ),
89 // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
90 operators = "([*^$|!~]?=)",
91 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
92 "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
94 // Prefer arguments quoted,
95 // then not containing pseudos/brackets,
96 // then attribute selectors/non-parenthetical expressions,
98 // These preferences are here to reduce the number of selectors
99 // needing tokenize in the PSEUDO preFilter
100 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
102 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
103 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
105 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
106 rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
107 rpseudo = new RegExp( pseudos ),
108 ridentifier = new RegExp( "^" + identifier + "$" ),
111 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
112 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
113 "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
114 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
115 "ATTR": new RegExp( "^" + attributes ),
116 "PSEUDO": new RegExp( "^" + pseudos ),
117 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
118 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
119 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
120 // For use in libraries implementing .is()
121 // We use this for POS matching in `select`
122 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
123 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
126 rsibling = /[\x20\t\r\n\f]*[+~]/,
128 rnative = /^[^{]+\{\s*\[native code/,
130 // Easily-parseable/retrievable ID or TAG or CLASS selectors
131 rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
133 rinputs = /^(?:input|select|textarea|button)$/i,
137 rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
139 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
140 runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
141 funescape = function( _, escaped ) {
142 var high = "0x" + escaped - 0x10000;
143 // NaN means non-codepoint
144 return high !== high ?
148 String.fromCharCode( high + 0x10000 ) :
149 // Supplemental Plane codepoint (surrogate pair)
150 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
153 // Optimize for push.apply( _, NodeList )
156 (arr = slice.call( preferredDoc.childNodes )),
157 preferredDoc.childNodes
159 // Support: Android<4.0
160 // Detect silently failing push.apply
161 arr[ preferredDoc.childNodes.length ].nodeType;
163 push = { apply: arr.length ?
165 // Leverage slice if possible
166 function( target, els ) {
167 push_native.apply( target, slice.call(els) );
171 // Otherwise append directly
172 function( target, els ) {
173 var j = target.length,
175 // Can't trust NodeList.length
176 while ( (target[j++] = els[i++]) ) {}
177 target.length = j - 1;
183 * For feature detection
184 * @param {Function} fn The function to test for native support
186 function isNative( fn ) {
187 return rnative.test( fn + "" );
191 * Create key-value caches of limited size
192 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
193 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
194 * deleting the oldest entry
196 function createCache() {
200 cache = function( key, value ) {
201 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
202 if ( keys.push( key += " " ) > Expr.cacheLength ) {
203 // Only keep the most recent entries
204 delete cache[ keys.shift() ];
206 cache[ key ] = value;
214 * Mark a function for special use by Sizzle
215 * @param {Function} fn The function to mark
217 function markFunction( fn ) {
218 fn[ expando ] = true;
223 * Support testing using an element
224 * @param {Function} fn Passed the created div and expects a boolean result
226 function assert( fn ) {
227 var div = document.createElement("div");
234 // release memory in IE
239 function Sizzle( selector, context, results, seed ) {
240 var match, elem, m, nodeType,
242 i, groups, old, nid, newContext, newSelector;
244 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
245 setDocument( context );
248 context = context || document;
249 results = results || [];
251 if ( !selector || typeof selector !== "string" ) {
255 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
259 if ( documentIsHTML && !seed ) {
262 if ( (match = rquickExpr.exec( selector )) ) {
263 // Speed-up: Sizzle("#ID")
264 if ( (m = match[1]) ) {
265 if ( nodeType === 9 ) {
266 elem = context.getElementById( m );
267 // Check parentNode to catch when Blackberry 4.6 returns
268 // nodes that are no longer in the document #6963
269 if ( elem && elem.parentNode ) {
270 // Handle the case where IE, Opera, and Webkit return items
271 // by name instead of ID
272 if ( elem.id === m ) {
273 results.push( elem );
280 // Context is not a document
281 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
282 contains( context, elem ) && elem.id === m ) {
283 results.push( elem );
288 // Speed-up: Sizzle("TAG")
289 } else if ( match[2] ) {
290 push.apply( results, context.getElementsByTagName( selector ) );
293 // Speed-up: Sizzle(".CLASS")
294 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
295 push.apply( results, context.getElementsByClassName( m ) );
301 if ( support.qsa && !rbuggyQSA.test(selector) ) {
304 newContext = context;
305 newSelector = nodeType === 9 && selector;
307 // qSA works strangely on Element-rooted queries
308 // We can work around this by specifying an extra ID on the root
309 // and working up from there (Thanks to Andrew Dupont for the technique)
310 // IE 8 doesn't work on object elements
311 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
312 groups = tokenize( selector );
314 if ( (old = context.getAttribute("id")) ) {
315 nid = old.replace( rescape, "\\$&" );
317 context.setAttribute( "id", nid );
319 nid = "[id='" + nid + "'] ";
323 groups[i] = nid + toSelector( groups[i] );
325 newContext = rsibling.test( selector ) && context.parentNode || context;
326 newSelector = groups.join(",");
332 newContext.querySelectorAll( newSelector )
338 context.removeAttribute("id");
346 return select( selector.replace( rtrim, "$1" ), context, results, seed );
351 * @param {Element|Object} elem An element or a document
353 isXML = Sizzle.isXML = function( elem ) {
354 // documentElement is verified for cases where it doesn't yet exist
355 // (such as loading iframes in IE - #4833)
356 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
357 return documentElement ? documentElement.nodeName !== "HTML" : false;
361 * Sets document-related variables once based on the current document
362 * @param {Element|Object} [doc] An element or document object to use to set the document
363 * @returns {Object} Returns the current document
365 setDocument = Sizzle.setDocument = function( node ) {
366 var doc = node ? node.ownerDocument || node : preferredDoc;
368 // If no document and documentElement is available, return
369 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
375 docElem = doc.documentElement;
378 documentIsHTML = !isXML( doc );
380 // Check if getElementsByTagName("*") returns only elements
381 support.getElementsByTagName = assert(function( div ) {
382 div.appendChild( doc.createComment("") );
383 return !div.getElementsByTagName("*").length;
386 // Check if attributes should be retrieved by attribute nodes
387 support.attributes = assert(function( div ) {
388 div.innerHTML = "<select></select>";
389 var type = typeof div.lastChild.getAttribute("multiple");
390 // IE8 returns a string for some attributes even when not present
391 return type !== "boolean" && type !== "string";
394 // Check if getElementsByClassName can be trusted
395 support.getElementsByClassName = assert(function( div ) {
396 // Opera can't find a second classname (in 9.6)
397 div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
398 if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
402 // Safari 3.2 caches class attributes and doesn't catch changes
403 div.lastChild.className = "e";
404 return div.getElementsByClassName("e").length === 2;
407 // Check if getElementsByName privileges form controls or returns elements by ID
408 // If so, assume (for broader support) that getElementById returns elements by name
409 support.getByName = assert(function( div ) {
411 div.id = expando + 0;
412 // Support: Windows 8 Native Apps
413 // Assigning innerHTML with "name" attributes throws uncatchable exceptions
414 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx
415 div.appendChild( document.createElement("a") ).setAttribute( "name", expando );
416 div.appendChild( document.createElement("i") ).setAttribute( "name", expando );
417 docElem.appendChild( div );
420 var pass = doc.getElementsByName &&
421 // buggy browsers will return fewer than the correct 2
422 doc.getElementsByName( expando ).length === 2 +
423 // buggy browsers will return more than the correct 0
424 doc.getElementsByName( expando + 0 ).length;
427 docElem.removeChild( div );
432 // Support: Webkit<537.32
433 // Detached nodes confoundingly follow *each other*
434 support.sortDetached = assert(function( div1 ) {
435 return div1.compareDocumentPosition &&
436 // Should return 1, but Webkit returns 4 (following)
437 (div1.compareDocumentPosition( document.createElement("div") ) & 1);
440 // IE6/7 return modified attributes
441 Expr.attrHandle = assert(function( div ) {
442 div.innerHTML = "<a href='#'></a>";
443 return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
444 div.firstChild.getAttribute("href") === "#";
448 "href": function( elem ) {
449 return elem.getAttribute( "href", 2 );
451 "type": function( elem ) {
452 return elem.getAttribute("type");
456 // ID find and filter
457 if ( support.getByName ) {
458 Expr.find["ID"] = function( id, context ) {
459 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
460 var m = context.getElementById( id );
461 // Check parentNode to catch when Blackberry 4.6 returns
462 // nodes that are no longer in the document #6963
463 return m && m.parentNode ? [m] : [];
466 Expr.filter["ID"] = function( id ) {
467 var attrId = id.replace( runescape, funescape );
468 return function( elem ) {
469 return elem.getAttribute("id") === attrId;
473 Expr.find["ID"] = function( id, context ) {
474 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
475 var m = context.getElementById( id );
478 m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
484 Expr.filter["ID"] = function( id ) {
485 var attrId = id.replace( runescape, funescape );
486 return function( elem ) {
487 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
488 return node && node.value === attrId;
494 Expr.find["TAG"] = support.getElementsByTagName ?
495 function( tag, context ) {
496 if ( typeof context.getElementsByTagName !== strundefined ) {
497 return context.getElementsByTagName( tag );
500 function( tag, context ) {
504 results = context.getElementsByTagName( tag );
506 // Filter out possible comments
508 while ( (elem = results[i++]) ) {
509 if ( elem.nodeType === 1 ) {
520 Expr.find["NAME"] = support.getByName && function( tag, context ) {
521 if ( typeof context.getElementsByName !== strundefined ) {
522 return context.getElementsByName( name );
527 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
528 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
529 return context.getElementsByClassName( className );
533 // QSA and matchesSelector support
535 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
538 // qSa(:focus) reports false when true (Chrome 21),
539 // no need to also add to buggyMatches since matches checks buggyQSA
540 // A support test would require too much code (would include document ready)
541 rbuggyQSA = [ ":focus" ];
543 if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
545 // Regex strategy adopted from Diego Perini
546 assert(function( div ) {
547 // Select is set to empty string on purpose
548 // This is to test IE's treatment of not explicitly
549 // setting a boolean content attribute,
550 // since its presence should be enough
551 // http://bugs.jquery.com/ticket/12359
552 div.innerHTML = "<select><option selected=''></option></select>";
554 // IE8 - Some boolean attributes are not treated correctly
555 if ( !div.querySelectorAll("[selected]").length ) {
556 rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
559 // Webkit/Opera - :checked should return selected option elements
560 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
561 // IE8 throws error here and will not see later tests
562 if ( !div.querySelectorAll(":checked").length ) {
563 rbuggyQSA.push(":checked");
567 assert(function( div ) {
569 // Opera 10-12/IE8 - ^= $= *= and empty values
570 // Should not select anything
571 div.innerHTML = "<input type='hidden' i=''/>";
572 if ( div.querySelectorAll("[i^='']").length ) {
573 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
576 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
577 // IE8 throws error here and will not see later tests
578 if ( !div.querySelectorAll(":enabled").length ) {
579 rbuggyQSA.push( ":enabled", ":disabled" );
582 // Opera 10-11 does not throw on post-comma invalid pseudos
583 div.querySelectorAll("*,:x");
584 rbuggyQSA.push(",.*:");
588 if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
589 docElem.mozMatchesSelector ||
590 docElem.webkitMatchesSelector ||
591 docElem.oMatchesSelector ||
592 docElem.msMatchesSelector) )) ) {
594 assert(function( div ) {
595 // Check to see if it's possible to do matchesSelector
596 // on a disconnected node (IE 9)
597 support.disconnectedMatch = matches.call( div, "div" );
599 // This should fail with an exception
600 // Gecko does not error, returns false instead
601 matches.call( div, "[s!='']:x" );
602 rbuggyMatches.push( "!=", pseudos );
606 rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
607 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
609 // Element contains another
610 // Purposefully does not implement inclusive descendant
611 // As in, an element does not contain itself
612 contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
614 var adown = a.nodeType === 9 ? a.documentElement : a,
615 bup = b && b.parentNode;
616 return a === bup || !!( bup && bup.nodeType === 1 && (
618 adown.contains( bup ) :
619 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
624 while ( (b = b.parentNode) ) {
633 // Document order sorting
634 sortOrder = docElem.compareDocumentPosition ?
637 // Flag for duplicate removal
643 var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
646 // Disconnected nodes
648 (recompare && b.compareDocumentPosition( a ) === compare) ) {
650 // Choose the first element that is related to our preferred document
651 if ( a === doc || contains(preferredDoc, a) ) {
654 if ( b === doc || contains(preferredDoc, b) ) {
658 // Maintain original order
660 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
664 return compare & 4 ? -1 : 1;
667 // Not directly comparable, sort on existence of method
668 return a.compareDocumentPosition ? -1 : 1;
678 // Exit early if the nodes are identical
683 // Parentless nodes are either documents or disconnected
684 } else if ( !aup || !bup ) {
685 return a === doc ? -1 :
691 // If the nodes are siblings, we can do a quick check
692 } else if ( aup === bup ) {
693 return siblingCheck( a, b );
696 // Otherwise we need full lists of their ancestors for comparison
698 while ( (cur = cur.parentNode) ) {
702 while ( (cur = cur.parentNode) ) {
706 // Walk down the tree looking for a discrepancy
707 while ( ap[i] === bp[i] ) {
712 // Do a sibling check if the nodes have a common ancestor
713 siblingCheck( ap[i], bp[i] ) :
715 // Otherwise nodes in our document sort first
716 ap[i] === preferredDoc ? -1 :
717 bp[i] === preferredDoc ? 1 :
724 Sizzle.matches = function( expr, elements ) {
725 return Sizzle( expr, null, null, elements );
728 Sizzle.matchesSelector = function( elem, expr ) {
729 // Set document vars if needed
730 if ( ( elem.ownerDocument || elem ) !== document ) {
734 // Make sure that attribute selectors are quoted
735 expr = expr.replace( rattributeQuotes, "='$1']" );
737 // rbuggyQSA always contains :focus, so no need for an existence check
738 if ( support.matchesSelector && documentIsHTML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
740 var ret = matches.call( elem, expr );
742 // IE 9's matchesSelector returns false on disconnected nodes
743 if ( ret || support.disconnectedMatch ||
744 // As well, disconnected nodes are said to be in a document
746 elem.document && elem.document.nodeType !== 11 ) {
752 return Sizzle( expr, document, null, [elem] ).length > 0;
755 Sizzle.contains = function( context, elem ) {
756 // Set document vars if needed
757 if ( ( context.ownerDocument || context ) !== document ) {
758 setDocument( context );
760 return contains( context, elem );
763 Sizzle.attr = function( elem, name ) {
766 // Set document vars if needed
767 if ( ( elem.ownerDocument || elem ) !== document ) {
771 if ( documentIsHTML ) {
772 name = name.toLowerCase();
774 if ( (val = Expr.attrHandle[ name ]) ) {
777 if ( !documentIsHTML || support.attributes ) {
778 return elem.getAttribute( name );
780 return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
782 val && val.specified ? val.value : null;
785 Sizzle.error = function( msg ) {
786 throw new Error( "Syntax error, unrecognized expression: " + msg );
789 // Document sorting and removing duplicates
790 Sizzle.uniqueSort = function( results ) {
796 // Unless we *know* we can detect duplicates, assume their presence
797 hasDuplicate = !support.detectDuplicates;
798 // Compensate for sort limitations
799 recompare = !support.sortDetached;
800 sortInput = !support.sortStable && results.slice( 0 );
801 results.sort( sortOrder );
803 if ( hasDuplicate ) {
804 while ( (elem = results[i++]) ) {
805 if ( elem === results[ i ] ) {
806 j = duplicates.push( i );
810 results.splice( duplicates[ j ], 1 );
818 * Checks document order of two siblings
821 * @returns Returns -1 if a precedes b, 1 if a follows b
823 function siblingCheck( a, b ) {
825 diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
827 // Use IE sourceIndex if available on both nodes
832 // Check if b follows a
834 while ( (cur = cur.nextSibling) ) {
844 // Returns a function to use in pseudos for input types
845 function createInputPseudo( type ) {
846 return function( elem ) {
847 var name = elem.nodeName.toLowerCase();
848 return name === "input" && elem.type === type;
852 // Returns a function to use in pseudos for buttons
853 function createButtonPseudo( type ) {
854 return function( elem ) {
855 var name = elem.nodeName.toLowerCase();
856 return (name === "input" || name === "button") && elem.type === type;
860 // Returns a function to use in pseudos for positionals
861 function createPositionalPseudo( fn ) {
862 return markFunction(function( argument ) {
863 argument = +argument;
864 return markFunction(function( seed, matches ) {
866 matchIndexes = fn( [], seed.length, argument ),
867 i = matchIndexes.length;
869 // Match elements found at the specified indexes
871 if ( seed[ (j = matchIndexes[i]) ] ) {
872 seed[j] = !(matches[j] = seed[j]);
880 * Utility function for retrieving the text value of an array of DOM nodes
881 * @param {Array|Element} elem
883 getText = Sizzle.getText = function( elem ) {
887 nodeType = elem.nodeType;
890 // If no nodeType, this is expected to be an array
891 for ( ; (node = elem[i]); i++ ) {
892 // Do not traverse comment nodes
893 ret += getText( node );
895 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
896 // Use textContent for elements
897 // innerText usage removed for consistency of new lines (see #11153)
898 if ( typeof elem.textContent === "string" ) {
899 return elem.textContent;
901 // Traverse its children
902 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
903 ret += getText( elem );
906 } else if ( nodeType === 3 || nodeType === 4 ) {
907 return elem.nodeValue;
909 // Do not include comment or processing instruction nodes
914 Expr = Sizzle.selectors = {
916 // Can be adjusted by the user
919 createPseudo: markFunction,
926 ">": { dir: "parentNode", first: true },
927 " ": { dir: "parentNode" },
928 "+": { dir: "previousSibling", first: true },
929 "~": { dir: "previousSibling" }
933 "ATTR": function( match ) {
934 match[1] = match[1].replace( runescape, funescape );
936 // Move the given value to match[3] whether quoted or unquoted
937 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
939 if ( match[2] === "~=" ) {
940 match[3] = " " + match[3] + " ";
943 return match.slice( 0, 4 );
946 "CHILD": function( match ) {
947 /* matches from matchExpr["CHILD"]
948 1 type (only|nth|...)
949 2 what (child|of-type)
950 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
951 4 xn-component of xn+y argument ([+-]?\d*n|)
952 5 sign of xn-component
954 7 sign of y-component
957 match[1] = match[1].toLowerCase();
959 if ( match[1].slice( 0, 3 ) === "nth" ) {
960 // nth-* requires argument
962 Sizzle.error( match[0] );
965 // numeric x and y parameters for Expr.filter.CHILD
966 // remember that false/true cast respectively to 0/1
967 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
968 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
970 // other types prohibit arguments
971 } else if ( match[3] ) {
972 Sizzle.error( match[0] );
978 "PSEUDO": function( match ) {
980 unquoted = !match[5] && match[2];
982 if ( matchExpr["CHILD"].test( match[0] ) ) {
986 // Accept quoted arguments as-is
990 // Strip excess characters from unquoted arguments
991 } else if ( unquoted && rpseudo.test( unquoted ) &&
992 // Get excess from tokenize (recursively)
993 (excess = tokenize( unquoted, true )) &&
994 // advance to the next closing parenthesis
995 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
997 // excess is a negative index
998 match[0] = match[0].slice( 0, excess );
999 match[2] = unquoted.slice( 0, excess );
1002 // Return only captures needed by the pseudo filter method (type and argument)
1003 return match.slice( 0, 3 );
1009 "TAG": function( nodeName ) {
1010 if ( nodeName === "*" ) {
1011 return function() { return true; };
1014 nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
1015 return function( elem ) {
1016 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1020 "CLASS": function( className ) {
1021 var pattern = classCache[ className + " " ];
1024 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1025 classCache( className, function( elem ) {
1026 return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
1030 "ATTR": function( name, operator, check ) {
1031 return function( elem ) {
1032 var result = Sizzle.attr( elem, name );
1034 if ( result == null ) {
1035 return operator === "!=";
1043 return operator === "=" ? result === check :
1044 operator === "!=" ? result !== check :
1045 operator === "^=" ? check && result.indexOf( check ) === 0 :
1046 operator === "*=" ? check && result.indexOf( check ) > -1 :
1047 operator === "$=" ? check && result.slice( -check.length ) === check :
1048 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1049 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1054 "CHILD": function( type, what, argument, first, last ) {
1055 var simple = type.slice( 0, 3 ) !== "nth",
1056 forward = type.slice( -4 ) !== "last",
1057 ofType = what === "of-type";
1059 return first === 1 && last === 0 ?
1061 // Shortcut for :nth-*(n)
1063 return !!elem.parentNode;
1066 function( elem, context, xml ) {
1067 var cache, outerCache, node, diff, nodeIndex, start,
1068 dir = simple !== forward ? "nextSibling" : "previousSibling",
1069 parent = elem.parentNode,
1070 name = ofType && elem.nodeName.toLowerCase(),
1071 useCache = !xml && !ofType;
1075 // :(first|last|only)-(child|of-type)
1079 while ( (node = node[ dir ]) ) {
1080 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1084 // Reverse direction for :only-* (if we haven't yet done so)
1085 start = dir = type === "only" && !start && "nextSibling";
1090 start = [ forward ? parent.firstChild : parent.lastChild ];
1092 // non-xml :nth-child(...) stores cache data on `parent`
1093 if ( forward && useCache ) {
1094 // Seek `elem` from a previously-cached index
1095 outerCache = parent[ expando ] || (parent[ expando ] = {});
1096 cache = outerCache[ type ] || [];
1097 nodeIndex = cache[0] === dirruns && cache[1];
1098 diff = cache[0] === dirruns && cache[2];
1099 node = nodeIndex && parent.childNodes[ nodeIndex ];
1101 while ( (node = ++nodeIndex && node && node[ dir ] ||
1103 // Fallback to seeking `elem` from the start
1104 (diff = nodeIndex = 0) || start.pop()) ) {
1106 // When found, cache indexes on `parent` and break
1107 if ( node.nodeType === 1 && ++diff && node === elem ) {
1108 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1113 // Use previously-cached element index if available
1114 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1117 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1119 // Use the same loop as above to seek `elem` from the start
1120 while ( (node = ++nodeIndex && node && node[ dir ] ||
1121 (diff = nodeIndex = 0) || start.pop()) ) {
1123 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1124 // Cache the index of each encountered element
1126 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
1129 if ( node === elem ) {
1136 // Incorporate the offset, then check against cycle size
1138 return diff === first || ( diff % first === 0 && diff / first >= 0 );
1143 "PSEUDO": function( pseudo, argument ) {
1144 // pseudo-class names are case-insensitive
1145 // http://www.w3.org/TR/selectors/#pseudo-classes
1146 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1147 // Remember that setFilters inherits from pseudos
1149 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1150 Sizzle.error( "unsupported pseudo: " + pseudo );
1152 // The user may use createPseudo to indicate that
1153 // arguments are needed to create the filter function
1154 // just as Sizzle does
1155 if ( fn[ expando ] ) {
1156 return fn( argument );
1159 // But maintain support for old signatures
1160 if ( fn.length > 1 ) {
1161 args = [ pseudo, pseudo, "", argument ];
1162 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1163 markFunction(function( seed, matches ) {
1165 matched = fn( seed, argument ),
1168 idx = indexOf.call( seed, matched[i] );
1169 seed[ idx ] = !( matches[ idx ] = matched[i] );
1173 return fn( elem, 0, args );
1182 // Potentially complex pseudos
1183 "not": markFunction(function( selector ) {
1184 // Trim the selector passed to compile
1185 // to avoid treating leading and trailing
1186 // spaces as combinators
1189 matcher = compile( selector.replace( rtrim, "$1" ) );
1191 return matcher[ expando ] ?
1192 markFunction(function( seed, matches, context, xml ) {
1194 unmatched = matcher( seed, null, xml, [] ),
1197 // Match elements unmatched by `matcher`
1199 if ( (elem = unmatched[i]) ) {
1200 seed[i] = !(matches[i] = elem);
1204 function( elem, context, xml ) {
1206 matcher( input, null, xml, results );
1207 return !results.pop();
1211 "has": markFunction(function( selector ) {
1212 return function( elem ) {
1213 return Sizzle( selector, elem ).length > 0;
1217 "contains": markFunction(function( text ) {
1218 return function( elem ) {
1219 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
1223 // "Whether an element is represented by a :lang() selector
1224 // is based solely on the element's language value
1225 // being equal to the identifier C,
1226 // or beginning with the identifier C immediately followed by "-".
1227 // The matching of C against the element's language value is performed case-insensitively.
1228 // The identifier C does not have to be a valid language name."
1229 // http://www.w3.org/TR/selectors/#lang-pseudo
1230 "lang": markFunction( function( lang ) {
1231 // lang value must be a valid identifier
1232 if ( !ridentifier.test(lang || "") ) {
1233 Sizzle.error( "unsupported lang: " + lang );
1235 lang = lang.replace( runescape, funescape ).toLowerCase();
1236 return function( elem ) {
1239 if ( (elemLang = documentIsHTML ?
1241 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
1243 elemLang = elemLang.toLowerCase();
1244 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
1246 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
1252 "target": function( elem ) {
1253 var hash = window.location && window.location.hash;
1254 return hash && hash.slice( 1 ) === elem.id;
1257 "root": function( elem ) {
1258 return elem === docElem;
1261 "focus": function( elem ) {
1262 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
1265 // Boolean properties
1266 "enabled": function( elem ) {
1267 return elem.disabled === false;
1270 "disabled": function( elem ) {
1271 return elem.disabled === true;
1274 "checked": function( elem ) {
1275 // In CSS3, :checked should return both checked and selected elements
1276 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1277 var nodeName = elem.nodeName.toLowerCase();
1278 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
1281 "selected": function( elem ) {
1282 // Accessing this property makes selected-by-default
1283 // options in Safari work properly
1284 if ( elem.parentNode ) {
1285 elem.parentNode.selectedIndex;
1288 return elem.selected === true;
1292 "empty": function( elem ) {
1293 // http://www.w3.org/TR/selectors/#empty-pseudo
1294 // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
1295 // not comment, processing instructions, or others
1296 // Thanks to Diego Perini for the nodeName shortcut
1297 // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
1298 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1299 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
1306 "parent": function( elem ) {
1307 return !Expr.pseudos["empty"]( elem );
1310 // Element/input types
1311 "header": function( elem ) {
1312 return rheader.test( elem.nodeName );
1315 "input": function( elem ) {
1316 return rinputs.test( elem.nodeName );
1319 "button": function( elem ) {
1320 var name = elem.nodeName.toLowerCase();
1321 return name === "input" && elem.type === "button" || name === "button";
1324 "text": function( elem ) {
1326 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
1327 // use getAttribute instead to test this case
1328 return elem.nodeName.toLowerCase() === "input" &&
1329 elem.type === "text" &&
1330 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
1333 // Position-in-collection
1334 "first": createPositionalPseudo(function() {
1338 "last": createPositionalPseudo(function( matchIndexes, length ) {
1339 return [ length - 1 ];
1342 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
1343 return [ argument < 0 ? argument + length : argument ];
1346 "even": createPositionalPseudo(function( matchIndexes, length ) {
1348 for ( ; i < length; i += 2 ) {
1349 matchIndexes.push( i );
1351 return matchIndexes;
1354 "odd": createPositionalPseudo(function( matchIndexes, length ) {
1356 for ( ; i < length; i += 2 ) {
1357 matchIndexes.push( i );
1359 return matchIndexes;
1362 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1363 var i = argument < 0 ? argument + length : argument;
1364 for ( ; --i >= 0; ) {
1365 matchIndexes.push( i );
1367 return matchIndexes;
1370 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1371 var i = argument < 0 ? argument + length : argument;
1372 for ( ; ++i < length; ) {
1373 matchIndexes.push( i );
1375 return matchIndexes;
1380 // Add button/input type pseudos
1381 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
1382 Expr.pseudos[ i ] = createInputPseudo( i );
1384 for ( i in { submit: true, reset: true } ) {
1385 Expr.pseudos[ i ] = createButtonPseudo( i );
1388 function tokenize( selector, parseOnly ) {
1389 var matched, match, tokens, type,
1390 soFar, groups, preFilters,
1391 cached = tokenCache[ selector + " " ];
1394 return parseOnly ? 0 : cached.slice( 0 );
1399 preFilters = Expr.preFilter;
1403 // Comma and first run
1404 if ( !matched || (match = rcomma.exec( soFar )) ) {
1406 // Don't consume trailing commas as valid
1407 soFar = soFar.slice( match[0].length ) || soFar;
1409 groups.push( tokens = [] );
1415 if ( (match = rcombinators.exec( soFar )) ) {
1416 matched = match.shift();
1419 // Cast descendant combinators to space
1420 type: match[0].replace( rtrim, " " )
1422 soFar = soFar.slice( matched.length );
1426 for ( type in Expr.filter ) {
1427 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
1428 (match = preFilters[ type ]( match ))) ) {
1429 matched = match.shift();
1435 soFar = soFar.slice( matched.length );
1444 // Return the length of the invalid excess
1445 // if we're just parsing
1446 // Otherwise, throw an error or return tokens
1450 Sizzle.error( selector ) :
1452 tokenCache( selector, groups ).slice( 0 );
1455 function toSelector( tokens ) {
1457 len = tokens.length,
1459 for ( ; i < len; i++ ) {
1460 selector += tokens[i].value;
1465 function addCombinator( matcher, combinator, base ) {
1466 var dir = combinator.dir,
1467 checkNonElements = base && dir === "parentNode",
1470 return combinator.first ?
1471 // Check against closest ancestor/preceding element
1472 function( elem, context, xml ) {
1473 while ( (elem = elem[ dir ]) ) {
1474 if ( elem.nodeType === 1 || checkNonElements ) {
1475 return matcher( elem, context, xml );
1480 // Check against all ancestor/preceding elements
1481 function( elem, context, xml ) {
1482 var data, cache, outerCache,
1483 dirkey = dirruns + " " + doneName;
1485 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
1487 while ( (elem = elem[ dir ]) ) {
1488 if ( elem.nodeType === 1 || checkNonElements ) {
1489 if ( matcher( elem, context, xml ) ) {
1495 while ( (elem = elem[ dir ]) ) {
1496 if ( elem.nodeType === 1 || checkNonElements ) {
1497 outerCache = elem[ expando ] || (elem[ expando ] = {});
1498 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
1499 if ( (data = cache[1]) === true || data === cachedruns ) {
1500 return data === true;
1503 cache = outerCache[ dir ] = [ dirkey ];
1504 cache[1] = matcher( elem, context, xml ) || cachedruns;
1505 if ( cache[1] === true ) {
1515 function elementMatcher( matchers ) {
1516 return matchers.length > 1 ?
1517 function( elem, context, xml ) {
1518 var i = matchers.length;
1520 if ( !matchers[i]( elem, context, xml ) ) {
1529 function condense( unmatched, map, filter, context, xml ) {
1533 len = unmatched.length,
1534 mapped = map != null;
1536 for ( ; i < len; i++ ) {
1537 if ( (elem = unmatched[i]) ) {
1538 if ( !filter || filter( elem, context, xml ) ) {
1539 newUnmatched.push( elem );
1547 return newUnmatched;
1550 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
1551 if ( postFilter && !postFilter[ expando ] ) {
1552 postFilter = setMatcher( postFilter );
1554 if ( postFinder && !postFinder[ expando ] ) {
1555 postFinder = setMatcher( postFinder, postSelector );
1557 return markFunction(function( seed, results, context, xml ) {
1561 preexisting = results.length,
1563 // Get initial elements from seed or context
1564 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
1566 // Prefilter to get matcher input, preserving a map for seed-results synchronization
1567 matcherIn = preFilter && ( seed || !selector ) ?
1568 condense( elems, preMap, preFilter, context, xml ) :
1571 matcherOut = matcher ?
1572 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
1573 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
1575 // ...intermediate processing is necessary
1578 // ...otherwise use results directly
1582 // Find primary matches
1584 matcher( matcherIn, matcherOut, context, xml );
1589 temp = condense( matcherOut, postMap );
1590 postFilter( temp, [], context, xml );
1592 // Un-match failing elements by moving them back to matcherIn
1595 if ( (elem = temp[i]) ) {
1596 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
1602 if ( postFinder || preFilter ) {
1604 // Get the final matcherOut by condensing this intermediate into postFinder contexts
1606 i = matcherOut.length;
1608 if ( (elem = matcherOut[i]) ) {
1609 // Restore matcherIn since elem is not yet a final match
1610 temp.push( (matcherIn[i] = elem) );
1613 postFinder( null, (matcherOut = []), temp, xml );
1616 // Move matched elements from seed to results to keep them synchronized
1617 i = matcherOut.length;
1619 if ( (elem = matcherOut[i]) &&
1620 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
1622 seed[temp] = !(results[temp] = elem);
1627 // Add elements to results, through postFinder if defined
1629 matcherOut = condense(
1630 matcherOut === results ?
1631 matcherOut.splice( preexisting, matcherOut.length ) :
1635 postFinder( null, results, matcherOut, xml );
1637 push.apply( results, matcherOut );
1643 function matcherFromTokens( tokens ) {
1644 var checkContext, matcher, j,
1645 len = tokens.length,
1646 leadingRelative = Expr.relative[ tokens[0].type ],
1647 implicitRelative = leadingRelative || Expr.relative[" "],
1648 i = leadingRelative ? 1 : 0,
1650 // The foundational matcher ensures that elements are reachable from top-level context(s)
1651 matchContext = addCombinator( function( elem ) {
1652 return elem === checkContext;
1653 }, implicitRelative, true ),
1654 matchAnyContext = addCombinator( function( elem ) {
1655 return indexOf.call( checkContext, elem ) > -1;
1656 }, implicitRelative, true ),
1657 matchers = [ function( elem, context, xml ) {
1658 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
1659 (checkContext = context).nodeType ?
1660 matchContext( elem, context, xml ) :
1661 matchAnyContext( elem, context, xml ) );
1664 for ( ; i < len; i++ ) {
1665 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
1666 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
1668 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
1670 // Return special upon seeing a positional matcher
1671 if ( matcher[ expando ] ) {
1672 // Find the next relative operator (if any) for proper handling
1674 for ( ; j < len; j++ ) {
1675 if ( Expr.relative[ tokens[j].type ] ) {
1680 i > 1 && elementMatcher( matchers ),
1681 i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
1683 i < j && matcherFromTokens( tokens.slice( i, j ) ),
1684 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
1685 j < len && toSelector( tokens )
1688 matchers.push( matcher );
1692 return elementMatcher( matchers );
1695 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
1696 // A counter to specify which element is currently being matched
1697 var matcherCachedRuns = 0,
1698 bySet = setMatchers.length > 0,
1699 byElement = elementMatchers.length > 0,
1700 superMatcher = function( seed, context, xml, results, expandContext ) {
1701 var elem, j, matcher,
1705 unmatched = seed && [],
1706 outermost = expandContext != null,
1707 contextBackup = outermostContext,
1708 // We must always have either seed elements or context
1709 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
1710 // Use integer dirruns iff this is the outermost matcher
1711 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
1714 outermostContext = context !== document && context;
1715 cachedruns = matcherCachedRuns;
1718 // Add elements passing elementMatchers directly to results
1719 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
1720 for ( ; (elem = elems[i]) != null; i++ ) {
1721 if ( byElement && elem ) {
1723 while ( (matcher = elementMatchers[j++]) ) {
1724 if ( matcher( elem, context, xml ) ) {
1725 results.push( elem );
1730 dirruns = dirrunsUnique;
1731 cachedruns = ++matcherCachedRuns;
1735 // Track unmatched elements for set filters
1737 // They will have gone through all possible matchers
1738 if ( (elem = !matcher && elem) ) {
1742 // Lengthen the array for every element, matched or not
1744 unmatched.push( elem );
1749 // Apply set filters to unmatched elements
1751 if ( bySet && i !== matchedCount ) {
1753 while ( (matcher = setMatchers[j++]) ) {
1754 matcher( unmatched, setMatched, context, xml );
1758 // Reintegrate element matches to eliminate the need for sorting
1759 if ( matchedCount > 0 ) {
1761 if ( !(unmatched[i] || setMatched[i]) ) {
1762 setMatched[i] = pop.call( results );
1767 // Discard index placeholder values to get only actual matches
1768 setMatched = condense( setMatched );
1771 // Add matches to results
1772 push.apply( results, setMatched );
1774 // Seedless set matches succeeding multiple successful matchers stipulate sorting
1775 if ( outermost && !seed && setMatched.length > 0 &&
1776 ( matchedCount + setMatchers.length ) > 1 ) {
1778 Sizzle.uniqueSort( results );
1782 // Override manipulation of globals by nested matchers
1784 dirruns = dirrunsUnique;
1785 outermostContext = contextBackup;
1792 markFunction( superMatcher ) :
1796 compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
1799 elementMatchers = [],
1800 cached = compilerCache[ selector + " " ];
1803 // Generate a function of recursive functions that can be used to check each element
1805 group = tokenize( selector );
1809 cached = matcherFromTokens( group[i] );
1810 if ( cached[ expando ] ) {
1811 setMatchers.push( cached );
1813 elementMatchers.push( cached );
1817 // Cache the compiled function
1818 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
1823 function multipleContexts( selector, contexts, results ) {
1825 len = contexts.length;
1826 for ( ; i < len; i++ ) {
1827 Sizzle( selector, contexts[i], results );
1832 function select( selector, context, results, seed ) {
1833 var i, tokens, token, type, find,
1834 match = tokenize( selector );
1837 // Try to minimize operations if there is only one group
1838 if ( match.length === 1 ) {
1840 // Take a shortcut and set the context if the root selector is an ID
1841 tokens = match[0] = match[0].slice( 0 );
1842 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
1843 context.nodeType === 9 && documentIsHTML &&
1844 Expr.relative[ tokens[1].type ] ) {
1846 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
1851 selector = selector.slice( tokens.shift().value.length );
1854 // Fetch a seed set for right-to-left matching
1855 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
1859 // Abort if we hit a combinator
1860 if ( Expr.relative[ (type = token.type) ] ) {
1863 if ( (find = Expr.find[ type ]) ) {
1864 // Search, expanding context for leading sibling combinators
1866 token.matches[0].replace( runescape, funescape ),
1867 rsibling.test( tokens[0].type ) && context.parentNode || context
1870 // If seed is empty or no tokens remain, we can return early
1871 tokens.splice( i, 1 );
1872 selector = seed.length && toSelector( tokens );
1874 push.apply( results, seed );
1885 // Compile and execute a filtering function
1886 // Provide `match` to avoid retokenization if we modified the selector above
1887 compile( selector, match )(
1892 rsibling.test( selector )
1898 Expr.pseudos["nth"] = Expr.pseudos["eq"];
1900 // Easy API for creating new setFilters
1901 function setFilters() {}
1902 setFilters.prototype = Expr.filters = Expr.pseudos;
1903 Expr.setFilters = new setFilters();
1905 // Check sort stability
1906 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
1908 // Initialize with the default document
1911 // Always assume the presence of duplicates if sort doesn't
1912 // pass them to our comparison function (as in Google Chrome).
1913 [0, 0].sort( sortOrder );
1914 support.detectDuplicates = hasDuplicate;
1917 if ( typeof define === "function" && define.amd ) {
1918 define(function() { return Sizzle; });
1920 window.Sizzle = Sizzle;