From 6d4966e83dc12387e3abc331ce51efebc8631be3 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Sat, 13 Dec 2025 14:05:05 +0100 Subject: [PATCH] implement document.write --- src/browser/dom/document.zig | 59 +++++++++++++++++++++++++++++++ src/browser/page.zig | 4 +++ src/tests/dom/document_write.html | 25 +++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/tests/dom/document_write.html diff --git a/src/browser/dom/document.zig b/src/browser/dom/document.zig index db675aea..7763cd3e 100644 --- a/src/browser/dom/document.zig +++ b/src/browser/dom/document.zig @@ -319,9 +319,68 @@ pub const Document = struct { log.debug(.web_api, "not implemented", .{ .feature = "Document hasFocus" }); return true; } + + pub fn _open(_: *parser.Document, page: *Page) !*parser.DocumentHTML { + if (page.open) { + return page.window.document; + } + + // This implementation is invalid. + // According to MDN, we should cleanup registered listeners. + // So we sould cleanup previous DOM memory. + // But this implementation is more simple for now. + const html_doc = try parser.documentHTMLParseFromStr(""); + try page.setDocument(html_doc); + page.open = true; + + return page.window.document; + } + + pub fn _close(_: *parser.Document, page: *Page) !void { + page.open = false; + } + + pub fn _write(self: *parser.Document, str: []const u8, page: *Page) !void { + if (!page.open) { + _ = try _open(self, page); + } + const document = parser.documentHTMLToDocument(page.window.document); + const fragment = try parser.documentParseFragmentFromStr(document, str); + const fragment_node = parser.documentFragmentToNode(fragment); + + const fragment_html = parser.nodeFirstChild(fragment_node) orelse return; + const fragment_head = parser.nodeFirstChild(fragment_html) orelse return; + const fragment_body = parser.nodeNextSibling(fragment_head) orelse return; + + const document_node = parser.documentToNode(document); + const document_html = parser.nodeFirstChild(document_node) orelse return; + const document_head = parser.nodeFirstChild(document_html) orelse return; + const document_body = parser.nodeNextSibling(document_head) orelse return; + + { + const children = try parser.nodeGetChildNodes(fragment_head); + // always index 0, because nodeAppendChild moves the node out of + // the nodeList and into the new tree + while (parser.nodeListItem(children, 0)) |child| { + _ = try parser.nodeAppendChild(document_head, child); + } + } + + { + const children = try parser.nodeGetChildNodes(fragment_body); + // always index 0, because nodeAppendChild moves the node out of + // the nodeList and into the new tree + while (parser.nodeListItem(children, 0)) |child| { + _ = try parser.nodeAppendChild(document_body, child); + } + } + } }; const testing = @import("../../testing.zig"); test "Browser: DOM.Document" { try testing.htmlRunner("dom/document.html"); } +test "Browser: DOM.Document.write" { + try testing.htmlRunner("dom/document_write.html"); +} diff --git a/src/browser/page.zig b/src/browser/page.zig index e33e1c7a..c3869803 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -103,6 +103,10 @@ pub const Page = struct { notified_network_idle: IdleNotification = .init, notified_network_almost_idle: IdleNotification = .init, + // Indicates if the page's document is open or close. + // Relates with https://developer.mozilla.org/en-US/docs/Web/API/Document/open + open: bool = false, + const Mode = union(enum) { pre: void, err: anyerror, diff --git a/src/tests/dom/document_write.html b/src/tests/dom/document_write.html new file mode 100644 index 00000000..7d004981 --- /dev/null +++ b/src/tests/dom/document_write.html @@ -0,0 +1,25 @@ + + + +
+ OK +

+ +

+

And

+
+ + +