88 * * Positional selectors (:first; :eq(n); :odd; etc.)
99 * * Type selectors (:input; :checkbox; :button; etc.)
1010 * * State-based selectors (:animated; :visible; :hidden; etc.)
11- * * :has(selector)
12- * * :not(complex selector)
11+ * * :has(selector) in browsers without native support
12+ * * :not(complex selector) in IE
1313 * * custom selectors via jQuery extensions
14- * * Leading combinators (e.g., $collection.find("> *"))
1514 * * Reliable functionality on XML fragments
16- * * Requiring all parts of a selector to match elements under context
17- * (e.g., $div.find("div > *") now matches children of $div)
1815 * * Matching against non-elements
1916 * * Reliable sorting of disconnected nodes
2017 * * querySelectorAll bug fixes (e.g., unreliable :focus on WebKit)
2623
2724import jQuery from "./core.js" ;
2825import document from "./var/document.js" ;
29- import documentElement from "./var/documentElement.js" ;
3026import whitespace from "./var/whitespace.js" ;
3127
3228// The following utils are attached directly to the jQuery object.
3329import "./selector/escapeSelector.js" ;
3430import "./selector/uniqueSort.js" ;
31+ import isIE from "./var/isIE.js" ;
32+ import booleans from "./selector/var/booleans.js" ;
33+ import rleadingCombinator from "./selector/var/rleadingCombinator.js" ;
34+ import rdescend from "./selector/var/rdescend.js" ;
35+ import rsibling from "./selector/var/rsibling.js" ;
36+ import matches from "./selector/var/matches.js" ;
37+ import testContext from "./selector/testContext.js" ;
38+ import filterMatchExpr from "./selector/filterMatchExpr.js" ;
39+ import preFilter from "./selector/preFilter.js" ;
40+ import tokenize from "./selector/tokenize.js" ;
41+ import toSelector from "./selector/toSelector.js" ;
3542
36- // Support: IE 9 - 11+
37- // IE requires a prefix.
38- var matches = documentElement . matches || documentElement . msMatchesSelector ;
43+ var matchExpr = jQuery . extend ( {
44+ bool : new RegExp ( "^(?:" + booleans + ")$" , "i" ) ,
45+ needsContext : new RegExp ( "^" + whitespace + "*[>+~]" )
46+ } , filterMatchExpr ) ;
3947
4048jQuery . extend ( {
4149 find : function ( selector , context , results , seed ) {
42- var elem , nodeType ,
50+ var elem , nid , groups , newSelector ,
51+ newContext = context && context . ownerDocument ,
52+
53+ // nodeType defaults to 9, since context defaults to document
54+ nodeType = context ? context . nodeType : 9 ,
4355 i = 0 ;
4456
4557 results = results || [ ] ;
@@ -51,7 +63,7 @@ jQuery.extend( {
5163 }
5264
5365 // Early return if context is not an element, document or document fragment
54- if ( ( nodeType = context . nodeType ) !== 1 && nodeType !== 9 && nodeType !== 11 ) {
66+ if ( nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
5567 return [ ] ;
5668 }
5769
@@ -62,18 +74,65 @@ jQuery.extend( {
6274 }
6375 }
6476 } else {
65- jQuery . merge ( results , context . querySelectorAll ( selector ) ) ;
77+
78+ newSelector = selector ;
79+ newContext = context ;
80+
81+ // qSA considers elements outside a scoping root when evaluating child or
82+ // descendant combinators, which is not what we want.
83+ // In such cases, we work around the behavior by prefixing every selector in the
84+ // list with an ID selector referencing the scope context.
85+ // The technique has to be used as well when a leading combinator is used
86+ // as such selectors are not recognized by querySelectorAll.
87+ // Thanks to Andrew Dupont for this technique.
88+ if ( nodeType === 1 &&
89+ ( rdescend . test ( selector ) || rleadingCombinator . test ( selector ) ) ) {
90+
91+ // Expand context for sibling selectors
92+ newContext = rsibling . test ( selector ) &&
93+ testContext ( context . parentNode ) ||
94+ context ;
95+
96+ // Outside of IE, if we're not changing the context we can
97+ // use :scope instead of an ID.
98+ if ( newContext !== context || isIE ) {
99+
100+ // Capture the context ID, setting it first if necessary
101+ if ( ( nid = context . getAttribute ( "id" ) ) ) {
102+ nid = jQuery . escapeSelector ( nid ) ;
103+ } else {
104+ context . setAttribute ( "id" , ( nid = jQuery . expando ) ) ;
105+ }
106+ }
107+
108+ // Prefix every selector in the list
109+ groups = tokenize ( selector ) ;
110+ i = groups . length ;
111+ while ( i -- ) {
112+ groups [ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
113+ toSelector ( groups [ i ] ) ;
114+ }
115+ newSelector = groups . join ( "," ) ;
116+ }
117+
118+ try {
119+ jQuery . merge ( results , newContext . querySelectorAll ( newSelector ) ) ;
120+ } finally {
121+ if ( nid === jQuery . expando ) {
122+ context . removeAttribute ( "id" ) ;
123+ }
124+ }
66125 }
67126
68127 return results ;
69128 } ,
70129 expr : {
71- attrHandle : { } ,
72- match : {
73- bool : new RegExp ( "^(?:checked|selected|async|autofocus|autoplay|controls|defer" +
74- "|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$" , "i" ) ,
75- needsContext : new RegExp ( "^" + whitespace + "*[>+~]" )
76- }
130+
131+ // Can be adjusted by the user
132+ cacheLength : 50 ,
133+
134+ match : matchExpr ,
135+ preFilter : preFilter
77136 }
78137} ) ;
79138
0 commit comments