diff --git a/src/browser/webapi/HTMLDocument.zig b/src/browser/webapi/HTMLDocument.zig
index cca20e59..aad61378 100644
--- a/src/browser/webapi/HTMLDocument.zig
+++ b/src/browser/webapi/HTMLDocument.zig
@@ -74,30 +74,76 @@ pub fn getBody(self: *HTMLDocument) ?*Element.Html.Body {
}
pub fn getTitle(self: *HTMLDocument, page: *Page) ![]const u8 {
- const head = self.getHead() orelse return "";
- var it = head.asNode().childrenIterator();
- while (it.next()) |node| {
- if (node.is(Element.Html.Title)) |title| {
- var buf = std.Io.Writer.Allocating.init(page.call_arena);
- try title.asElement().getInnerText(&buf.writer);
- return buf.written();
+ // Search the entire document for the first
element
+ const root = self._proto.getDocumentElement() orelse return "";
+ const title_element = blk: {
+ var walker = @import("TreeWalker.zig").Full.init(root.asNode(), .{});
+ while (walker.next()) |node| {
+ if (node.is(Element.Html.Title)) |title| {
+ break :blk title;
+ }
+ }
+ return "";
+ };
+
+ var buf = std.Io.Writer.Allocating.init(page.call_arena);
+ try title_element.asNode().getTextContent(&buf.writer);
+ const text = buf.written();
+
+ if (text.len == 0) {
+ return "";
+ }
+
+ var started = false;
+ var in_whitespace = false;
+ var result: std.ArrayList(u8) = .empty;
+ try result.ensureTotalCapacity(page.call_arena, text.len);
+
+ for (text) |c| {
+ const is_ascii_ws = c == ' ' or c == '\t' or c == '\n' or c == '\r' or c == '\x0C';
+
+ if (is_ascii_ws) {
+ if (started) {
+ in_whitespace = true;
+ }
+ } else {
+ if (in_whitespace) {
+ result.appendAssumeCapacity(' ');
+ in_whitespace = false;
+ }
+ result.appendAssumeCapacity(c);
+ started = true;
}
}
- return "";
+
+ return result.items;
}
pub fn setTitle(self: *HTMLDocument, title: []const u8, page: *Page) !void {
const head = self.getHead() orelse return;
+
+ // Find existing title element in head
var it = head.asNode().childrenIterator();
while (it.next()) |node| {
if (node.is(Element.Html.Title)) |title_element| {
- return title_element.asElement().replaceChildren(&.{.{ .text = title }}, page);
+ // Replace children, but don't create text node for empty string
+ if (title.len == 0) {
+ return title_element.asElement().replaceChildren(&.{}, page);
+ } else {
+ return title_element.asElement().replaceChildren(&.{.{ .text = title }}, page);
+ }
}
}
+ // No title element found, create one
const title_node = try page.createElement(null, "title", null);
const title_element = title_node.as(Element);
- try title_element.replaceChildren(&.{.{ .text = title }}, page);
+
+ // Only add text if non-empty
+ if (title.len > 0) {
+ try title_element.replaceChildren(&.{.{ .text = title }}, page);
+ }
+
_ = try head.asNode().appendChild(title_node, page);
}