mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
First implementation of Event system
Signed-off-by: Francis Bouvier <francis@lightpanda.io>
This commit is contained in:
@@ -4,6 +4,7 @@ const Console = @import("jsruntime").Console;
|
|||||||
|
|
||||||
const DOM = @import("dom/dom.zig");
|
const DOM = @import("dom/dom.zig");
|
||||||
const HTML = @import("html/html.zig");
|
const HTML = @import("html/html.zig");
|
||||||
|
const Events = @import("events/event.zig");
|
||||||
|
|
||||||
pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
||||||
|
|
||||||
@@ -11,5 +12,6 @@ pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
|||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = generate.Tuple(.{
|
||||||
Console,
|
Console,
|
||||||
DOM.Interfaces,
|
DOM.Interfaces,
|
||||||
|
Events.Interfaces,
|
||||||
HTML.Interfaces,
|
HTML.Interfaces,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const jsruntime = @import("jsruntime");
|
||||||
|
const Callback = jsruntime.Callback;
|
||||||
|
const Case = jsruntime.test_utils.Case;
|
||||||
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
const DOMException = @import("exceptions.zig").DOMException;
|
const DOMException = @import("exceptions.zig").DOMException;
|
||||||
@@ -6,4 +13,55 @@ pub const EventTarget = struct {
|
|||||||
pub const Self = parser.EventTarget;
|
pub const Self = parser.EventTarget;
|
||||||
pub const Exception = DOMException;
|
pub const Exception = DOMException;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
// JS funcs
|
||||||
|
// --------
|
||||||
|
|
||||||
|
const js_handler = struct {
|
||||||
|
fn handle(event: ?*parser.Event, data: ?*anyopaque) callconv(.C) void {
|
||||||
|
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data.?);
|
||||||
|
const func = @as(*Callback, @ptrCast(ptr));
|
||||||
|
func.call(.{event}) catch unreachable;
|
||||||
|
// NOTE: we can not call func.deinit here
|
||||||
|
// b/c the handler can be called several times
|
||||||
|
// as the event goes through the ancestors
|
||||||
|
// TODO: check the event phase to call func.deinit and free func
|
||||||
|
}
|
||||||
|
}.handle;
|
||||||
|
|
||||||
|
pub fn _addEventListener(
|
||||||
|
self: *parser.EventTarget,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
eventType: []const u8,
|
||||||
|
cbk: Callback,
|
||||||
|
) !void {
|
||||||
|
// TODO: when can we free this allocation?
|
||||||
|
const cbk_ptr = try alloc.create(Callback);
|
||||||
|
cbk_ptr.* = cbk;
|
||||||
|
const func = @as(*anyopaque, @ptrCast(cbk_ptr));
|
||||||
|
try parser.eventTargetAddEventListener(self, eventType, func, js_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _dispatchEvent(self: *parser.EventTarget, event: *parser.Event) !bool {
|
||||||
|
return try parser.eventTargetDispatchEvent(self, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(_: *parser.EventTarget, _: std.mem.Allocator) void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
pub fn testExecFn(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
) anyerror!void {
|
||||||
|
var basic = [_]Case{
|
||||||
|
.{ .src = "let event = new Event('myEvent')", .ex = "undefined" },
|
||||||
|
.{ .src = "let content = document.getElementById('content')", .ex = "undefined" },
|
||||||
|
.{ .src = "var nb = 0; content.addEventListener('myEvent', function(event) {nb ++;})", .ex = "undefined" },
|
||||||
|
.{ .src = "content.dispatchEvent(event)", .ex = "true" },
|
||||||
|
.{ .src = "nb", .ex = "2" }, // 2 because the callback is called twice
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &basic);
|
||||||
|
}
|
||||||
|
|||||||
29
src/events/event.zig
Normal file
29
src/events/event.zig
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const generate = @import("../generate.zig");
|
||||||
|
|
||||||
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
|
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
||||||
|
|
||||||
|
pub const Event = struct {
|
||||||
|
pub const Self = parser.Event;
|
||||||
|
pub const Exception = DOMException;
|
||||||
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
// JS funcs
|
||||||
|
// --------
|
||||||
|
|
||||||
|
pub fn constructor(eventType: []const u8) !*parser.Event {
|
||||||
|
const event = try parser.eventCreate();
|
||||||
|
try parser.eventInit(event, eventType);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event interfaces
|
||||||
|
pub const Interfaces = generate.Tuple(.{
|
||||||
|
Event,
|
||||||
|
});
|
||||||
|
const Generated = generate.Union.compile(Interfaces);
|
||||||
|
pub const Union = Generated._union;
|
||||||
@@ -341,9 +341,51 @@ fn DOMErr(except: DOMException) DOMError!void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event
|
||||||
|
pub const Event = c.dom_event;
|
||||||
|
pub const EventHandler = fn (?*Event, ?*anyopaque) callconv(.C) void;
|
||||||
|
|
||||||
|
pub fn eventCreate() !*Event {
|
||||||
|
var evt: ?*Event = undefined;
|
||||||
|
const err = c._dom_event_create(&evt);
|
||||||
|
try DOMErr(err);
|
||||||
|
return evt.?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventInit(evt: *Event, eventType: []const u8) !void {
|
||||||
|
const s = try strFromData(eventType);
|
||||||
|
const err = c._dom_event_init(evt, s, false, false);
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
// EventTarget
|
// EventTarget
|
||||||
pub const EventTarget = c.dom_event_target;
|
pub const EventTarget = c.dom_event_target;
|
||||||
|
|
||||||
|
fn eventTargetVtable(et: *EventTarget) c.dom_event_target_vtable {
|
||||||
|
return getVtable(c.dom_event_target_vtable, EventTarget, et);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventTargetAddEventListener(
|
||||||
|
et: *EventTarget,
|
||||||
|
eventType: []const u8,
|
||||||
|
data: ?*anyopaque,
|
||||||
|
comptime handler: EventHandler,
|
||||||
|
) !void {
|
||||||
|
const s = try strFromData(eventType);
|
||||||
|
var listener: ?*c.dom_event_listener = undefined;
|
||||||
|
const errLst = c.dom_event_listener_create(handler, data, &listener);
|
||||||
|
try DOMErr(errLst);
|
||||||
|
const err = eventTargetVtable(et).add_event_listener.?(et, s, listener, true);
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventTargetDispatchEvent(et: *EventTarget, event: *Event) !bool {
|
||||||
|
var res: bool = undefined;
|
||||||
|
const err = eventTargetVtable(et).dispatch_event.?(et, event, &res);
|
||||||
|
try DOMErr(err);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// NodeType
|
// NodeType
|
||||||
|
|
||||||
pub const NodeType = enum(u4) {
|
pub const NodeType = enum(u4) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const NamedNodeMapExecFn = @import("dom/namednodemap.zig").testExecFn;
|
|||||||
const DOMTokenListExecFn = @import("dom/token_list.zig").testExecFn;
|
const DOMTokenListExecFn = @import("dom/token_list.zig").testExecFn;
|
||||||
const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn;
|
const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn;
|
||||||
const AttrTestExecFn = @import("dom/attribute.zig").testExecFn;
|
const AttrTestExecFn = @import("dom/attribute.zig").testExecFn;
|
||||||
|
const EventTargetTestExecFn = @import("dom/event_target.zig").testExecFn;
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ fn testsAllExecFn(
|
|||||||
DOMTokenListExecFn,
|
DOMTokenListExecFn,
|
||||||
NodeListTestExecFn,
|
NodeListTestExecFn,
|
||||||
AttrTestExecFn,
|
AttrTestExecFn,
|
||||||
|
EventTargetTestExecFn,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline for (testFns) |testFn| {
|
inline for (testFns) |testFn| {
|
||||||
|
|||||||
Reference in New Issue
Block a user