mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Merge pull request #1576 from lightpanda-io/navigation-is-event-target
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Navigation is the EventTarget
This commit is contained in:
@@ -175,6 +175,13 @@ pub fn eventTarget(self: *Factory, child: anytype) !*@TypeOf(child) {
|
|||||||
return chain.get(1);
|
return chain.get(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn standaloneEventTarget(self: *Factory, child: anytype) !*EventTarget {
|
||||||
|
const allocator = self._slab.allocator();
|
||||||
|
const et = try allocator.create(EventTarget);
|
||||||
|
et.* = .{ ._type = unionInit(EventTarget.Type, child) };
|
||||||
|
return et;
|
||||||
|
}
|
||||||
|
|
||||||
// this is a root object
|
// this is a root object
|
||||||
pub fn event(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
pub fn event(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
||||||
const chain = try PrototypeChain(
|
const chain = try PrototypeChain(
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ pub fn init(self: *Session, browser: *Browser, notification: *Notification) !voi
|
|||||||
.page = null,
|
.page = null,
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.history = .{},
|
.history = .{},
|
||||||
.navigation = .{},
|
// The prototype (EventTarget) for Navigation is created when a Page is created.
|
||||||
|
.navigation = .{ ._proto = undefined },
|
||||||
.storage_shed = .{},
|
.storage_shed = .{},
|
||||||
.browser = browser,
|
.browser = browser,
|
||||||
.notification = notification,
|
.notification = notification,
|
||||||
|
|||||||
@@ -861,7 +861,6 @@ pub const JsApis = flattenTypes(&.{
|
|||||||
@import("../webapi/VisualViewport.zig"),
|
@import("../webapi/VisualViewport.zig"),
|
||||||
@import("../webapi/PerformanceObserver.zig"),
|
@import("../webapi/PerformanceObserver.zig"),
|
||||||
@import("../webapi/navigation/Navigation.zig"),
|
@import("../webapi/navigation/Navigation.zig"),
|
||||||
@import("../webapi/navigation/NavigationEventTarget.zig"),
|
|
||||||
@import("../webapi/navigation/NavigationHistoryEntry.zig"),
|
@import("../webapi/navigation/NavigationHistoryEntry.zig"),
|
||||||
@import("../webapi/navigation/NavigationActivation.zig"),
|
@import("../webapi/navigation/NavigationActivation.zig"),
|
||||||
@import("../webapi/canvas/CanvasRenderingContext2D.zig"),
|
@import("../webapi/canvas/CanvasRenderingContext2D.zig"),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub const Type = union(enum) {
|
|||||||
media_query_list: *@import("css/MediaQueryList.zig"),
|
media_query_list: *@import("css/MediaQueryList.zig"),
|
||||||
message_port: *@import("MessagePort.zig"),
|
message_port: *@import("MessagePort.zig"),
|
||||||
text_track_cue: *@import("media/TextTrackCue.zig"),
|
text_track_cue: *@import("media/TextTrackCue.zig"),
|
||||||
navigation: *@import("navigation/NavigationEventTarget.zig"),
|
navigation: *@import("navigation/Navigation.zig"),
|
||||||
screen: *@import("Screen.zig"),
|
screen: *@import("Screen.zig"),
|
||||||
screen_orientation: *@import("Screen.zig").Orientation,
|
screen_orientation: *@import("Screen.zig").Orientation,
|
||||||
visual_viewport: *@import("VisualViewport.zig"),
|
visual_viewport: *@import("VisualViewport.zig"),
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ const URL = @import("../URL.zig");
|
|||||||
const js = @import("../../js/js.zig");
|
const js = @import("../../js/js.zig");
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
|
|
||||||
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||||
|
|
||||||
const EventTarget = @import("../EventTarget.zig");
|
const EventTarget = @import("../EventTarget.zig");
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Navigation
|
// https://developer.mozilla.org/en-US/docs/Web/API/Navigation
|
||||||
@@ -36,9 +38,10 @@ const NavigationState = @import("root.zig").NavigationState;
|
|||||||
|
|
||||||
const NavigationHistoryEntry = @import("NavigationHistoryEntry.zig");
|
const NavigationHistoryEntry = @import("NavigationHistoryEntry.zig");
|
||||||
const NavigationCurrentEntryChangeEvent = @import("../event/NavigationCurrentEntryChangeEvent.zig");
|
const NavigationCurrentEntryChangeEvent = @import("../event/NavigationCurrentEntryChangeEvent.zig");
|
||||||
const NavigationEventTarget = @import("NavigationEventTarget.zig");
|
|
||||||
|
|
||||||
_proto: *NavigationEventTarget = undefined,
|
_proto: *EventTarget,
|
||||||
|
_on_currententrychange: ?js.Function.Global = null,
|
||||||
|
|
||||||
_current_navigation_kind: ?NavigationKind = null,
|
_current_navigation_kind: ?NavigationKind = null,
|
||||||
|
|
||||||
_index: usize = 0,
|
_index: usize = 0,
|
||||||
@@ -48,7 +51,7 @@ _next_entry_id: usize = 0,
|
|||||||
_activation: ?NavigationActivation = null,
|
_activation: ?NavigationActivation = null,
|
||||||
|
|
||||||
fn asEventTarget(self: *Navigation) *EventTarget {
|
fn asEventTarget(self: *Navigation) *EventTarget {
|
||||||
return self._proto.asEventTarget();
|
return self._proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onRemovePage(self: *Navigation) void {
|
pub fn onRemovePage(self: *Navigation) void {
|
||||||
@@ -56,9 +59,7 @@ pub fn onRemovePage(self: *Navigation) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn onNewPage(self: *Navigation, page: *Page) !void {
|
pub fn onNewPage(self: *Navigation, page: *Page) !void {
|
||||||
self._proto = try page._factory.eventTarget(
|
self._proto = try page._factory.standaloneEventTarget(self);
|
||||||
NavigationEventTarget{ ._proto = undefined },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getActivation(self: *const Navigation) ?NavigationActivation {
|
pub fn getActivation(self: *const Navigation) ?NavigationActivation {
|
||||||
@@ -124,13 +125,19 @@ pub fn forward(self: *Navigation, page: *Page) !NavigationReturn {
|
|||||||
return self.navigateInner(next_entry._url, .{ .traverse = new_index }, page);
|
return self.navigateInner(next_entry._url, .{ .traverse = new_index }, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateEntries(self: *Navigation, url: [:0]const u8, kind: NavigationKind, page: *Page, dispatch: bool) !void {
|
pub fn updateEntries(
|
||||||
|
self: *Navigation,
|
||||||
|
url: [:0]const u8,
|
||||||
|
kind: NavigationKind,
|
||||||
|
page: *Page,
|
||||||
|
should_dispatch: bool,
|
||||||
|
) !void {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.replace => |state| {
|
.replace => |state| {
|
||||||
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, page, dispatch);
|
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, page, should_dispatch);
|
||||||
},
|
},
|
||||||
.push => |state| {
|
.push => |state| {
|
||||||
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, dispatch);
|
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, should_dispatch);
|
||||||
},
|
},
|
||||||
.traverse => |index| {
|
.traverse => |index| {
|
||||||
self._index = index;
|
self._index = index;
|
||||||
@@ -166,7 +173,7 @@ pub fn pushEntry(
|
|||||||
_url: [:0]const u8,
|
_url: [:0]const u8,
|
||||||
state: NavigationState,
|
state: NavigationState,
|
||||||
page: *Page,
|
page: *Page,
|
||||||
dispatch: bool,
|
should_dispatch: bool,
|
||||||
) !*NavigationHistoryEntry {
|
) !*NavigationHistoryEntry {
|
||||||
const arena = page._session.arena;
|
const arena = page._session.arena;
|
||||||
const url = try arena.dupeZ(u8, _url);
|
const url = try arena.dupeZ(u8, _url);
|
||||||
@@ -197,13 +204,13 @@ pub fn pushEntry(
|
|||||||
self._index = index;
|
self._index = index;
|
||||||
|
|
||||||
if (previous) |prev| {
|
if (previous) |prev| {
|
||||||
if (dispatch) {
|
if (should_dispatch) {
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
.wrap("currententrychange"),
|
.wrap("currententrychange"),
|
||||||
.{ .from = prev, .navigationType = @tagName(.push) },
|
.{ .from = prev, .navigationType = @tagName(.push) },
|
||||||
page,
|
page,
|
||||||
);
|
);
|
||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(.{ .currententrychange = event }, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +222,7 @@ pub fn replaceEntry(
|
|||||||
_url: [:0]const u8,
|
_url: [:0]const u8,
|
||||||
state: NavigationState,
|
state: NavigationState,
|
||||||
page: *Page,
|
page: *Page,
|
||||||
dispatch: bool,
|
should_dispatch: bool,
|
||||||
) !*NavigationHistoryEntry {
|
) !*NavigationHistoryEntry {
|
||||||
const arena = page._session.arena;
|
const arena = page._session.arena;
|
||||||
const url = try arena.dupeZ(u8, _url);
|
const url = try arena.dupeZ(u8, _url);
|
||||||
@@ -236,13 +243,13 @@ pub fn replaceEntry(
|
|||||||
|
|
||||||
self._entries.items[self._index] = entry;
|
self._entries.items[self._index] = entry;
|
||||||
|
|
||||||
if (dispatch) {
|
if (should_dispatch) {
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
.wrap("currententrychange"),
|
.wrap("currententrychange"),
|
||||||
.{ .from = previous, .navigationType = @tagName(.replace) },
|
.{ .from = previous, .navigationType = @tagName(.replace) },
|
||||||
page,
|
page,
|
||||||
);
|
);
|
||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(.{ .currententrychange = event }, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -334,7 +341,7 @@ pub fn navigateInner(
|
|||||||
.{ .from = previous, .navigationType = @tagName(kind) },
|
.{ .from = previous, .navigationType = @tagName(kind) },
|
||||||
page,
|
page,
|
||||||
);
|
);
|
||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(.{ .currententrychange = event }, page);
|
||||||
|
|
||||||
_ = try committed.persist();
|
_ = try committed.persist();
|
||||||
_ = try finished.persist();
|
_ = try finished.persist();
|
||||||
@@ -376,7 +383,7 @@ pub fn reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigation
|
|||||||
.{ .from = previous, .navigationType = @tagName(.reload) },
|
.{ .from = previous, .navigationType = @tagName(.reload) },
|
||||||
page,
|
page,
|
||||||
);
|
);
|
||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(.{ .currententrychange = event }, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.navigateInner(entry._url, .reload, page);
|
return self.navigateInner(entry._url, .reload, page);
|
||||||
@@ -418,7 +425,52 @@ pub fn updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions,
|
|||||||
.{ .from = previous, .navigationType = null },
|
.{ .from = previous, .navigationType = null },
|
||||||
page,
|
page,
|
||||||
);
|
);
|
||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(.{ .currententrychange = event }, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DispatchType = union(enum) {
|
||||||
|
currententrychange: *NavigationCurrentEntryChangeEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn dispatch(self: *Navigation, event_type: DispatchType, page: *Page) !void {
|
||||||
|
const event, const field = blk: {
|
||||||
|
break :blk switch (event_type) {
|
||||||
|
.currententrychange => |cec| .{ cec.asEvent(), "_on_currententrychange" },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
defer if (!event._v8_handoff) event.deinit(false);
|
||||||
|
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
if (page.js.local == null) {
|
||||||
|
log.fatal(.bug, "null context scope", .{ .src = "Navigation.dispatch", .url = page.url });
|
||||||
|
std.debug.assert(page.js.local != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const func = @field(self, field) orelse return;
|
||||||
|
|
||||||
|
var ls: js.Local.Scope = undefined;
|
||||||
|
page.js.localScope(&ls);
|
||||||
|
defer ls.deinit();
|
||||||
|
|
||||||
|
return page._event_manager.dispatchWithFunction(
|
||||||
|
self.asEventTarget(),
|
||||||
|
event,
|
||||||
|
ls.toLocal(func),
|
||||||
|
.{ .context = "Navigation" },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getOnCurrentEntryChange(self: *Navigation) ?js.Function.Global {
|
||||||
|
return self._on_currententrychange;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setOnCurrentEntryChange(self: *Navigation, listener: ?js.Function) !void {
|
||||||
|
if (listener) |listen| {
|
||||||
|
self._on_currententrychange = try listen.persistWithThis(self);
|
||||||
|
} else {
|
||||||
|
self._on_currententrychange = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
@@ -441,4 +493,10 @@ pub const JsApi = struct {
|
|||||||
pub const navigate = bridge.function(Navigation.navigate, .{});
|
pub const navigate = bridge.function(Navigation.navigate, .{});
|
||||||
pub const traverseTo = bridge.function(Navigation.traverseTo, .{});
|
pub const traverseTo = bridge.function(Navigation.traverseTo, .{});
|
||||||
pub const updateCurrentEntry = bridge.function(Navigation.updateCurrentEntry, .{});
|
pub const updateCurrentEntry = bridge.function(Navigation.updateCurrentEntry, .{});
|
||||||
|
|
||||||
|
pub const oncurrententrychange = bridge.accessor(
|
||||||
|
Navigation.getOnCurrentEntryChange,
|
||||||
|
Navigation.setOnCurrentEntryChange,
|
||||||
|
.{},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
|
||||||
//
|
|
||||||
// Francis Bouvier <francis@lightpanda.io>
|
|
||||||
// Pierre Tachoire <pierre@lightpanda.io>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const log = @import("../../../log.zig");
|
|
||||||
|
|
||||||
const js = @import("../../js/js.zig");
|
|
||||||
const Page = @import("../../Page.zig");
|
|
||||||
|
|
||||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
|
||||||
|
|
||||||
const EventTarget = @import("../EventTarget.zig");
|
|
||||||
const NavigationCurrentEntryChangeEvent = @import("../event/NavigationCurrentEntryChangeEvent.zig");
|
|
||||||
|
|
||||||
pub const NavigationEventTarget = @This();
|
|
||||||
|
|
||||||
_proto: *EventTarget,
|
|
||||||
_on_currententrychange: ?js.Function.Global = null,
|
|
||||||
|
|
||||||
pub fn asEventTarget(self: *NavigationEventTarget) *EventTarget {
|
|
||||||
return self._proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DispatchType = union(enum) {
|
|
||||||
currententrychange: *NavigationCurrentEntryChangeEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn dispatch(self: *NavigationEventTarget, event_type: DispatchType, page: *Page) !void {
|
|
||||||
const event, const field = blk: {
|
|
||||||
break :blk switch (event_type) {
|
|
||||||
.currententrychange => |cec| .{ cec.asEvent(), "_on_currententrychange" },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
if (comptime IS_DEBUG) {
|
|
||||||
if (page.js.local == null) {
|
|
||||||
log.fatal(.bug, "null context scope", .{ .src = "NavigationEventTarget.dispatch", .url = page.url });
|
|
||||||
std.debug.assert(page.js.local != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const func = @field(self, field) orelse return;
|
|
||||||
|
|
||||||
var ls: js.Local.Scope = undefined;
|
|
||||||
page.js.localScope(&ls);
|
|
||||||
defer ls.deinit();
|
|
||||||
|
|
||||||
return page._event_manager.dispatchWithFunction(
|
|
||||||
self.asEventTarget(),
|
|
||||||
event,
|
|
||||||
ls.toLocal(func),
|
|
||||||
.{ .context = "Navigation" },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getOnCurrentEntryChange(self: *NavigationEventTarget) ?js.Function.Global {
|
|
||||||
return self._on_currententrychange;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setOnCurrentEntryChange(self: *NavigationEventTarget, listener: ?js.Function) !void {
|
|
||||||
if (listener) |listen| {
|
|
||||||
self._on_currententrychange = try listen.persistWithThis(self);
|
|
||||||
} else {
|
|
||||||
self._on_currententrychange = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const JsApi = struct {
|
|
||||||
pub const bridge = js.Bridge(NavigationEventTarget);
|
|
||||||
|
|
||||||
pub const Meta = struct {
|
|
||||||
pub const name = "NavigationEventTarget";
|
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const oncurrententrychange = bridge.accessor(
|
|
||||||
NavigationEventTarget.getOnCurrentEntryChange,
|
|
||||||
NavigationEventTarget.setOnCurrentEntryChange,
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user