From 4c0437b3fb74210a3390400634863d3b37fb4483 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sun, 2 Nov 2025 11:49:35 +0800 Subject: [PATCH] History placeholder --- src/browser/Factory.zig | 4 ++ src/browser/Page.zig | 2 + src/browser/js/bridge.zig | 1 + src/browser/webapi/History.zig | 84 ++++++++++++++++++++++++++++++++++ src/browser/webapi/Window.zig | 7 +++ 5 files changed, 98 insertions(+) create mode 100644 src/browser/webapi/History.zig diff --git a/src/browser/Factory.zig b/src/browser/Factory.zig index b1b41f9d..7d75fb40 100644 --- a/src/browser/Factory.zig +++ b/src/browser/Factory.zig @@ -46,6 +46,7 @@ _size_112_8: MemoryPoolAligned([112]u8, .@"8"), _size_120_8: MemoryPoolAligned([120]u8, .@"8"), _size_128_8: MemoryPoolAligned([128]u8, .@"8"), _size_144_8: MemoryPoolAligned([144]u8, .@"8"), +_size_152_8: MemoryPoolAligned([152]u8, .@"8"), _size_456_8: MemoryPoolAligned([456]u8, .@"8"), _size_520_8: MemoryPoolAligned([520]u8, .@"8"), _size_648_8: MemoryPoolAligned([648]u8, .@"8"), @@ -72,6 +73,7 @@ pub fn init(page: *Page) Factory { ._size_120_8 = MemoryPoolAligned([120]u8, .@"8").init(page.arena), ._size_128_8 = MemoryPoolAligned([128]u8, .@"8").init(page.arena), ._size_144_8 = MemoryPoolAligned([144]u8, .@"8").init(page.arena), + ._size_152_8 = MemoryPoolAligned([152]u8, .@"8").init(page.arena), ._size_456_8 = MemoryPoolAligned([456]u8, .@"8").init(page.arena), ._size_520_8 = MemoryPoolAligned([520]u8, .@"8").init(page.arena), ._size_648_8 = MemoryPoolAligned([648]u8, .@"8").init(page.arena), @@ -231,6 +233,7 @@ pub fn createT(self: *Factory, comptime T: type) !*T { if (comptime SO == 120) return @ptrCast(try self._size_120_8.create()); if (comptime SO == 128) return @ptrCast(try self._size_128_8.create()); if (comptime SO == 144) return @ptrCast(try self._size_144_8.create()); + if (comptime SO == 152) return @ptrCast(try self._size_152_8.create()); if (comptime SO == 456) return @ptrCast(try self._size_456_8.create()); if (comptime SO == 520) return @ptrCast(try self._size_520_8.create()); if (comptime SO == 648) return @ptrCast(try self._size_648_8.create()); @@ -311,6 +314,7 @@ fn destroyChain(self: *Factory, value: anytype, comptime first: bool) void { 120 => self._size_120_8.destroy(@ptrCast(value)), 128 => self._size_128_8.destroy(@ptrCast(value)), 144 => self._size_144_8.destroy(@ptrCast(value)), + 152 => self._size_152_8.destroy(@ptrCast(value)), 456 => self._size_456_8.destroy(@ptrCast(value)), 520 => self._size_520_8.destroy(@ptrCast(value)), 648 => self._size_648_8.destroy(@ptrCast(value)), diff --git a/src/browser/Page.zig b/src/browser/Page.zig index b44dfb3c..dbb2a984 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -16,6 +16,7 @@ const Mime = @import("Mime.zig"); const Factory = @import("Factory.zig"); const Session = @import("Session.zig"); const Scheduler = @import("Scheduler.zig"); +const History = @import("webapi/History.zig"); const EventManager = @import("EventManager.zig"); const ScriptManager = @import("ScriptManager.zig"); const polyfill = @import("polyfill/polyfill.zig"); @@ -142,6 +143,7 @@ fn reset(self: *Page, comptime initializing: bool) !void { self.window = try self._factory.eventTarget(Window{ ._document = self.document, ._storage_bucket = storage_bucket, + ._history = History.init(self), ._proto = undefined, ._location = &default_location, }); diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index 0eed8dc9..38226456 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -446,6 +446,7 @@ pub const JsApis = flattenTypes(&.{ @import("../webapi/css/MediaQueryList.zig"), @import("../webapi/Document.zig"), @import("../webapi/HTMLDocument.zig"), + @import("../webapi/History.zig"), @import("../webapi/KeyValueList.zig"), @import("../webapi/DocumentFragment.zig"), @import("../webapi/DocumentType.zig"), diff --git a/src/browser/webapi/History.zig b/src/browser/webapi/History.zig new file mode 100644 index 00000000..ada62226 --- /dev/null +++ b/src/browser/webapi/History.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const js = @import("../js/js.zig"); + +const Page = @import("../Page.zig"); + +const History = @This(); + +_page: *Page, +_length: u32 = 1, +_state: ?js.Object = null, + +pub fn init(page: *Page) History { + return .{ + ._page = page, + }; +} + +pub fn deinit(self: *History) void { + if (self._state) |state| { + js.q.JS_FreeValue(self._page.js.ctx, state.value); + } +} + +pub fn getLength(self: *const History) u32 { + return self._length; +} + +pub fn getState(self: *const History) ?js.Object { + return self._state; +} + +pub fn pushState(self: *History, state: js.Object, _title: []const u8, url: ?[]const u8, page: *Page) !void { + _ = _title; // title is ignored in modern browsers + _ = url; // For minimal implementation, we don't actually navigate + _ = page; + + self._state = state; + self._length += 1; +} + +pub fn replaceState(self: *History, state: js.Object, _title: []const u8, url: ?[]const u8, page: *Page) !void { + _ = _title; + _ = url; + _ = page; + self._state = state; + // Note: replaceState doesn't change length +} + +pub fn back(self: *History, page: *Page) void { + _ = self; + _ = page; + // Minimal implementation: no-op +} + +pub fn forward(self: *History, page: *Page) void { + _ = self; + _ = page; + // Minimal implementation: no-op +} + +pub fn go(self: *History, delta: i32, page: *Page) void { + _ = self; + _ = delta; + _ = page; + // Minimal implementation: no-op +} + +pub const JsApi = struct { + pub const bridge = js.Bridge(History); + + pub const Meta = struct { + pub const name = "History"; + pub var class_id: bridge.ClassId = 0; + pub const prototype_chain = bridge.prototypeChain(); + }; + + pub const length = bridge.accessor(History.getLength, null, .{}); + pub const state = bridge.accessor(History.getState, null, .{}); + pub const pushState = bridge.function(History.pushState, .{}); + pub const replaceState = bridge.function(History.replaceState, .{}); + pub const back = bridge.function(History.back, .{}); + pub const forward = bridge.function(History.forward, .{}); + pub const go = bridge.function(History.go, .{}); +}; diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig index 9aa918c4..944ea860 100644 --- a/src/browser/webapi/Window.zig +++ b/src/browser/webapi/Window.zig @@ -5,6 +5,7 @@ const builtin = @import("builtin"); const log = @import("../../log.zig"); const Page = @import("../Page.zig"); const Console = @import("Console.zig"); +const History = @import("History.zig"); const Navigator = @import("Navigator.zig"); const Document = @import("Document.zig"); const Location = @import("Location.zig"); @@ -20,6 +21,7 @@ _proto: *EventTarget, _document: *Document, _console: Console = .init, _navigator: Navigator = .init, +_history: History, _storage_bucket: *storage.Bucket, _on_load: ?js.Function = null, _location: *Location, @@ -62,6 +64,10 @@ pub fn getLocation(self: *const Window) *Location { return self._location; } +pub fn getHistory(self: *Window) *History { + return &self._history; +} + pub fn getOnLoad(self: *const Window) ?js.Function { return self._on_load; } @@ -264,6 +270,7 @@ pub const JsApi = struct { pub const sessionStorage = bridge.accessor(Window.getSessionStorage, null, .{ .cache = "sessionStorage" }); pub const document = bridge.accessor(Window.getDocument, null, .{ .cache = "document" }); pub const location = bridge.accessor(Window.getLocation, null, .{ .cache = "location" }); + pub const history = bridge.accessor(Window.getHistory, null, .{ .cache = "history" }); pub const onload = bridge.accessor(Window.getOnLoad, Window.setOnLoad, .{}); pub const fetch = bridge.function(Window.fetch, .{}); pub const setTimeout = bridge.function(Window.setTimeout, .{});