From d7155e666268896a2569542f18dfa62700dd7237 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Fri, 4 Jul 2025 19:23:19 +0800 Subject: [PATCH] An empty anchor should return empty strings for its getters document.createElement('a').host or .href or .. should return an empty string. However, URL.constructor(document.createElement('a')) should fail. Because HTMLAnchorElement uses URL.constructor, we have the wrong behavior. This adds a guard for an empty anchor. This might not cover all of the cases which are valid for an anchor but invalid for a URL.constructor, but it's the most common. --- src/browser/html/elements.zig | 16 ++++++++++++++-- src/browser/url/url.zig | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/browser/html/elements.zig b/src/browser/html/elements.zig index 40a3b2b7..6136d2b7 100644 --- a/src/browser/html/elements.zig +++ b/src/browser/html/elements.zig @@ -271,8 +271,18 @@ pub const HTMLAnchorElement = struct { return try parser.nodeSetTextContent(parser.anchorToNode(self), v); } - inline fn url(self: *parser.Anchor, page: *Page) !URL { - return URL.constructor(.{ .element = @alignCast(@ptrCast(self)) }, null, page); // TODO inject base url + fn url(self: *parser.Anchor, page: *Page) !URL { + // Although the URL.constructor union accepts an .{.element = X}, we + // can't use this here because the behavior is different. + // new URL(document.createElement('a') + // should fail (a.href isn't a valid URL) + // But + // document.createElement('a').host + // should not fail, it should return an empty string + if (try parser.elementGetAttribute(@alignCast(@ptrCast(self)), "href")) |href| { + return URL.constructor(.{ .string = href }, null, page); // TODO inject base url + } + return .empty; } // TODO return a disposable string @@ -1559,6 +1569,8 @@ test "Browser.HTML.Element" { try runner.testCases(&.{ .{ "let a = document.createElement('a');", null }, + .{ "a.href", "" }, + .{ "a.host", "" }, .{ "a.href = 'about'", null }, .{ "a.href", "https://lightpanda.io/opensource-browser/about" }, }, .{}); diff --git a/src/browser/url/url.zig b/src/browser/url/url.zig index 6d31d3c5..1b6e2c86 100644 --- a/src/browser/url/url.zig +++ b/src/browser/url/url.zig @@ -54,6 +54,11 @@ pub const URL = struct { uri: std.Uri, search_params: URLSearchParams, + pub const empty = URL{ + .uri = .{ .scheme = "" }, + .search_params = .{}, + }; + const URLArg = union(enum) { url: *URL, element: *parser.ElementHTML,