Skip to content

Commit 05e7079

Browse files
committed
functional history WebAPI
1 parent f03fcc9 commit 05e7079

File tree

3 files changed

+63
-33
lines changed

3 files changed

+63
-33
lines changed

src/browser/html/History.zig

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ const Page = @import("../page.zig").Page;
2525
const History = @This();
2626

2727
const HistoryEntry = struct {
28-
url: ?[]const u8,
29-
// Serialized Env.JsObject
30-
state: []u8,
28+
url: []const u8,
29+
// Serialized as JSON.
30+
state: ?[]u8,
3131
};
3232

3333
const ScrollRestorationMode = enum {
@@ -64,52 +64,78 @@ pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
6464
self.scrollRestoration = ScrollRestorationMode.fromString(mode) orelse self.scrollRestoration;
6565
}
6666

67-
pub fn get_state(self: *History, page: *Page) !?Env.JsObject {
67+
pub fn get_state(self: *History, page: *Page) !?Env.Value {
6868
if (self.current) |curr| {
6969
const entry = self.stack.items[curr];
70-
const object = try Env.JsObject.fromJson(page.main_context, entry.state);
71-
return object;
70+
if (entry.state) |state| {
71+
const value = try Env.Value.fromJson(page.main_context, state);
72+
return value;
73+
} else {
74+
return null;
75+
}
7276
} else {
7377
return null;
7478
}
7579
}
7680

77-
pub fn _pushState(self: *History, state: Env.JsObject, _: ?[]const u8, url: ?[]const u8, page: *Page) !void {
78-
const json = try state.toJson(page.arena);
79-
const entry = HistoryEntry{ .state = json, .url = url };
80-
try self.stack.append(page.session.arena, entry);
81-
self.current = self.stack.items.len;
82-
}
81+
pub fn pushNavigation(self: *History, _url: []const u8, page: *Page) !void {
82+
const arena = page.session.arena;
83+
const url = try arena.dupe(u8, _url);
8384

84-
// TODO implement the function
85-
// data must handle any argument. We could expect a std.json.Value but
86-
// https://github.com/lightpanda-io/zig-js-runtime/issues/267 is missing.
87-
pub fn _replaceState(self: *History, state: Env.JsObject, _: ?[]const u8, url: ?[]const u8) void {
88-
_ = self;
89-
_ = url;
90-
_ = state;
85+
const entry = HistoryEntry{ .state = null, .url = url };
86+
try self.stack.append(arena, entry);
87+
self.current = self.stack.items.len - 1;
9188
}
9289

93-
// TODO implement the function
94-
pub fn _go(self: *History, delta: ?i32) void {
95-
_ = self;
96-
_ = delta;
90+
pub fn _pushState(self: *History, state: Env.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
91+
const arena = page.session.arena;
92+
93+
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
94+
const json = try state.toJson(page.session.arena);
95+
const entry = HistoryEntry{ .state = json, .url = url };
96+
try self.stack.append(arena, entry);
97+
self.current = self.stack.items.len - 1;
9798
}
9899

99-
pub fn _back(self: *History) void {
100+
pub fn _replaceState(self: *History, state: Env.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
101+
const arena = page.session.arena;
102+
100103
if (self.current) |curr| {
101-
if (curr > 0) {
102-
self.current = curr - 1;
103-
}
104+
const entry = &self.stack.items[curr];
105+
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
106+
const json = try state.toJson(arena);
107+
entry.* = HistoryEntry{ .state = json, .url = url };
108+
} else {
109+
try self._pushState(state, "", _url, page);
104110
}
105111
}
106112

107-
pub fn _forward(self: *History) void {
108-
if (self.current) |curr| {
109-
if (curr < self.stack.items.len) {
110-
self.current = curr + 1;
111-
}
113+
pub fn go(self: *History, delta: i32, page: *Page) !void {
114+
// 0 behaves the same as no argument, both reloading the page.
115+
// If this is getting called, there SHOULD be an entry, atleast from pushNavigation.
116+
const current = self.current.?;
117+
118+
const index_s: i64 = @intCast(@as(i64, @intCast(current)) + @as(i64, @intCast(delta)));
119+
if (index_s < 0 or index_s > self.stack.items.len - 1) {
120+
return;
112121
}
122+
123+
const index = @as(usize, @intCast(index_s));
124+
const entry = self.stack.items[index];
125+
self.current = index;
126+
try page.navigateFromWebAPI(entry.url, .{ .reason = .history });
127+
}
128+
129+
pub fn _go(self: *History, _delta: ?i32, page: *Page) !void {
130+
try self.go(_delta orelse 0, page);
131+
}
132+
133+
pub fn _back(self: *History, page: *Page) !void {
134+
try self.go(-1, page);
135+
}
136+
137+
pub fn _forward(self: *History, page: *Page) !void {
138+
try self.go(1, page);
113139
}
114140

115141
const testing = @import("../../testing.zig");

src/browser/page.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,9 @@ pub const Page = struct {
806806
unreachable;
807807
},
808808
}
809+
810+
// Push the navigation after a successful load.
811+
try self.session.history.pushNavigation(self.url.raw, self);
809812
}
810813

811814
fn pageErrorCallback(ctx: *anyopaque, err: anyerror) void {
@@ -1136,6 +1139,7 @@ pub const NavigateReason = enum {
11361139
address_bar,
11371140
form,
11381141
script,
1142+
history,
11391143
};
11401144

11411145
pub const NavigateOpts = struct {

src/cdp/domains/page.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ pub fn pageNavigate(arena: Allocator, bc: anytype, event: *const Notification.Pa
174174
var cdp = bc.cdp;
175175
const reason_: ?[]const u8 = switch (event.opts.reason) {
176176
.anchor => "anchorClick",
177-
.script => "scriptInitiated",
177+
.script, .history => "scriptInitiated",
178178
.form => switch (event.opts.method) {
179179
.GET => "formSubmissionGet",
180180
.POST => "formSubmissionPost",

0 commit comments

Comments
 (0)