diff --git a/src/browser/events/event.zig b/src/browser/events/event.zig
index 0fa31921..ba6b367d 100644
--- a/src/browser/events/event.zig
+++ b/src/browser/events/event.zig
@@ -17,6 +17,7 @@
// along with this program. If not, see .
const std = @import("std");
+const js = @import("../js/js.zig");
const Allocator = std.mem.Allocator;
const log = @import("../../log.zig");
@@ -231,8 +232,6 @@ pub const EventHandler = struct {
node: parser.EventNode,
listener: *parser.EventListener,
- const js = @import("../js/js.zig");
-
pub const Listener = union(enum) {
function: js.Function,
object: js.Object,
@@ -404,6 +403,40 @@ const SignalCallback = struct {
}
};
+pub fn DirectEventHandler(
+ comptime TargetT: type,
+ target: *TargetT,
+ event_type: []const u8,
+ maybe_listener: ?EventHandler.Listener,
+ cb: *?js.Function,
+ page_arena: std.mem.Allocator,
+) !void {
+ const event_target = parser.toEventTarget(TargetT, target);
+
+ // Check if we have a listener set.
+ if (cb.*) |callback| {
+ const listener = try parser.eventTargetHasListener(event_target, event_type, false, callback.id);
+ std.debug.assert(listener != null);
+ try parser.eventTargetRemoveEventListener(event_target, event_type, listener.?, false);
+ }
+
+ if (maybe_listener) |listener| {
+ switch (listener) {
+ // If an object is given as listener, do nothing.
+ .object => {},
+ .function => |callback| {
+ _ = try EventHandler.register(page_arena, event_target, event_type, listener, null) orelse unreachable;
+ cb.* = callback;
+
+ return;
+ },
+ }
+ }
+
+ // Just unset the listener.
+ cb.* = null;
+}
+
const testing = @import("../../testing.zig");
test "Browser: Event" {
try testing.htmlRunner("events/event.html");
diff --git a/src/browser/html/History.zig b/src/browser/html/History.zig
index e7b6b866..4412e887 100644
--- a/src/browser/html/History.zig
+++ b/src/browser/html/History.zig
@@ -177,5 +177,6 @@ pub const PopStateEvent = struct {
const testing = @import("../../testing.zig");
test "Browser: HTML.History" {
- try testing.htmlRunner("html/history.html");
+ try testing.htmlRunner("html/history/history.html");
+ try testing.htmlRunner("html/history/history2.html");
}
diff --git a/src/browser/html/Navigation.zig b/src/browser/html/Navigation.zig
index e16d01ff..defa50c2 100644
--- a/src/browser/html/Navigation.zig
+++ b/src/browser/html/Navigation.zig
@@ -23,6 +23,7 @@ const URL = @import("../../url.zig").URL;
const js = @import("../js/js.zig");
const Page = @import("../page.zig").Page;
+const DirectEventHandler = @import("../events/event.zig").DirectEventHandler;
const EventTarget = @import("../dom/event_target.zig").EventTarget;
const EventHandler = @import("../events/event.zig").EventHandler;
@@ -62,6 +63,8 @@ index: usize = 0,
entries: std.ArrayListUnmanaged(*NavigationHistoryEntry) = .empty,
next_entry_id: usize = 0,
+oncurrententrychange_callback: ?js.Function = null,
+
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
const NavigationHistoryEntry = struct {
pub const prototype = *EventTarget;
@@ -199,6 +202,16 @@ pub fn _forward(self: *Navigation, page: *Page) !NavigationReturn {
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
}
+/// Returns `oncurrententrychange_callback`.
+pub fn get_oncurrententrychange(self: *const Navigation) ?js.Function {
+ return self.oncurrententrychange_callback;
+}
+
+/// Sets `oncurrententrychange_callback`.
+pub fn set_oncurrententrychange(self: *Navigation, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
+ try DirectEventHandler(Navigation, self, "currententrychange", maybe_listener, &self.oncurrententrychange_callback, page.arena);
+}
+
// This is for after true navigation processing, where we need to ensure that our entries are up to date.
// This is only really safe to run in the `pageDoneCallback` where we can guarantee that the URL and NavigationKind are correct.
pub fn processNavigation(self: *Navigation, page: *Page) !void {
@@ -456,5 +469,5 @@ pub const NavigationCurrentEntryChangeEvent = struct {
const testing = @import("../../testing.zig");
test "Browser: Navigation" {
- try testing.htmlRunner("html/navigation.html");
+ try testing.htmlRunner("html/navigation/navigation.html");
}
diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig
index 3947c526..e89ab203 100644
--- a/src/browser/html/window.zig
+++ b/src/browser/html/window.zig
@@ -44,6 +44,8 @@ const fetchFn = @import("../fetch/fetch.zig").fetch;
const storage = @import("../storage/storage.zig");
const ErrorEvent = @import("error_event.zig").ErrorEvent;
+const DirectEventHandler = @import("../events/event.zig").DirectEventHandler;
+
// https://dom.spec.whatwg.org/#interface-window-extensions
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#window
pub const Window = struct {
@@ -70,6 +72,7 @@ pub const Window = struct {
scroll_x: u32 = 0,
scroll_y: u32 = 0,
onload_callback: ?js.Function = null,
+ onpopstate_callback: ?js.Function = null,
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
var fbs = std.io.fixedBufferStream("");
@@ -111,31 +114,17 @@ pub const Window = struct {
/// Sets `onload_callback`.
pub fn set_onload(self: *Window, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
- const event_target = parser.toEventTarget(Window, self);
- const event_type = "load";
+ try DirectEventHandler(Window, self, "load", maybe_listener, &self.onload_callback, page.arena);
+ }
- // Check if we have a listener set.
- if (self.onload_callback) |callback| {
- const listener = try parser.eventTargetHasListener(event_target, event_type, false, callback.id);
- std.debug.assert(listener != null);
- try parser.eventTargetRemoveEventListener(event_target, event_type, listener.?, false);
- }
+ /// Returns `onpopstate_callback`.
+ pub fn get_onpopstate(self: *const Window) ?js.Function {
+ return self.onpopstate_callback;
+ }
- if (maybe_listener) |listener| {
- switch (listener) {
- // If an object is given as listener, do nothing.
- .object => {},
- .function => |callback| {
- _ = try EventHandler.register(page.arena, event_target, event_type, listener, null) orelse unreachable;
- self.onload_callback = callback;
-
- return;
- },
- }
- }
-
- // Just unset the listener.
- self.onload_callback = null;
+ /// Sets `onpopstate_callback`.
+ pub fn set_onpopstate(self: *Window, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
+ try DirectEventHandler(Window, self, "popstate", maybe_listener, &self.onpopstate_callback, page.arena);
}
pub fn get_location(self: *Window) *Location {
diff --git a/src/tests/html/history.html b/src/tests/html/history/history.html
similarity index 91%
rename from src/tests/html/history.html
rename to src/tests/html/history/history.html
index 60b54b52..fbb7dd95 100644
--- a/src/tests/html/history.html
+++ b/src/tests/html/history/history.html
@@ -1,5 +1,5 @@
-
+
+
+
diff --git a/src/tests/html/history2.html b/src/tests/html/history/history_after_nav.html
similarity index 75%
rename from src/tests/html/history2.html
rename to src/tests/html/history/history_after_nav.html
index 735c71e9..d9e4e66d 100644
--- a/src/tests/html/history2.html
+++ b/src/tests/html/history/history_after_nav.html
@@ -1,5 +1,5 @@
-
+
+
diff --git a/src/tests/html/navigation2.html b/src/tests/html/navigation/navigation2.html
similarity index 85%
rename from src/tests/html/navigation2.html
rename to src/tests/html/navigation/navigation2.html
index 3b8ad282..b16fa917 100644
--- a/src/tests/html/navigation2.html
+++ b/src/tests/html/navigation/navigation2.html
@@ -1,5 +1,5 @@
-
+