diff --git a/src/html/window.zig b/src/html/window.zig index 5c844a49..cba2337a 100644 --- a/src/html/window.zig +++ b/src/html/window.zig @@ -1,6 +1,9 @@ const std = @import("std"); const parser = @import("../netsurf.zig"); +const c = @cImport({ + @cInclude("events/event_target.h"); +}); const EventTarget = @import("../dom/event_target.zig").EventTarget; @@ -10,6 +13,9 @@ pub const Window = struct { pub const prototype = *EventTarget; pub const mem_guarantied = true; + // Extend libdom event target for pure zig struct. + base: parser.EventTargetTBase = parser.EventTargetTBase{}, + document: ?*parser.Document = null, target: []const u8, @@ -42,6 +48,4 @@ pub const Window = struct { pub fn get_name(self: *Window) []const u8 { return self.target; } - - // TODO we need to re-implement EventTarget interface. }; diff --git a/src/netsurf.zig b/src/netsurf.zig index 7b40363c..a950d1a7 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -3,6 +3,7 @@ const std = @import("std"); const c = @cImport({ @cInclude("dom/dom.h"); @cInclude("dom/bindings/hubbub/parser.h"); + @cInclude("events/event_target.h"); }); const Callback = @import("jsruntime").Callback; @@ -622,6 +623,33 @@ pub fn eventTargetDispatchEvent(et: *EventTarget, event: *Event) !bool { return res; } +// EventTargetBase is used to implement EventTarget for pure zig struct. +pub const EventTargetTBase = struct { + const Self = @This(); + + vtable: ?*const c.struct_dom_event_target_vtable = &c.struct_dom_event_target_vtable{ + .dispatch_event = dispatch_event, + .remove_event_listener = remove_event_listener, + .add_event_listener = add_event_listener, + }, + eti: c.dom_event_target_internal = c.dom_event_target_internal{ .listeners = null }, + + pub fn add_event_listener(et: [*c]c.dom_event_target, t: [*c]c.dom_string, l: ?*c.struct_dom_event_listener, capture: bool) callconv(.C) c.dom_exception { + const self = @as(*Self, @ptrCast(et)); + return c._dom_event_target_add_event_listener(&self.eti, t, l, capture); + } + + pub fn dispatch_event(et: [*c]c.dom_event_target, evt: ?*c.struct_dom_event, res: [*c]bool) callconv(.C) c.dom_exception { + const self = @as(*Self, @ptrCast(et)); + return c._dom_event_target_dispatch(et, &self.eti, evt, c.DOM_BUBBLING_PHASE, res); + } + + pub fn remove_event_listener(et: [*c]c.dom_event_target, t: [*c]c.dom_string, l: ?*c.struct_dom_event_listener, capture: bool) callconv(.C) c.dom_exception { + const self = @as(*Self, @ptrCast(et)); + return c._dom_event_target_add_event_listener(&self.eti, t, l, capture); + } +}; + // NodeType pub const NodeType = enum(u4) { diff --git a/src/run_tests.zig b/src/run_tests.zig index 22adffe9..ae5a247e 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -6,6 +6,7 @@ const generate = @import("generate.zig"); const parser = @import("netsurf.zig"); const apiweb = @import("apiweb.zig"); +const Window = @import("html/window.zig").Window; const documentTestExecFn = @import("dom/document.zig").testExecFn; const HTMLDocumentTestExecFn = @import("html/document.zig").testExecFn; @@ -135,3 +136,13 @@ test "run browser tests" { try dump.HTMLFileTestFn(out); } + +test "Window is a libdom event target" { + var window = Window.create(null); + + const event = try parser.eventCreate(); + try parser.eventInit(event, "foo", .{}); + + const et = @as(*parser.EventTarget, @ptrCast(&window)); + _ = try parser.eventTargetDispatchEvent(et, event); +}