8
8
* * Positional selectors (:first; :eq(n); :odd; etc.)
9
9
* * Type selectors (:input; :checkbox; :button; etc.)
10
10
* * 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
13
13
* * custom selectors via jQuery extensions
14
- * * Leading combinators (e.g., $collection.find("> *"))
15
14
* * 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)
18
15
* * Matching against non-elements
19
16
* * Reliable sorting of disconnected nodes
20
17
* * querySelectorAll bug fixes (e.g., unreliable :focus on WebKit)
26
23
27
24
import jQuery from "./core.js" ;
28
25
import document from "./var/document.js" ;
29
- import documentElement from "./var/documentElement.js" ;
30
26
import whitespace from "./var/whitespace.js" ;
31
27
32
28
// The following utils are attached directly to the jQuery object.
33
29
import "./selector/escapeSelector.js" ;
34
30
import "./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" ;
35
42
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 ) ;
39
47
40
48
jQuery . extend ( {
41
49
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 ,
43
55
i = 0 ;
44
56
45
57
results = results || [ ] ;
@@ -51,7 +63,7 @@ jQuery.extend( {
51
63
}
52
64
53
65
// 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 ) {
55
67
return [ ] ;
56
68
}
57
69
@@ -62,18 +74,65 @@ jQuery.extend( {
62
74
}
63
75
}
64
76
} 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
+ }
66
125
}
67
126
68
127
return results ;
69
128
} ,
70
129
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
77
136
}
78
137
} ) ;
79
138
0 commit comments