Skip to content

Commit b0786f0

Browse files
committed
add direct event handlers
1 parent 05199df commit b0786f0

File tree

9 files changed

+95
-33
lines changed

9 files changed

+95
-33
lines changed

src/browser/events/event.zig

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818

1919
const std = @import("std");
20+
const js = @import("../js/js.zig");
2021
const Allocator = std.mem.Allocator;
2122

2223
const log = @import("../../log.zig");
@@ -228,8 +229,6 @@ pub const EventHandler = struct {
228229
node: parser.EventNode,
229230
listener: *parser.EventListener,
230231

231-
const js = @import("../js/js.zig");
232-
233232
pub const Listener = union(enum) {
234233
function: js.Function,
235234
object: js.Object,
@@ -401,6 +400,40 @@ const SignalCallback = struct {
401400
}
402401
};
403402

403+
pub fn DirectEventHandler(
404+
comptime TargetT: type,
405+
target: *TargetT,
406+
event_type: []const u8,
407+
maybe_listener: ?EventHandler.Listener,
408+
cb: *?js.Function,
409+
page_arena: std.mem.Allocator,
410+
) !void {
411+
const event_target = parser.toEventTarget(TargetT, target);
412+
413+
// Check if we have a listener set.
414+
if (cb.*) |callback| {
415+
const listener = try parser.eventTargetHasListener(event_target, event_type, false, callback.id);
416+
std.debug.assert(listener != null);
417+
try parser.eventTargetRemoveEventListener(event_target, event_type, listener.?, false);
418+
}
419+
420+
if (maybe_listener) |listener| {
421+
switch (listener) {
422+
// If an object is given as listener, do nothing.
423+
.object => {},
424+
.function => |callback| {
425+
_ = try EventHandler.register(page_arena, event_target, event_type, listener, null) orelse unreachable;
426+
cb.* = callback;
427+
428+
return;
429+
},
430+
}
431+
}
432+
433+
// Just unset the listener.
434+
cb.* = null;
435+
}
436+
404437
const testing = @import("../../testing.zig");
405438
test "Browser: Event" {
406439
try testing.htmlRunner("events/event.html");

src/browser/html/History.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,5 +177,6 @@ pub const PopStateEvent = struct {
177177

178178
const testing = @import("../../testing.zig");
179179
test "Browser: HTML.History" {
180-
try testing.htmlRunner("html/history.html");
180+
try testing.htmlRunner("html/history/history.html");
181+
try testing.htmlRunner("html/history/history2.html");
181182
}

src/browser/html/Navigation.zig

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const URL = @import("../../url.zig").URL;
2323
const js = @import("../js/js.zig");
2424
const Page = @import("../page.zig").Page;
2525

26+
const DirectEventHandler = @import("../events/event.zig").DirectEventHandler;
2627
const EventTarget = @import("../dom/event_target.zig").EventTarget;
2728
const EventHandler = @import("../events/event.zig").EventHandler;
2829

@@ -62,6 +63,8 @@ index: usize = 0,
6263
entries: std.ArrayListUnmanaged(*NavigationHistoryEntry) = .empty,
6364
next_entry_id: usize = 0,
6465

66+
oncurrententrychange_callback: ?js.Function = null,
67+
6568
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationHistoryEntry
6669
const NavigationHistoryEntry = struct {
6770
pub const prototype = *EventTarget;
@@ -199,6 +202,16 @@ pub fn _forward(self: *Navigation, page: *Page) !NavigationReturn {
199202
return self.navigate(next_entry.url, .{ .traverse = new_index }, page);
200203
}
201204

205+
/// Returns `oncurrententrychange_callback`.
206+
pub fn get_oncurrententrychange(self: *const Navigation) ?js.Function {
207+
return self.oncurrententrychange_callback;
208+
}
209+
210+
/// Sets `oncurrententrychange_callback`.
211+
pub fn set_oncurrententrychange(self: *Navigation, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
212+
try DirectEventHandler(Navigation, self, "currententrychange", maybe_listener, &self.oncurrententrychange_callback, page.arena);
213+
}
214+
202215
// This is for after true navigation processing, where we need to ensure that our entries are up to date.
203216
// This is only really safe to run in the `pageDoneCallback` where we can guarantee that the URL and NavigationKind are correct.
204217
pub fn processNavigation(self: *Navigation, page: *Page) !void {
@@ -456,5 +469,5 @@ pub const NavigationCurrentEntryChangeEvent = struct {
456469

457470
const testing = @import("../../testing.zig");
458471
test "Browser: Navigation" {
459-
try testing.htmlRunner("html/navigation.html");
472+
try testing.htmlRunner("html/navigation/navigation.html");
460473
}

src/browser/html/window.zig

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const fetchFn = @import("../fetch/fetch.zig").fetch;
4343

4444
const storage = @import("../storage/storage.zig");
4545

46+
const DirectEventHandler = @import("../events/event.zig").DirectEventHandler;
47+
4648
// https://dom.spec.whatwg.org/#interface-window-extensions
4749
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#window
4850
pub const Window = struct {
@@ -69,6 +71,7 @@ pub const Window = struct {
6971
scroll_x: u32 = 0,
7072
scroll_y: u32 = 0,
7173
onload_callback: ?js.Function = null,
74+
onpopstate_callback: ?js.Function = null,
7275

7376
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
7477
var fbs = std.io.fixedBufferStream("");
@@ -110,31 +113,17 @@ pub const Window = struct {
110113

111114
/// Sets `onload_callback`.
112115
pub fn set_onload(self: *Window, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
113-
const event_target = parser.toEventTarget(Window, self);
114-
const event_type = "load";
115-
116-
// Check if we have a listener set.
117-
if (self.onload_callback) |callback| {
118-
const listener = try parser.eventTargetHasListener(event_target, event_type, false, callback.id);
119-
std.debug.assert(listener != null);
120-
try parser.eventTargetRemoveEventListener(event_target, event_type, listener.?, false);
121-
}
122-
123-
if (maybe_listener) |listener| {
124-
switch (listener) {
125-
// If an object is given as listener, do nothing.
126-
.object => {},
127-
.function => |callback| {
128-
_ = try EventHandler.register(page.arena, event_target, event_type, listener, null) orelse unreachable;
129-
self.onload_callback = callback;
116+
try DirectEventHandler(Window, self, "load", maybe_listener, &self.onload_callback, page.arena);
117+
}
130118

131-
return;
132-
},
133-
}
134-
}
119+
/// Returns `onpopstate_callback`.
120+
pub fn get_onpopstate(self: *const Window) ?js.Function {
121+
return self.onpopstate_callback;
122+
}
135123

136-
// Just unset the listener.
137-
self.onload_callback = null;
124+
/// Sets `onpopstate_callback`.
125+
pub fn set_onpopstate(self: *Window, maybe_listener: ?EventHandler.Listener, page: *Page) !void {
126+
try DirectEventHandler(Window, self, "popstate", maybe_listener, &self.onpopstate_callback, page.arena);
138127
}
139128

140129
pub fn get_window(self: *Window) *Window {

src/tests/html/history.html renamed to src/tests/html/history/history.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<script src="../testing.js"></script>
2+
<script src="../../testing.js"></script>
33

44
<script id=history>
55
testing.expectEqual('auto', history.scrollRestoration);
@@ -11,7 +11,7 @@
1111
testing.expectEqual('auto', history.scrollRestoration);
1212
testing.expectEqual(null, history.state)
1313

14-
history.pushState({ testInProgress: true }, null, 'http://127.0.0.1:9582/src/tests/html/history2.html');
14+
history.pushState({ testInProgress: true }, null, 'http://127.0.0.1:9582/src/tests/html/history/history_after_nav.html');
1515
testing.expectEqual({ testInProgress: true }, history.state);
1616

1717
history.pushState({ testInProgress: false }, null, 'http://127.0.0.1:9582/xhr/json');
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<script src="../../testing.js"></script>
3+
4+
<script id=history2>
5+
history.pushState(
6+
{"new": "field", testComplete: true },
7+
null,
8+
'http://127.0.0.1:9582/src/tests/html/history/history_after_nav.html'
9+
);
10+
11+
let popstateEventFired = false;
12+
let popstateEventState = null;
13+
14+
// uses the window event listener.
15+
window.onpopstate = (event) => {
16+
popstateEventFired = true;
17+
popstateEventState = event.state;
18+
};
19+
20+
testing.eventually(() => {
21+
testing.expectEqual(true, popstateEventFired);
22+
testing.expectEqual(true, popstateEventState.testComplete);
23+
})
24+
25+
history.back();
26+
</script>

src/tests/html/history2.html renamed to src/tests/html/history/history_after_nav.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<script src="../testing.js"></script>
2+
<script src="../../testing.js"></script>
33

44
<script id=history2>
55
testing.expectEqual(true, history.state && history.state.testInProgress);

src/tests/html/navigation.html renamed to src/tests/html/navigation/navigation.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<script src="../testing.js"></script>
2+
<script src="../../testing.js"></script>
33

44
<script id=navigation>
55
testing.expectEqual('object', typeof navigation);
@@ -12,7 +12,7 @@
1212
const currentIndex = navigation.currentEntry.index;
1313

1414
navigation.navigate(
15-
'http://127.0.0.1:9582/src/tests/html/navigation2.html',
15+
'http://127.0.0.1:9582/src/tests/html/navigation/navigation2.html',
1616
{ state: { currentIndex: currentIndex, navTestInProgress: true } }
1717
);
1818
</script>

src/tests/html/navigation2.html renamed to src/tests/html/navigation/navigation2.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<script src="../testing.js"></script>
2+
<script src="../../testing.js"></script>
33

44
<script id=navigation2>
55
const state = navigation.currentEntry.getState();

0 commit comments

Comments
 (0)