seperate Navigation State and History State

This commit is contained in:
Muki Kiboigo
2025-11-12 09:37:22 -08:00
parent 56e30a9c97
commit f475f3440e
3 changed files with 39 additions and 17 deletions

View File

@@ -48,7 +48,7 @@ pub fn set_scrollRestoration(self: *History, mode: ScrollRestorationMode) void {
} }
pub fn get_state(_: *History, page: *Page) !?js.Value { pub fn get_state(_: *History, page: *Page) !?js.Value {
if (page.session.navigation.currentEntry().state) |state| { if (page.session.navigation.currentEntry().state.value) |state| {
const value = try js.Value.fromJson(page.js, state); const value = try js.Value.fromJson(page.js, state);
return value; return value;
} else { } else {
@@ -61,7 +61,7 @@ pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw); const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
const json = state.toJson(arena) catch return error.DataClone; const json = state.toJson(arena) catch return error.DataClone;
_ = try page.session.navigation.pushEntry(url, json, page, true); _ = try page.session.navigation.pushEntry(url, .{ .source = .history, .value = json }, page, true);
} }
pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void { pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
@@ -69,7 +69,7 @@ pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url:
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw); const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
const json = try state.toJson(arena); const json = try state.toJson(arena);
_ = try page.session.navigation.replaceEntry(url, json, page, true); _ = try page.session.navigation.replaceEntry(url, .{ .source = .history, .value = json }, page, true);
} }
pub fn go(_: *const History, delta: i32, page: *Page) !void { pub fn go(_: *const History, delta: i32, page: *Page) !void {
@@ -86,7 +86,7 @@ pub fn go(_: *const History, delta: i32, page: *Page) !void {
if (entry.url) |url| { if (entry.url) |url| {
if (try page.isSameOrigin(url)) { if (try page.isSameOrigin(url)) {
PopStateEvent.dispatch(entry.state, page); PopStateEvent.dispatch(entry.state.value, page);
} }
} }

View File

@@ -35,6 +35,7 @@ const Navigation = @This();
const NavigationKind = @import("root.zig").NavigationKind; const NavigationKind = @import("root.zig").NavigationKind;
const NavigationHistoryEntry = @import("root.zig").NavigationHistoryEntry; const NavigationHistoryEntry = @import("root.zig").NavigationHistoryEntry;
const NavigationTransition = @import("root.zig").NavigationTransition; const NavigationTransition = @import("root.zig").NavigationTransition;
const NavigationState = @import("root.zig").NavigationState;
const NavigationCurrentEntryChangeEvent = @import("root.zig").NavigationCurrentEntryChangeEvent; const NavigationCurrentEntryChangeEvent = @import("root.zig").NavigationCurrentEntryChangeEvent;
const NavigationEventTarget = @import("NavigationEventTarget.zig"); const NavigationEventTarget = @import("NavigationEventTarget.zig");
@@ -110,10 +111,10 @@ pub fn _forward(self: *Navigation, page: *Page) !NavigationReturn {
pub fn updateEntries(self: *Navigation, url: []const u8, kind: NavigationKind, page: *Page, dispatch: bool) !void { pub fn updateEntries(self: *Navigation, url: []const u8, kind: NavigationKind, page: *Page, dispatch: bool) !void {
switch (kind) { switch (kind) {
.replace => { .replace => {
_ = try self.replaceEntry(url, null, page, dispatch); _ = try self.replaceEntry(url, .{ .source = .navigation, .value = null }, page, dispatch);
}, },
.push => |state| { .push => |state| {
_ = try self.pushEntry(url, state, page, dispatch); _ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, dispatch);
}, },
.traverse => |index| { .traverse => |index| {
self.index = index; self.index = index;
@@ -132,7 +133,13 @@ pub fn processNavigation(self: *Navigation, page: *Page) !void {
/// Pushes an entry into the Navigation stack WITHOUT actually navigating to it. /// Pushes an entry into the Navigation stack WITHOUT actually navigating to it.
/// For that, use `navigate`. /// For that, use `navigate`.
pub fn pushEntry(self: *Navigation, _url: []const u8, state: ?[]const u8, page: *Page, dispatch: bool) !*NavigationHistoryEntry { pub fn pushEntry(
self: *Navigation,
_url: []const u8,
state: NavigationState,
page: *Page,
dispatch: bool,
) !*NavigationHistoryEntry {
const arena = page.session.arena; const arena = page.session.arena;
const url = try arena.dupe(u8, _url); const url = try arena.dupe(u8, _url);
@@ -171,7 +178,13 @@ pub fn pushEntry(self: *Navigation, _url: []const u8, state: ?[]const u8, page:
return entry; return entry;
} }
pub fn replaceEntry(self: *Navigation, _url: []const u8, state: ?[]const u8, page: *Page, dispatch: bool) !*NavigationHistoryEntry { pub fn replaceEntry(
self: *Navigation,
_url: []const u8,
state: NavigationState,
page: *Page,
dispatch: bool,
) !*NavigationHistoryEntry {
const arena = page.session.arena; const arena = page.session.arena;
const url = try arena.dupe(u8, _url); const url = try arena.dupe(u8, _url);
@@ -242,7 +255,7 @@ pub fn navigate(
// todo: Fire navigate event // todo: Fire navigate event
try finished.resolve({}); try finished.resolve({});
_ = try self.pushEntry(url, state, page, true); _ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, true);
} else { } else {
try page.navigateFromWebAPI(url, .{ .reason = .navigation }, kind); try page.navigateFromWebAPI(url, .{ .reason = .navigation }, kind);
} }
@@ -290,7 +303,7 @@ pub fn _reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigatio
const entry = self.currentEntry(); const entry = self.currentEntry();
if (opts.state) |state| { if (opts.state) |state| {
const previous = entry; const previous = entry;
entry.state = state.toJson(arena) catch return error.DataClone; entry.state = .{ .source = .navigation, .value = state.toJson(arena) catch return error.DataClone };
NavigationCurrentEntryChangeEvent.dispatch(self, previous, .reload); NavigationCurrentEntryChangeEvent.dispatch(self, previous, .reload);
} }
@@ -323,6 +336,6 @@ pub fn _updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions
const arena = page.session.arena; const arena = page.session.arena;
const previous = self.currentEntry(); const previous = self.currentEntry();
self.currentEntry().state = options.state.toJson(arena) catch return error.DataClone; self.currentEntry().state = .{ .source = .navigation, .value = options.state.toJson(arena) catch return error.DataClone };
NavigationCurrentEntryChangeEvent.dispatch(self, previous, null); NavigationCurrentEntryChangeEvent.dispatch(self, previous, null);
} }

View File

@@ -56,6 +56,11 @@ pub const NavigationKind = union(NavigationType) {
reload, reload,
}; };
pub const NavigationState = struct {
source: enum { history, navigation },
value: ?[]const u8,
};
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry // https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
pub const NavigationHistoryEntry = struct { pub const NavigationHistoryEntry = struct {
pub const prototype = *EventTarget; pub const prototype = *EventTarget;
@@ -64,7 +69,7 @@ pub const NavigationHistoryEntry = struct {
id: []const u8, id: []const u8,
key: []const u8, key: []const u8,
url: ?[]const u8, url: ?[]const u8,
state: ?[]const u8, state: NavigationState,
pub fn get_id(self: *const NavigationHistoryEntry) []const u8 { pub fn get_id(self: *const NavigationHistoryEntry) []const u8 {
return self.id; return self.id;
@@ -95,12 +100,16 @@ pub const NavigationHistoryEntry = struct {
return self.url; return self.url;
} }
pub fn _getState(self: *const NavigationHistoryEntry, page: *Page) !?js.Value { pub const StateReturn = union(enum) { value: ?js.Value, undefined: void };
if (self.state) |state| {
return try js.Value.fromJson(page.js, state); pub fn _getState(self: *const NavigationHistoryEntry, page: *Page) !StateReturn {
} else { if (self.state.source == .navigation) {
return null; if (self.state.value) |value| {
return .{ .value = try js.Value.fromJson(page.js, value) };
}
} }
return .undefined;
} }
}; };