diff options
author | Michał Gołębiowski-Owczarek <m.goleb@gmail.com> | 2022-12-19 18:43:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-19 18:43:30 +0100 |
commit | 09d988b774e7ff4acfb69c0cde2dab373559aaca (patch) | |
tree | 99e41463a57ab4a82c3198922f1df96ca0a33091 /src | |
parent | 024d87195ac46690023e2b0b308d4406a8a5a27e (diff) | |
download | jquery-09d988b774e7ff4acfb69c0cde2dab373559aaca.tar.gz jquery-09d988b774e7ff4acfb69c0cde2dab373559aaca.zip |
Selector: Make selector lists work with `qSA` again
jQuery 3.6.2 started using `CSS.supports( "selector(SELECTOR)" )` before using
`querySelectorAll` on the selector. This was to solve gh-5098 - some selectors,
like `:has()`, now had their parameters parsed in a forgiving way, meaning
that `:has(:fakepseudo)` no longer throws but just returns 0 results, breaking
that jQuery mechanism.
A recent spec change made `CSS.supports( "selector(SELECTOR)" )` always use
non-forgiving parsing, allowing us to use this API for what we've used
`try-catch` before.
To solve the issue on the spec side for older jQuery versions, `:has()`
parameters are no longer using forgiving parsing in the latest spec update
but our new mechanism is more future-proof anyway.
However, the jQuery implementation has a bug - in
`CSS.supports( "selector(SELECTOR)" )`, `SELECTOR` needs to be
a `<complex-selector>` and not a `<complex-selector-list>`. Which means that
selector lists now skip `qSA` and go to the jQuery custom traversal:
```js
CSS.supports("selector(div:valid, span)"); // false
CSS.supports("selector(div:valid)"); // true
CSS.supports("selector(span)"); // true
```
To solve this, this commit wraps the selector list passed to
`CSS.supports( "selector(:is(SELECTOR))" )` with `:is`, making it a single
selector again.
See:
* https://w3c.github.io/csswg-drafts/css-conditional-4/#at-supports-ext
* https://w3c.github.io/csswg-drafts/selectors-4/#typedef-complex-selector
* https://w3c.github.io/csswg-drafts/selectors-4/#typedef-complex-selector-list
Fixes gh-5177
Closes gh-5178
Ref w3c/csswg-drafts#7280
Diffstat (limited to 'src')
-rw-r--r-- | src/selector.js | 11 | ||||
-rw-r--r-- | src/selector/rbuggyQSA.js | 5 | ||||
-rw-r--r-- | src/selector/support.js | 3 |
3 files changed, 13 insertions, 6 deletions
diff --git a/src/selector.js b/src/selector.js index e6ec6a326..117ee3051 100644 --- a/src/selector.js +++ b/src/selector.js @@ -255,15 +255,20 @@ function find( selector, context, results, seed ) { // `qSA` may not throw for unrecognized parts using forgiving parsing: // https://drafts.csswg.org/selectors/#forgiving-selector - // like the `:has()` pseudo-class: - // https://drafts.csswg.org/selectors/#relational + // like the `:is()` pseudo-class: + // https://drafts.csswg.org/selectors/#matches // `CSS.supports` is still expected to return `false` then: // https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn // https://drafts.csswg.org/css-conditional-4/#dfn-support-selector if ( support.cssSupportsSelector && + // `CSS.supports( "selector(...)" )` requires the argument to the + // `selector` function to be a `<complex-selector>`, not + // a `<complex-selector-list>` which our selector may be. Wrapping with + // `:is` works around the issue and is supported by all browsers + // we support except for IE which will fail the support test anyway. // eslint-disable-next-line no-undef - !CSS.supports( "selector(" + newSelector + ")" ) ) { + !CSS.supports( "selector(:is(" + newSelector + "))" ) ) { // Support: IE 11+ // Throw to get to the same code path as an error directly in qSA. diff --git a/src/selector/rbuggyQSA.js b/src/selector/rbuggyQSA.js index e8bfd0bf7..709fb0f63 100644 --- a/src/selector/rbuggyQSA.js +++ b/src/selector/rbuggyQSA.js @@ -27,9 +27,8 @@ if ( !support.cssSupportsSelector ) { // `:has()` uses a forgiving selector list as an argument so our regular // `try-catch` mechanism fails to catch `:has()` with arguments not supported // natively like `:has(:contains("Foo"))`. Where supported & spec-compliant, - // we now use `CSS.supports("selector(SELECTOR_TO_BE_TESTED)")` but outside - // that, let's mark `:has` as buggy to always use jQuery traversal for - // `:has()`. + // we now use `CSS.supports("selector(:is(SELECTOR_TO_BE_TESTED))")`, but + // outside that we mark `:has` as buggy. rbuggyQSA.push( ":has" ); } diff --git a/src/selector/support.js b/src/selector/support.js index ea9f24050..387c41bfe 100644 --- a/src/selector/support.js +++ b/src/selector/support.js @@ -1,5 +1,8 @@ import support from "../var/support.js"; +// Support: IE 11+ +// IE doesn't support `CSS.supports( "selector(...)" )`; it will throw +// in this support test. try { /* eslint-disable no-undef */ |