Address review feedback on the legacy KeyboardEvent.keyCode and
KeyboardEvent.charCode getters:
* `getKeyCode` and `getCharCode` now early-return 0 when the event is
not trusted, matching Chrome's behavior. Synthetic events created via
`new KeyboardEvent(...)` from script have `isTrusted === false` and
therefore expose 0 for both legacy attributes; only events dispatched
by the user agent itself surface the legacy mapping.
* `getCharCode` now uses `_type_string.eql(comptime .wrap("keypress"))`
to match the idiom used elsewhere in the project.
* The charCode mapping is moved into a pure `Key.charCode()` helper that
mirrors `Key.keyCode()`, including a `.Enter => 13` arm so a trusted
`keypress` for Enter exposes `\r` (U+000D) per spec.
The JS test fixture is consolidated into a single block asserting the
Chrome-correct behavior for synthetic events. The full per-key mapping
table is now exercised via two pure-function Zig unit tests on
`Key.keyCode()` and `Key.charCode()`.
Both getters were stubs returning 0. Per W3C UI Events § Annex C, keyCode
should report the legacy fixed virtual key code for the key being pressed
(e.g. 84 for 't'/'T', 16 for Shift, 13 for Enter), and charCode should
report the Unicode code point of the character produced on keypress events.
Adds a keyCode() method to the Key union that maps each named variant to
its spec-defined value and computes the uppercase-ASCII fallback for
.standard printable characters. getKeyCode delegates to it. getCharCode
checks the event type and returns the first byte of _key.standard for
keypress, 0 elsewhere.
For shift-modified symbol keys (e.g. shift+1='!'), keyCode falls back to
the modified char's ASCII rather than the unmodified key's value, since
KeyboardEvent doesn't currently store the unmodified key. Spec-strict
behavior would need plumbing unmodifiedText through KeyboardEventOptions
— left as a follow-up.
Closes#2291
- Drop redundant `step_attr.len == 3` guard in `snapToStep`. Zig's
`std.ascii.eqlIgnoreCase` already short-circuits on length mismatch
(`ascii.zig:329`), so the outer length check is wasted work.
- Implement the `value` content attribute fallback for step base.
Per https://html.spec.whatwg.org/multipage/input.html#concept-input-min
the chain is `min` content attr -> `value` content attr -> 0. The
fallback was previously skipped (step base went straight from `min`
to 0), which meant `<input type=range value="3.5" max=10>` then
`el.value = '5.3'` snapped to `5` instead of the spec-required `5.5`.
Threads `value_attr` through `sanitizeRange` so the fallback engages
whenever `min` is absent or unparseable but a parseable `value`
content attr exists.
Three new test cases cover the fallback path (s10), the unparseable
`value` attr that falls through to 0 (s11), and `min` taking precedence
over `value` attr (s12).
Anchor click, form submit, and `location.href = ...` assignments queue a
navigation through `Frame.scheduleNavigation`, which then tears down the
originating page and rebuilds the frame in `Session.processRootQueuedNavigation`
before `Frame.navigate` issues the HTTP request. The originator's URL was
discarded with the old arena, so the request went out without a Referer
header — even though the HTML "navigate" algorithm and Fetch §4.5 require
one. `Frame.headersForRequest` (#1449) handled subresource fetches but was
never called from the navigation path.
Capture the originating frame's URL into a new `referer` field on
`NavigateOpts` at scheduling time, dup'd into the `QueuedNavigation` arena
so it survives the page tear-down. `Frame.navigate` adds it as a
`Referer:` header alongside the existing per-request headers. Iframe
initial navigation (`Frame.zig:1282`) also sets `referer = parent.url`
since the parent frame outlives that direct `navigate` call. CDP
`Page.navigate` (`.reason = .address_bar`) and `Page.reload` continue to
omit Referer — matches Chrome.
Closes#2281
Per WHATWG HTML "Suffering from a step mismatch", value sanitization for
<input type=range> rounds the value to the nearest valid `step base + step * n`
after the existing min/max clamp. Ties round toward positive infinity; if the
rounded-up neighbor exceeds max, the rounded-down neighbor is used instead.
`step` defaults to 1; `step="any"` (case-insensitive) disables step matching.
When the post-snap value matches the parsed input value exactly, the original
string is returned unchanged so assignments like `el.value = "1.0"` round-trip
without canonicalization.
Closes#2277