Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd153c37

Browse files
authored
Selector: Use jQuery:has ifCSS.supports(selector(...)) non-compliant
jQuery has followed the following logic for selector handling for ages:1. Modify the selector to adhere to scoping rules jQuery mandates.2. Try `qSA` on the modified selector. If it succeeds, use the results.3. If `qSA` threw an error, run the jQuery custom traversal instead.It worked fine so far but now CSS has a concept of forgiving selector lists thatsome selectors like `:is()` & `:has()` use. That means providing unrecognizedselectors as parameters to `:is()` & `:has()` no longer throws an error, it willjust return no results. That made browsers with native `:has()` support breakselectors using jQuery extensions inside, e.g. `:has(:contains("Item"))`.Detecting support for selectors can also be done via:```jsCSS.supports( "selector(SELECTOR_TO_BE_TESTED)" )```which returns a boolean. There was a recent spec change requiring this API toalways use non-forgiving parsing:w3c/csswg-drafts#7280 (comment)However, no browsers have implemented this change so far.To solve this, two changes are being made:1. In browsers supports the new spec change to `CSS.supports( "selector()" )`, use it before trying `qSA`.2. Otherwise, add `:has` to the buggy selectors list.Fixesgh-5098Closesgh-5107Refw3c/csswg-drafts#7676
1 parent78321f0 commitd153c37

File tree

5 files changed

+97
-17
lines changed

5 files changed

+97
-17
lines changed

‎src/selector.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import whitespace from "./var/whitespace.js";
99
importrbuggyQSAfrom"./selector/rbuggyQSA.js";
1010
importrtrimfrom"./var/rtrim.js";
1111
importisIEfrom"./var/isIE.js";
12+
importsupportfrom"./selector/support.js";
1213

1314
// The following utils are attached directly to the jQuery object.
1415
import"./selector/contains.js";
@@ -252,6 +253,27 @@ function find( selector, context, results, seed ) {
252253
}
253254

