Skip to content

Commit c3ad054

Browse files
committed
add toJson object and fromJson value
1 parent 202e137 commit c3ad054

File tree

7 files changed

+146
-98
lines changed

7 files changed

+146
-98
lines changed

src/browser/html/History.zig

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
2+
//
3+
// Francis Bouvier <francis@lightpanda.io>
4+
// Pierre Tachoire <pierre@lightpanda.io>
5+
//
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU Affero General Public License as
8+
// published by the Free Software Foundation, either version 3 of the
9+
// License, or (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU Affero General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU Affero General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
const std = @import("std");
20+
21+
const Env = @import("../env.zig").Env;
22+
const Page = @import("../page.zig").Page;
23+
24+
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface
25+
const History = @This();
26+
27+
const HistoryEntry = struct {
28+
url: ?[]const u8,
29+
// Serialized Env.JsObject
30+
state: []u8,
31+
};
32+
33+
const ScrollRestorationMode = enum {
34+
auto,
35+
manual,
36+
37+
pub fn fromString(str: []const u8) ?ScrollRestorationMode {
38+
for (std.enums.values(ScrollRestorationMode)) |mode| {
39+
if (std.ascii.eqlIgnoreCase(str, @tagName(mode))) {
40+
return mode;
41+
}
42+
} else {
43+
return null;
44+
}
45+
}
46+
};
47+
48+
scrollRestoration: ScrollRestorationMode = .auto,
49+
stack: std.ArrayListUnmanaged(HistoryEntry) = .empty,
50+
current: ?usize = null,
51+
52+
pub fn get_length(self: *History) u32 {
53+
return @intCast(self.stack.items.len);
54+
}
55+
56+
pub fn get_scrollRestoration(self: *History) []const u8 {
57+
return switch (self.scrollRestoration) {
58+
.auto => "auto",
59+
.manual => "manual",
60+
};
61+
}
62+
63+
pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
64+
self.scrollRestoration = ScrollRestorationMode.fromString(mode) orelse self.scrollRestoration;
65+
}
66+
67+
pub fn get_state(self: *History, page: *Page) !?Env.JsObject {
68+
if (self.current) |curr| {
69+
const entry = self.stack.items[curr];
70+
const object = try Env.JsObject.fromJson(page.main_context, entry.state);
71+
return object;
72+
} else {
73+
return null;
74+
}
75+
}
76+
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+
}
83+
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;
91+
}
92+
93+
// TODO implement the function
94+
pub fn _go(self: *History, delta: ?i32) void {
95+
_ = self;
96+
_ = delta;
97+
}
98+
99+
pub fn _back(self: *History) void {
100+
if (self.current) |curr| {
101+
if (curr > 0) {
102+
self.current = curr - 1;
103+
}
104+
}
105+
}
106+
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+
}
112+
}
113+
}
114+
115+
const testing = @import("../../testing.zig");
116+
test "Browser: HTML.History" {
117+
try testing.htmlRunner("html/history.html");
118+
}

src/browser/html/history.zig

Lines changed: 0 additions & 93 deletions
This file was deleted.

src/browser/html/html.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const HTMLElem = @import("elements.zig");
2121
const SVGElem = @import("svg_elements.zig");
2222
const Window = @import("window.zig").Window;
2323
const Navigator = @import("navigator.zig").Navigator;
24-
const History = @import("history.zig").History;
24+
const History = @import("History.zig");
2525
const Location = @import("location.zig").Location;
2626
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
2727

src/browser/html/window.zig

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const Env = @import("../env.zig").Env;
2424
const Page = @import("../page.zig").Page;
2525

2626
const Navigator = @import("navigator.zig").Navigator;
27-
const History = @import("history.zig").History;
27+
const History = @import("History.zig");
2828
const Location = @import("location.zig").Location;
2929
const Crypto = @import("../crypto/crypto.zig").Crypto;
3030
const Console = @import("../console/console.zig").Console;
@@ -54,7 +54,6 @@ pub const Window = struct {
5454

5555
document: *parser.DocumentHTML,
5656
target: []const u8 = "",
57-
history: History = .{},
5857
location: Location = .{},
5958
storage_shelf: ?*storage.Shelf = null,
6059

@@ -179,8 +178,8 @@ pub const Window = struct {
179178
return self.document;
180179
}
181180

182-
pub fn get_history(self: *Window) *History {
183-
return &self.history;
181+
pub fn get_history(_: *Window, page: *Page) *History {
182+
return &page.session.history;
184183
}
185184

186185
// The interior height of the window in pixels, including the height of the horizontal scroll bar, if present.

src/browser/session.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const Env = @import("env.zig").Env;
2424
const Page = @import("page.zig").Page;
2525
const Browser = @import("browser.zig").Browser;
2626
const NavigateOpts = @import("page.zig").NavigateOpts;
27+
const History = @import("html/History.zig");
2728

2829
const log = @import("../log.zig");
2930
const parser = @import("netsurf.zig");
@@ -53,6 +54,10 @@ pub const Session = struct {
5354
storage_shed: storage.Shed,
5455
cookie_jar: storage.CookieJar,
5556

57+
// History is persistent across the "tab".
58+
// https://developer.mozilla.org/en-US/docs/Web/API/History
59+
history: History = .{},
60+
5661
page: ?Page = null,
5762

5863
// If the current page want to navigate to a new page

src/runtime/js.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
20052005
return writer.writeAll(try self.toString());
20062006
}
20072007

2008+
pub fn toJson(self: JsObject, allocator: std.mem.Allocator) ![]u8 {
2009+
const json_string = try v8.Json.stringify(self.js_context.v8_context, self.js_obj.toValue(), null);
2010+
const str = try jsStringToZig(allocator, json_string, self.js_context.isolate);
2011+
return str;
2012+
}
2013+
20082014
pub fn persist(self: JsObject) !JsObject {
20092015
var js_context = self.js_context;
20102016
const js_obj = self.js_obj;
@@ -2400,6 +2406,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
24002406
const js_context = self.js_context;
24012407
return valueToString(allocator, self.value, js_context.isolate, js_context.v8_context);
24022408
}
2409+
2410+
pub fn fromJson(ctx: *JsContext, json: []const u8) !Value {
2411+
const json_string = v8.String.initUtf8(ctx.isolate, json);
2412+
const value = try v8.Json.parse(ctx.v8_context, json_string);
2413+
return Value{ .js_context = ctx, .value = value };
2414+
}
24032415
};
24042416

24052417
pub const ValueIterator = struct {

src/tests/html/history.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,10 @@
2222
testing.expectEqual(undefined, history.forward());
2323
testing.expectEqual(undefined, history.back());
2424
</script>
25+
26+
<script id=history-states>
27+
testing.expectEqual(null, history.state)
28+
29+
history.pushState({}, { "abc": "def" }, '');
30+
testing.expectEqual({ "abc": "def"}, history.state);
31+
</script>

0 commit comments

Comments
 (0)