diff --git a/src/browser/EventManager.zig b/src/browser/EventManager.zig
index 5ed22c45..0307662c 100644
--- a/src/browser/EventManager.zig
+++ b/src/browser/EventManager.zig
@@ -83,12 +83,14 @@ pub fn register(self: *EventManager, target: *EventTarget, typ: []const u8, call
var node = gop.value_ptr.*.first;
while (node) |n| {
const listener: *Listener = @alignCast(@fieldParentPtr("node", n));
- const is_duplicate = switch (callback) {
- .object => |obj| listener.function.eqlObject(obj),
- .function => |func| listener.function.eqlFunction(func),
- };
- if (is_duplicate and listener.capture == opts.capture) {
- return;
+ if (listener.typ.eqlSlice(typ)) {
+ const is_duplicate = switch (callback) {
+ .object => |obj| listener.function.eqlObject(obj),
+ .function => |func| listener.function.eqlFunction(func),
+ };
+ if (is_duplicate and listener.capture == opts.capture) {
+ return;
+ }
}
node = n.next;
}
@@ -132,6 +134,7 @@ pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) !void
}
event._target = target;
+ event._dispatch_target = target; // Store original target for composedPath()
var was_handled = false;
defer if (was_handled) {
@@ -173,6 +176,7 @@ pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *E
if (comptime opts.inject_target) {
event._target = target;
+ event._dispatch_target = target; // Store original target for composedPath()
}
var was_dispatched = false;
diff --git a/src/browser/Page.zig b/src/browser/Page.zig
index 58b63dfb..48efcb44 100644
--- a/src/browser/Page.zig
+++ b/src/browser/Page.zig
@@ -503,7 +503,7 @@ pub fn documentIsLoaded(self: *Page) void {
}
pub fn _documentIsLoaded(self: *Page) !void {
- const event = try Event.init("DOMContentLoaded", .{ .bubbles = true }, self);
+ const event = try Event.initTrusted("DOMContentLoaded", .{ .bubbles = true }, self);
try self._event_manager.dispatch(
self.document.asEventTarget(),
event,
@@ -549,7 +549,7 @@ fn _documentIsComplete(self: *Page) !void {
self.document._ready_state = .complete;
// dispatch window.load event
- const event = try Event.init("load", .{}, self);
+ const event = try Event.initTrusted("load", .{}, self);
// this event is weird, it's dispatched directly on the window, but
// with the document as the target
event._target = self.document.asEventTarget();
@@ -560,7 +560,7 @@ fn _documentIsComplete(self: *Page) !void {
.{ .inject_target = false, .context = "page load" },
);
- const pageshow_event = try PageTransitionEvent.init("pageshow", .{}, self);
+ const pageshow_event = try PageTransitionEvent.initTrusted("pageshow", .{}, self);
try self._event_manager.dispatchWithFunction(
self.window.asEventTarget(),
pageshow_event.asEvent(),
@@ -1174,7 +1174,7 @@ pub fn deliverSlotchangeEvents(self: *Page) void {
self._slots_pending_slotchange.clearRetainingCapacity();
for (slots) |slot| {
- const event = Event.init("slotchange", .{ .bubbles = true }, self) catch |err| {
+ const event = Event.initTrusted("slotchange", .{ .bubbles = true }, self) catch |err| {
log.err(.page, "deliverSlotchange.init", .{ .err = err });
continue;
};
@@ -2419,6 +2419,7 @@ pub fn triggerMouseClick(self: *Page, x: f64, y: f64) !void {
const event = try @import("webapi/event/MouseEvent.zig").init("click", .{
.bubbles = true,
.cancelable = true,
+ .composed = true,
.clientX = x,
.clientY = y,
}, self);
diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig
index 363e1fa1..1936f390 100644
--- a/src/browser/ScriptManager.zig
+++ b/src/browser/ScriptManager.zig
@@ -833,7 +833,7 @@ pub const Script = struct {
const cb = cb_ orelse return;
const Event = @import("webapi/Event.zig");
- const event = Event.init(typ, .{}, page) catch |err| {
+ const event = Event.initTrusted(typ, .{}, page) catch |err| {
log.warn(.js, "script internal callback", .{
.url = self.url,
.type = typ,
diff --git a/src/browser/tests/event/keyboard.html b/src/browser/tests/event/keyboard.html
index 54419903..b6c3ddd8 100644
--- a/src/browser/tests/event/keyboard.html
+++ b/src/browser/tests/event/keyboard.html
@@ -88,3 +88,18 @@
testing.expectEqual(true, isKeyPress);
+
+
diff --git a/src/browser/tests/event/mouse.html b/src/browser/tests/event/mouse.html
index 4f8dd17f..896ba62b 100644
--- a/src/browser/tests/event/mouse.html
+++ b/src/browser/tests/event/mouse.html
@@ -35,3 +35,18 @@
testing.expectEqual('click', evt.type);
testing.expectEqual(true, evt instanceof MouseEvent);
+
+
diff --git a/src/browser/tests/events.html b/src/browser/tests/events.html
index 84300217..a6706847 100644
--- a/src/browser/tests/events.html
+++ b/src/browser/tests/events.html
@@ -612,3 +612,21 @@
content.dispatchEvent(new Event('he2'));
}
+
+
diff --git a/src/browser/tests/legacy/events/event.html b/src/browser/tests/legacy/events/event.html
index 752d64ba..a24cfbdb 100644
--- a/src/browser/tests/legacy/events/event.html
+++ b/src/browser/tests/legacy/events/event.html
@@ -27,7 +27,7 @@
testing.expectEqual(true, evt.bubbles);
testing.expectEqual(true, evt.cancelable);
testing.expectEqual(true, evt.defaultPrevented);
- testing.expectEqual(true, evt.isTrusted);
+ testing.expectEqual(false, evt.isTrusted);
testing.expectEqual(true, evt.timeStamp >= Math.floor(startTime));
diff --git a/src/browser/tests/shadowroot/events.html b/src/browser/tests/shadowroot/events.html
index de6f7cdc..c0832f21 100644
--- a/src/browser/tests/shadowroot/events.html
+++ b/src/browser/tests/shadowroot/events.html
@@ -184,3 +184,100 @@
host.remove();
}
+
+
+
+
+
+
diff --git a/src/browser/webapi/AbortSignal.zig b/src/browser/webapi/AbortSignal.zig
index 9d01ef64..c4b0f7ed 100644
--- a/src/browser/webapi/AbortSignal.zig
+++ b/src/browser/webapi/AbortSignal.zig
@@ -80,7 +80,7 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, page: *Page) !void {
}
// Dispatch abort event
- const event = try Event.init("abort", .{}, page);
+ const event = try Event.initTrusted("abort", .{}, page);
try page._event_manager.dispatchWithFunction(
self.asEventTarget(),
event,
diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig
index a4d20ed1..70289a37 100644
--- a/src/browser/webapi/Document.zig
+++ b/src/browser/webapi/Document.zig
@@ -251,7 +251,7 @@ pub fn createTextNode(_: *const Document, data: []const u8, page: *Page) !*Node
pub fn createCDATASection(self: *const Document, data: []const u8, page: *Page) !*Node {
switch (self._type) {
- .html => return error.NotSupported, // cannot create a CDataSection in an HTMLDocument
+ .html => return error.NotSupported, // cannot create a CDataSection in an HTMLDocument
.xml => return page.createCDATASection(data),
.generic => return page.createCDATASection(data),
}
@@ -570,7 +570,7 @@ pub fn getChildElementCount(self: *Document) u32 {
return i;
}
- pub fn getAdoptedStyleSheets(self: *Document, page: *Page) !js.Object {
+pub fn getAdoptedStyleSheets(self: *Document, page: *Page) !js.Object {
if (self._adopted_style_sheets) |ass| {
return ass;
}
diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig
index 0fbf547f..a3c8ed0e 100644
--- a/src/browser/webapi/Element.zig
+++ b/src/browser/webapi/Element.zig
@@ -596,7 +596,7 @@ pub fn focus(self: *Element, page: *Page) !void {
return;
}
- const blur_event = try Event.init("blur", null, page);
+ const blur_event = try Event.initTrusted("blur", null, page);
try page._event_manager.dispatch(old.asEventTarget(), blur_event);
}
@@ -604,7 +604,7 @@ pub fn focus(self: *Element, page: *Page) !void {
page.document._active_element = self;
}
- const focus_event = try Event.init("focus", null, page);
+ const focus_event = try Event.initTrusted("focus", null, page);
try page._event_manager.dispatch(self.asEventTarget(), focus_event);
}
@@ -614,7 +614,7 @@ pub fn blur(self: *Element, page: *Page) !void {
page.document._active_element = null;
const Event = @import("Event.zig");
- const blur_event = try Event.init("blur", null, page);
+ const blur_event = try Event.initTrusted("blur", null, page);
try page._event_manager.dispatch(self.asEventTarget(), blur_event);
}
diff --git a/src/browser/webapi/Event.zig b/src/browser/webapi/Event.zig
index 7aa14cff..f32f21ab 100644
--- a/src/browser/webapi/Event.zig
+++ b/src/browser/webapi/Event.zig
@@ -35,12 +35,14 @@ _composed: bool = false,
_type_string: String,
_target: ?*EventTarget = null,
_current_target: ?*EventTarget = null,
+_dispatch_target: ?*EventTarget = null, // Original target for composedPath()
_prevent_default: bool = false,
_stop_propagation: bool = false,
_stop_immediate_propagation: bool = false,
_event_phase: EventPhase = .none,
_time_stamp: u64 = 0,
_needs_retargeting: bool = false,
+_isTrusted: bool = false,
pub const EventPhase = enum(u8) {
none = 0,
@@ -68,14 +70,22 @@ pub const Options = struct {
composed: bool = false,
};
+pub fn initTrusted(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
+ return initWithTrusted(typ, opts_, true, page);
+}
+
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
+ return initWithTrusted(typ, opts_, false, page);
+}
+
+fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*Event {
const opts = opts_ orelse Options{};
// Round to 2ms for privacy (browsers do this)
const raw_timestamp = @import("../../datetime.zig").milliTimestamp(.monotonic);
const time_stamp = (raw_timestamp / 2) * 2;
- return page._factory.create(Event{
+ const event = try page._factory.create(Event{
._type = .generic,
._bubbles = opts.bubbles,
._time_stamp = time_stamp,
@@ -83,6 +93,21 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
._composed = opts.composed,
._type_string = try String.init(page.arena, typ, .{}),
});
+
+ event._isTrusted = trusted;
+ return event;
+}
+
+pub fn initEvent(
+ self: *Event,
+ event_string: []const u8,
+ bubbles: ?bool,
+ cancelable: ?bool,
+ page: *Page,
+) !void {
+ self._type_string = try String.init(page.arena, event_string, .{});
+ self._bubbles = bubbles orelse false;
+ self._cancelable = cancelable orelse false;
}
pub fn as(self: *Event, comptime T: type) *T {
@@ -159,14 +184,27 @@ pub fn getTimeStamp(self: *const Event) u64 {
return self._time_stamp;
}
+pub fn setTrusted(self: *Event) void {
+ self._isTrusted = true;
+}
+
+pub fn setUntrusted(self: *Event) void {
+ self._isTrusted = false;
+}
+
+pub fn getIsTrusted(self: *const Event) bool {
+ return self._isTrusted;
+}
+
pub fn composedPath(self: *Event, page: *Page) ![]const *EventTarget {
// Return empty array if event is not being dispatched
if (self._event_phase == .none) {
return &.{};
}
- // If there's no target, return empty array
- const target = self._target orelse return &.{};
+ // Use dispatch_target (original target) if available, otherwise fall back to target
+ // This is important because _target gets retargeted during event dispatch
+ const target = self._dispatch_target orelse self._target orelse return &.{};
// Only nodes have a propagation path
const target_node = switch (target._type) {
@@ -179,6 +217,9 @@ pub fn composedPath(self: *Event, page: *Page) ![]const *EventTarget {
var path_buffer: [128]*EventTarget = undefined;
var stopped_at_shadow_boundary = false;
+ // Track closed shadow boundaries (position in path and host position)
+ var closed_shadow_boundary: ?struct { shadow_end: usize, host_start: usize } = null;
+
var node: ?*Node = target_node;
while (node) |n| {
if (path_len >= path_buffer.len) {
@@ -198,7 +239,17 @@ pub fn composedPath(self: *Event, page: *Page) ![]const *EventTarget {
break;
}
- // Otherwise, jump to the shadow host and continue
+ // Track the first closed shadow boundary we encounter
+ if (shadow._mode == .closed and closed_shadow_boundary == null) {
+ // Mark where the shadow root is in the path
+ // The next element will be the host
+ closed_shadow_boundary = .{
+ .shadow_end = path_len - 1, // index of shadow root
+ .host_start = path_len, // index where host will be
+ };
+ }
+
+ // Jump to the shadow host and continue
node = shadow._host.asNode();
continue;
}
@@ -215,9 +266,40 @@ pub fn composedPath(self: *Event, page: *Page) ![]const *EventTarget {
}
}
- // Allocate and return the path using call_arena (short-lived)
- const path = try page.call_arena.alloc(*EventTarget, path_len);
- @memcpy(path, path_buffer[0..path_len]);
+ // Determine visible path based on current_target and closed shadow boundaries
+ var visible_start_index: usize = 0;
+
+ if (closed_shadow_boundary) |boundary| {
+ // Check if current_target is outside the closed shadow
+ // If current_target is null or is at/after the host position, hide shadow internals
+ const current_target = self._current_target;
+
+ if (current_target) |ct| {
+ // Find current_target in the path
+ var ct_index: ?usize = null;
+ for (path_buffer[0..path_len], 0..) |elem, i| {
+ if (elem == ct) {
+ ct_index = i;
+ break;
+ }
+ }
+
+ // If current_target is at or after the host (outside the closed shadow),
+ // hide everything from target up to the host
+ if (ct_index) |idx| {
+ if (idx >= boundary.host_start) {
+ visible_start_index = boundary.host_start;
+ }
+ }
+ }
+ }
+
+ // Calculate the visible portion of the path
+ const visible_path_len = if (path_len > visible_start_index) path_len - visible_start_index else 0;
+
+ // Allocate and return the visible path using call_arena (short-lived)
+ const path = try page.call_arena.alloc(*EventTarget, visible_path_len);
+ @memcpy(path, path_buffer[visible_start_index..path_len]);
return path;
}
@@ -257,16 +339,21 @@ pub fn inheritOptions(comptime T: type, comptime additions: anytype) type {
});
}
-pub fn populatePrototypes(self: anytype, opts: anytype) void {
+pub fn populatePrototypes(self: anytype, opts: anytype, trusted: bool) void {
const T = @TypeOf(self.*);
if (@hasField(T, "_proto")) {
- populatePrototypes(self._proto, opts);
+ populatePrototypes(self._proto, opts, trusted);
}
if (@hasDecl(T, "populateFromOptions")) {
T.populateFromOptions(self, opts);
}
+
+ // Set isTrusted at the Event level (base of prototype chain)
+ if (T == Event or @hasField(T, "_isTrusted")) {
+ self._isTrusted = trusted;
+ }
}
pub const JsApi = struct {
@@ -289,10 +376,12 @@ pub const JsApi = struct {
pub const eventPhase = bridge.accessor(Event.getEventPhase, null, .{});
pub const defaultPrevented = bridge.accessor(Event.getDefaultPrevented, null, .{});
pub const timeStamp = bridge.accessor(Event.getTimeStamp, null, .{});
+ pub const isTrusted = bridge.accessor(Event.getIsTrusted, null, .{});
pub const preventDefault = bridge.function(Event.preventDefault, .{});
pub const stopPropagation = bridge.function(Event.stopPropagation, .{});
pub const stopImmediatePropagation = bridge.function(Event.stopImmediatePropagation, .{});
pub const composedPath = bridge.function(Event.composedPath, .{});
+ pub const initEvent = bridge.function(Event.initEvent, .{});
// Event phase constants
pub const NONE = bridge.property(@intFromEnum(EventPhase.none));
diff --git a/src/browser/webapi/History.zig b/src/browser/webapi/History.zig
index 9511e4d4..5ff5c860 100644
--- a/src/browser/webapi/History.zig
+++ b/src/browser/webapi/History.zig
@@ -79,7 +79,7 @@ fn goInner(delta: i32, page: *Page) !void {
if (entry._url) |url| {
if (try page.isSameOrigin(url)) {
- const event = try PopStateEvent.init("popstate", .{ .state = entry._state.value }, page);
+ const event = try PopStateEvent.initTrusted("popstate", .{ .state = entry._state.value }, page);
try page._event_manager.dispatchWithFunction(
page.window.asEventTarget(),
diff --git a/src/browser/webapi/MessagePort.zig b/src/browser/webapi/MessagePort.zig
index 4d72a934..ea6e79ca 100644
--- a/src/browser/webapi/MessagePort.zig
+++ b/src/browser/webapi/MessagePort.zig
@@ -129,7 +129,7 @@ const PostMessageCallback = struct {
return null;
}
- const event = MessageEvent.init("message", .{
+ const event = MessageEvent.initTrusted("message", .{
.data = self.message,
.origin = "",
.source = null,
diff --git a/src/browser/webapi/Range.zig b/src/browser/webapi/Range.zig
index 8f220e67..feca23c4 100644
--- a/src/browser/webapi/Range.zig
+++ b/src/browser/webapi/Range.zig
@@ -33,7 +33,7 @@ pub fn asAbstractRange(self: *Range) *AbstractRange {
}
pub fn init(page: *Page) !*Range {
- return page._factory.abstractRange(Range{._proto = undefined}, page);
+ return page._factory.abstractRange(Range{ ._proto = undefined }, page);
}
pub fn setStart(self: *Range, node: *Node, offset: u32) !void {
@@ -106,7 +106,7 @@ pub fn collapse(self: *Range, to_start: ?bool) void {
}
pub fn cloneRange(self: *const Range, page: *Page) !*Range {
- const clone = try page._factory.abstractRange(Range{._proto = undefined}, page);
+ const clone = try page._factory.abstractRange(Range{ ._proto = undefined }, page);
clone._proto._end_offset = self._proto._end_offset;
clone._proto._start_offset = self._proto._start_offset;
clone._proto._end_container = self._proto._end_container;
diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig
index 1fcfec80..2aaff9f7 100644
--- a/src/browser/webapi/Window.zig
+++ b/src/browser/webapi/Window.zig
@@ -270,7 +270,7 @@ pub fn cancelIdleCallback(self: *Window, id: u32) void {
}
pub fn reportError(self: *Window, err: js.Object, page: *Page) !void {
- const error_event = try ErrorEvent.init("error", .{
+ const error_event = try ErrorEvent.initTrusted("error", .{
.@"error" = err,
.message = err.toString() catch "Unknown error",
.bubbles = false,
@@ -410,7 +410,7 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
return null;
}
- const event = try Event.init("scroll", .{ .bubbles = true }, p);
+ const event = try Event.initTrusted("scroll", .{ .bubbles = true }, p);
try p._event_manager.dispatch(p.document.asEventTarget(), event);
pos.state = .end;
@@ -437,7 +437,7 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
.end => {},
.done => return null,
}
- const event = try Event.init("scrollend", .{ .bubbles = true }, p);
+ const event = try Event.initTrusted("scrollend", .{ .bubbles = true }, p);
try p._event_manager.dispatch(p.document.asEventTarget(), event);
pos.state = .done;
@@ -586,7 +586,7 @@ const PostMessageCallback = struct {
const self: *PostMessageCallback = @ptrCast(@alignCast(ctx));
defer self.deinit();
- const message_event = try MessageEvent.init("message", .{
+ const message_event = try MessageEvent.initTrusted("message", .{
.data = self.message,
.origin = self.origin,
.source = self.window,
diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig
index 8de457b6..fc033441 100644
--- a/src/browser/webapi/element/Html.zig
+++ b/src/browser/webapi/element/Html.zig
@@ -306,6 +306,7 @@ pub fn click(self: *HtmlElement, page: *Page) !void {
const event = try @import("../event/MouseEvent.zig").init("click", .{
.bubbles = true,
.cancelable = true,
+ .composed = true,
.clientX = 0,
.clientY = 0,
}, page);
diff --git a/src/browser/webapi/event/CompositionEvent.zig b/src/browser/webapi/event/CompositionEvent.zig
index a758c621..f77489dc 100644
--- a/src/browser/webapi/event/CompositionEvent.zig
+++ b/src/browser/webapi/event/CompositionEvent.zig
@@ -40,7 +40,7 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CompositionEvent {
._data = if (opts.data) |str| try page.dupeString(str) else "",
});
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, false);
return event;
}
diff --git a/src/browser/webapi/event/CustomEvent.zig b/src/browser/webapi/event/CustomEvent.zig
index 6456b6cf..55f6b87c 100644
--- a/src/browser/webapi/event/CustomEvent.zig
+++ b/src/browser/webapi/event/CustomEvent.zig
@@ -49,23 +49,23 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, false);
return event;
}
- pub fn initCustomEvent(
+pub fn initCustomEvent(
self: *CustomEvent,
event_string: []const u8,
- bubbles: bool,
- cancelable: bool,
+ bubbles: ?bool,
+ cancelable: ?bool,
detail_: ?js.Object,
page: *Page,
) !void {
// 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(page.arena, event_string, .{});
- self._proto._bubbles = bubbles;
- self._proto._cancelable = cancelable;
+ self._proto._bubbles = bubbles orelse false;
+ self._proto._cancelable = cancelable orelse false;
// Detail is stored separately.
if (detail_) |detail| {
self._detail = try detail.persist();
diff --git a/src/browser/webapi/event/ErrorEvent.zig b/src/browser/webapi/event/ErrorEvent.zig
index 08124d7f..25e2e787 100644
--- a/src/browser/webapi/event/ErrorEvent.zig
+++ b/src/browser/webapi/event/ErrorEvent.zig
@@ -44,6 +44,14 @@ pub const ErrorEventOptions = struct {
const Options = Event.inheritOptions(ErrorEvent, ErrorEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent {
+ return initWithTrusted(typ, opts_, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent {
+ return initWithTrusted(typ, opts_, true, page);
+}
+
+fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*ErrorEvent {
const arena = page.arena;
const opts = opts_ orelse Options{};
@@ -60,7 +68,7 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/KeyboardEvent.zig b/src/browser/webapi/event/KeyboardEvent.zig
index eaa04e64..d0f47d23 100644
--- a/src/browser/webapi/event/KeyboardEvent.zig
+++ b/src/browser/webapi/event/KeyboardEvent.zig
@@ -182,7 +182,15 @@ const Options = Event.inheritOptions(
KeyboardEventOptions,
);
+pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*KeyboardEvent {
+ return initWithTrusted(typ, _opts, true, page);
+}
+
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*KeyboardEvent {
+ return initWithTrusted(typ, _opts, false, page);
+}
+
+fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*KeyboardEvent {
const opts = _opts orelse Options{};
const event = try page._factory.uiEvent(
@@ -201,7 +209,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*KeyboardEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/MessageEvent.zig b/src/browser/webapi/event/MessageEvent.zig
index 9f24c517..086bb0e5 100644
--- a/src/browser/webapi/event/MessageEvent.zig
+++ b/src/browser/webapi/event/MessageEvent.zig
@@ -38,6 +38,14 @@ const MessageEventOptions = struct {
const Options = Event.inheritOptions(MessageEvent, MessageEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent {
+ return initWithTrusted(typ, opts_, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent {
+ return initWithTrusted(typ, opts_, true, page);
+}
+
+fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*MessageEvent {
const opts = opts_ orelse Options{};
const event = try page._factory.event(
@@ -50,7 +58,7 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/MouseEvent.zig b/src/browser/webapi/event/MouseEvent.zig
index 50d5f879..977034cf 100644
--- a/src/browser/webapi/event/MouseEvent.zig
+++ b/src/browser/webapi/event/MouseEvent.zig
@@ -88,7 +88,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*MouseEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, false);
return event;
}
diff --git a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig
index 40c8122a..b22e32f0 100644
--- a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig
+++ b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig
@@ -40,9 +40,18 @@ const Options = Event.inheritOptions(
NavigationCurrentEntryChangeEventOptions,
);
-pub fn init(
+pub fn init(typ: []const u8, opts: Options, page: *Page) !*NavigationCurrentEntryChangeEvent {
+ return initWithTrusted(typ, opts, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, opts: Options, page: *Page) !*NavigationCurrentEntryChangeEvent {
+ return initWithTrusted(typ, opts, true, page);
+}
+
+fn initWithTrusted(
typ: []const u8,
opts: Options,
+ trusted: bool,
page: *Page,
) !*NavigationCurrentEntryChangeEvent {
const navigation_type = if (opts.navigationType) |nav_type_str|
@@ -59,7 +68,7 @@ pub fn init(
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/PageTransitionEvent.zig b/src/browser/webapi/event/PageTransitionEvent.zig
index 2b7d063f..37b7edf1 100644
--- a/src/browser/webapi/event/PageTransitionEvent.zig
+++ b/src/browser/webapi/event/PageTransitionEvent.zig
@@ -35,6 +35,14 @@ const PageTransitionEventOptions = struct {
const Options = Event.inheritOptions(PageTransitionEvent, PageTransitionEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PageTransitionEvent {
+ return initWithTrusted(typ, _opts, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*PageTransitionEvent {
+ return initWithTrusted(typ, _opts, true, page);
+}
+
+fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*PageTransitionEvent {
const opts = _opts orelse Options{};
const event = try page._factory.event(
@@ -45,7 +53,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PageTransitionEvent
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/PopStateEvent.zig b/src/browser/webapi/event/PopStateEvent.zig
index 45a088c5..305ef5cc 100644
--- a/src/browser/webapi/event/PopStateEvent.zig
+++ b/src/browser/webapi/event/PopStateEvent.zig
@@ -35,6 +35,14 @@ const PopStateEventOptions = struct {
const Options = Event.inheritOptions(PopStateEvent, PopStateEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PopStateEvent {
+ return initWithTrusted(typ, _opts, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*PopStateEvent {
+ return initWithTrusted(typ, _opts, true, page);
+}
+
+fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*PopStateEvent {
const opts = _opts orelse Options{};
const event = try page._factory.event(
@@ -45,7 +53,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PopStateEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/ProgressEvent.zig b/src/browser/webapi/event/ProgressEvent.zig
index 8fbfbb87..61fe49c9 100644
--- a/src/browser/webapi/event/ProgressEvent.zig
+++ b/src/browser/webapi/event/ProgressEvent.zig
@@ -34,6 +34,14 @@ const ProgressEventOptions = struct {
const Options = Event.inheritOptions(ProgressEvent, ProgressEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEvent {
+ return initWithTrusted(typ, _opts, false, page);
+}
+
+pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEvent {
+ return initWithTrusted(typ, _opts, true, page);
+}
+
+fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*ProgressEvent {
const opts = _opts orelse Options{};
const event = try page._factory.event(
@@ -45,7 +53,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, trusted);
return event;
}
diff --git a/src/browser/webapi/event/UIEvent.zig b/src/browser/webapi/event/UIEvent.zig
index c30e8743..2ea51f7a 100644
--- a/src/browser/webapi/event/UIEvent.zig
+++ b/src/browser/webapi/event/UIEvent.zig
@@ -57,7 +57,7 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*UIEvent {
},
);
- Event.populatePrototypes(event, opts);
+ Event.populatePrototypes(event, opts, false);
return event;
}
diff --git a/src/browser/webapi/navigation/Navigation.zig b/src/browser/webapi/navigation/Navigation.zig
index b1fcb225..e3e38a7b 100644
--- a/src/browser/webapi/navigation/Navigation.zig
+++ b/src/browser/webapi/navigation/Navigation.zig
@@ -201,7 +201,7 @@ pub fn pushEntry(
if (previous) |prev| {
if (dispatch) {
- const event = try NavigationCurrentEntryChangeEvent.init(
+ const event = try NavigationCurrentEntryChangeEvent.initTrusted(
"currententrychange",
.{ .from = prev, .navigationType = @tagName(.push) },
page,
@@ -240,7 +240,7 @@ pub fn replaceEntry(
self._entries.items[self._index] = entry;
if (dispatch) {
- const event = try NavigationCurrentEntryChangeEvent.init(
+ const event = try NavigationCurrentEntryChangeEvent.initTrusted(
"currententrychange",
.{ .from = previous, .navigationType = @tagName(.replace) },
page,
@@ -324,7 +324,7 @@ pub fn navigateInner(
}
// If we haven't navigated off, let us fire off an a currententrychange.
- const event = try NavigationCurrentEntryChangeEvent.init(
+ const event = try NavigationCurrentEntryChangeEvent.initTrusted(
"currententrychange",
.{ .from = previous, .navigationType = @tagName(kind) },
page,
@@ -363,7 +363,7 @@ pub fn reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigation
const previous = entry;
entry._state = .{ .source = .navigation, .value = state.toJson(arena) catch return error.DataClone };
- const event = try NavigationCurrentEntryChangeEvent.init(
+ const event = try NavigationCurrentEntryChangeEvent.initTrusted(
"currententrychange",
.{ .from = previous, .navigationType = @tagName(.reload) },
page,
@@ -405,7 +405,7 @@ pub fn updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions,
.value = options.state.toJson(arena) catch return error.DataClone,
};
- const event = try NavigationCurrentEntryChangeEvent.init(
+ const event = try NavigationCurrentEntryChangeEvent.initTrusted(
"currententrychange",
.{ .from = previous, .navigationType = null },
page,
diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig
index 0d903249..c3aef7f6 100644
--- a/src/browser/webapi/net/XMLHttpRequest.zig
+++ b/src/browser/webapi/net/XMLHttpRequest.zig
@@ -416,7 +416,7 @@ fn stateChanged(self: *XMLHttpRequest, state: ReadyState, page: *Page) !void {
self._ready_state = state;
- const event = try Event.init("readystatechange", .{}, page);
+ const event = try Event.initTrusted("readystatechange", .{}, page);
try page._event_manager.dispatchWithFunction(
self.asEventTarget(),
event,
diff --git a/src/browser/webapi/net/XMLHttpRequestEventTarget.zig b/src/browser/webapi/net/XMLHttpRequestEventTarget.zig
index af861c74..b8efe47d 100644
--- a/src/browser/webapi/net/XMLHttpRequestEventTarget.zig
+++ b/src/browser/webapi/net/XMLHttpRequestEventTarget.zig
@@ -57,7 +57,7 @@ pub fn dispatch(self: *XMLHttpRequestEventTarget, comptime event_type: DispatchT
};
const progress = progress_ orelse Progress{};
- const event = try ProgressEvent.init(
+ const event = try ProgressEvent.initTrusted(
typ,
.{ .total = progress.total, .loaded = progress.loaded },
page,
diff --git a/src/cdp/domains/input.zig b/src/cdp/domains/input.zig
index 388d986b..492e9b9e 100644
--- a/src/cdp/domains/input.zig
+++ b/src/cdp/domains/input.zig
@@ -60,7 +60,7 @@ fn dispatchKeyEvent(cmd: anytype) !void {
const page = bc.session.currentPage() orelse return;
const KeyboardEvent = @import("../../browser/webapi/event/KeyboardEvent.zig");
- const keyboard_event = try KeyboardEvent.init("keydown", .{
+ const keyboard_event = try KeyboardEvent.initTrusted("keydown", .{
.key = params.key,
.code = params.code,
.altKey = params.modifiers & 1 == 1,