mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-07 20:01:47 -04:00
webapi: fix UIEvent.view default, initCustomEvent guard, KeyboardEvent flags
Fixes 4 failing tests in WPT /dom/events/Event-init-while-dispatching.html
(1/5 -> 5/5), and as a side effect most of
Event-subclasses-constructors.html (16/49 -> 46/49). Three distinct
bugs, all about synthetic (constructor-created) events not following
the spec's dictionary defaults:
- UIEvent.view defaulted to the window: the constructor stored
`opts.view orelse frame.window` and the getter fell back to the
window too, so `new UIEvent("x").view` was never null. Per
UIEventInit, view defaults to null. The window fallback is kept for
*trusted* (browser-generated) UI events only, which do target the
window, so internal dispatch call sites stay unchanged.
- initCustomEvent was missing the "short-circuit while dispatching"
guard that initEvent and the other legacy initializers have.
- KeyboardEvent's constructor unconditionally forced bubbles,
cancelable and composed to true (correct only for trusted key events
per UI Events); synthetic KeyboardEvents now follow the EventInit
defaults.
The unit tests asserting the old view-defaults-to-window behavior are
updated to expect null.
Coverage: /dom/events/Event-init-while-dispatching.html 1/5 -> 5/5,
/dom/events/Event-subclasses-constructors.html 16/49 -> 46/49. No
regressions across /dom/events.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b2cfc35f4
commit
b309640ab0
5 files changed
+29
-11
No files matched your search
@@ -11,7 +11,8 @@
|
||||
testing.expectEqual("test", event.type);
|
||||
testing.expectEqual("", event.data);
|
||||
testing.expectEqual(0, event.detail);
|
||||
testing.expectEqual(window, event.view);
|
||||
// per UIEventInit, view defaults to null for synthetic events
|
||||
testing.expectEqual(null, event.view);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
testing.expectEqual(5, evt.detail);
|
||||
testing.expectEqual(true, evt.bubbles);
|
||||
testing.expectEqual(true, evt.cancelable);
|
||||
testing.expectEqual(window, evt.view);
|
||||
testing.expectEqual(null, evt.view);
|
||||
</script>
|
||||
|
||||
<script id=uiEventWithView>
|
||||
@@ -30,7 +30,7 @@
|
||||
testing.expectEqual(0, evt3.detail);
|
||||
testing.expectEqual(false, evt3.bubbles);
|
||||
testing.expectEqual(false, evt3.cancelable);
|
||||
testing.expectEqual(window, evt3.view);
|
||||
testing.expectEqual(null, evt3.view);
|
||||
</script>
|
||||
|
||||
<script id=uiEventInheritance>
|
||||
|
||||
@@ -66,6 +66,11 @@ pub fn initCustomEvent(
|
||||
cancelable: ?bool,
|
||||
detail_: ?js.Value.Global,
|
||||
) !void {
|
||||
// Like initEvent, a no-op while the event is being dispatched.
|
||||
if (self._proto._event_phase != .none) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function can only be called after the constructor has called.
|
||||
// So we assume proto is initialized already by constructor.
|
||||
self._proto._type_string = try String.init(self._proto._arena, event_string, .{});
|
||||
|
||||
@@ -321,11 +321,15 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
||||
|
||||
Event.populatePrototypes(event, opts, trusted);
|
||||
|
||||
// https://w3c.github.io/uievents/#event-type-keyup
|
||||
const rootevt = event._proto._proto;
|
||||
rootevt._bubbles = true;
|
||||
rootevt._cancelable = true;
|
||||
rootevt._composed = true;
|
||||
if (trusted) {
|
||||
// Browser-generated key events bubble, are cancelable and composed:
|
||||
// https://w3c.github.io/uievents/#event-type-keyup
|
||||
// Synthetic ones follow the EventInit dictionary defaults.
|
||||
const rootevt = event._proto._proto;
|
||||
rootevt._bubbles = true;
|
||||
rootevt._cancelable = true;
|
||||
rootevt._composed = true;
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*UIEvent {
|
||||
._type = .generic,
|
||||
._proto = undefined,
|
||||
._detail = opts.detail,
|
||||
._view = opts.view orelse frame.window,
|
||||
._view = opts.view,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -109,8 +109,16 @@ pub fn getDetail(self: *UIEvent) u32 {
|
||||
|
||||
// sourceCapabilities not implemented
|
||||
|
||||
pub fn getView(self: *UIEvent, frame: *Frame) *Window {
|
||||
return self._view orelse frame.window;
|
||||
pub fn getView(self: *UIEvent, frame: *Frame) ?*Window {
|
||||
if (self._view) |view| {
|
||||
return view;
|
||||
}
|
||||
// Trusted (browser-generated) UI events implicitly target the window;
|
||||
// synthetic events default to a null view per the UIEventInit dictionary.
|
||||
if (self._proto._is_trusted) {
|
||||
return frame.window;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Legacy: see https://w3c.github.io/uievents/#dom-uievent-which
|
||||
|
||||
Reference in new issue
Block a user