A trusted keydown for ArrowLeft/ArrowRight/Home/End (and ArrowUp/ArrowDown
on a single-line <input>) fell through Frame.user_input.editKey, which only
handled Backspace/Delete and printable keys, so the caret never moved, Shift
never extended the selection, and a plain arrow never collapsed one.
innerInsert's no-selection arm also appended to the end of the value instead
of inserting at the caret. Add a moveCaret helper to the shared text entry
mixin (byte offsets stepping over whole UTF-8 sequences, line moves bounded
by '\n'), route the keys to it from editKey, and insert at the caret.
Closes#3423
`select()`, `setSelectionRange()` and `howSelected()` in the TextEntry mixin
read the `_value` slot directly. That slot only holds an *assigned* value, so
a `<textarea>abcdef</textarea>` straight out of the parser has none and every
selection call collapsed the caret to 0 — while `textarea.value` returned
"abcdef" all along, since `getValue()` falls back to the child text node.
Route the three sites through `getValue()`, matching `innerDelete()`, which
already did. Per HTML, "set the selection range" clamps against the element's
API value, and a textarea's API value is its raw value.
`howSelected()` now also clamps: `selectionStart`/`selectionEnd` store their
argument verbatim, so an offset can outlive a shorter value and reach
`innerInsert()`'s `.partial` arm as an out-of-range slice index.
Closes#3421
macOS adds an internal 'was written' bit to F_GETFL once the fd has been
written to, so the exact comparison fails there (expected 6, found 65542)
even though the send timed out as intended and O_NONBLOCK is still set.
This was already micro-optimizes, but (a) it was needless generic and (b) was
faster than std.mem.eql in some cases, but slower than others. It now applies
both the len/ptr check skip AND the block compare.
macOS delivers loopback traffic asynchronously, so LoopTest.accept could
call Server.accept before the handshake ACK landed (NotAccepted) and the
tests could read before the request bytes landed (WouldBlock, RST, and a
double disconnect that cast a -1 socket to usize in KQueue.socketEvent).
Poll for readiness first. Also accept any non-zero SO_KEEPALIVE: BSD
getsockopt returns the option bit, not 1.
The `value` setter on <input> and <textarea> updated the value but left
the text entry cursor where it was. The HTML Standard requires it to move
the cursor to the end of the new value, unselect any selected text and
reset the selection direction to "none".
The visible consequence is that a set-then-Backspace sequence deletes
nothing: the caret is still at 0 on a fresh control, so innerDelete()
returns early.
Input.setValue moves the caret only for types that have a text entry
cursor (selectionAvailable), and uses the sanitized length so a text
input that stripped CR/LF lands on the right offset. TextArea.setValue
always has one.
setUserValue delegates to setValue, and the text_entry.zig edit paths
that need a specific caret (innerInsert's .full/.partial arms,
innerDelete) already assign the selection after calling it, so they are
unaffected. innerInsert's .none arm appends at the end and previously
left the caret behind; it now follows the inserted text.
Attribute-driven and form-reset updates assign _value directly rather
than through setValue, so they keep the caret untouched.
Closes#3419
InputEvent.initWithTrusted overwrote _bubbles/_cancelable/_composed for
every InputEvent right after Event.populatePrototypes had applied the
caller's options, forcing _cancelable = false. user_input.zig#allowEdit
asks for a cancelable beforeinput so a listener can veto the edit, but
preventDefault() is a no-op on a non-cancelable event, so the character
was inserted and `input` fired regardless.
Guard the flag block with `if (trusted)` — the shape KeyboardEvent
already uses — and derive _cancelable from the event type: `beforeinput`
is cancelable, `input` is not. Constructed events and
document.createEvent('InputEvent') now follow the EventInit dictionary
defaults instead of being forced to bubbling and composed.
Closes#3413
terminate() can cancel a still-inflight script fetch. That's a cancellation, not
a failure: a terminated worker must fire no further events, and Chrome is silent
here. We logged an error and fired an ErrorEvent — observable by Cloudflare
challenge scripts, which create a blob-URL worker and terminate it in the same
tick.
On error.TransferCanceled, skip the log and the error event; same log skip in
SharedWorkerGlobalScope.
This was tried in https://github.com/lightpanda-io/browser/pull/3189, but is
now ambiguous thanks to https://github.com/lightpanda-io/browser/pull/3368
which introduced a distinct `error.TransferCanceled`.
A custom element created in a windowless document (think DOMParser, or new
Document(), ...) doesn't have a custom element registry and thus should remain
undefined.
This repurposes the existing Frame._skip_custom_element_upgrade boolean into a
tri-state enum to capture the 3 possible states: `construct` and `bare_context`
capture the previous boolean state, and `undefined` is now used for this third
state.
This fixes (non-fatal) errors on decathlon.com. It also fixes a few WPT cases
and advances a few more (which are now failing for a different reason).
rust-url treats a trailing 'C:'/'C|' path segment as a Windows drive
letter when shortening a path with '..', for every scheme. Per the URL
Standard that exemption only applies to file:. Work around it in the
Rust binding (fix pending upstream in servo/rust-url#1138) so that
new URL('..', 'abc://x/y/z/C:/') resolves to 'abc://x/y/z/'.