254255
try{
256+
257+
// `qSA` may not throw for unrecognized parts using forgiving parsing:
258+
// https://drafts.csswg.org/selectors/#forgiving-selector
259+
// like the `:has()` pseudo-class:
260+
// https://drafts.csswg.org/selectors/#relational
261+
// `CSS.supports` is still expected to return `false` then:
262+
// https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn
263+
// https://drafts.csswg.org/css-conditional-4/#dfn-support-selector
264+
if(support.cssSupportsSelector&&
265+
266+
// eslint-disable-next-line no-undef
267+
!CSS.supports("selector("+newSelector+")")){
268+
269+
// Support: IE 11+
270+
// Throw to get to the same code path as an error directly in qSA.
271+
// Note: once we only support browser supporting
272+
// `CSS.supports('selector(...)')`, we can most likely drop
273+
// the `try-catch`. IE doesn't implement the API.
274+
thrownewError();
275+
}
276+
255277
push.apply(results,
256278
newContext.querySelectorAll(newSelector)
257279
);

‎src/selector/rbuggyQSA.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
importisIEfrom"../var/isIE.js";
22
importwhitespacefrom"../var/whitespace.js";
3+
importsupportfrom"./support.js";
34

4-
varrbuggyQSA=isIE&&newRegExp(
5+
varrbuggyQSA=[];
56

6-
// Support: IE 9 - 11+
7-
// IE's :disabled selector does not pick up the children of disabled fieldsets
8-
":enabled|:disabled|"+
7+
if(isIE){
8+
rbuggyQSA.push(
99

10-
// Support: IE 11+
11-
// IE 11 doesn't find elements on a `[name='']` query in some cases.
12-
// Adding a temporary attribute to the document before the selection works
13-
// around the issue.
14-
"\\["+whitespace+"*name"+whitespace+"*="+
15-
whitespace+"*(?:''|\"\")"
10+
// Support: IE 9 - 11+
11+
// IE's :disabled selector does not pick up the children of disabled fieldsets
12+
":enabled",
13+
":disabled",
1614

17-
);
15+
// Support: IE 11+
16+
// IE 11 doesn't find elements on a `[name='']` query in some cases.
17+
// Adding a temporary attribute to the document before the selection works
18+
// around the issue.
19+
"\\["+whitespace+"*name"+whitespace+"*="+
20+
whitespace+"*(?:''|\"\")"
21+
);
22+
}
23+
24+
if(!support.cssSupportsSelector){
25+
26+
// Support: Chrome 105+, Safari 15.4+
27+
// `:has()` uses a forgiving selector list as an argument so our regular
28+
// `try-catch` mechanism fails to catch `:has()` with arguments not supported
29+
// natively like `:has(:contains("Foo"))`. Where supported & spec-compliant,
30+
// we now use `CSS.supports("selector(SELECTOR_TO_BE_TESTED)")` but outside
31+
// that, let's mark `:has` as buggy to always use jQuery traversal for
32+
// `:has()`.
33+
rbuggyQSA.push(":has");
34+
}
35+
36+
rbuggyQSA=rbuggyQSA.length&&newRegExp(rbuggyQSA.join("|"));
1837

1938
exportdefaultrbuggyQSA;

‎src/selector/support.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
importsupportfrom"../var/support.js";
2+
3+
try{
4+
/* eslint-disable no-undef */
5+
6+
// Support: Chrome 105+, Firefox 104+, Safari 15.4+
7+
// Make sure forgiving mode is not used in `CSS.supports( "selector(...)" )`.
8+
//
9+
// `:is()` uses a forgiving selector list as an argument and is widely
10+
// implemented, so it's a good one to test against.
11+
support.cssSupportsSelector=CSS.supports("selector(*)")&&
12+
13+
// `*` is needed as Safari & newer Chrome implemented something in between
14+
// for `:has()` - it throws in `qSA` if it only contains an unsupported
15+
// argument but multiple ones, one of which is supported, are fine.
16+
// We want to play safe in case `:is()` gets the same treatment.
17+
!CSS.supports("selector(:is(*,:jqfake))");
18+
19+
/* eslint-enable */
20+
}catch(e){
21+
support.cssSupportsSelector=false;
22+
}
23+
24+
exportdefaultsupport;

‎test/unit/selector.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,13 +931,23 @@ QUnit.test( "pseudo - nth-last-of-type", function( assert ) {
931931
});
932932

933933
QUnit[QUnit.jQuerySelectors ?"test" :"skip"]("pseudo - has",function(assert){
934-
assert.expect(3);
934+
assert.expect(4);
935935

936936
assert.t("Basic test","p:has(a)",["firstp","ap","en","sap"]);
937937
assert.t("Basic test (irrelevant whitespace)","p:has( a )",["firstp","ap","en","sap"]);
938938
assert.t("Nested with overlapping candidates",
939939
"#qunit-fixture div:has(div:has(div:not([id])))",
940940
["moretests","t2037","fx-test-group","fx-queue"]);
941+
942+
// Support: Safari 15.4+, Chrome 105+
943+
// `qSA` in Safari/Chrome throws for `:has()` with only unsupported arguments
944+
// but if you add a supported arg to the list, it will run and just potentially
945+
// return no results. Make sure this is accounted for. (gh-5098)
946+
// Note: Chrome 105 has this behavior only in 105.0.5195.125 or newer;
947+
// initially it shipped with a fully forgiving parsing in `:has()`.
948+
assert.t("Nested with list arguments",
949+
"#qunit-fixture div:has(faketag, div:has(faketag, div:not([id])))",
950+
["moretests","t2037","fx-test-group","fx-queue"]);
941951
});
942952

943953
QUnit[QUnit.jQuerySelectors ?"test" :"skip"]("pseudo - contains",function(assert){

‎test/unit/support.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,24 @@ testIframe(
5959
userAgent=window.navigator.userAgent,
6060
expectedMap={
6161
ie_11:{
62-
"reliableTrDimensions":false
62+
cssSupportsSelector:false,
63+
reliableTrDimensions:false
6364
},
6465
chrome:{
65-
"reliableTrDimensions":true
66+
cssSupportsSelector:false,
67+
reliableTrDimensions:true
6668
},
6769
safari:{
68-
"reliableTrDimensions":true
70+
cssSupportsSelector:false,
71+
reliableTrDimensions:true
6972
},
7073
firefox:{
71-
"reliableTrDimensions":false
74+
cssSupportsSelector:false,
75+
reliableTrDimensions:false
7276
},
7377
ios:{
74-
"reliableTrDimensions":true
78+
cssSupportsSelector:false,
79+
reliableTrDimensions:true
7580
}
7681
};
7782

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp