Skip to content

Commit c8395c2

Browse files
committed
add NavigationCurrentEntryChangeEvent
1 parent d4f56c0 commit c8395c2

File tree

4 files changed

+130
-33
lines changed

4 files changed

+130
-33
lines changed

src/browser/events/event.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const KeyboardEvent = @import("keyboard_event.zig").KeyboardEvent;
3737
const ErrorEvent = @import("../html/error_event.zig").ErrorEvent;
3838
const MessageEvent = @import("../dom/MessageChannel.zig").MessageEvent;
3939
const PopStateEvent = @import("../html/History.zig").PopStateEvent;
40+
const NavigationCurrentEntryChangeEvent = @import("../html/Navigation.zig").NavigationCurrentEntryChangeEvent;
4041

4142
// Event interfaces
4243
pub const Interfaces = .{
@@ -48,6 +49,7 @@ pub const Interfaces = .{
4849
ErrorEvent,
4950
MessageEvent,
5051
PopStateEvent,
52+
NavigationCurrentEntryChangeEvent,
5153
};
5254

5355
pub const Union = generate.Union(Interfaces);
@@ -76,6 +78,9 @@ pub const Event = struct {
7678
.message_event => .{ .MessageEvent = @as(*MessageEvent, @ptrCast(evt)).* },
7779
.keyboard_event => .{ .KeyboardEvent = @as(*parser.KeyboardEvent, @ptrCast(evt)) },
7880
.pop_state => .{ .PopStateEvent = @as(*PopStateEvent, @ptrCast(evt)).* },
81+
.navigation_current_entry_change_event => .{
82+
.NavigationCurrentEntryChangeEvent = @as(*NavigationCurrentEntryChangeEvent, @ptrCast(evt)).*,
83+
},
7984
};
8085
}
8186

src/browser/html/History.zig

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,6 @@ pub fn get_state(_: *History, page: *Page) !?js.Value {
5555
}
5656
}
5757

58-
pub fn dispatchPopStateEvent(state: ?[]const u8, page: *Page) void {
59-
log.debug(.script_event, "dispatch popstate event", .{
60-
.type = "popstate",
61-
.source = "history",
62-
});
63-
History._dispatchPopStateEvent(state, page) catch |err| {
64-
log.err(.app, "dispatch popstate event error", .{
65-
.err = err,
66-
.type = "popstate",
67-
.source = "history",
68-
});
69-
};
70-
}
71-
72-
fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
73-
var evt = try PopStateEvent.constructor("popstate", .{ .state = state });
74-
75-
_ = try parser.eventTargetDispatchEvent(
76-
@as(*parser.EventTarget, @ptrCast(&page.window)),
77-
&evt.proto,
78-
);
79-
}
80-
8158
pub fn _pushState(_: *const History, state: js.Object, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
8259
const arena = page.session.arena;
8360
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 {
11188

11289
if (entry.url) |url| {
11390
if (try page.isSameOrigin(url)) {
114-
History.dispatchPopStateEvent(entry.state, page);
91+
PopStateEvent.dispatch(entry.state, page);
11592
}
11693
}
11794

@@ -168,6 +145,34 @@ pub const PopStateEvent = struct {
168145
return null;
169146
}
170147
}
148+
149+
pub fn dispatch(state: ?[]const u8, page: *Page) void {
150+
log.debug(.script_event, "dispatch popstate event", .{
151+
.type = "popstate",
152+
.source = "history",
153+
});
154+
155+
var evt = PopStateEvent.constructor("popstate", .{ .state = state }) catch |err| {
156+
log.err(.app, "event constructor error", .{
157+
.err = err,
158+
.type = "popstate",
159+
.source = "history",
160+
});
161+
162+
return;
163+
};
164+
165+
_ = parser.eventTargetDispatchEvent(
166+
@as(*parser.EventTarget, @ptrCast(&page.window)),
167+
&evt.proto,
168+
) catch |err| {
169+
log.err(.app, "dispatch popstate event error", .{
170+
.err = err,
171+
.type = "popstate",
172+
.source = "history",
173+
});
174+
};
175+
}
171176
};
172177

