diff --git a/src/browser/ImportMap.zig b/src/browser/ImportMap.zig new file mode 100644 index 00000000..3066b95d --- /dev/null +++ b/src/browser/ImportMap.zig @@ -0,0 +1,535 @@ +// Copyright (C) 2023-2026 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Parsed + + + + + diff --git a/src/browser/webapi/element/html/Base.zig b/src/browser/webapi/element/html/Base.zig index 0c2f2e8a..bb5616c8 100644 --- a/src/browser/webapi/element/html/Base.zig +++ b/src/browser/webapi/element/html/Base.zig @@ -1,4 +1,7 @@ const js = @import("../../../js/js.zig"); +const URL = @import("../../../URL.zig"); +const Frame = @import("../../../Frame.zig"); + const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -14,6 +17,44 @@ pub fn asNode(self: *Base) *Node { return self.asElement().asNode(); } +pub fn getHref(self: *Base, frame: *Frame) ![]const u8 { + const element = self.asElement(); + const href = element.getAttributeSafe(comptime .wrap("href")) orelse return ""; + if (href.len == 0) { + return ""; + } + return URL.resolve(frame.call_arena, frame.url, href, .{}); +} + +pub fn setHref(self: *Base, value: []const u8, frame: *Frame) !void { + const element = self.asElement(); + try element.setAttributeSafe(comptime .wrap("href"), .wrap(value), frame); + + // Per HTML spec, the document's base URL is the href of the FIRST + // element in tree order that has an href attribute — not necessarily this + // one. Re-derive from scratch so that setting href on a non-authoritative + // , or clearing href on the authoritative one, both work correctly. + const node = element.asNode(); + if (!node.isConnected()) { + return; + } + + const owner = node.ownerFrame(frame); + const first = (try owner.document.querySelector(comptime .wrap("base[href]"), owner)) orelse { + owner.base_url = null; + return; + }; + const href = first.getAttributeSafe(comptime .wrap("href")) orelse { + owner.base_url = null; + return; + }; + if (href.len == 0) { + owner.base_url = null; + return; + } + owner.base_url = try URL.resolve(owner.arena, owner.url, href, .{}); +} + pub const JsApi = struct { pub const bridge = js.Bridge(Base); @@ -22,4 +63,11 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const href = bridge.accessor(Base.getHref, Base.setHref, .{ .ce_reactions = true }); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.Base" { + try testing.htmlRunner("element/html/base.html", .{}); +}