From bf296ad797c96f7ce27d9753f8b17ab86c87c152 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 23 Jun 2025 19:04:49 +0800 Subject: [PATCH] add ErrorEvent webapi --- src/browser/events/event.zig | 9 +-- src/browser/html/error_event.zig | 118 +++++++++++++++++++++++++++++ src/browser/html/html.zig | 1 + src/browser/netsurf.zig | 1 + src/browser/xhr/progress_event.zig | 4 +- 5 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 src/browser/html/error_event.zig diff --git a/src/browser/events/event.zig b/src/browser/events/event.zig index af8a75ae..14fd7a79 100644 --- a/src/browser/events/event.zig +++ b/src/browser/events/event.zig @@ -31,14 +31,10 @@ const EventTargetUnion = @import("../dom/event_target.zig").Union; const CustomEvent = @import("custom_event.zig").CustomEvent; const ProgressEvent = @import("../xhr/progress_event.zig").ProgressEvent; const MouseEvent = @import("mouse_event.zig").MouseEvent; +const ErrorEvent = @import("../html/error_event.zig").ErrorEvent; // Event interfaces -pub const Interfaces = .{ - Event, - CustomEvent, - ProgressEvent, - MouseEvent, -}; +pub const Interfaces = .{ Event, CustomEvent, ProgressEvent, MouseEvent, ErrorEvent }; pub const Union = generate.Union(Interfaces); @@ -62,6 +58,7 @@ pub const Event = struct { .custom_event => .{ .CustomEvent = @as(*CustomEvent, @ptrCast(evt)).* }, .progress_event => .{ .ProgressEvent = @as(*ProgressEvent, @ptrCast(evt)).* }, .mouse_event => .{ .MouseEvent = @as(*parser.MouseEvent, @ptrCast(evt)) }, + .error_event => .{ .ErrorEvent = @as(*ErrorEvent, @ptrCast(evt)).* }, }; } diff --git a/src/browser/html/error_event.zig b/src/browser/html/error_event.zig new file mode 100644 index 00000000..8f9c18a1 --- /dev/null +++ b/src/browser/html/error_event.zig @@ -0,0 +1,118 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +const Env = @import("../env.zig").Env; +const parser = @import("../netsurf.zig"); + +// https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent +pub const ErrorEvent = struct { + pub const prototype = *parser.Event; + pub const union_make_copy = true; + + proto: parser.Event, + message: []const u8, + filename: []const u8, + lineno: i32, + colno: i32, + @"error": ?Env.JsObject, + + const ErrorEventInit = struct { + message: []const u8 = "", + filename: []const u8 = "", + lineno: i32 = 0, + colno: i32 = 0, + @"error": ?Env.JsObject = null, + }; + + pub fn constructor(event_type: []const u8, opts: ?ErrorEventInit) !ErrorEvent { + const event = try parser.eventCreate(); + defer parser.eventDestroy(event); + try parser.eventInit(event, event_type, .{}); + try parser.eventSetInternalType(event, .event); + + const o = opts orelse ErrorEventInit{}; + + return .{ + .proto = event.*, + .message = o.message, + .filename = o.filename, + .lineno = o.lineno, + .colno = o.colno, + .@"error" = if (o.@"error") |e| try e.persist() else null, + }; + } + + pub fn get_message(self: *const ErrorEvent) []const u8 { + return self.message; + } + + pub fn get_filename(self: *const ErrorEvent) []const u8 { + return self.filename; + } + + pub fn get_lineno(self: *const ErrorEvent) i32 { + return self.lineno; + } + + pub fn get_colno(self: *const ErrorEvent) i32 { + return self.colno; + } + + const ErrorValue = union(enum) { + obj: Env.JsObject, + undefined: void, + }; + pub fn get_error(self: *const ErrorEvent) ErrorValue { + if (self.@"error") |e| { + return .{ .obj = e }; + } + return .{ .undefined = {} }; + } +}; + +const testing = @import("../../testing.zig"); +test "Browser.HTML.ErrorEvent" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "
" }); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "let e1 = new ErrorEvent('err1')", null }, + .{ "e1.message", "" }, + .{ "e1.filename", "" }, + .{ "e1.lineno", "0" }, + .{ "e1.colno", "0" }, + .{ "e1.error", "undefined" }, + + .{ + \\ let e2 = new ErrorEvent('err1', { + \\ message: 'm1', + \\ filename: 'fx19', + \\ lineno: 443, + \\ colno: 8999, + \\ error: 'under 9000!', + \\ + \\}) + , + null, + }, + .{ "e2.message", "m1" }, + .{ "e2.filename", "fx19" }, + .{ "e2.lineno", "443" }, + .{ "e2.colno", "8999" }, + .{ "e2.error", "under 9000!" }, + }, .{}); +} diff --git a/src/browser/html/html.zig b/src/browser/html/html.zig index 01f5f443..1ba0a340 100644 --- a/src/browser/html/html.zig +++ b/src/browser/html/html.zig @@ -37,4 +37,5 @@ pub const Interfaces = .{ Location, MediaQueryList, @import("screen.zig").Interfaces, + @import("error_event.zig").ErrorEvent, }; diff --git a/src/browser/netsurf.zig b/src/browser/netsurf.zig index 414dd56d..c8b3da02 100644 --- a/src/browser/netsurf.zig +++ b/src/browser/netsurf.zig @@ -525,6 +525,7 @@ pub const EventType = enum(u8) { progress_event = 1, custom_event = 2, mouse_event = 3, + error_event = 4, }; pub const MutationEvent = c.dom_mutation_event; diff --git a/src/browser/xhr/progress_event.zig b/src/browser/xhr/progress_event.zig index a64a8b23..d082f7b2 100644 --- a/src/browser/xhr/progress_event.zig +++ b/src/browser/xhr/progress_event.zig @@ -37,10 +37,10 @@ pub const ProgressEvent = struct { loaded: u64 = 0, total: u64 = 0, - pub fn constructor(eventType: []const u8, opts: ?EventInit) !ProgressEvent { + pub fn constructor(event_type: []const u8, opts: ?EventInit) !ProgressEvent { const event = try parser.eventCreate(); defer parser.eventDestroy(event); - try parser.eventInit(event, eventType, .{}); + try parser.eventInit(event, event_type, .{}); try parser.eventSetInternalType(event, .progress_event); const o = opts orelse EventInit{};