Manipulation: Support $el.html(selfRemovingScript) (#5378)
[jquery.git] / src / selector.js
blobd71e65ad4a99b4c02dec65dcde5559ead8553b49
1 import { jQuery } from "./core.js";
2 import { nodeName } from "./core/nodeName.js";
3 import { document as preferredDoc } from "./var/document.js";
4 import { indexOf } from "./var/indexOf.js";
5 import { pop } from "./var/pop.js";
6 import { push } from "./var/push.js";
7 import { whitespace } from "./var/whitespace.js";
8 import { rbuggyQSA } from "./selector/rbuggyQSA.js";
9 import { rtrimCSS } from "./var/rtrimCSS.js";
10 import { isIE } from "./var/isIE.js";
11 import { identifier } from "./selector/var/identifier.js";
12 import { booleans } from "./selector/var/booleans.js";
13 import { rleadingCombinator } from "./selector/var/rleadingCombinator.js";
14 import { rdescend } from "./selector/var/rdescend.js";
15 import { rsibling } from "./selector/var/rsibling.js";
16 import { matches } from "./selector/var/matches.js";
17 import { createCache } from "./selector/createCache.js";
18 import { testContext } from "./selector/testContext.js";
19 import { filterMatchExpr } from "./selector/filterMatchExpr.js";
20 import { preFilter } from "./selector/preFilter.js";
21 import { selectorError } from "./selector/selectorError.js";
22 import { unescapeSelector } from "./selector/unescapeSelector.js";
23 import { tokenize } from "./selector/tokenize.js";
24 import { toSelector } from "./selector/toSelector.js";
26 // The following utils are attached directly to the jQuery object.
27 import "./selector/escapeSelector.js";
28 import "./selector/uniqueSort.js";
30 var i,
31         outermostContext,
33         // Local document vars
34         document,
35         documentElement,
36         documentIsHTML,
38         // Instance-specific data
39         dirruns = 0,
40         done = 0,
41         classCache = createCache(),
42         compilerCache = createCache(),
43         nonnativeSelectorCache = createCache(),
45         // Regular expressions
47         // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
48         rwhitespace = new RegExp( whitespace + "+", "g" ),
50         ridentifier = new RegExp( "^" + identifier + "$" ),
52         matchExpr = jQuery.extend( {
53                 bool: new RegExp( "^(?:" + booleans + ")$", "i" ),
55                 // For use in libraries implementing .is()
56                 // We use this for POS matching in `select`
57                 needsContext: new RegExp( "^" + whitespace +
58                         "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
59                         "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
60         }, filterMatchExpr ),
62         rinputs = /^(?:input|select|textarea|button)$/i,
63         rheader = /^h\d$/i,
65         // Easily-parseable/retrievable ID or TAG or CLASS selectors
66         rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
68         // Used for iframes; see `setDocument`.
69         // Support: IE 9 - 11+
70         // Removing the function wrapper causes a "Permission Denied"
71         // error in IE.
72         unloadHandler = function() {
73                 setDocument();
74         },
76         inDisabledFieldset = addCombinator(
77                 function( elem ) {
78                         return elem.disabled === true && nodeName( elem, "fieldset" );
79                 },
80                 { dir: "parentNode", next: "legend" }
81         );
83 function find( selector, context, results, seed ) {
84         var m, i, elem, nid, match, groups, newSelector,
85                 newContext = context && context.ownerDocument,
87                 // nodeType defaults to 9, since context defaults to document
88                 nodeType = context ? context.nodeType : 9;
90         results = results || [];
92         // Return early from calls with invalid selector or context
93         if ( typeof selector !== "string" || !selector ||
94                 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
96                 return results;
97         }
99         // Try to shortcut find operations (as opposed to filters) in HTML documents
100         if ( !seed ) {
101                 setDocument( context );
102                 context = context || document;
104                 if ( documentIsHTML ) {
106                         // If the selector is sufficiently simple, try using a "get*By*" DOM method
107                         // (excepting DocumentFragment context, where the methods don't exist)
108                         if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
110                                 // ID selector
111                                 if ( ( m = match[ 1 ] ) ) {
113                                         // Document context
114                                         if ( nodeType === 9 ) {
115                                                 if ( ( elem = context.getElementById( m ) ) ) {
116                                                         push.call( results, elem );
117                                                 }
118                                                 return results;
120                                         // Element context
121                                         } else {
122                                                 if ( newContext && ( elem = newContext.getElementById( m ) ) &&
123                                                         jQuery.contains( context, elem ) ) {
125                                                         push.call( results, elem );
126                                                         return results;
127                                                 }
128                                         }
130                                 // Type selector
131                                 } else if ( match[ 2 ] ) {
132                                         push.apply( results, context.getElementsByTagName( selector ) );
133                                         return results;
135                                 // Class selector
136                                 } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {
137                                         push.apply( results, context.getElementsByClassName( m ) );
138                                         return results;
139                                 }
140                         }
142                         // Take advantage of querySelectorAll
143                         if ( !nonnativeSelectorCache[ selector + " " ] &&
144                                 ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {
146                                 newSelector = selector;
147                                 newContext = context;
149                                 // qSA considers elements outside a scoping root when evaluating child or
150                                 // descendant combinators, which is not what we want.
151                                 // In such cases, we work around the behavior by prefixing every selector in the
152                                 // list with an ID selector referencing the scope context.
153                                 // The technique has to be used as well when a leading combinator is used
154                                 // as such selectors are not recognized by querySelectorAll.
155                                 // Thanks to Andrew Dupont for this technique.
156                                 if ( nodeType === 1 &&
157                                         ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {
159                                         // Expand context for sibling selectors
160                                         newContext = rsibling.test( selector ) &&
161                                                 testContext( context.parentNode ) ||
162                                                 context;
164                                         // Outside of IE, if we're not changing the context we can
165                                         // use :scope instead of an ID.
166                                         // Support: IE 11+
167                                         // IE sometimes throws a "Permission denied" error when strict-comparing
168                                         // two documents; shallow comparisons work.
169                                         // eslint-disable-next-line eqeqeq
170                                         if ( newContext != context || isIE ) {
172                                                 // Capture the context ID, setting it first if necessary
173                                                 if ( ( nid = context.getAttribute( "id" ) ) ) {
174                                                         nid = jQuery.escapeSelector( nid );
175                                                 } else {
176                                                         context.setAttribute( "id", ( nid = jQuery.expando ) );
177                                                 }
178                                         }
180                                         // Prefix every selector in the list
181                                         groups = tokenize( selector );
182                                         i = groups.length;
183                                         while ( i-- ) {
184                                                 groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
185                                                         toSelector( groups[ i ] );
186                                         }
187                                         newSelector = groups.join( "," );
188                                 }
190                                 try {
191                                         push.apply( results,
192                                                 newContext.querySelectorAll( newSelector )
193                                         );
194                                         return results;
195                                 } catch ( qsaError ) {
196                                         nonnativeSelectorCache( selector, true );
197                                 } finally {
198                                         if ( nid === jQuery.expando ) {
199                                                 context.removeAttribute( "id" );
200                                         }
201                                 }
202                         }
203                 }
204         }
206         // All others
207         return select( selector.replace( rtrimCSS, "$1" ), context, results, seed );
211  * Mark a function for special use by jQuery selector module
212  * @param {Function} fn The function to mark
213  */
214 function markFunction( fn ) {
215         fn[ jQuery.expando ] = true;
216         return fn;
220  * Returns a function to use in pseudos for input types
221  * @param {String} type
222  */
223 function createInputPseudo( type ) {
224         return function( elem ) {
225                 return nodeName( elem, "input" ) && elem.type === type;
226         };
230  * Returns a function to use in pseudos for buttons
231  * @param {String} type
232  */
233 function createButtonPseudo( type ) {
234         return function( elem ) {
235                 return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) &&
236                         elem.type === type;
237         };
241  * Returns a function to use in pseudos for :enabled/:disabled
242  * @param {Boolean} disabled true for :disabled; false for :enabled
243  */
244 function createDisabledPseudo( disabled ) {
246         // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
247         return function( elem ) {
249                 // Only certain elements can match :enabled or :disabled
250                 // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
251                 // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
252                 if ( "form" in elem ) {
254                         // Check for inherited disabledness on relevant non-disabled elements:
255                         // * listed form-associated elements in a disabled fieldset
256                         //   https://html.spec.whatwg.org/multipage/forms.html#category-listed
257                         //   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
258                         // * option elements in a disabled optgroup
259                         //   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
260                         // All such elements have a "form" property.
261                         if ( elem.parentNode && elem.disabled === false ) {
263                                 // Option elements defer to a parent optgroup if present
264                                 if ( "label" in elem ) {
265                                         if ( "label" in elem.parentNode ) {
266                                                 return elem.parentNode.disabled === disabled;
267                                         } else {
268                                                 return elem.disabled === disabled;
269                                         }
270                                 }
272                                 // Support: IE 6 - 11+
273                                 // Use the isDisabled shortcut property to check for disabled fieldset ancestors
274                                 return elem.isDisabled === disabled ||
276                                         // Where there is no isDisabled, check manually
277                                         elem.isDisabled !== !disabled &&
278                                                 inDisabledFieldset( elem ) === disabled;
279                         }
281                         return elem.disabled === disabled;
283                 // Try to winnow out elements that can't be disabled before trusting the disabled property.
284                 // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
285                 // even exist on them, let alone have a boolean value.
286                 } else if ( "label" in elem ) {
287                         return elem.disabled === disabled;
288                 }
290                 // Remaining elements are neither :enabled nor :disabled
291                 return false;
292         };
296  * Returns a function to use in pseudos for positionals
297  * @param {Function} fn
298  */
299 function createPositionalPseudo( fn ) {
300         return markFunction( function( argument ) {
301                 argument = +argument;
302                 return markFunction( function( seed, matches ) {
303                         var j,
304                                 matchIndexes = fn( [], seed.length, argument ),
305                                 i = matchIndexes.length;
307                         // Match elements found at the specified indexes
308                         while ( i-- ) {
309                                 if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
310                                         seed[ j ] = !( matches[ j ] = seed[ j ] );
311                                 }
312                         }
313                 } );
314         } );
318  * Sets document-related variables once based on the current document
319  * @param {Element|Object} [node] An element or document object to use to set the document
320  */
321 function setDocument( node ) {
322         var subWindow,
323                 doc = node ? node.ownerDocument || node : preferredDoc;
325         // Return early if doc is invalid or already selected
326         // Support: IE 11+
327         // IE sometimes throws a "Permission denied" error when strict-comparing
328         // two documents; shallow comparisons work.
329         // eslint-disable-next-line eqeqeq
330         if ( doc == document || doc.nodeType !== 9 ) {
331                 return;
332         }
334         // Update global variables
335         document = doc;
336         documentElement = document.documentElement;
337         documentIsHTML = !jQuery.isXMLDoc( document );
339         // Support: IE 9 - 11+
340         // Accessing iframe documents after unload throws "permission denied" errors (see trac-13936)
341         // Support: IE 11+
342         // IE sometimes throws a "Permission denied" error when strict-comparing
343         // two documents; shallow comparisons work.
344         // eslint-disable-next-line eqeqeq
345         if ( isIE && preferredDoc != document &&
346                 ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
347                 subWindow.addEventListener( "unload", unloadHandler );
348         }
351 find.matches = function( expr, elements ) {
352         return find( expr, null, null, elements );
355 find.matchesSelector = function( elem, expr ) {
356         setDocument( elem );
358         if ( documentIsHTML &&
359                 !nonnativeSelectorCache[ expr + " " ] &&
360                 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
362                 try {
363                         return matches.call( elem, expr );
364                 } catch ( e ) {
365                         nonnativeSelectorCache( expr, true );
366                 }
367         }
369         return find( expr, document, null, [ elem ] ).length > 0;
372 jQuery.expr = {
374         // Can be adjusted by the user
375         cacheLength: 50,
377         createPseudo: markFunction,
379         match: matchExpr,
381         find: {
382                 ID: function( id, context ) {
383                         if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
384                                 var elem = context.getElementById( id );
385                                 return elem ? [ elem ] : [];
386                         }
387                 },
389                 TAG: function( tag, context ) {
390                         if ( typeof context.getElementsByTagName !== "undefined" ) {
391                                 return context.getElementsByTagName( tag );
393                                 // DocumentFragment nodes don't have gEBTN
394                         } else {
395                                 return context.querySelectorAll( tag );
396                         }
397                 },
399                 CLASS: function( className, context ) {
400                         if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
401                                 return context.getElementsByClassName( className );
402                         }
403                 }
404         },
406         relative: {
407                 ">": { dir: "parentNode", first: true },
408                 " ": { dir: "parentNode" },
409                 "+": { dir: "previousSibling", first: true },
410                 "~": { dir: "previousSibling" }
411         },
413         preFilter: preFilter,
415         filter: {
416                 ID: function( id ) {
417                         var attrId = unescapeSelector( id );
418                         return function( elem ) {
419                                 return elem.getAttribute( "id" ) === attrId;
420                         };
421                 },
423                 TAG: function( nodeNameSelector ) {
424                         var expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();
425                         return nodeNameSelector === "*" ?
427                                 function() {
428                                         return true;
429                                 } :
431                                 function( elem ) {
432                                         return nodeName( elem, expectedNodeName );
433                                 };
434                 },
436                 CLASS: function( className ) {
437                         var pattern = classCache[ className + " " ];
439                         return pattern ||
440                                 ( pattern = new RegExp( "(^|" + whitespace + ")" + className +
441                                         "(" + whitespace + "|$)" ) ) &&
442                                 classCache( className, function( elem ) {
443                                         return pattern.test(
444                                                 typeof elem.className === "string" && elem.className ||
445                                                         typeof elem.getAttribute !== "undefined" &&
446                                                                 elem.getAttribute( "class" ) ||
447                                                         ""
448                                         );
449                                 } );
450                 },
452                 ATTR: function( name, operator, check ) {
453                         return function( elem ) {
454                                 var result = jQuery.attr( elem, name );
456                                 if ( result == null ) {
457                                         return operator === "!=";
458                                 }
459                                 if ( !operator ) {
460                                         return true;
461                                 }
463                                 result += "";
465                                 if ( operator === "=" ) {
466                                         return result === check;
467                                 }
468                                 if ( operator === "!=" ) {
469                                         return result !== check;
470                                 }
471                                 if ( operator === "^=" ) {
472                                         return check && result.indexOf( check ) === 0;
473                                 }
474                                 if ( operator === "*=" ) {
475                                         return check && result.indexOf( check ) > -1;
476                                 }
477                                 if ( operator === "$=" ) {
478                                         return check && result.slice( -check.length ) === check;
479                                 }
480                                 if ( operator === "~=" ) {
481                                         return ( " " + result.replace( rwhitespace, " " ) + " " )
482                                                 .indexOf( check ) > -1;
483                                 }
484                                 if ( operator === "|=" ) {
485                                         return result === check || result.slice( 0, check.length + 1 ) === check + "-";
486                                 }
488                                 return false;
489                         };
490                 },
492                 CHILD: function( type, what, _argument, first, last ) {
493                         var simple = type.slice( 0, 3 ) !== "nth",
494                                 forward = type.slice( -4 ) !== "last",
495                                 ofType = what === "of-type";
497                         return first === 1 && last === 0 ?
499                                 // Shortcut for :nth-*(n)
500                                 function( elem ) {
501                                         return !!elem.parentNode;
502                                 } :
504                                 function( elem, _context, xml ) {
505                                         var cache, outerCache, node, nodeIndex, start,
506                                                 dir = simple !== forward ? "nextSibling" : "previousSibling",
507                                                 parent = elem.parentNode,
508                                                 name = ofType && elem.nodeName.toLowerCase(),
509                                                 useCache = !xml && !ofType,
510                                                 diff = false;
512                                         if ( parent ) {
514                                                 // :(first|last|only)-(child|of-type)
515                                                 if ( simple ) {
516                                                         while ( dir ) {
517                                                                 node = elem;
518                                                                 while ( ( node = node[ dir ] ) ) {
519                                                                         if ( ofType ?
520                                                                                 nodeName( node, name ) :
521                                                                                 node.nodeType === 1 ) {
523                                                                                 return false;
524                                                                         }
525                                                                 }
527                                                                 // Reverse direction for :only-* (if we haven't yet done so)
528                                                                 start = dir = type === "only" && !start && "nextSibling";
529                                                         }
530                                                         return true;
531                                                 }
533                                                 start = [ forward ? parent.firstChild : parent.lastChild ];
535                                                 // non-xml :nth-child(...) stores cache data on `parent`
536                                                 if ( forward && useCache ) {
538                                                         // Seek `elem` from a previously-cached index
539                                                         outerCache = parent[ jQuery.expando ] ||
540                                                                 ( parent[ jQuery.expando ] = {} );
541                                                         cache = outerCache[ type ] || [];
542                                                         nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
543                                                         diff = nodeIndex && cache[ 2 ];
544                                                         node = nodeIndex && parent.childNodes[ nodeIndex ];
546                                                         while ( ( node = ++nodeIndex && node && node[ dir ] ||
548                                                                 // Fallback to seeking `elem` from the start
549                                                                 ( diff = nodeIndex = 0 ) || start.pop() ) ) {
551                                                                 // When found, cache indexes on `parent` and break
552                                                                 if ( node.nodeType === 1 && ++diff && node === elem ) {
553                                                                         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
554                                                                         break;
555                                                                 }
556                                                         }
558                                                 } else {
560                                                         // Use previously-cached element index if available
561                                                         if ( useCache ) {
562                                                                 outerCache = elem[ jQuery.expando ] ||
563                                                                         ( elem[ jQuery.expando ] = {} );
564                                                                 cache = outerCache[ type ] || [];
565                                                                 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
566                                                                 diff = nodeIndex;
567                                                         }
569                                                         // xml :nth-child(...)
570                                                         // or :nth-last-child(...) or :nth(-last)?-of-type(...)
571                                                         if ( diff === false ) {
573                                                                 // Use the same loop as above to seek `elem` from the start
574                                                                 while ( ( node = ++nodeIndex && node && node[ dir ] ||
575                                                                         ( diff = nodeIndex = 0 ) || start.pop() ) ) {
577                                                                         if ( ( ofType ?
578                                                                                 nodeName( node, name ) :
579                                                                                 node.nodeType === 1 ) &&
580                                                                                 ++diff ) {
582                                                                                 // Cache the index of each encountered element
583                                                                                 if ( useCache ) {
584                                                                                         outerCache = node[ jQuery.expando ] ||
585                                                                                                 ( node[ jQuery.expando ] = {} );
586                                                                                         outerCache[ type ] = [ dirruns, diff ];
587                                                                                 }
589                                                                                 if ( node === elem ) {
590                                                                                         break;
591                                                                                 }
592                                                                         }
593                                                                 }
594                                                         }
595                                                 }
597                                                 // Incorporate the offset, then check against cycle size
598                                                 diff -= last;
599                                                 return diff === first || ( diff % first === 0 && diff / first >= 0 );
600                                         }
601                                 };
602                 },
604                 PSEUDO: function( pseudo, argument ) {
606                         // pseudo-class names are case-insensitive
607                         // https://www.w3.org/TR/selectors/#pseudo-classes
608                         // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
609                         // Remember that setFilters inherits from pseudos
610                         var fn = jQuery.expr.pseudos[ pseudo ] ||
611                                 jQuery.expr.setFilters[ pseudo.toLowerCase() ] ||
612                                 selectorError( "unsupported pseudo: " + pseudo );
614                         // The user may use createPseudo to indicate that
615                         // arguments are needed to create the filter function
616                         // just as jQuery does
617                         if ( fn[ jQuery.expando ] ) {
618                                 return fn( argument );
619                         }
621                         return fn;
622                 }
623         },
625         pseudos: {
627                 // Potentially complex pseudos
628                 not: markFunction( function( selector ) {
630                         // Trim the selector passed to compile
631                         // to avoid treating leading and trailing
632                         // spaces as combinators
633                         var input = [],
634                                 results = [],
635                                 matcher = compile( selector.replace( rtrimCSS, "$1" ) );
637                         return matcher[ jQuery.expando ] ?
638                                 markFunction( function( seed, matches, _context, xml ) {
639                                         var elem,
640                                                 unmatched = matcher( seed, null, xml, [] ),
641                                                 i = seed.length;
643                                         // Match elements unmatched by `matcher`
644                                         while ( i-- ) {
645                                                 if ( ( elem = unmatched[ i ] ) ) {
646                                                         seed[ i ] = !( matches[ i ] = elem );
647                                                 }
648                                         }
649                                 } ) :
650                                 function( elem, _context, xml ) {
651                                         input[ 0 ] = elem;
652                                         matcher( input, null, xml, results );
654                                         // Don't keep the element
655                                         // (see https://github.com/jquery/sizzle/issues/299)
656                                         input[ 0 ] = null;
657                                         return !results.pop();
658                                 };
659                 } ),
661                 has: markFunction( function( selector ) {
662                         return function( elem ) {
663                                 return find( selector, elem ).length > 0;
664                         };
665                 } ),
667                 contains: markFunction( function( text ) {
668                         text = unescapeSelector( text );
669                         return function( elem ) {
670                                 return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;
671                         };
672                 } ),
674                 // "Whether an element is represented by a :lang() selector
675                 // is based solely on the element's language value
676                 // being equal to the identifier C,
677                 // or beginning with the identifier C immediately followed by "-".
678                 // The matching of C against the element's language value is performed case-insensitively.
679                 // The identifier C does not have to be a valid language name."
680                 // https://www.w3.org/TR/selectors/#lang-pseudo
681                 lang: markFunction( function( lang ) {
683                         // lang value must be a valid identifier
684                         if ( !ridentifier.test( lang || "" ) ) {
685                                 selectorError( "unsupported lang: " + lang );
686                         }
687                         lang = unescapeSelector( lang ).toLowerCase();
688                         return function( elem ) {
689                                 var elemLang;
690                                 do {
691                                         if ( ( elemLang = documentIsHTML ?
692                                                 elem.lang :
693                                                 elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
695                                                 elemLang = elemLang.toLowerCase();
696                                                 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
697                                         }
698                                 } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
699                                 return false;
700                         };
701                 } ),
703                 // Miscellaneous
704                 target: function( elem ) {
705                         var hash = window.location && window.location.hash;
706                         return hash && hash.slice( 1 ) === elem.id;
707                 },
709                 root: function( elem ) {
710                         return elem === documentElement;
711                 },
713                 focus: function( elem ) {
714                         return elem === document.activeElement &&
715                                 document.hasFocus() &&
716                                 !!( elem.type || elem.href || ~elem.tabIndex );
717                 },
719                 // Boolean properties
720                 enabled: createDisabledPseudo( false ),
721                 disabled: createDisabledPseudo( true ),
723                 checked: function( elem ) {
725                         // In CSS3, :checked should return both checked and selected elements
726                         // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
727                         return ( nodeName( elem, "input" ) && !!elem.checked ) ||
728                                 ( nodeName( elem, "option" ) && !!elem.selected );
729                 },
731                 selected: function( elem ) {
733                         // Support: IE <=11+
734                         // Accessing the selectedIndex property
735                         // forces the browser to treat the default option as
736                         // selected when in an optgroup.
737                         if ( isIE && elem.parentNode ) {
738                                 // eslint-disable-next-line no-unused-expressions
739                                 elem.parentNode.selectedIndex;
740                         }
742                         return elem.selected === true;
743                 },
745                 // Contents
746                 empty: function( elem ) {
748                         // https://www.w3.org/TR/selectors/#empty-pseudo
749                         // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
750                         //   but not by others (comment: 8; processing instruction: 7; etc.)
751                         // nodeType < 6 works because attributes (2) do not appear as children
752                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
753                                 if ( elem.nodeType < 6 ) {
754                                         return false;
755                                 }
756                         }
757                         return true;
758                 },
760                 parent: function( elem ) {
761                         return !jQuery.expr.pseudos.empty( elem );
762                 },
764                 // Element/input types
765                 header: function( elem ) {
766                         return rheader.test( elem.nodeName );
767                 },
769                 input: function( elem ) {
770                         return rinputs.test( elem.nodeName );
771                 },
773                 button: function( elem ) {
774                         return nodeName( elem, "input" ) && elem.type === "button" ||
775                                 nodeName( elem, "button" );
776                 },
778                 text: function( elem ) {
779                         return nodeName( elem, "input" ) && elem.type === "text";
780                 },
782                 // Position-in-collection
783                 first: createPositionalPseudo( function() {
784                         return [ 0 ];
785                 } ),
787                 last: createPositionalPseudo( function( _matchIndexes, length ) {
788                         return [ length - 1 ];
789                 } ),
791                 eq: createPositionalPseudo( function( _matchIndexes, length, argument ) {
792                         return [ argument < 0 ? argument + length : argument ];
793                 } ),
795                 even: createPositionalPseudo( function( matchIndexes, length ) {
796                         var i = 0;
797                         for ( ; i < length; i += 2 ) {
798                                 matchIndexes.push( i );
799                         }
800                         return matchIndexes;
801                 } ),
803                 odd: createPositionalPseudo( function( matchIndexes, length ) {
804                         var i = 1;
805                         for ( ; i < length; i += 2 ) {
806                                 matchIndexes.push( i );
807                         }
808                         return matchIndexes;
809                 } ),
811                 lt: createPositionalPseudo( function( matchIndexes, length, argument ) {
812                         var i;
814                         if ( argument < 0 ) {
815                                 i = argument + length;
816                         } else if ( argument > length ) {
817                                 i = length;
818                         } else {
819                                 i = argument;
820                         }
822                         for ( ; --i >= 0; ) {
823                                 matchIndexes.push( i );
824                         }
825                         return matchIndexes;
826                 } ),
828                 gt: createPositionalPseudo( function( matchIndexes, length, argument ) {
829                         var i = argument < 0 ? argument + length : argument;
830                         for ( ; ++i < length; ) {
831                                 matchIndexes.push( i );
832                         }
833                         return matchIndexes;
834                 } )
835         }
838 jQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;
840 // Add button/input type pseudos
841 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
842         jQuery.expr.pseudos[ i ] = createInputPseudo( i );
844 for ( i in { submit: true, reset: true } ) {
845         jQuery.expr.pseudos[ i ] = createButtonPseudo( i );
848 // Easy API for creating new setFilters
849 function setFilters() {}
850 setFilters.prototype = jQuery.expr.filters = jQuery.expr.pseudos;
851 jQuery.expr.setFilters = new setFilters();
853 function addCombinator( matcher, combinator, base ) {
854         var dir = combinator.dir,
855                 skip = combinator.next,
856                 key = skip || dir,
857                 checkNonElements = base && key === "parentNode",
858                 doneName = done++;
860         return combinator.first ?
862                 // Check against closest ancestor/preceding element
863                 function( elem, context, xml ) {
864                         while ( ( elem = elem[ dir ] ) ) {
865                                 if ( elem.nodeType === 1 || checkNonElements ) {
866                                         return matcher( elem, context, xml );
867                                 }
868                         }
869                         return false;
870                 } :
872                 // Check against all ancestor/preceding elements
873                 function( elem, context, xml ) {
874                         var oldCache, outerCache,
875                                 newCache = [ dirruns, doneName ];
877                         // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
878                         if ( xml ) {
879                                 while ( ( elem = elem[ dir ] ) ) {
880                                         if ( elem.nodeType === 1 || checkNonElements ) {
881                                                 if ( matcher( elem, context, xml ) ) {
882                                                         return true;
883                                                 }
884                                         }
885                                 }
886                         } else {
887                                 while ( ( elem = elem[ dir ] ) ) {
888                                         if ( elem.nodeType === 1 || checkNonElements ) {
889                                                 outerCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );
891                                                 if ( skip && nodeName( elem, skip ) ) {
892                                                         elem = elem[ dir ] || elem;
893                                                 } else if ( ( oldCache = outerCache[ key ] ) &&
894                                                         oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
896                                                         // Assign to newCache so results back-propagate to previous elements
897                                                         return ( newCache[ 2 ] = oldCache[ 2 ] );
898                                                 } else {
900                                                         // Reuse newcache so results back-propagate to previous elements
901                                                         outerCache[ key ] = newCache;
903                                                         // A match means we're done; a fail means we have to keep checking
904                                                         if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
905                                                                 return true;
906                                                         }
907                                                 }
908                                         }
909                                 }
910                         }
911                         return false;
912                 };
915 function elementMatcher( matchers ) {
916         return matchers.length > 1 ?
917                 function( elem, context, xml ) {
918                         var i = matchers.length;
919                         while ( i-- ) {
920                                 if ( !matchers[ i ]( elem, context, xml ) ) {
921                                         return false;
922                                 }
923                         }
924                         return true;
925                 } :
926                 matchers[ 0 ];
929 function multipleContexts( selector, contexts, results ) {
930         var i = 0,
931                 len = contexts.length;
932         for ( ; i < len; i++ ) {
933                 find( selector, contexts[ i ], results );
934         }
935         return results;
938 function condense( unmatched, map, filter, context, xml ) {
939         var elem,
940                 newUnmatched = [],
941                 i = 0,
942                 len = unmatched.length,
943                 mapped = map != null;
945         for ( ; i < len; i++ ) {
946                 if ( ( elem = unmatched[ i ] ) ) {
947                         if ( !filter || filter( elem, context, xml ) ) {
948                                 newUnmatched.push( elem );
949                                 if ( mapped ) {
950                                         map.push( i );
951                                 }
952                         }
953                 }
954         }
956         return newUnmatched;
959 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
960         if ( postFilter && !postFilter[ jQuery.expando ] ) {
961                 postFilter = setMatcher( postFilter );
962         }
963         if ( postFinder && !postFinder[ jQuery.expando ] ) {
964                 postFinder = setMatcher( postFinder, postSelector );
965         }
966         return markFunction( function( seed, results, context, xml ) {
967                 var temp, i, elem, matcherOut,
968                         preMap = [],
969                         postMap = [],
970                         preexisting = results.length,
972                         // Get initial elements from seed or context
973                         elems = seed ||
974                                 multipleContexts( selector || "*",
975                                         context.nodeType ? [ context ] : context, [] ),
977                         // Prefilter to get matcher input, preserving a map for seed-results synchronization
978                         matcherIn = preFilter && ( seed || !selector ) ?
979                                 condense( elems, preMap, preFilter, context, xml ) :
980                                 elems;
982                 if ( matcher ) {
984                         // If we have a postFinder, or filtered seed, or non-seed postFilter
985                         // or preexisting results,
986                         matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
988                                 // ...intermediate processing is necessary
989                                 [] :
991                                 // ...otherwise use results directly
992                                 results;
994                         // Find primary matches
995                         matcher( matcherIn, matcherOut, context, xml );
996                 } else {
997                         matcherOut = matcherIn;
998                 }
1000                 // Apply postFilter
1001                 if ( postFilter ) {
1002                         temp = condense( matcherOut, postMap );
1003                         postFilter( temp, [], context, xml );
1005                         // Un-match failing elements by moving them back to matcherIn
1006                         i = temp.length;
1007                         while ( i-- ) {
1008                                 if ( ( elem = temp[ i ] ) ) {
1009                                         matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
1010                                 }
1011                         }
1012                 }
1014                 if ( seed ) {
1015                         if ( postFinder || preFilter ) {
1016                                 if ( postFinder ) {
1018                                         // Get the final matcherOut by condensing this intermediate into postFinder contexts
1019                                         temp = [];
1020                                         i = matcherOut.length;
1021                                         while ( i-- ) {
1022                                                 if ( ( elem = matcherOut[ i ] ) ) {
1024                                                         // Restore matcherIn since elem is not yet a final match
1025                                                         temp.push( ( matcherIn[ i ] = elem ) );
1026                                                 }
1027                                         }
1028                                         postFinder( null, ( matcherOut = [] ), temp, xml );
1029                                 }
1031                                 // Move matched elements from seed to results to keep them synchronized
1032                                 i = matcherOut.length;
1033                                 while ( i-- ) {
1034                                         if ( ( elem = matcherOut[ i ] ) &&
1035                                                 ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {
1037                                                 seed[ temp ] = !( results[ temp ] = elem );
1038                                         }
1039                                 }
1040                         }
1042                 // Add elements to results, through postFinder if defined
1043                 } else {
1044                         matcherOut = condense(
1045                                 matcherOut === results ?
1046                                         matcherOut.splice( preexisting, matcherOut.length ) :
1047                                         matcherOut
1048                         );
1049                         if ( postFinder ) {
1050                                 postFinder( null, results, matcherOut, xml );
1051                         } else {
1052                                 push.apply( results, matcherOut );
1053                         }
1054                 }
1055         } );
1058 function matcherFromTokens( tokens ) {
1059         var checkContext, matcher, j,
1060                 len = tokens.length,
1061                 leadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],
1062                 implicitRelative = leadingRelative || jQuery.expr.relative[ " " ],
1063                 i = leadingRelative ? 1 : 0,
1065                 // The foundational matcher ensures that elements are reachable from top-level context(s)
1066                 matchContext = addCombinator( function( elem ) {
1067                         return elem === checkContext;
1068                 }, implicitRelative, true ),
1069                 matchAnyContext = addCombinator( function( elem ) {
1070                         return indexOf.call( checkContext, elem ) > -1;
1071                 }, implicitRelative, true ),
1072                 matchers = [ function( elem, context, xml ) {
1074                         // Support: IE 11+
1075                         // IE sometimes throws a "Permission denied" error when strict-comparing
1076                         // two documents; shallow comparisons work.
1077                         // eslint-disable-next-line eqeqeq
1078                         var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (
1079                                 ( checkContext = context ).nodeType ?
1080                                         matchContext( elem, context, xml ) :
1081                                         matchAnyContext( elem, context, xml ) );
1083                         // Avoid hanging onto element
1084                         // (see https://github.com/jquery/sizzle/issues/299)
1085                         checkContext = null;
1086                         return ret;
1087                 } ];
1089         for ( ; i < len; i++ ) {
1090                 if ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {
1091                         matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
1092                 } else {
1093                         matcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
1095                         // Return special upon seeing a positional matcher
1096                         if ( matcher[ jQuery.expando ] ) {
1098                                 // Find the next relative operator (if any) for proper handling
1099                                 j = ++i;
1100                                 for ( ; j < len; j++ ) {
1101                                         if ( jQuery.expr.relative[ tokens[ j ].type ] ) {
1102                                                 break;
1103                                         }
1104                                 }
1105                                 return setMatcher(
1106                                         i > 1 && elementMatcher( matchers ),
1107                                         i > 1 && toSelector(
1109                                                 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
1110                                                 tokens.slice( 0, i - 1 )
1111                                                         .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
1112                                         ).replace( rtrimCSS, "$1" ),
1113                                         matcher,
1114                                         i < j && matcherFromTokens( tokens.slice( i, j ) ),
1115                                         j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
1116                                         j < len && toSelector( tokens )
1117                                 );
1118                         }
1119                         matchers.push( matcher );
1120                 }
1121         }
1123         return elementMatcher( matchers );
1126 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
1127         var bySet = setMatchers.length > 0,
1128                 byElement = elementMatchers.length > 0,
1129                 superMatcher = function( seed, context, xml, results, outermost ) {
1130                         var elem, j, matcher,
1131                                 matchedCount = 0,
1132                                 i = "0",
1133                                 unmatched = seed && [],
1134                                 setMatched = [],
1135                                 contextBackup = outermostContext,
1137                                 // We must always have either seed elements or outermost context
1138                                 elems = seed || byElement && jQuery.expr.find.TAG( "*", outermost ),
1140                                 // Use integer dirruns iff this is the outermost matcher
1141                                 dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );
1143                         if ( outermost ) {
1145                                 // Support: IE 11+
1146                                 // IE sometimes throws a "Permission denied" error when strict-comparing
1147                                 // two documents; shallow comparisons work.
1148                                 // eslint-disable-next-line eqeqeq
1149                                 outermostContext = context == document || context || outermost;
1150                         }
1152                         // Add elements passing elementMatchers directly to results
1153                         for ( ; ( elem = elems[ i ] ) != null; i++ ) {
1154                                 if ( byElement && elem ) {
1155                                         j = 0;
1157                                         // Support: IE 11+
1158                                         // IE sometimes throws a "Permission denied" error when strict-comparing
1159                                         // two documents; shallow comparisons work.
1160                                         // eslint-disable-next-line eqeqeq
1161                                         if ( !context && elem.ownerDocument != document ) {
1162                                                 setDocument( elem );
1163                                                 xml = !documentIsHTML;
1164                                         }
1165                                         while ( ( matcher = elementMatchers[ j++ ] ) ) {
1166                                                 if ( matcher( elem, context || document, xml ) ) {
1167                                                         push.call( results, elem );
1168                                                         break;
1169                                                 }
1170                                         }
1171                                         if ( outermost ) {
1172                                                 dirruns = dirrunsUnique;
1173                                         }
1174                                 }
1176                                 // Track unmatched elements for set filters
1177                                 if ( bySet ) {
1179                                         // They will have gone through all possible matchers
1180                                         if ( ( elem = !matcher && elem ) ) {
1181                                                 matchedCount--;
1182                                         }
1184                                         // Lengthen the array for every element, matched or not
1185                                         if ( seed ) {
1186                                                 unmatched.push( elem );
1187                                         }
1188                                 }
1189                         }
1191                         // `i` is now the count of elements visited above, and adding it to `matchedCount`
1192                         // makes the latter nonnegative.
1193                         matchedCount += i;
1195                         // Apply set filters to unmatched elements
1196                         // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
1197                         // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
1198                         // no element matchers and no seed.
1199                         // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
1200                         // case, which will result in a "00" `matchedCount` that differs from `i` but is also
1201                         // numerically zero.
1202                         if ( bySet && i !== matchedCount ) {
1203                                 j = 0;
1204                                 while ( ( matcher = setMatchers[ j++ ] ) ) {
1205                                         matcher( unmatched, setMatched, context, xml );
1206                                 }
1208                                 if ( seed ) {
1210                                         // Reintegrate element matches to eliminate the need for sorting
1211                                         if ( matchedCount > 0 ) {
1212                                                 while ( i-- ) {
1213                                                         if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
1214                                                                 setMatched[ i ] = pop.call( results );
1215                                                         }
1216                                                 }
1217                                         }
1219                                         // Discard index placeholder values to get only actual matches
1220                                         setMatched = condense( setMatched );
1221                                 }
1223                                 // Add matches to results
1224                                 push.apply( results, setMatched );
1226                                 // Seedless set matches succeeding multiple successful matchers stipulate sorting
1227                                 if ( outermost && !seed && setMatched.length > 0 &&
1228                                         ( matchedCount + setMatchers.length ) > 1 ) {
1230                                         jQuery.uniqueSort( results );
1231                                 }
1232                         }
1234                         // Override manipulation of globals by nested matchers
1235                         if ( outermost ) {
1236                                 dirruns = dirrunsUnique;
1237                                 outermostContext = contextBackup;
1238                         }
1240                         return unmatched;
1241                 };
1243         return bySet ?
1244                 markFunction( superMatcher ) :
1245                 superMatcher;
1248 function compile( selector, match /* Internal Use Only */ ) {
1249         var i,
1250                 setMatchers = [],
1251                 elementMatchers = [],
1252                 cached = compilerCache[ selector + " " ];
1254         if ( !cached ) {
1256                 // Generate a function of recursive functions that can be used to check each element
1257                 if ( !match ) {
1258                         match = tokenize( selector );
1259                 }
1260                 i = match.length;
1261                 while ( i-- ) {
1262                         cached = matcherFromTokens( match[ i ] );
1263                         if ( cached[ jQuery.expando ] ) {
1264                                 setMatchers.push( cached );
1265                         } else {
1266                                 elementMatchers.push( cached );
1267                         }
1268                 }
1270                 // Cache the compiled function
1271                 cached = compilerCache( selector,
1272                         matcherFromGroupMatchers( elementMatchers, setMatchers ) );
1274                 // Save selector and tokenization
1275                 cached.selector = selector;
1276         }
1277         return cached;
1281  * A low-level selection function that works with jQuery's compiled
1282  *  selector functions
1283  * @param {String|Function} selector A selector or a pre-compiled
1284  *  selector function built with jQuery selector compile
1285  * @param {Element} context
1286  * @param {Array} [results]
1287  * @param {Array} [seed] A set of elements to match against
1288  */
1289 function select( selector, context, results, seed ) {
1290         var i, tokens, token, type, find,
1291                 compiled = typeof selector === "function" && selector,
1292                 match = !seed && tokenize( ( selector = compiled.selector || selector ) );
1294         results = results || [];
1296         // Try to minimize operations if there is only one selector in the list and no seed
1297         // (the latter of which guarantees us context)
1298         if ( match.length === 1 ) {
1300                 // Reduce context if the leading compound selector is an ID
1301                 tokens = match[ 0 ] = match[ 0 ].slice( 0 );
1302                 if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
1303                                 context.nodeType === 9 && documentIsHTML &&
1304                                 jQuery.expr.relative[ tokens[ 1 ].type ] ) {
1306                         context = ( jQuery.expr.find.ID(
1307                                 unescapeSelector( token.matches[ 0 ] ),
1308                                 context
1309                         ) || [] )[ 0 ];
1310                         if ( !context ) {
1311                                 return results;
1313                         // Precompiled matchers will still verify ancestry, so step up a level
1314                         } else if ( compiled ) {
1315                                 context = context.parentNode;
1316                         }
1318                         selector = selector.slice( tokens.shift().value.length );
1319                 }
1321                 // Fetch a seed set for right-to-left matching
1322                 i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;
1323                 while ( i-- ) {
1324                         token = tokens[ i ];
1326                         // Abort if we hit a combinator
1327                         if ( jQuery.expr.relative[ ( type = token.type ) ] ) {
1328                                 break;
1329                         }
1330                         if ( ( find = jQuery.expr.find[ type ] ) ) {
1332                                 // Search, expanding context for leading sibling combinators
1333                                 if ( ( seed = find(
1334                                         unescapeSelector( token.matches[ 0 ] ),
1335                                         rsibling.test( tokens[ 0 ].type ) &&
1336                                                 testContext( context.parentNode ) || context
1337                                 ) ) ) {
1339                                         // If seed is empty or no tokens remain, we can return early
1340                                         tokens.splice( i, 1 );
1341                                         selector = seed.length && toSelector( tokens );
1342                                         if ( !selector ) {
1343                                                 push.apply( results, seed );
1344                                                 return results;
1345                                         }
1347                                         break;
1348                                 }
1349                         }
1350                 }
1351         }
1353         // Compile and execute a filtering function if one is not provided
1354         // Provide `match` to avoid retokenization if we modified the selector above
1355         ( compiled || compile( selector, match ) )(
1356                 seed,
1357                 context,
1358                 !documentIsHTML,
1359                 results,
1360                 !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
1361         );
1362         return results;
1365 // Initialize against the default document
1366 setDocument();
1368 jQuery.find = find;
1370 // These have always been private, but they used to be documented as part of
1371 // Sizzle so let's maintain them for now for backwards compatibility purposes.
1372 find.compile = compile;
1373 find.select = select;
1374 find.setDocument = setDocument;
1375 find.tokenize = tokenize;
1377 export { jQuery, jQuery as $ };