Skip to content

Commit 46d982c

Browse files
committed
basic navigation functional
1 parent 5d2f7c9 commit 46d982c

File tree

10 files changed

+252
-136
lines changed

10 files changed

+252
-136
lines changed

src/browser/html/History.zig

Lines changed: 28 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -25,71 +25,36 @@ const Page = @import("../page.zig").Page;
2525
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface
2626
const History = @This();
2727

28-
const HistoryEntry = struct {
29-
url: []const u8,
30-
// This is serialized as JSON because
31-
// History must survive a JsContext.
32-
state: ?[]u8,
33-
};
34-
3528
const ScrollRestorationMode = enum {
29+
pub const ENUM_JS_USE_TAG = true;
30+
3631
auto,
3732
manual,
38-
39-
pub fn fromString(str: []const u8) ?ScrollRestorationMode {
40-
for (std.enums.values(ScrollRestorationMode)) |mode| {
41-
if (std.ascii.eqlIgnoreCase(str, @tagName(mode))) {
42-
return mode;
43-
}
44-
} else {
45-
return null;
46-
}
47-
}
48-
49-
pub fn toString(self: ScrollRestorationMode) []const u8 {
50-
return @tagName(self);
51-
}
5233
};
5334

5435
scroll_restoration: ScrollRestorationMode = .auto,
55-
stack: std.ArrayListUnmanaged(HistoryEntry) = .empty,
56-
current: ?usize = null,
5736

58-
pub fn get_length(self: *History) u32 {
59-
return @intCast(self.stack.items.len);
37+
pub fn get_length(_: *History, page: *Page) u32 {
38+
return @intCast(page.session.navigation.entries.items.len);
6039
}
6140

6241
pub fn get_scrollRestoration(self: *History) ScrollRestorationMode {
6342
return self.scroll_restoration;
6443
}
6544

66-
pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
67-
self.scroll_restoration = ScrollRestorationMode.fromString(mode) orelse self.scroll_restoration;
45+
pub fn set_scrollRestoration(self: *History, mode: ScrollRestorationMode) void {
46+
self.scroll_restoration = mode;
6847
}
6948

70-
pub fn get_state(self: *History, page: *Page) !?js.Value {
71-
if (self.current) |curr| {
72-
const entry = self.stack.items[curr];
73-
if (entry.state) |state| {
74-
const value = try js.Value.fromJson(page.js, state);
75-
return value;
76-
} else {
77-
return null;
78-
}
49+
pub fn get_state(_: *History, page: *Page) !?js.Value {
50+
if (page.session.navigation.currentEntry().state) |state| {
51+
const value = try js.Value.fromJson(page.js, state);
52+
return value;
7953
} else {
8054
return null;
8155
}
8256
}
8357

84-
pub fn pushNavigation(self: *History, _url: []const u8, page: *Page) !void {
85-
const arena = page.session.arena;
86-
const url = try arena.dupe(u8, _url);
87-
88-
const entry = HistoryEntry{ .state = null, .url = url };
89-
try self.stack.append(arena, entry);
90-
self.current = self.stack.items.len - 1;
91-
}
92-
9358
pub fn dispatchPopStateEvent(state: ?[]const u8, page: *Page) void {
9459
log.debug(.script_event, "dispatch popstate event", .{
9560
.type = "popstate",
@@ -113,48 +78,42 @@ fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
11378
);
11479
}
11580

116-
pub fn _pushState(self: *History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
81+
pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
11782
const arena = page.session.arena;
118-
119-
const json = try state.toJson(arena);
12083
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
121-
const entry = HistoryEntry{ .state = json, .url = url };
122-
try self.stack.append(arena, entry);
123-
self.current = self.stack.items.len - 1;
84+
_ = try page.session.navigation.pushEntry(url, .{ .state = state }, page);
12485
}
12586

126-
pub fn _replaceState(self: *History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
87+
pub fn _replaceState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
12788
const arena = page.session.arena;
12889

129-
if (self.current) |curr| {
130-
const entry = &self.stack.items[curr];
131-
const json = try state.toJson(arena);
132-
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
133-
entry.* = HistoryEntry{ .state = json, .url = url };
134-
} else {
135-
try self._pushState(state, "", _url, page);
136-
}
90+
const entry = page.session.navigation.currentEntry();
91+
const json = try state.toJson(arena);
92+
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
93+
94+
entry.state = json;
95+
entry.url = url;
13796
}
13897

139-
pub fn go(self: *History, delta: i32, page: *Page) !void {
98+
pub fn go(_: *const History, delta: i32, page: *Page) !void {
14099
// 0 behaves the same as no argument, both reloading the page.
141-
// If this is getting called, there SHOULD be an entry, atleast from pushNavigation.
142-
const current = self.current.?;
143100

101+
const current = page.session.navigation.index;
144102
const index_s: i64 = @intCast(@as(i64, @intCast(current)) + @as(i64, @intCast(delta)));
145-
if (index_s < 0 or index_s > self.stack.items.len - 1) {
103+
if (index_s < 0 or index_s > page.session.navigation.entries.items.len - 1) {
146104
return;
147105
}
148106

149107
const index = @as(usize, @intCast(index_s));
150-
const entry = self.stack.items[index];
151-
self.current = index;
108+
const entry = page.session.navigation.entries.items[index];
152109

153-
if (try page.isSameOrigin(entry.url)) {
154-
History.dispatchPopStateEvent(entry.state, page);
110+
if (entry.url) |url| {
111+
if (try page.isSameOrigin(url)) {
112+
History.dispatchPopStateEvent(entry.state, page);
113+
}
155114
}
156115

157-
try page.navigateFromWebAPI(entry.url, .{ .reason = .history });
116+
_ = try entry.navigate(page, .force);
158117
}
159118

160119
pub fn _go(self: *History, _delta: ?i32, page: *Page) !void {

0 commit comments

Comments
 (0)