Skip to content

Commit 9f0f84b

Browse files
Merge pull request #658 from lightpanda-io/ready_state
Add document.readyState
2 parents 1ff422a + 2b6cf95 commit 9f0f84b

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

src/browser/env.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,16 @@ pub const SessionState = struct {
6161
// shorter-lived than the arena above, which
6262
// exists for the entire rendering of the page
6363
call_arena: std.mem.Allocator = undefined,
64+
65+
pub fn getNodeWrapper(self: *SessionState, comptime T: type, node: *parser.Node) !*T {
66+
if (parser.nodeGetEmbedderData(node)) |wrap| {
67+
return @alignCast(@ptrCast(wrap));
68+
}
69+
70+
const wrap = try self.arena.create(T);
71+
wrap.* = T{};
72+
73+
parser.nodeSetEmbedderData(node, wrap);
74+
return wrap;
75+
}
6476
};

src/browser/html/document.zig

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ pub const HTMLDocument = struct {
3636
pub const prototype = *Document;
3737
pub const subtype = .node;
3838

39+
ready_state: ReadyState = .loading,
40+
41+
const ReadyState = enum {
42+
loading,
43+
interactive,
44+
complete,
45+
};
46+
3947
// JS funcs
4048
// --------
4149

@@ -176,6 +184,11 @@ pub const HTMLDocument = struct {
176184
return state.window;
177185
}
178186

187+
pub fn get_readyState(node: *parser.DocumentHTML, state: *SessionState) ![]const u8 {
188+
const self = try state.getNodeWrapper(HTMLDocument, @ptrCast(node));
189+
return @tagName(self.ready_state);
190+
}
191+
179192
// noop legacy functions
180193
// https://html.spec.whatwg.org/#Document-partial
181194
pub fn _clear(_: *parser.DocumentHTML) void {}
@@ -212,6 +225,22 @@ pub const HTMLDocument = struct {
212225
pub fn set_bgColor(_: *parser.DocumentHTML, _: []const u8) []const u8 {
213226
return "";
214227
}
228+
229+
pub fn documentIsLoaded(html_doc: *parser.DocumentHTML, state: *SessionState) !void {
230+
const self = try state.getNodeWrapper(HTMLDocument, @ptrCast(html_doc));
231+
self.ready_state = .interactive;
232+
233+
const evt = try parser.eventCreate();
234+
defer parser.eventDestroy(evt);
235+
236+
try parser.eventInit(evt, "DOMContentLoaded", .{ .bubbles = true, .cancelable = true });
237+
_ = try parser.eventTargetDispatchEvent(parser.toEventTarget(parser.DocumentHTML, html_doc), evt);
238+
}
239+
240+
pub fn documentIsComplete(html_doc: *parser.DocumentHTML, state: *SessionState) !void {
241+
const self = try state.getNodeWrapper(HTMLDocument, @ptrCast(html_doc));
242+
self.ready_state = .complete;
243+
}
215244
};
216245

217246
// Tests
@@ -276,4 +305,18 @@ test "Browser.HTML.Document" {
276305
try runner.testCases(&.{
277306
.{ "document.defaultView.document == document", "true" },
278307
}, .{});
308+
309+
try runner.testCases(&.{
310+
.{ "document.readyState", "loading" },
311+
}, .{});
312+
313+
try HTMLDocument.documentIsLoaded(runner.state.document.?, &runner.state);
314+
try runner.testCases(&.{
315+
.{ "document.readyState", "interactive" },
316+
}, .{});
317+
318+
try HTMLDocument.documentIsComplete(runner.state.document.?, &runner.state);
319+
try runner.testCases(&.{
320+
.{ "document.readyState", "complete" },
321+
}, .{});
279322
}

src/browser/netsurf.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,14 @@ pub fn nodeGetPrefix(node: *Node) !?[]const u8 {
12741274
return strToData(s.?);
12751275
}
12761276

1277+
pub fn nodeGetEmbedderData(node: *Node) ?*anyopaque {
1278+
return c._dom_node_get_embedder_data(node);
1279+
}
1280+
1281+
pub fn nodeSetEmbedderData(node: *Node, data: *anyopaque) void {
1282+
c._dom_node_set_embedder_data(node, data);
1283+
}
1284+
12771285
// nodeToElement is an helper to convert a node to an element.
12781286
pub inline fn nodeToElement(node: *Node) *Element {
12791287
return @as(*Element, @ptrCast(node));

src/browser/page.zig

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const Window = @import("html/window.zig").Window;
3131
const Walker = @import("dom/walker.zig").WalkerDepthFirst;
3232
const Env = @import("env.zig").Env;
3333
const Loop = @import("../runtime/loop.zig").Loop;
34+
const HTMLDocument = @import("html/document.zig").HTMLDocument;
3435

3536
const URL = @import("../url.zig").URL;
3637

@@ -347,16 +348,11 @@ pub const Page = struct {
347348
self.evalScript(&s) catch |err| log.warn("evaljs: {any}", .{err});
348349
try parser.documentHTMLSetCurrentScript(html_doc, null);
349350
}
350-
351351
// dispatch DOMContentLoaded before the transition to "complete",
352352
// at the point where all subresources apart from async script elements
353353
// have loaded.
354354
// https://html.spec.whatwg.org/#reporting-document-loading-status
355-
const evt = try parser.eventCreate();
356-
defer parser.eventDestroy(evt);
357-
358-
try parser.eventInit(evt, "DOMContentLoaded", .{ .bubbles = true, .cancelable = true });
359-
_ = try parser.eventTargetDispatchEvent(parser.toEventTarget(parser.DocumentHTML, html_doc), evt);
355+
try HTMLDocument.documentIsLoaded(html_doc, &self.state);
360356

361357
// eval async scripts.
362358
for (async_scripts.items) |s| {
@@ -365,9 +361,7 @@ pub const Page = struct {
365361
try parser.documentHTMLSetCurrentScript(html_doc, null);
366362
}
367363

368-
// TODO wait for async scripts
369-
370-
// TODO set document.readyState to complete
364+
try HTMLDocument.documentIsComplete(html_doc, &self.state);
371365

372366
// dispatch window.load event
373367
const loadevt = try parser.eventCreate();

0 commit comments

Comments
 (0)