Skip to content

Commit 3483dfa

Browse files
Check if event target has listener before adding it
Signed-off-by: Francis Bouvier <[email protected]>
1 parent e7dcf42 commit 3483dfa

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

src/dom/event_target.zig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ pub const EventTarget = struct {
3737
// TODO: hanle EventListenerOptions
3838
// see #https://github.com/lightpanda-io/jsruntime-lib/issues/114
3939
) !void {
40+
41+
// check if event target has already this listener
42+
const lst = try parser.eventTargetHasListener(self, eventType, cbk.id());
43+
if (lst != null) {
44+
return;
45+
}
46+
4047
// TODO: when can we free this allocation?
4148
const cbk_ptr = try alloc.create(Callback);
4249
cbk_ptr.* = cbk;
@@ -85,6 +92,14 @@ pub fn testExecFn(
8592
};
8693
try checkCases(js_env, &basic);
8794

95+
var basic_twice = [_]Case{
96+
.{ .src = "nb = 0", .ex = "0" },
97+
.{ .src = "content.addEventListener('basic', cbk)", .ex = "undefined" },
98+
.{ .src = "content.dispatchEvent(new Event('basic'))", .ex = "true" },
99+
.{ .src = "nb", .ex = "1" },
100+
};
101+
try checkCases(js_env, &basic_twice);
102+
88103
var basic_child = [_]Case{
89104
.{ .src = "nb = 0; evt = undefined; phase = undefined; cur = undefined", .ex = "undefined" },
90105
.{ .src = "para.dispatchEvent(new Event('basic'))", .ex = "true" },

src/netsurf.zig

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,13 +458,58 @@ const event_handler = struct {
458458
}
459459
}.handle;
460460

461+
// EventListener
462+
pub const EventListener = c.dom_event_listener;
463+
464+
pub fn eventListenerGetData(lst: *EventListener) ?*anyopaque {
465+
return c.dom_event_listener_get_data(lst);
466+
}
467+
461468
// EventTarget
462469
pub const EventTarget = c.dom_event_target;
463470

464471
fn eventTargetVtable(et: *EventTarget) c.dom_event_target_vtable {
465472
return getVtable(c.dom_event_target_vtable, EventTarget, et);
466473
}
467474

475+
pub fn eventTargetHasListener(et: *EventTarget, typ: []const u8, cbk_id: usize) !?*EventListener {
476+
const str = try strFromData(typ);
477+
478+
const EventListenerEntry = c.listener_entry;
479+
var current: ?*EventListenerEntry = null;
480+
var next: ?*EventListenerEntry = undefined;
481+
var lst: ?*EventListener = undefined;
482+
483+
// iterate over the EventTarget's listeners
484+
while (true) {
485+
const err = eventTargetVtable(et).iter_event_listener.?(et, str, current, &next, &lst);
486+
try DOMErr(err);
487+
488+
if (lst) |listener| {
489+
// the EventTarget has a listener for this event type,
490+
// let's check if the callback is the same
491+
defer c.dom_event_listener_unref(listener);
492+
const data = eventListenerGetData(listener);
493+
if (data) |d| {
494+
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(d);
495+
const cbk = @as(*Callback, @ptrCast(ptr));
496+
if (cbk_id == cbk.id())
497+
return lst;
498+
}
499+
}
500+
501+
if (next == null) {
502+
// no more listeners, end of the iteration
503+
break;
504+
}
505+
506+
// next iteration
507+
current = next;
508+
}
509+
510+
return null;
511+
}
512+
468513
pub fn eventTargetAddEventListener(
469514
et: *EventTarget,
470515
typ: []const u8,
@@ -473,7 +518,7 @@ pub fn eventTargetAddEventListener(
473518
) !void {
474519
const s = try strFromData(typ);
475520
const ctx = @as(*anyopaque, @ptrCast(cbk_ptr));
476-
var listener: ?*c.dom_event_listener = undefined;
521+
var listener: ?*EventListener = undefined;
477522
const errLst = c.dom_event_listener_create(event_handler, ctx, &listener);
478523
try DOMErr(errLst);
479524
const err = eventTargetVtable(et).add_event_listener.?(et, s, listener, capture);

vendor/jsruntime-lib

0 commit comments

Comments
 (0)