mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
add toJson object and fromJson value
This commit is contained in:
118
src/browser/html/History.zig
Normal file
118
src/browser/html/History.zig
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
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,
|
||||
// Serialized Env.JsObject
|
||||
state: []u8,
|
||||
};
|
||||
|
||||
const ScrollRestorationMode = enum {
|
||||
auto,
|
||||
manual,
|
||||
|
||||
pub fn fromString(str: []const u8) ?ScrollRestorationMode {
|
||||
for (std.enums.values(ScrollRestorationMode)) |mode| {
|
||||
if (std.ascii.eqlIgnoreCase(str, @tagName(mode))) {
|
||||
return mode;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scrollRestoration: 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_scrollRestoration(self: *History) []const u8 {
|
||||
return switch (self.scrollRestoration) {
|
||||
.auto => "auto",
|
||||
.manual => "manual",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
|
||||
self.scrollRestoration = ScrollRestorationMode.fromString(mode) orelse self.scrollRestoration;
|
||||
}
|
||||
|
||||
pub fn get_state(self: *History, page: *Page) !?Env.JsObject {
|
||||
if (self.current) |curr| {
|
||||
const entry = self.stack.items[curr];
|
||||
const object = try Env.JsObject.fromJson(page.main_context, entry.state);
|
||||
return object;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _pushState(self: *History, state: Env.JsObject, _: ?[]const u8, url: ?[]const u8, page: *Page) !void {
|
||||
const json = try state.toJson(page.arena);
|
||||
const entry = HistoryEntry{ .state = json, .url = url };
|
||||
try self.stack.append(page.session.arena, entry);
|
||||
self.current = self.stack.items.len;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
// data must handle any argument. We could expect a std.json.Value but
|
||||
// https://github.com/lightpanda-io/zig-js-runtime/issues/267 is missing.
|
||||
pub fn _replaceState(self: *History, state: Env.JsObject, _: ?[]const u8, url: ?[]const u8) void {
|
||||
_ = self;
|
||||
_ = url;
|
||||
_ = state;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
pub fn _go(self: *History, delta: ?i32) void {
|
||||
_ = self;
|
||||
_ = delta;
|
||||
}
|
||||
|
||||
pub fn _back(self: *History) void {
|
||||
if (self.current) |curr| {
|
||||
if (curr > 0) {
|
||||
self.current = curr - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _forward(self: *History) void {
|
||||
if (self.current) |curr| {
|
||||
if (curr < self.stack.items.len) {
|
||||
self.current = curr + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
test "Browser: HTML.History" {
|
||||
try testing.htmlRunner("html/history.html");
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface
|
||||
pub const History = struct {
|
||||
const ScrollRestorationMode = enum {
|
||||
auto,
|
||||
manual,
|
||||
};
|
||||
|
||||
scrollRestoration: ScrollRestorationMode = .auto,
|
||||
state: std.json.Value = .null,
|
||||
|
||||
// count tracks the history length until we implement correctly pushstate.
|
||||
count: u32 = 0,
|
||||
|
||||
pub fn get_length(self: *History) u32 {
|
||||
// TODO return the real history length value.
|
||||
return self.count;
|
||||
}
|
||||
|
||||
pub fn get_scrollRestoration(self: *History) []const u8 {
|
||||
return switch (self.scrollRestoration) {
|
||||
.auto => "auto",
|
||||
.manual => "manual",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
|
||||
if (std.mem.eql(u8, "manual", mode)) self.scrollRestoration = .manual;
|
||||
if (std.mem.eql(u8, "auto", mode)) self.scrollRestoration = .auto;
|
||||
}
|
||||
|
||||
pub fn get_state(self: *History) std.json.Value {
|
||||
return self.state;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
// data must handle any argument. We could expect a std.json.Value but
|
||||
// https://github.com/lightpanda-io/zig-js-runtime/issues/267 is missing.
|
||||
pub fn _pushState(self: *History, data: []const u8, _: ?[]const u8, url: ?[]const u8) void {
|
||||
self.count += 1;
|
||||
_ = url;
|
||||
_ = data;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
// data must handle any argument. We could expect a std.json.Value but
|
||||
// https://github.com/lightpanda-io/zig-js-runtime/issues/267 is missing.
|
||||
pub fn _replaceState(self: *History, data: []const u8, _: ?[]const u8, url: ?[]const u8) void {
|
||||
_ = self;
|
||||
_ = url;
|
||||
_ = data;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
pub fn _go(self: *History, delta: ?i32) void {
|
||||
_ = self;
|
||||
_ = delta;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
pub fn _back(self: *History) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
// TODO implement the function
|
||||
pub fn _forward(self: *History) void {
|
||||
_ = self;
|
||||
}
|
||||
};
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
test "Browser: HTML.History" {
|
||||
try testing.htmlRunner("html/history.html");
|
||||
}
|
||||
@@ -21,7 +21,7 @@ const HTMLElem = @import("elements.zig");
|
||||
const SVGElem = @import("svg_elements.zig");
|
||||
const Window = @import("window.zig").Window;
|
||||
const Navigator = @import("navigator.zig").Navigator;
|
||||
const History = @import("history.zig").History;
|
||||
const History = @import("History.zig");
|
||||
const Location = @import("location.zig").Location;
|
||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Navigator = @import("navigator.zig").Navigator;
|
||||
const History = @import("history.zig").History;
|
||||
const History = @import("History.zig");
|
||||
const Location = @import("location.zig").Location;
|
||||
const Crypto = @import("../crypto/crypto.zig").Crypto;
|
||||
const Console = @import("../console/console.zig").Console;
|
||||
@@ -54,7 +54,6 @@ pub const Window = struct {
|
||||
|
||||
document: *parser.DocumentHTML,
|
||||
target: []const u8 = "",
|
||||
history: History = .{},
|
||||
location: Location = .{},
|
||||
storage_shelf: ?*storage.Shelf = null,
|
||||
|
||||
@@ -179,8 +178,8 @@ pub const Window = struct {
|
||||
return self.document;
|
||||
}
|
||||
|
||||
pub fn get_history(self: *Window) *History {
|
||||
return &self.history;
|
||||
pub fn get_history(_: *Window, page: *Page) *History {
|
||||
return &page.session.history;
|
||||
}
|
||||
|
||||
// The interior height of the window in pixels, including the height of the horizontal scroll bar, if present.
|
||||
|
||||
@@ -24,6 +24,7 @@ const Env = @import("env.zig").Env;
|
||||
const Page = @import("page.zig").Page;
|
||||
const Browser = @import("browser.zig").Browser;
|
||||
const NavigateOpts = @import("page.zig").NavigateOpts;
|
||||
const History = @import("html/History.zig");
|
||||
|
||||
const log = @import("../log.zig");
|
||||
const parser = @import("netsurf.zig");
|
||||
@@ -53,6 +54,10 @@ pub const Session = struct {
|
||||
storage_shed: storage.Shed,
|
||||
cookie_jar: storage.CookieJar,
|
||||
|
||||
// History is persistent across the "tab".
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/History
|
||||
history: History = .{},
|
||||
|
||||
page: ?Page = null,
|
||||
|
||||
// If the current page want to navigate to a new page
|
||||
|
||||
@@ -2005,6 +2005,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
||||
return writer.writeAll(try self.toString());
|
||||
}
|
||||
|
||||
pub fn toJson(self: JsObject, allocator: std.mem.Allocator) ![]u8 {
|
||||
const json_string = try v8.Json.stringify(self.js_context.v8_context, self.js_obj.toValue(), null);
|
||||
const str = try jsStringToZig(allocator, json_string, self.js_context.isolate);
|
||||
return str;
|
||||
}
|
||||
|
||||
pub fn persist(self: JsObject) !JsObject {
|
||||
var js_context = self.js_context;
|
||||
const js_obj = self.js_obj;
|
||||
@@ -2400,6 +2406,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
||||
const js_context = self.js_context;
|
||||
return valueToString(allocator, self.value, js_context.isolate, js_context.v8_context);
|
||||
}
|
||||
|
||||
pub fn fromJson(ctx: *JsContext, json: []const u8) !Value {
|
||||
const json_string = v8.String.initUtf8(ctx.isolate, json);
|
||||
const value = try v8.Json.parse(ctx.v8_context, json_string);
|
||||
return Value{ .js_context = ctx, .value = value };
|
||||
}
|
||||
};
|
||||
|
||||
pub const ValueIterator = struct {
|
||||
|
||||
@@ -22,3 +22,10 @@
|
||||
testing.expectEqual(undefined, history.forward());
|
||||
testing.expectEqual(undefined, history.back());
|
||||
</script>
|
||||
|
||||
<script id=history-states>
|
||||
testing.expectEqual(null, history.state)
|
||||
|
||||
history.pushState({}, { "abc": "def" }, '');
|
||||
testing.expectEqual({ "abc": "def"}, history.state);
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user