Merge pull request #1033 from lightpanda-io/nikneym/custom-event

Support for CustomEvent in document.createEvent
This commit is contained in:
Karl Seguin
2025-09-10 15:23:34 +08:00
committed by GitHub
4 changed files with 59 additions and 7 deletions

View File

@@ -36,6 +36,8 @@ const CSSStyleSheet = @import("../cssom/CSSStyleSheet.zig");
const NodeIterator = @import("node_iterator.zig").NodeIterator;
const Range = @import("range.zig").Range;
const CustomEvent = @import("../events/custom_event.zig").CustomEvent;
const Env = @import("../env.zig").Env;
const DOMImplementation = @import("implementation.zig").DOMImplementation;
@@ -110,13 +112,21 @@ pub const Document = struct {
return try parser.documentGetDoctype(self);
}
pub fn _createEvent(_: *parser.Document, eventCstr: []const u8) !*parser.Event {
// TODO: for now only "Event" constructor is supported
// see table on https://dom.spec.whatwg.org/#dom-document-createevent $2
pub fn _createEvent(_: *parser.Document, eventCstr: []const u8) !union(enum) {
base: *parser.Event,
custom: CustomEvent,
} {
if (std.ascii.eqlIgnoreCase(eventCstr, "Event") or std.ascii.eqlIgnoreCase(eventCstr, "Events")) {
return try parser.eventCreate();
return .{ .base = try parser.eventCreate() };
}
return parser.DOMError.NotSupported;
// Not documented in MDN but supported in Chrome.
// This is actually both instance of `Event` and `CustomEvent`.
if (std.ascii.eqlIgnoreCase(eventCstr, "CustomEvent")) {
return .{ .custom = try CustomEvent.constructor(eventCstr, null) };
}
return error.NotSupported;
}
pub fn _getElementById(self: *parser.Document, id: []const u8) !?ElementUnion {

View File

@@ -19,6 +19,7 @@
const parser = @import("../netsurf.zig");
const Event = @import("event.zig").Event;
const JsObject = @import("../env.zig").JsObject;
const netsurf = @import("../netsurf.zig");
// https://dom.spec.whatwg.org/#interface-customevent
pub const CustomEvent = struct {
@@ -55,6 +56,27 @@ pub const CustomEvent = struct {
pub fn get_detail(self: *CustomEvent) ?JsObject {
return self.detail;
}
// Initializes an already created `CustomEvent`.
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent
pub fn _initCustomEvent(
self: *CustomEvent,
event_type: []const u8,
can_bubble: bool,
cancelable: bool,
maybe_detail: ?JsObject,
) !void {
// This function can only be called after the constructor has called.
// So we assume proto is initialized already by constructor.
self.proto.type = try netsurf.strFromData(event_type);
self.proto.bubble = can_bubble;
self.proto.cancelable = cancelable;
self.proto.is_initialised = true;
// Detail is stored separately.
if (maybe_detail) |detail| {
self.detail = try detail.persist();
}
}
};
const testing = @import("../../testing.zig");

View File

@@ -106,7 +106,7 @@ inline fn strToData(s: *String) []const u8 {
return data[0..c.dom_string_byte_length(s)];
}
inline fn strFromData(data: []const u8) !*String {
pub inline fn strFromData(data: []const u8) !*String {
var s: ?*String = null;
const err = c.dom_string_create(data.ptr, data.len, &s);
try DOMErr(err);

View File

@@ -60,7 +60,7 @@
let byTagNameAll = document.getElementsByTagName('*');
// If you add a script block (or change the HTML in any other way on this
// page), this test will break. Adjust it accordingly.
testing.expectEqual(20, byTagNameAll.length);
testing.expectEqual(21, byTagNameAll.length);
testing.expectEqual('html', byTagNameAll.item(0).localName);
testing.expectEqual('SCRIPT', byTagNameAll.item(11).tagName);
@@ -167,3 +167,23 @@
acss.push(new CSSStyleSheet());
testing.expectEqual(1, acss.length);
</script>
<script id=createEvent>
const event = document.createEvent("Event");
testing.expectEqual(true, event instanceof Event);
testing.expectEqual("", event.type);
const customEvent = document.createEvent("CustomEvent");
customEvent.initCustomEvent("hey", false, false);
testing.expectEqual(true, customEvent instanceof CustomEvent);
testing.expectEqual(true, customEvent instanceof Event);
testing.withError(
(err) => {
// TODO: Check the error type.
},
() => document.createEvent("InvalidType"),
);
</script>