173178
const testing = @import("../../testing.zig");

src/browser/html/Navigation.zig

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub const Interfaces = .{
3939
};
4040

4141
pub const NavigationType = enum {
42+
pub const ENUM_JS_USE_TAG = true;
43+
4244
push,
4345
replace,
4446
traverse,
@@ -56,7 +58,8 @@ pub const prototype = *EventTarget;
5658
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .plain },
5759

5860
index: usize = 0,
59-
entries: std.ArrayListUnmanaged(NavigationHistoryEntry) = .empty,
61+
// Need to be stable pointers, because Events can reference entries.
62+
entries: std.ArrayListUnmanaged(*NavigationHistoryEntry) = .empty,
6063
next_entry_id: usize = 0,
6164

6265
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
@@ -75,7 +78,7 @@ const NavigationHistoryEntry = struct {
7578

7679
pub fn get_index(self: *const NavigationHistoryEntry, page: *Page) i32 {
7780
const navigation = page.session.navigation;
78-
for (navigation.entries.items, 0..) |*entry, i| {
81+
for (navigation.entries.items, 0..) |entry, i| {
7982
if (std.mem.eql(u8, entry.id, self.id)) {
8083
return @intCast(i);
8184
}
@@ -151,11 +154,11 @@ pub fn get_canGoForward(self: *const Navigation) bool {
151154
}
152155

153156
pub fn currentEntry(self: *Navigation) *NavigationHistoryEntry {
154-
return &self.entries.items[self.index];
157+
return self.entries.items[self.index];
155158
}
156159

157-
pub fn get_currentEntry(self: *const Navigation) NavigationHistoryEntry {
158-
return self.entries.items[self.index];
160+
pub fn get_currentEntry(self: *Navigation) *NavigationHistoryEntry {
161+
return self.currentEntry();
159162
}
160163

161164
pub fn get_transition(_: *const Navigation) ?NavigationTransition {
@@ -180,7 +183,7 @@ pub fn _back(self: *Navigation, page: *Page) !NavigationReturn {
180183
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
181184
}
182185

183-
pub fn _entries(self: *const Navigation) []NavigationHistoryEntry {
186+
pub fn _entries(self: *const Navigation) []*NavigationHistoryEntry {
184187
return self.entries.items;
185188
}
186189

@@ -222,7 +225,7 @@ pub fn processNavigation(self: *Navigation, page: *Page) !void {
222225

223226
/// Pushes an entry into the Navigation stack WITHOUT actually navigating to it.
224227
/// For that, use `navigate`.
225-
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page) !NavigationHistoryEntry {
228+
pub fn pushEntry(self: *Navigation, _url: ?[]const u8, state: ?[]const u8, page: *Page) !*NavigationHistoryEntry {
226229
const arena = page.session.arena;
227230

228231
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:
231234
if (self.entries.items.len > self.index + 1) {
232235
self.entries.shrinkRetainingCapacity(self.index + 1);
233236
}
234-
self.index = self.entries.items.len;
237+
238+
const index = self.entries.items.len;
235239

236240
const id = self.next_entry_id;
237241
self.next_entry_id += 1;
238242

239243
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
240244

241-
const entry = NavigationHistoryEntry{
245+
const entry = try arena.create(NavigationHistoryEntry);
246+
entry.* = NavigationHistoryEntry{
242247
.id = id_str,
243248
.key = id_str,
244249
.url = url,
245250
.state = state,
246251
};
247252

253+
// we don't always have a current entry...
254+
const previous = if (self.entries.items.len > 0) self.currentEntry() else null;
248255
try self.entries.append(arena, entry);
256+
if (previous) |prev| {
257+
NavigationCurrentEntryChangeEvent.dispatch(prev, .push, page);
258+
}
259+
260+
self.index = index;
261+
249262
return entry;
250263
}
251264

@@ -337,7 +350,9 @@ pub fn _reload(self: *Navigation, _opts: ?ReloadOptions, page: *Page) !Navigatio
337350
const opts = _opts orelse ReloadOptions{};
338351
const entry = self.currentEntry();
339352
if (opts.state) |state| {
353+
const previous = entry;
340354
entry.state = state.toJson(arena) catch return error.DataClone;
355+
NavigationCurrentEntryChangeEvent.dispatch(previous, .reload, page);
341356
}
342357

343358
return self.navigate(entry.url, .reload, page);
@@ -365,9 +380,80 @@ pub const UpdateCurrentEntryOptions = struct {
365380

366381
pub fn _updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions, page: *Page) !void {
367382
const arena = page.session.arena;
383+
384+
const previous = self.currentEntry();
368385
self.currentEntry().state = options.state.toJson(arena) catch return error.DataClone;
386+
NavigationCurrentEntryChangeEvent.dispatch(previous, null, page);
369387
}
370388

389+
const Event = @import("../events/event.zig").Event;
390+
391+
pub const NavigationCurrentEntryChangeEvent = struct {
392+
pub const prototype = *Event;
393+
pub const union_make_copy = true;
394+
395+
pub const EventInit = struct {
396+
from: *NavigationHistoryEntry,
397+
navigation_type: ?NavigationType = null,
398+
};
399+
400+
proto: parser.Event,
401+
from: *NavigationHistoryEntry,
402+
navigation_type: ?NavigationType,
403+
404+
pub fn constructor(event_type: []const u8, opts: EventInit) !NavigationCurrentEntryChangeEvent {
405+
const event = try parser.eventCreate();
406+
defer parser.eventDestroy(event);
407+
try parser.eventInit(event, event_type, .{});
408+
parser.eventSetInternalType(event, .navigation_current_entry_change_event);
409+
410+
return .{
411+
.proto = event.*,
412+
.from = opts.from,
413+
.navigation_type = opts.navigation_type,
414+
};
415+
}
416+
417+
pub fn get_from(self: *NavigationCurrentEntryChangeEvent) *NavigationHistoryEntry {
418+
return self.from;
419+
}
420+
421+
pub fn get_navigationType(self: *const NavigationCurrentEntryChangeEvent) ?NavigationType {
422+
return self.navigation_type;
423+
}
424+
425+
pub fn dispatch(from: *NavigationHistoryEntry, typ: ?NavigationType, page: *Page) void {
426+
log.debug(.script_event, "dispatch event", .{
427+
.type = "currententrychange",
428+
.source = "navigation",
429+
});
430+
431+
var evt = NavigationCurrentEntryChangeEvent.constructor(
432+
"currententrychange",
433+
.{ .from = from, .navigation_type = typ },
434+
) catch |err| {
435+
log.err(.app, "event constructor error", .{
436+
.err = err,
437+
.type = "currententrychange",
438+
.source = "navigation",
439+
});
440+
441+
return;
442+
};
443+
444+
_ = parser.eventTargetDispatchEvent(
445+
@as(*parser.EventTarget, @ptrCast(&page.session.navigation)),
446+
&evt.proto,
447+
) catch |err| {
448+
log.err(.app, "dispatch event error", .{
449+
.err = err,
450+
.type = "currententrychange",
451+
.source = "navigation",
452+
});
453+
};
454+
}
455+
};
456+
371457
const testing = @import("../../testing.zig");
372458
test "Browser: Navigation" {
373459
try testing.htmlRunner("html/navigation.html");

src/browser/netsurf.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ pub const EventType = enum(u8) {
559559
message_event = 7,
560560
keyboard_event = 8,
561561
pop_state = 9,
562+
navigation_current_entry_change_event = 10,
562563
};
563564

564565
pub const MutationEvent = c.dom_mutation_event;

0 commit comments

Comments
 (0)