diff --git a/src/browser/html/History.zig b/src/browser/html/History.zig
index b920d66d..d67da3f5 100644
--- a/src/browser/html/History.zig
+++ b/src/browser/html/History.zig
@@ -25,13 +25,6 @@ const Page = @import("../page.zig").Page;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface
const History = @This();
-const HistoryEntry = struct {
- url: []const u8,
- // This is serialized as JSON because
- // History must survive a JsContext.
- state: ?[]u8,
-};
-
const ScrollRestorationMode = enum {
pub const ENUM_JS_USE_TAG = true;
@@ -40,11 +33,9 @@ const ScrollRestorationMode = enum {
};
scroll_restoration: ScrollRestorationMode = .auto,
-stack: std.ArrayListUnmanaged(HistoryEntry) = .empty,
-current: ?usize = null,
-pub fn get_length(self: *History) u32 {
- return @intCast(self.stack.items.len);
+pub fn get_length(_: *History, page: *Page) u32 {
+ return @intCast(page.session.navigation.entries.items.len);
}
pub fn get_scrollRestoration(self: *History) ScrollRestorationMode {
@@ -55,29 +46,15 @@ pub fn set_scrollRestoration(self: *History, mode: ScrollRestorationMode) void {
self.scroll_restoration = mode;
}
-pub fn get_state(self: *History, page: *Page) !?js.Value {
- if (self.current) |curr| {
- const entry = self.stack.items[curr];
- if (entry.state) |state| {
- const value = try js.Value.fromJson(page.js, state);
- return value;
- } else {
- return null;
- }
+pub fn get_state(_: *History, page: *Page) !?js.Value {
+ if (page.session.navigation.currentEntry().state) |state| {
+ const value = try js.Value.fromJson(page.js, state);
+ return value;
} else {
return null;
}
}
-pub fn pushNavigation(self: *History, _url: []const u8, page: *Page) !void {
- const arena = page.session.arena;
- const url = try arena.dupe(u8, _url);
-
- const entry = HistoryEntry{ .state = null, .url = url };
- try self.stack.append(arena, entry);
- self.current = self.stack.items.len - 1;
-}
-
pub fn dispatchPopStateEvent(state: ?[]const u8, page: *Page) void {
log.debug(.script_event, "dispatch popstate event", .{
.type = "popstate",
@@ -101,48 +78,42 @@ fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
);
}
-pub fn _pushState(self: *History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
+pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
+ const arena = page.session.arena;
+ const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
+ _ = try page.session.navigation.pushEntry(url, .{ .state = state }, page);
+}
+
+pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
const arena = page.session.arena;
+ const entry = page.session.navigation.currentEntry();
const json = try state.toJson(arena);
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
- const entry = HistoryEntry{ .state = json, .url = url };
- try self.stack.append(arena, entry);
- self.current = self.stack.items.len - 1;
+
+ entry.state = json;
+ entry.url = url;
}
-pub fn _replaceState(self: *History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
- const arena = page.session.arena;
-
- if (self.current) |curr| {
- const entry = &self.stack.items[curr];
- const json = try state.toJson(arena);
- const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
- entry.* = HistoryEntry{ .state = json, .url = url };
- } else {
- try self._pushState(state, "", _url, page);
- }
-}
-
-pub fn go(self: *History, delta: i32, page: *Page) !void {
+pub fn go(_: *const History, delta: i32, page: *Page) !void {
// 0 behaves the same as no argument, both reloading the page.
- // If this is getting called, there SHOULD be an entry, atleast from pushNavigation.
- const current = self.current.?;
+ const current = page.session.navigation.index;
const index_s: i64 = @intCast(@as(i64, @intCast(current)) + @as(i64, @intCast(delta)));
- if (index_s < 0 or index_s > self.stack.items.len - 1) {
+ if (index_s < 0 or index_s > page.session.navigation.entries.items.len - 1) {
return;
}
const index = @as(usize, @intCast(index_s));
- const entry = self.stack.items[index];
- self.current = index;
+ const entry = page.session.navigation.entries.items[index];
- if (try page.isSameOrigin(entry.url)) {
- History.dispatchPopStateEvent(entry.state, page);
+ if (entry.url) |url| {
+ if (try page.isSameOrigin(url)) {
+ History.dispatchPopStateEvent(entry.state, page);
+ }
}
- try page.navigateFromWebAPI(entry.url, .{ .reason = .history });
+ _ = try entry.navigate(page, .force);
}
pub fn _go(self: *History, _delta: ?i32, page: *Page) !void {
diff --git a/src/browser/page.zig b/src/browser/page.zig
index 833c683f..f6283f07 100644
--- a/src/browser/page.zig
+++ b/src/browser/page.zig
@@ -816,7 +816,7 @@ pub const Page = struct {
}
// Push the navigation after a successful load.
- try self.session.history.pushNavigation(self.url.raw, self);
+ _ = try self.session.navigation.pushEntry(self.url.raw, null, self);
}
fn pageErrorCallback(ctx: *anyopaque, err: anyerror) void {
diff --git a/src/tests/html/history.html b/src/tests/html/history.html
index 2c5591a4..0f4ff95f 100644
--- a/src/tests/html/history.html
+++ b/src/tests/html/history.html
@@ -5,7 +5,6 @@
testing.expectEqual('auto', history.scrollRestoration);
history.scrollRestoration = 'manual';
- history.scrollRestoration = 'foo';
testing.expectEqual('manual', history.scrollRestoration);
history.scrollRestoration = 'auto';
diff --git a/src/tests/html/navigation.html b/src/tests/html/navigation.html
new file mode 100644
index 00000000..f1ff61fb
--- /dev/null
+++ b/src/tests/html/navigation.html
@@ -0,0 +1,49 @@
+
+
+