Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions src/browser/events/event.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ 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;
const AbortSignal = @import("../html/AbortController.zig").AbortSignal;

// Event interfaces
pub const Interfaces = .{ Event, CustomEvent, ProgressEvent, MouseEvent, ErrorEvent };
Expand Down Expand Up @@ -144,6 +145,10 @@ pub const EventHandler = struct {
callback: Function,
node: parser.EventNode,
listener: *parser.EventListener,
target: *parser.EventTarget,
typ: []const u8,
abort_node: parser.EventNode,
abort_listener: *parser.EventListener,

const Env = @import("../env.zig").Env;
const Function = Env.Function;
Expand Down Expand Up @@ -175,7 +180,7 @@ pub const EventHandler = struct {
// that the listener won't call preventDefault() and thus can safely
// run the default as needed).
passive: ?bool,
signal: ?bool, // currently does nothing
signal: ?*AbortSignal,
};
};

Expand All @@ -188,6 +193,7 @@ pub const EventHandler = struct {
) !?*EventHandler {
var once = false;
var capture = false;
var abort_signal: ?*AbortSignal = null;
if (opts_) |opts| {
switch (opts) {
.capture => |c| capture = c,
Expand All @@ -198,7 +204,7 @@ pub const EventHandler = struct {
// error. If we don't error, this function call would succeed
// but the behavior might be wrong. At this point, it's
// better to be explicit and error.
if (f.signal orelse false) return error.NotImplemented;
abort_signal = f.signal;
once = f.once orelse false;
capture = f.capture orelse false;
},
Expand All @@ -222,6 +228,12 @@ pub const EventHandler = struct {
.func = handle,
},
.listener = undefined,
.target = target,
.typ = typ,
.abort_node = .{
.func = handle_abort,
},
.abort_listener = undefined,
};

eh.listener = try parser.eventTargetAddEventListener(
Expand All @@ -230,6 +242,16 @@ pub const EventHandler = struct {
&eh.node,
capture,
);

if (abort_signal) |signal| {
eh.abort_listener = try parser.eventTargetAddEventListener(
parser.toEventTarget(AbortSignal, signal),
"abort",
&eh.abort_node,
false,
);
}

return eh;
}

Expand Down Expand Up @@ -260,6 +282,27 @@ pub const EventHandler = struct {
) catch {};
}
}
fn handle_abort(node: *parser.EventNode, event: *parser.Event) void {
const self: *EventHandler = @fieldParentPtr("abort_node", node);

// Remove the event listener from the target
parser.eventTargetRemoveEventListener(
self.target,
self.typ,
self.listener,
self.capture,
) catch {};

// Also remove the abort listener since we can't abort twice anyway
const target_abort = (parser.eventTarget(event) catch return).?;
const typ_abort = parser.eventType(event) catch return;
parser.eventTargetRemoveEventListener(
target_abort,
typ_abort,
self.abort_listener,
false,
) catch {};
}
};

const testing = @import("../../testing.zig");
Expand Down Expand Up @@ -367,5 +410,18 @@ test "Browser.Event" {
.{ "document.dispatchEvent(new Event('count'))", "true" },
.{ "document.dispatchEvent(new Event('count'))", "true" },
.{ "nb", "1" },
.{ "document.removeEventListener('count', cbk)", "undefined" },
}, .{});

try runner.testCases(&.{
.{ "nb = 0; function cbk(event) { nb ++; }", null },
.{ "let ac = new AbortController()", null },
.{ "document.addEventListener('count', cbk, {signal: ac.signal})", null },
.{ "document.dispatchEvent(new Event('count'))", "true" },
.{ "document.dispatchEvent(new Event('count'))", "true" },
.{ "ac.abort()", null },
.{ "document.dispatchEvent(new Event('count'))", "true" },
.{ "nb", "2" },
.{ "document.removeEventListener('count', cbk)", "undefined" },
}, .{});
}