Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/browser/browser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ pub const Page = struct {

renderer: FlatRenderer,

window_clicked_event_node: parser.EventNode,

scope: *Env.Scope,

// current_script is the script currently evaluated by the page.
Expand All @@ -263,6 +265,7 @@ pub const Page = struct {
.url = URL.empty,
.session = session,
.renderer = FlatRenderer.init(arena),
.window_clicked_event_node = .{ .func = windowClicked },
.state = .{
.arena = arena,
.document = null,
Expand Down Expand Up @@ -423,12 +426,10 @@ pub const Page = struct {
self.doc = doc;

const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError;
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Element, document_element),
arena,
"click",
windowClicked,
self,
&self.window_clicked_event_node,
false,
);

Expand Down Expand Up @@ -698,8 +699,8 @@ pub const Page = struct {
_ = try parser.elementDispatchEvent(element, @ptrCast(event));
}

fn windowClicked(ctx: *anyopaque, event: *parser.Event) void {
const self: *Page = @alignCast(@ptrCast(ctx));
fn windowClicked(node: *parser.EventNode, event: *parser.Event) void {
const self: *Page = @fieldParentPtr("window_clicked_event_node", node);
self._windowClicked(event) catch |err| {
log.err("window click handler: {}", .{err});
};
Expand Down
20 changes: 9 additions & 11 deletions src/browser/dom/event_target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub const EventTarget = struct {

pub fn _addEventListener(
self: *parser.EventTarget,
eventType: []const u8,
typ: []const u8,
cbk: Env.Callback,
capture: ?bool,
state: *SessionState,
Expand All @@ -56,37 +56,36 @@ pub const EventTarget = struct {
// check if event target has already this listener
const lst = try parser.eventTargetHasListener(
self,
eventType,
typ,
capture orelse false,
cbk.id,
);
if (lst != null) {
return;
}

const eh = try EventHandler.init(state.arena, try cbk.withThis(self));

try parser.eventTargetAddEventListener(
self,
state.arena,
eventType,
EventHandler,
.{ .cbk = cbk },
typ,
&eh.node,
capture orelse false,
);
}

pub fn _removeEventListener(
self: *parser.EventTarget,
eventType: []const u8,
typ: []const u8,
cbk: Env.Callback,
capture: ?bool,
state: *SessionState,
// TODO: hanle EventListenerOptions
// see #https://github.com/lightpanda-io/jsruntime-lib/issues/114
) !void {
// check if event target has already this listener
const lst = try parser.eventTargetHasListener(
self,
eventType,
typ,
capture orelse false,
cbk.id,
);
Expand All @@ -97,8 +96,7 @@ pub const EventTarget = struct {
// remove listener
try parser.eventTargetRemoveEventListener(
self,
state.arena,
eventType,
typ,
lst.?,
capture orelse false,
);
Expand Down
41 changes: 16 additions & 25 deletions src/browser/dom/mutation_observer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -59,56 +59,45 @@ pub const MutationObserver = struct {
.node = node,
.options = options,
.mutation_observer = self,
.event_node = .{ .id = self.cbk.id, .func = Observer.handle },
};

const arena = self.arena;

// register node's events
if (options.childList or options.subtree) {
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Node, node),
arena,
"DOMNodeInserted",
Observer.handle,
observer,
&observer.event_node,
false,
);
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Node, node),
arena,
"DOMNodeRemoved",
Observer.handle,
observer,
&observer.event_node,
false,
);
}
if (options.attr()) {
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Node, node),
arena,
"DOMAttrModified",
Observer.handle,
observer,
&observer.event_node,
false,
);
}
if (options.cdata()) {
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Node, node),
arena,
"DOMCharacterDataModified",
Observer.handle,
observer,
&observer.event_node,
false,
);
}
if (options.subtree) {
try parser.eventTargetAddZigListener(
try parser.eventTargetAddEventListener(
parser.toEventTarget(parser.Node, node),
arena,
"DOMSubtreeModified",
Observer.handle,
observer,
&observer.event_node,
false,
);
}
Expand Down Expand Up @@ -221,6 +210,8 @@ const Observer = struct {
// and batch the mutation records.
mutation_observer: *MutationObserver,

event_node: parser.EventNode,

fn appliesTo(o: *const Observer, target: *parser.Node) bool {
// mutation on any target is always ok.
if (o.options.subtree) {
Expand Down Expand Up @@ -250,9 +241,9 @@ const Observer = struct {
return false;
}

fn handle(ctx: *anyopaque, event: *parser.Event) void {
// retrieve the observer from the data.
var self: *Observer = @alignCast(@ptrCast(ctx));
fn handle(en: *parser.EventNode, event: *parser.Event) void {
const self: *Observer = @fieldParentPtr("event_node", en);

var mutation_observer = self.mutation_observer;

const node = blk: {
Expand Down
28 changes: 25 additions & 3 deletions src/browser/events/event.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

const std = @import("std");
const Allocator = std.mem.Allocator;

const parser = @import("../netsurf.zig");
const Callback = @import("../env.zig").Callback;
Expand Down Expand Up @@ -136,14 +137,35 @@ pub const Event = struct {
};

pub const EventHandler = struct {
fn handle(event: ?*parser.Event, data: *const parser.JSEventHandlerData) void {
callback: Callback,
node: parser.EventNode,

pub fn init(allocator: Allocator, callback: Callback) !*EventHandler {
const eh = try allocator.create(EventHandler);
eh.* = .{
.callback = callback,
.node = .{
.id = callback.id,
.func = handle,
},
};
return eh;
}

fn handle(node: *parser.EventNode, event: *parser.Event) void {
const ievent = Event.toInterface(event) catch |err| {
log.err("Event.toInterface: {}", .{err});
return;
};

const self: *EventHandler = @fieldParentPtr("node", node);
var result: Callback.Result = undefined;
data.cbk.tryCall(.{if (event) |evt| Event.toInterface(evt) catch unreachable else null}, &result) catch {
self.callback.tryCall(.{ievent}, &result) catch {
log.err("event handler error: {s}", .{result.exception});
log.debug("stack:\n{s}", .{result.stack orelse "???"});
};
}
}.handle;
};

const testing = @import("../../testing.zig");
test "Browser.Event" {
Expand Down
Loading
Loading