diff --git a/src/browser/html/AbortController.zig b/src/browser/html/AbortController.zig new file mode 100644 index 00000000..c08875e9 --- /dev/null +++ b/src/browser/html/AbortController.zig @@ -0,0 +1,112 @@ +// 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 std = @import("std"); +const parser = @import("../netsurf.zig"); +const EventTarget = @import("../dom/event_target.zig").EventTarget; + +pub const Interfaces = .{ + AbortController, + Signal, +}; + +const AbortController = @This(); + +signal: ?Signal = null, + +pub fn constructor() AbortController { + return .{}; +} + +pub fn get_signal(self: *AbortController) *Signal { + if (self.signal) |*s| { + return s; + } + self.signal = .init; + return &self.signal.?; +} + +pub fn abort(self: *AbortController, reason_: ?[]const u8) void { + const signal = &self.signal; + + signal.aborted = true; + signal.reason = reason_ orelse "AbortError"; + + const abort_event = try parser.eventCreate(); + defer parser.eventDestroy(abort_event); + try parser.eventInit(abort_event, "abort", .{}); + _ = try parser.eventTargetDispatchEvent( + parser.toEventTarget(Signal, signal), + abort_event, + ); +} + +pub const Signal = struct { + pub const prototype = *EventTarget; + + aborted: bool, + reason: ?[]const u8, + proto: parser.EventTargetTBase, + + pub const init: Signal = .{ + .proto = .{}, + .reason = null, + .aborted = false, + }; + + pub fn get_aborted(self: *const Signal) bool { + return self.aborted; + } + + const Reason = union(enum) { + reason: []const u8, + undefined: void, + }; + pub fn get_reason(self: *const Signal) Reason { + if (self.reason) |r| { + return .{ .reason = r }; + } + return .{ .undefined = {} }; + } +}; + +const testing = @import("../../testing.zig"); +test "Browser.HTML.AbortController" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{}); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "var called = false", null }, + .{ "var a1 = new AbortController()", null }, + .{ "var s1 = a1.signal", null }, + .{ "s1.reason", "undefined" }, + .{ "var target;", null }, + .{ + \\ s1.addEventListener('abort', (e) => { + \\ called = 1; + \\ target = e.target; + \\ + \\ }); + \\ target == s1 + , "true" }, + .{ "a1.abort()", null }, + .{ "s1.aborted", "true" }, + .{ "s1.reason", "undefined" }, + .{ "called", "1" }, + }, .{}); +} diff --git a/src/browser/html/html.zig b/src/browser/html/html.zig index f6134bf8..d722ad53 100644 --- a/src/browser/html/html.zig +++ b/src/browser/html/html.zig @@ -39,4 +39,5 @@ pub const Interfaces = .{ @import("DataSet.zig"), @import("screen.zig").Interfaces, @import("error_event.zig").ErrorEvent, + @import("AbortController.zig").Interfaces, };