mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 09:46:05 -04:00
webapi: invoke event target separately for capture and bubble passes
Fixes the failing test in WPT /dom/events/Event-dispatch-handlers-
changed.html ("Dispatch additional events inside an event listener").
At the target, listeners were run in a single pass mixing capture and
bubble listeners, with one snapshot of the listener list. Per the DOM
dispatch algorithm, the target participates in both the capturing and
the bubbling iterations of the event path, and each invoke clones the
listener list separately: a bubble listener added by one of the
target's capture listeners must run during the bubbling pass. The
single pass used one snapshot, so such a listener never ran.
The at-target step now dispatches twice — capture listeners first, then
non-capture listeners — re-fetching the listener list (and taking a new
sentinel snapshot) for the second pass, and honoring stopPropagation /
stopImmediatePropagation between the two.
Coverage: /dom/events/Event-dispatch-handlers-changed.html 0/1 -> 1/1,
/dom/events/EventTarget-dispatchEvent.html 4/25 -> 5/25. No regressions
across /dom/events.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Karl Seguin
parent
27ba864697
commit
b59400c836
@@ -300,8 +300,18 @@ fn dispatchNode(self: *EventManager, target: *Node, event: *Event, comptime opts
|
||||
}
|
||||
}
|
||||
|
||||
// Per spec, the target is invoked once during the capturing iteration
|
||||
// and once during the bubbling iteration, each with its own snapshot
|
||||
// of the listener list: a bubble listener added while running the
|
||||
// target's capture listeners must run.
|
||||
if (self.base.getListeners(target_et, event._type_string)) |list| {
|
||||
try self.dispatchPhase(list, target_et, event, &was_handled, &ls.local, comptime .init(null, opts));
|
||||
try self.dispatchPhase(list, target_et, event, &was_handled, &ls.local, comptime .init(true, opts));
|
||||
if (event._stop_propagation) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (self.base.getListeners(target_et, event._type_string)) |list| {
|
||||
try self.dispatchPhase(list, target_et, event, &was_handled, &ls.local, comptime .init(false, opts));
|
||||
if (event._stop_propagation) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user