From a1aba064d37d1c4a6d78e276a034fe15555380fa Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Thu, 8 Feb 2024 14:22:02 +0100 Subject: [PATCH 1/4] WIP UIEvent Signed-off-by: Francis Bouvier --- src/events/event.zig | 2 ++ src/events/event_ui.zig | 48 +++++++++++++++++++++++++++++++++++++++++ src/netsurf.zig | 32 +++++++++++++++++++++++++++ src/run_tests.zig | 2 ++ 4 files changed, 84 insertions(+) create mode 100644 src/events/event_ui.zig diff --git a/src/events/event.zig b/src/events/event.zig index fe939621..d07e4493 100644 --- a/src/events/event.zig +++ b/src/events/event.zig @@ -12,6 +12,7 @@ const parser = @import("../netsurf.zig"); const DOMException = @import("../dom/exceptions.zig").DOMException; const EventTarget = @import("../dom/event_target.zig").EventTarget; const EventTargetUnion = @import("../dom/event_target.zig").Union; +const UIEvent = @import("event_ui.zig").UIEvent; // https://dom.spec.whatwg.org/#event pub const Event = struct { @@ -107,6 +108,7 @@ pub const Event = struct { // Event interfaces pub const Interfaces = generate.Tuple(.{ Event, + UIEvent, }); const Generated = generate.Union.compile(Interfaces); pub const Union = Generated._union; diff --git a/src/events/event_ui.zig b/src/events/event_ui.zig new file mode 100644 index 00000000..d2ab29e6 --- /dev/null +++ b/src/events/event_ui.zig @@ -0,0 +1,48 @@ +const std = @import("std"); + +const jsruntime = @import("jsruntime"); +const Case = jsruntime.test_utils.Case; +const checkCases = jsruntime.test_utils.checkCases; + +const parser = @import("../netsurf.zig"); + +const Event = @import("event.zig").Event; +const Window = @import("../html/window.zig").Window; + +pub const UIEvent = struct { + pub const Self = parser.UIEvent; + pub const mem_guarantied = true; + + pub const UIEventInit = parser.UIEventInit; + + // JS + // -- + + pub fn constructor(typ: []const u8, opts: ?UIEventInit) !*parser.UIEvent { + const evt = try parser.uiEventCreate(); + try parser.uiEventInit(evt, typ, opts orelse UIEventInit{}); + return evt; + } + + // pub fn get_detail(self: parser.EventUI) !u32 { + // return try parser.eventUIDetail(self); + // } + + // pub fn get_view(self: parser.Event) !?Window { + // return try parser.eventUIView(self); + // } +}; + +pub fn testExecFn( + _: std.mem.Allocator, + js_env: *jsruntime.Env, +) anyerror!void { + var ui_event = [_]Case{ + .{ .src = "let content = document.getElementById('content')", .ex = "undefined" }, + .{ .src = "var evt", .ex = "undefined" }, + .{ .src = "content.addEventListener('evt', function(e) {evt = e})", .ex = "undefined" }, + .{ .src = "content.dispatchEvent(new UIEvent('evt'))", .ex = "true" }, + .{ .src = "evt instanceof UIEvent", .ex = "true" }, + }; + try checkCases(js_env, &ui_event); +} diff --git a/src/netsurf.zig b/src/netsurf.zig index 7b40363c..0f46cf4f 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -7,6 +7,8 @@ const c = @cImport({ const Callback = @import("jsruntime").Callback; +const Window = @import("html/window.zig").Window; + // Vtable // ------ @@ -443,6 +445,36 @@ pub fn eventPreventDefault(evt: *Event) !void { try DOMErr(err); } +// UIEvent +pub const UIEvent = c.dom_ui_event; + +pub fn uiEventCreate() !*UIEvent { + var evt: ?*UIEvent = undefined; + const err = c._dom_ui_event_create(&evt); + try DOMErr(err); + return evt.?; +} + +pub const UIEventInit = struct { + bubbles: bool = false, + cancelable: bool = false, + + view: ?Window = null, + detail: i32 = 0, +}; + +pub fn uiEventInit(evt: *UIEvent, typ: []const u8, opts: UIEventInit) !void { + const err = c._dom_ui_event_init( + evt, + try strFromData(typ), + opts.bubbles, + opts.cancelable, + null, + opts.detail, + ); + try DOMErr(err); +} + // EventHandler fn event_handler_cbk(data: *anyopaque) *Callback { const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data); diff --git a/src/run_tests.zig b/src/run_tests.zig index 22adffe9..3f70ccc8 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -22,6 +22,7 @@ const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn; const AttrTestExecFn = @import("dom/attribute.zig").testExecFn; const EventTargetTestExecFn = @import("dom/event_target.zig").testExecFn; const EventTestExecFn = @import("events/event.zig").testExecFn; +const UIEventTestExecFn = @import("events/event_ui.zig").testExecFn; pub const Types = jsruntime.reflect(apiweb.Interfaces); @@ -77,6 +78,7 @@ fn testsAllExecFn( AttrTestExecFn, EventTargetTestExecFn, EventTestExecFn, + UIEventTestExecFn, }; inline for (testFns) |testFn| { From b744ac438e70f8907f4697247cff4c3aa9a2ff9f Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 8 Feb 2024 14:44:44 +0100 Subject: [PATCH 2/4] netsurf: import event and ui_event headers --- src/netsurf.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/netsurf.zig b/src/netsurf.zig index 0f46cf4f..68bcdcd7 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -3,6 +3,8 @@ const std = @import("std"); const c = @cImport({ @cInclude("dom/dom.h"); @cInclude("dom/bindings/hubbub/parser.h"); + @cInclude("events/event.h"); + @cInclude("events/ui_event.h"); }); const Callback = @import("jsruntime").Callback; From 110a43d2397e0b383a4b28fc8ba78f773b8cbb87 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 8 Feb 2024 15:04:49 +0100 Subject: [PATCH 3/4] event: add detail and view implementations --- src/events/event_ui.zig | 15 +++++++++------ src/netsurf.zig | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/events/event_ui.zig b/src/events/event_ui.zig index d2ab29e6..c2aad6b8 100644 --- a/src/events/event_ui.zig +++ b/src/events/event_ui.zig @@ -24,13 +24,13 @@ pub const UIEvent = struct { return evt; } - // pub fn get_detail(self: parser.EventUI) !u32 { - // return try parser.eventUIDetail(self); - // } + pub fn get_detail(self: *parser.UIEvent) !i32 { + return try parser.uiEventDetail(self); + } - // pub fn get_view(self: parser.Event) !?Window { - // return try parser.eventUIView(self); - // } + pub fn get_view(self: *parser.UIEvent) !?Window { + return try parser.uiEventView(self); + } }; pub fn testExecFn( @@ -43,6 +43,9 @@ pub fn testExecFn( .{ .src = "content.addEventListener('evt', function(e) {evt = e})", .ex = "undefined" }, .{ .src = "content.dispatchEvent(new UIEvent('evt'))", .ex = "true" }, .{ .src = "evt instanceof UIEvent", .ex = "true" }, + .{ .src = "evt.__proto__.constructor.name", .ex = "UIEvent" }, + .{ .src = "evt.detail", .ex = "0" }, + .{ .src = "evt.view", .ex = "null" }, }; try checkCases(js_env, &ui_event); } diff --git a/src/netsurf.zig b/src/netsurf.zig index 68bcdcd7..a8401d10 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -471,12 +471,28 @@ pub fn uiEventInit(evt: *UIEvent, typ: []const u8, opts: UIEventInit) !void { try strFromData(typ), opts.bubbles, opts.cancelable, + // TODO pass the Window as view. + // opts.view null, opts.detail, ); try DOMErr(err); } +pub fn uiEventDetail(evt: *UIEvent) !i32 { + var res: i32 = undefined; + const err = c._dom_ui_event_get_detail(evt, &res); + try DOMErr(err); + return res; +} + +pub fn uiEventView(_: *UIEvent) !?Window { + // TODO retrieve the Window as view. + // const err = c._dom_ui_event_get_view(evt, &res); + // try DOMErr(err); + return null; +} + // EventHandler fn event_handler_cbk(data: *anyopaque) *Callback { const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data); From 988b301e9f524208566f63b4c46edf7b8cb650cb Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 8 Feb 2024 15:10:29 +0100 Subject: [PATCH 4/4] event: rename ui_event file --- src/events/event.zig | 2 +- src/events/{event_ui.zig => ui_event.zig} | 0 src/run_tests.zig | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/events/{event_ui.zig => ui_event.zig} (100%) diff --git a/src/events/event.zig b/src/events/event.zig index d07e4493..56aeb037 100644 --- a/src/events/event.zig +++ b/src/events/event.zig @@ -12,7 +12,7 @@ const parser = @import("../netsurf.zig"); const DOMException = @import("../dom/exceptions.zig").DOMException; const EventTarget = @import("../dom/event_target.zig").EventTarget; const EventTargetUnion = @import("../dom/event_target.zig").Union; -const UIEvent = @import("event_ui.zig").UIEvent; +const UIEvent = @import("ui_event.zig").UIEvent; // https://dom.spec.whatwg.org/#event pub const Event = struct { diff --git a/src/events/event_ui.zig b/src/events/ui_event.zig similarity index 100% rename from src/events/event_ui.zig rename to src/events/ui_event.zig diff --git a/src/run_tests.zig b/src/run_tests.zig index 3f70ccc8..d771b508 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -22,7 +22,7 @@ const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn; const AttrTestExecFn = @import("dom/attribute.zig").testExecFn; const EventTargetTestExecFn = @import("dom/event_target.zig").testExecFn; const EventTestExecFn = @import("events/event.zig").testExecFn; -const UIEventTestExecFn = @import("events/event_ui.zig").testExecFn; +const UIEventTestExecFn = @import("events/ui_event.zig").testExecFn; pub const Types = jsruntime.reflect(apiweb.Interfaces);