`CSS.supports( "selector(...)" )` has different semantics than selectors passed
to `querySelectorAll`. Apart from the fact that the former returns `false` for
unrecognized selectors and the latter throws, `qSA` is more forgiving and
accepts some invalid selectors, auto-correcting them where needed - for
example, mismatched brackers are auto-closed. This behavior difference is
breaking for many users.
To add to that, a recent CSSWG resolution made `:is()` & `:where()` the only
pseudos with forgiving parsing; browsers are in the process of making `:has()`
parsing unforgiving.
Taking all that into account, we go back to our previous try-catch approach
without relying on `CSS.supports( "selector(...)" )`. The only difference
is we detect forgiving parsing in `:has()` and mark the selector as buggy.
Fixesjquery/jquery#5194
Closes gh-493
Ref jquery/jquery#5098
Ref jquery/jquery#5206
Ref jquery/jquery#5207
Ref gh-486
Ref w3c/csswg-drafts#7676
Sizzle 2.3.7 started using `CSS.supports( "selector(SELECTOR)" )` before using
`querySelectorAll` on the selector. This was to solve jquery/jquery#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 Sizzle 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 Sizzle 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 Sizzle 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-listFixesjquery/jquery#5177
Closes gh-491
Ref w3c/csswg-drafts#7280
The `<template/>` element `contents` property is a document fragment that may
have a `null` `documentElement`. In Safari 16 this happens in more cases due
to recent spec changes - in particular, even if that document fragment is
explicitly adopted into an outer document. We're testing both of those cases
now.
The above behavior made `Sizzle.contains` crash when run on certain elements
within the `<template/>` element. As it turns out, we don't need
to query the supposed container `documentElement` if it has the
`Node.DOCUMENT_NODE` (9) `nodeType`; we can call `.contains()` directly on
the `document`. That avoids the crash.
However, we still need to fall back to `documentElement` if one is
defined as IE <9 have a broken `.contains()` on the document.
Fixesjquery/jquery#5147
Closes gh-490
Ref jquery/jquery#5158
Sizzle 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 Sizzle custom traversal instead.
It worked fine so far but now CSS has a concept of forgiving selector lists that
some selectors like `:is()` & `:has()` use. That means providing unrecognized
selectors as parameters to `:is()` & `:has()` no longer throws an error, it will
just return no results. That made browsers with native `:has()` support break
selectors using jQuery extensions inside, e.g. `:has(:contains("Item"))`.
Detecting support for selectors can also be done via:
```js
CSS.supports( "selector(SELECTOR_TO_BE_TESTED)" )
```
which returns a boolean. There was a recent spec change requiring this API to
always use non-forgiving parsing:
https://github.com/w3c/csswg-drafts/issues/7280#issuecomment-1143852187
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.
Fixesjquery/jquery#5098
Closes gh-486
Ref jquery/jquery#5107
Ref w3c/csswg-drafts#7676
Running `grunt` will now just build Sizzle, do a size comparison & run ESLint,
similarly to what we do in jQuery. `grunt test` is used to run unit tests and
it requires running `grunt` or `grunt build` before to generate the built
Sizzle version.
Fixes gh-239
Closes gh-467
qSA in IE 11/Edge often (but not always) don't find elements with an empty
name attribute selector (`[name=""]`). Detect that & fall back to Sizzle
traversal.
Interestingly, IE 10 & older don't seem to have the issue.
Closes gh-461
Fixesjquery/jquery#4435
PR gh-456 introduced a test catching not throwing on badly-escaped identifiers
by Firefox 3.6-5. Unfortunately, it was placed just before a test Opera 10-11
fails, making Opera fail quicker and not adding a post-comma invalid selector
to rbuggyQSA.
This commit fixes the regression & introduces a unit test ensuring the throwing.
Unfortunately, the issue is fixed in Opera 11.6 which is the lowest one Sizzle
officially supports but I verified the fix manually against Opera 10.6, 11.1
& 11.5.
Closes gh-463
Ref gh-456
There was a test for Shadow DOM nodes working as root but it was using Shadow
DOM v0 that only Chromium implements and which it plans to remove in the future.
The test was reworked to rely on Shadow DOM v1.
jQuery master already uses the new API in its tests.
Closes gh-464
An optimization added in jquery/sizzle#431 skips the temporary IDs for selectors
not using child or descendant combinators. For sibling combinators, though, this
pushes a selector with a leading combinator to qSA directly which crashes and
falls back to a slower Sizzle route.
This commit makes selectors with leading combinators not skip the selector
rewriting. Note that after jquery/jquery#4454 & jquery/sizzle#453, all modern
browsers other than Edge leverage the :scope pseudo-class, avoiding temporary
id attributes.
Closes gh-460
Ref gh-431
The `:scope` pseudo-class[1] has surprisingly good browser support: Chrome,
Firefox & Safari have supported if for a long time; only IE & Edge lack support.
This commit leverages this pseudo-class to get rid of the ID hack in most cases.
Adding a temporary ID may cause layout thrashing which was reported a few times
in [the past.
We can't completely eliminate the ID hack in modern browses as sibling selectors
require us to change context to the parent and then `:scope` stops applying to
what we'd like. But it'd still improve performance in the vast majority of
cases.
[1] https://developer.mozilla.org/en-US/docs/Web/CSS/:scopeFixesjquery/jquery#4453
Closes gh-453
Ref jquery/jquery#4454
Ref jquery/jquery#4332
Ref gh-405
IE/Edge sometimes crash when comparing documents between frames using the strict
equality operator (`===` & `!==`). Funnily enough, shallow comparisons
(`==` & `!=`) work without crashing.
Fixesjquery/jquery#4441
Closes gh-459
Ref jquery/jquery#4471
The Karma version currently used by Sizzle often re-runs tests in all browsers
from the current browser set if one of them fails. To improve reliability, split
iOS into two browser sets similarly to how desktop browsers & Android are split.
Closes gh-457
Sizzle hasn't been able to finish all its unit tests successfully for a long time. This commit attempts to make it work again (at least most of the time).
Summary of the changes:
1. A new "karma-tests" task is created; it runs tests in various browser sets
but does it sequentially in separate processes to avoid Karma bugs that cause
browsers from previous sets to somehow still be waited on during subsequent
runs, failing the build.
2. Upgrade tested browsers.
3. Run iOS tests at the end (as it fails more often than other browsers).
4. Use real iOS 10.3 device in Karma.
We can't upgrade Karma as the latest version (`4.2.0`) hangs in IE 7 (IE 8 seems to work fine there).
Closes gh-455
According to:
https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
the escape doesn't need to be followed by a whitespace only if it's not a hex
digit or a newline. However, old Firefox (3.6 - 5 only) doesn't throw if an
escaped newline is not followed by a space. Fallback to Sizzle in such cases.
Fixes gh-454
Closes gh-456