Merge pull request #3567 from lightpanda-io/navigation-success

add `navigationsuccess` and `navigationerror`
This commit is contained in:
Karl Seguin authored and GitHub committed 2026-09-22 10:45:59 +08:00
commit a1fb83c31c
1 file changed
+74 -7
+74 -7
View File
@@ -26,6 +26,7 @@ const Factory = @import("../../Factory.zig");
const Event = @import("../Event.zig");
const EventTarget = @import("../EventTarget.zig");
const ErrorEvent = @import("../event/ErrorEvent.zig");
const log = lp.log;
@@ -44,6 +45,8 @@ const NavigationCurrentEntryChangeEvent = @import("../event/NavigationCurrentEnt
_proto: *EventTarget,
_on_currententrychange: ?js.Function.Global = null,
_on_navigatesuccess: ?js.Function.Global = null,
_on_navigateerror: ?js.Function.Global = null,
_current_navigation_kind: ?NavigationKind = null,
@@ -66,6 +69,12 @@ pub fn onRemoveFrame(self: *Navigation) void {
if (self._on_currententrychange) |cb| cb.release();
self._on_currententrychange = null;
if (self._on_navigatesuccess) |cb| cb.release();
self._on_navigatesuccess = null;
if (self._on_navigateerror) |cb| cb.release();
self._on_navigateerror = null;
for (self._entries.items) |entry| {
if (entry._on_dispose) |cb| cb.release();
entry._on_dispose = null;
@@ -303,6 +312,29 @@ pub fn replaceEntry(
return entry;
}
fn fireNavigateSuccess(self: *Navigation, frame: *Frame) void {
if (!frame.hasDirectListeners(
self.asEventTarget(),
"navigatesuccess",
self._on_navigatesuccess,
)) {
return;
}
const event = Event.initTrusted(
.wrap("navigatesuccess"),
null,
frame.page,
) catch |err| {
log.warn(.event, "Navigation.fireNavigateSuccess", .{ .err = err });
return;
};
self.dispatch(self._on_navigatesuccess, event, frame) catch |err| {
log.warn(.event, "Navigation.fireNavigateSuccess dispatch", .{ .err = err });
};
}
fn fireCurrentEntryChangeEvent(
self: *Navigation,
previous: *NavigationHistoryEntry,
@@ -335,6 +367,16 @@ fn fireCurrentEntryChangeEvent(
};
}
fn resolveFinished(
self: *Navigation,
resolver: js.PromiseResolver,
comptime source: []const u8,
frame: *Frame,
) void {
resolver.resolve(source, {});
self.fireNavigateSuccess(frame);
}
const NavigateOptions = struct {
history: ?[]const u8 = null,
info: ?js.Value = null,
@@ -381,9 +423,8 @@ pub fn navigateInner(
committed.resolve("navigation push", {});
// todo: Fire navigate event
finished.resolve("navigation push", {});
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, frame, true);
self.resolveFinished(finished, "navigation push", frame);
} else {
try frame.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .{ .script = frame });
}
@@ -394,9 +435,8 @@ pub fn navigateInner(
committed.resolve("navigation replace", {});
// todo: Fire navigate event
finished.resolve("navigation replace", {});
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, frame, true);
self.resolveFinished(finished, "navigation replace", frame);
} else {
try frame.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .{ .script = frame });
}
@@ -409,7 +449,8 @@ pub fn navigateInner(
committed.resolve("navigation traverse", {});
// todo: Fire navigate event
finished.resolve("navigation traverse", {});
self.fireCurrentEntryChangeEvent(previous, kind, frame);
self.resolveFinished(finished, "navigation traverse", frame);
} else {
try frame.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .{ .script = frame });
}
@@ -423,8 +464,6 @@ pub fn navigateInner(
try frame.queueHashChange(old_url, new_url);
}
self.fireCurrentEntryChangeEvent(previous, kind, frame);
_ = try committed.persist();
_ = try finished.persist();
return .{
@@ -524,6 +563,24 @@ fn setOnCurrentEntryChange(self: *Navigation, listener: ?js.Function) !void {
}
}
fn getOnNavigateSuccess(self: *Navigation) ?js.Function.Global {
return self._on_navigatesuccess;
}
fn setOnNavigateSuccess(self: *Navigation, listener: ?js.Function) !void {
if (self._on_navigatesuccess) |old| old.release();
self._on_navigatesuccess = if (listener) |l| try l.persistWithThis(self) else null;
}
fn getOnNavigateError(self: *Navigation) ?js.Function.Global {
return self._on_navigateerror;
}
fn setOnNavigateError(self: *Navigation, listener: ?js.Function) !void {
if (self._on_navigateerror) |old| old.release();
self._on_navigateerror = if (listener) |l| try l.persistWithThis(self) else null;
}
pub const JsApi = struct {
pub const bridge = js.Bridge(Navigation);
@@ -551,6 +608,16 @@ pub const JsApi = struct {
Navigation.setOnCurrentEntryChange,
.{},
);
pub const onnavigatesuccess = bridge.accessor(
Navigation.getOnNavigateSuccess,
Navigation.setOnNavigateSuccess,
.{},
);
pub const onnavigateerror = bridge.accessor(
Navigation.getOnNavigateError,
Navigation.setOnNavigateError,
.{},
);
};
const testing = @import("../../../testing.zig");