mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
add NavigationCurrentEntryChangeEvent
This commit is contained in:
@@ -38,6 +38,7 @@ const ErrorEvent = @import("../html/error_event.zig").ErrorEvent;
|
|||||||
const MessageEvent = @import("../dom/MessageChannel.zig").MessageEvent;
|
const MessageEvent = @import("../dom/MessageChannel.zig").MessageEvent;
|
||||||
const PopStateEvent = @import("../html/History.zig").PopStateEvent;
|
const PopStateEvent = @import("../html/History.zig").PopStateEvent;
|
||||||
const CompositionEvent = @import("composition_event.zig").CompositionEvent;
|
const CompositionEvent = @import("composition_event.zig").CompositionEvent;
|
||||||
|
const NavigationCurrentEntryChangeEvent = @import("../html/Navigation.zig").NavigationCurrentEntryChangeEvent;
|
||||||
|
|
||||||
// Event interfaces
|
// Event interfaces
|
||||||
pub const Interfaces = .{
|
pub const Interfaces = .{
|
||||||
@@ -50,6 +51,7 @@ pub const Interfaces = .{
|
|||||||
MessageEvent,
|
MessageEvent,
|
||||||
PopStateEvent,
|
PopStateEvent,
|
||||||
CompositionEvent,
|
CompositionEvent,
|
||||||
|
NavigationCurrentEntryChangeEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Union = generate.Union(Interfaces);
|
pub const Union = generate.Union(Interfaces);
|
||||||
@@ -79,6 +81,9 @@ pub const Event = struct {
|
|||||||
.keyboard_event => .{ .KeyboardEvent = @as(*parser.KeyboardEvent, @ptrCast(evt)) },
|
.keyboard_event => .{ .KeyboardEvent = @as(*parser.KeyboardEvent, @ptrCast(evt)) },
|
||||||
.pop_state => .{ .PopStateEvent = @as(*PopStateEvent, @ptrCast(evt)).* },
|
.pop_state => .{ .PopStateEvent = @as(*PopStateEvent, @ptrCast(evt)).* },
|
||||||
.composition_event => .{ .CompositionEvent = (@as(*CompositionEvent, @fieldParentPtr("proto", evt))).* },
|
.composition_event => .{ .CompositionEvent = (@as(*CompositionEvent, @fieldParentPtr("proto", evt))).* },
|
||||||
|
.navigation_current_entry_change_event => .{
|
||||||
|
.NavigationCurrentEntryChangeEvent = @as(*NavigationCurrentEntryChangeEvent, @ptrCast(evt)).*,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,29 +55,6 @@ pub fn get_state(_: *History, page: *Page) !?js.Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatchPopStateEvent(state: ?[]const u8, page: *Page) void {
|
|
||||||
log.debug(.script_event, "dispatch popstate event", .{
|
|
||||||
.type = "popstate",
|
|
||||||
.source = "history",
|
|
||||||
});
|
|
||||||
History._dispatchPopStateEvent(state, page) catch |err| {
|
|
||||||
log.err(.app, "dispatch popstate event error", .{
|
|
||||||
.err = err,
|
|
||||||
.type = "popstate",
|
|
||||||
.source = "history",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
|
|
||||||
var evt = try PopStateEvent.constructor("popstate", .{ .state = state });
|
|
||||||
|
|
||||||
_ = try parser.eventTargetDispatchEvent(
|
|
||||||
@as(*parser.EventTarget, @ptrCast(&page.window)),
|
|
||||||
&evt.proto,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||||
const arena = page.session.arena;
|
const arena = page.session.arena;
|
||||||
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
|
const url = if (_url) |u| try arena.dupe(u8, u) else try arena.dupe(u8, page.url.raw);
|
||||||
@@ -111,7 +88,7 @@ pub fn go(_: *const History, delta: i32, page: *Page) !void {
|
|||||||
|
|
||||||
if (entry.url) |url| {
|
if (entry.url) |url| {
|
||||||
if (try page.isSameOrigin(url)) {
|
if (try page.isSameOrigin(url)) {
|
||||||
History.dispatchPopStateEvent(entry.state, page);
|
PopStateEvent.dispatch(entry.state, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +145,34 @@ pub const PopStateEvent = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dispatch(state: ?[]const u8, page: *Page) void {
|
||||||
|
log.debug(.script_event, "dispatch popstate event", .{
|
||||||
|
.type = "popstate",
|
||||||
|
.source = "history",
|
||||||
|
});
|
||||||
|
|
||||||
|
var evt = PopStateEvent.constructor("popstate", .{ .state = state }) catch |err| {
|
||||||
|
log.err(.app, "event constructor error", .{
|
||||||
|
.err = err,
|
||||||
|
.type = "popstate",
|
||||||
|
.source = "history",
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = parser.eventTargetDispatchEvent(
|
||||||
|
@as(*parser.EventTarget, @ptrCast(&page.window)),
|
||||||
|
&evt.proto,
|
||||||
|
) catch |err| {
|
||||||
|
log.err(.app, "dispatch popstate event error", .{
|
||||||
|
.err = err,
|
||||||
|
.type = "popstate",
|
||||||
|
.source = "history",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ pub const Interfaces = .{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const NavigationType = enum {
|
pub const NavigationType = enum {
|
||||||
|
pub const ENUM_JS_USE_TAG = true;
|
||||||
|
|
||||||
push,
|
push,
|
||||||
replace,
|
replace,
|
||||||
traverse,
|
traverse,
|
||||||
@@ -56,7 +58,8 @@ pub const prototype = *EventTarget;
|
|||||||
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .plain },
|
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .plain },
|
||||||
|
|
||||||
index: usize = 0,
|
index: usize = 0,
|
||||||
entries: std.ArrayListUnmanaged(NavigationHistoryEntry) = .empty,
|
// Need to be stable pointers, because Events can reference entries.
|
||||||
|
entries: std.ArrayListUnmanaged(*NavigationHistoryEntry) = .empty,
|
||||||
next_entry_id: usize = 0,
|
next_entry_id: usize = 0,
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
|
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
|
||||||
@@ -75,7 +78,7 @@ const NavigationHistoryEntry = struct {
|
|||||||
|
|
||||||
pub fn get_index(self: *const NavigationHistoryEntry, page: *Page) i32 {
|
pub fn get_index(self: *const NavigationHistoryEntry, page: *Page) i32 {
|
||||||
const navigation = page.session.navigation;
|
const navigation = page.session.navigation;
|
||||||
for (navigation.entries.items, 0..) |*entry, i| {
|
for (navigation.entries.items, 0..) |entry, i| {
|
||||||
if (std.mem.eql(u8, entry.id, self.id)) {
|
if (std.mem.eql(u8, entry.id, self.id)) {
|
||||||
return @intCast(i);
|
return @intCast(i);
|
||||||
}
|
}
|
||||||
@@ -151,11 +154,11 @@ pub fn get_canGoForward(self: *const Navigation) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn currentEntry(self: *Navigation) *NavigationHistoryEntry {
|
pub fn currentEntry(self: *Navigation) *NavigationHistoryEntry {
|
||||||
return &self.entries.items[self.index];
|
return self.entries.items[self.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_currentEntry(self: *const Navigation) NavigationHistoryEntry {
|
pub fn get_currentEntry(self: *Navigation) *NavigationHistoryEntry {
|
||||||
return self.entries.items[self.index];
|
return self.currentEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_transition(_: *const Navigation) ?NavigationTransition {
|
pub fn get_transition(_: *const Navigation) ?NavigationTransition {
|
||||||
@@ -180,7 +183,7 @@ pub fn _back(self: *Navigation, page: *Page) !NavigationReturn {
|
|||||||
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
|
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _entries(self: *const Navigation) []NavigationHistoryEntry {
|
pub fn _entries(self: *const Navigation) []*NavigationHistoryEntry {
|
||||||
return self.entries.items;
|
return self.entries.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ pub fn processNavigation(self: *Navigation, page: *Page) !void {
|
|||||||
|
|
||||||
/// Pushes an entry into the Navigation stack WITHOUT actually navigating to it.
|
/// Pushes an entry into the Navigation stack WITHOUT actually navigating to it.
|
||||||
/// For that, use `navigate`.
|
/// For that, use `navigate`.
|
||||||
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page) !NavigationHistoryEntry {
|
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page) !*NavigationHistoryEntry {
|
||||||
const arena = page.session.arena;
|
const arena = page.session.arena;
|
||||||
|
|
||||||
const url = if (_url) |u| try arena.dupe(u8, u) else null;
|
const url = if (_url) |u| try arena.dupe(u8, u) else null;
|
||||||
@@ -231,21 +234,31 @@ pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page:
|
|||||||
if (self.entries.items.len > self.index + 1) {
|
if (self.entries.items.len > self.index + 1) {
|
||||||
self.entries.shrinkRetainingCapacity(self.index + 1);
|
self.entries.shrinkRetainingCapacity(self.index + 1);
|
||||||
}
|
}
|
||||||
self.index = self.entries.items.len;
|
|
||||||
|
const index = self.entries.items.len;
|
||||||
|
|
||||||
const id = self.next_entry_id;
|
const id = self.next_entry_id;
|
||||||
self.next_entry_id += 1;
|
self.next_entry_id += 1;
|
||||||
|
|
||||||
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
|
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
|
||||||
|
|
||||||
const entry = NavigationHistoryEntry{
|
const entry = try arena.create(NavigationHistoryEntry);
|
||||||
|
entry.* = NavigationHistoryEntry{
|
||||||
.id = id_str,
|
.id = id_str,
|
||||||
.key = id_str,
|
.key = id_str,
|
||||||
.url = url,
|
.url = url,
|
||||||
.state = state,
|
.state = state,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// we don't always have a current entry...
|
||||||
|
const previous = if (self.entries.items.len > 0) self.currentEntry() else null;
|
||||||
try self.entries.append(arena, entry);
|
try self.entries.append(arena, entry);
|
||||||
|
if (previous) |prev| {
|
||||||
|
NavigationCurrentEntryChangeEvent.dispatch(prev, .push, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.index = index;
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +350,9 @@ pub fn _reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigatio
|
|||||||
const opts = _opts orelse ReloadOptions{};
|
const opts = _opts orelse ReloadOptions{};
|
||||||
const entry = self.currentEntry();
|
const entry = self.currentEntry();
|
||||||
if (opts.state) |state| {
|
if (opts.state) |state| {
|
||||||
|
const previous = entry;
|
||||||
entry.state = state.toJson(arena) catch return error.DataClone;
|
entry.state = state.toJson(arena) catch return error.DataClone;
|
||||||
|
NavigationCurrentEntryChangeEvent.dispatch(previous, .reload, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.navigate(entry.url, .reload, page);
|
return self.navigate(entry.url, .reload, page);
|
||||||
@@ -365,9 +380,80 @@ pub const UpdateCurrentEntryOptions = struct {
|
|||||||
|
|
||||||
pub fn _updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions, page: *Page) !void {
|
pub fn _updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions, page: *Page) !void {
|
||||||
const arena = page.session.arena;
|
const arena = page.session.arena;
|
||||||
|
|
||||||
|
const previous = self.currentEntry();
|
||||||
self.currentEntry().state = options.state.toJson(arena) catch return error.DataClone;
|
self.currentEntry().state = options.state.toJson(arena) catch return error.DataClone;
|
||||||
|
NavigationCurrentEntryChangeEvent.dispatch(previous, null, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Event = @import("../events/event.zig").Event;
|
||||||
|
|
||||||
|
pub const NavigationCurrentEntryChangeEvent = struct {
|
||||||
|
pub const prototype = *Event;
|
||||||
|
pub const union_make_copy = true;
|
||||||
|
|
||||||
|
pub const EventInit = struct {
|
||||||
|
from: *NavigationHistoryEntry,
|
||||||
|
navigation_type: ?NavigationType = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
proto: parser.Event,
|
||||||
|
from: *NavigationHistoryEntry,
|
||||||
|
navigation_type: ?NavigationType,
|
||||||
|
|
||||||
|
pub fn constructor(event_type: []const u8, opts: EventInit) !NavigationCurrentEntryChangeEvent {
|
||||||
|
const event = try parser.eventCreate();
|
||||||
|
defer parser.eventDestroy(event);
|
||||||
|
try parser.eventInit(event, event_type, .{});
|
||||||
|
parser.eventSetInternalType(event, .navigation_current_entry_change_event);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.proto = event.*,
|
||||||
|
.from = opts.from,
|
||||||
|
.navigation_type = opts.navigation_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_from(self: *NavigationCurrentEntryChangeEvent) *NavigationHistoryEntry {
|
||||||
|
return self.from;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_navigationType(self: *const NavigationCurrentEntryChangeEvent) ?NavigationType {
|
||||||
|
return self.navigation_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch(from: *NavigationHistoryEntry, typ: ?NavigationType, page: *Page) void {
|
||||||
|
log.debug(.script_event, "dispatch event", .{
|
||||||
|
.type = "currententrychange",
|
||||||
|
.source = "navigation",
|
||||||
|
});
|
||||||
|
|
||||||
|
var evt = NavigationCurrentEntryChangeEvent.constructor(
|
||||||
|
"currententrychange",
|
||||||
|
.{ .from = from, .navigation_type = typ },
|
||||||
|
) catch |err| {
|
||||||
|
log.err(.app, "event constructor error", .{
|
||||||
|
.err = err,
|
||||||
|
.type = "currententrychange",
|
||||||
|
.source = "navigation",
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = parser.eventTargetDispatchEvent(
|
||||||
|
@as(*parser.EventTarget, @ptrCast(&page.session.navigation)),
|
||||||
|
&evt.proto,
|
||||||
|
) catch |err| {
|
||||||
|
log.err(.app, "dispatch event error", .{
|
||||||
|
.err = err,
|
||||||
|
.type = "currententrychange",
|
||||||
|
.source = "navigation",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
test "Browser: Navigation" {
|
test "Browser: Navigation" {
|
||||||
try testing.htmlRunner("html/navigation.html");
|
try testing.htmlRunner("html/navigation.html");
|
||||||
|
|||||||
@@ -560,6 +560,7 @@ pub const EventType = enum(u8) {
|
|||||||
keyboard_event = 8,
|
keyboard_event = 8,
|
||||||
pop_state = 9,
|
pop_state = 9,
|
||||||
composition_event = 10,
|
composition_event = 10,
|
||||||
|
navigation_current_entry_change_event = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MutationEvent = c.dom_mutation_event;
|
pub const MutationEvent = c.dom_mutation_event;
|
||||||
|
|||||||
Reference in New Issue
Block a user