Skip to content

Commit 835042b

Browse files
authored
Merge pull request #851 from lightpanda-io/add_event_listener_signal
Add support for the signal option of addEventListener
2 parents 907490e + 07693e5 commit 835042b

File tree

1 file changed

+85
-8
lines changed

1 file changed

+85
-8
lines changed

src/browser/events/event.zig

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const Page = @import("../page.zig").Page;
2727
const DOMException = @import("../dom/exceptions.zig").DOMException;
2828
const EventTarget = @import("../dom/event_target.zig").EventTarget;
2929
const EventTargetUnion = @import("../dom/event_target.zig").Union;
30+
const AbortSignal = @import("../html/AbortController.zig").AbortSignal;
3031

3132
const CustomEvent = @import("custom_event.zig").CustomEvent;
3233
const ProgressEvent = @import("../xhr/progress_event.zig").ProgressEvent;
@@ -175,7 +176,7 @@ pub const EventHandler = struct {
175176
// that the listener won't call preventDefault() and thus can safely
176177
// run the default as needed).
177178
passive: ?bool,
178-
signal: ?bool, // currently does nothing
179+
signal: ?*AbortSignal, // currently does nothing
179180
};
180181
};
181182

@@ -188,25 +189,44 @@ pub const EventHandler = struct {
188189
) !?*EventHandler {
189190
var once = false;
190191
var capture = false;
192+
var signal: ?*AbortSignal = null;
193+
191194
if (opts_) |opts| {
192195
switch (opts) {
193196
.capture => |c| capture = c,
194197
.flags => |f| {
195-
// Done this way so that, for common cases that _only_ set
196-
// capture, i.e. {captrue: true}, it works.
197-
// But for any case that sets any of the other flags, we
198-
// error. If we don't error, this function call would succeed
199-
// but the behavior might be wrong. At this point, it's
200-
// better to be explicit and error.
201-
if (f.signal orelse false) return error.NotImplemented;
202198
once = f.once orelse false;
199+
signal = f.signal orelse null;
203200
capture = f.capture orelse false;
204201
},
205202
}
206203
}
207204

208205
const callback = (try listener.callback(target)) orelse return null;
209206

207+
if (signal) |s| {
208+
std.debug.print("add signal\n", .{});
209+
const signal_target = parser.toEventTarget(AbortSignal, s);
210+
211+
const scb = try allocator.create(SignalCallback);
212+
scb.* = .{
213+
.target = target,
214+
.capture = capture,
215+
.callback_id = callback.id,
216+
.typ = try allocator.dupe(u8, typ),
217+
.signal_target = signal_target,
218+
.signal_listener = undefined,
219+
.node = .{.func = SignalCallback.handle },
220+
};
221+
222+
scb.signal_listener = try parser.eventTargetAddEventListener(
223+
signal_target,
224+
"abort",
225+
&scb.node,
226+
false,
227+
);
228+
}
229+
210230
// check if event target has already this listener
211231
if (try parser.eventTargetHasListener(target, typ, capture, callback.id) != null) {
212232
return null;
@@ -262,6 +282,50 @@ pub const EventHandler = struct {
262282
}
263283
};
264284

285+
const SignalCallback = struct {
286+
typ: []const u8,
287+
capture: bool,
288+
callback_id: usize,
289+
node : parser.EventNode,
290+
target: *parser.EventTarget,
291+
signal_target: *parser.EventTarget,
292+
signal_listener: *parser.EventListener,
293+
294+
fn handle(node: *parser.EventNode, _: *parser.Event) void {
295+
const self: *SignalCallback = @fieldParentPtr("node", node);
296+
self._handle() catch |err| {
297+
log.err(.app, "event signal handler", .{ .err = err });
298+
};
299+
}
300+
301+
fn _handle(self: *SignalCallback) !void {
302+
const lst = try parser.eventTargetHasListener(
303+
self.target,
304+
self.typ,
305+
self.capture,
306+
self.callback_id,
307+
);
308+
if (lst == null) {
309+
return;
310+
}
311+
312+
try parser.eventTargetRemoveEventListener(
313+
self.target,
314+
self.typ,
315+
lst.?,
316+
self.capture,
317+
);
318+
319+
// remove the abort signal listener itself
320+
try parser.eventTargetRemoveEventListener(
321+
self.signal_target,
322+
"abort",
323+
self.signal_listener,
324+
false,
325+
);
326+
}
327+
};
328+
265329
const testing = @import("../../testing.zig");
266330
test "Browser.Event" {
267331
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
@@ -367,5 +431,18 @@ test "Browser.Event" {
367431
.{ "document.dispatchEvent(new Event('count'))", "true" },
368432
.{ "document.dispatchEvent(new Event('count'))", "true" },
369433
.{ "nb", "1" },
434+
.{ "document.removeEventListener('count', cbk)", "undefined" },
435+
}, .{});
436+
437+
try runner.testCases(&.{
438+
.{ "nb = 0; function cbk(event) { nb ++; }", null },
439+
.{ "let ac = new AbortController()", null},
440+
.{ "document.addEventListener('count', cbk, {signal: ac.signal})", null },
441+
.{ "document.dispatchEvent(new Event('count'))", "true" },
442+
.{ "document.dispatchEvent(new Event('count'))", "true" },
443+
.{ "ac.abort()", null},
444+
.{ "document.dispatchEvent(new Event('count'))", "true" },
445+
.{ "nb", "2" },
446+
.{ "document.removeEventListener('count', cbk)", "undefined" },
370447
}, .{});
371448
}

0 commit comments

Comments
 (0)