diff --git a/src/SemanticTree.zig b/src/SemanticTree.zig index 63a78542c..8862c3e9f 100644 --- a/src/SemanticTree.zig +++ b/src/SemanticTree.zig @@ -201,7 +201,7 @@ fn walk( var name = try axn.getName(self.frame, self.arena, ctx.label_index); const has_explicit_label = if (node.is(Element)) |el| - el.getAttributeSafe(comptime .wrap("aria-label")) != null or el.getAttributeSafe(comptime .wrap("title")) != null + el.getAttributeInterned("aria-label") != null or el.getAttributeInterned("title") != null else false; @@ -681,12 +681,12 @@ pub fn getNodeDetails( if (node.is(Element)) |el| { tag_name = el.getTagNameLower(); is_disabled = el.isDisabled(); - id_attr = el.getAttributeSafe(comptime .wrap("id")); - class_attr = el.getAttributeSafe(comptime .wrap("class")); + id_attr = el.getId(); + class_attr = el.getClassName(); selector = try SelectorPath.init(arena, frame).build(el); - placeholder = el.getAttributeSafe(comptime .wrap("placeholder")); + placeholder = el.getAttributeInterned("placeholder"); - if (el.getAttributeSafe(comptime .wrap("href"))) |h| { + if (el.getAttributeInterned("href")) |h| { const URL = lp.URL; href = URL.resolve(arena, frame.base(), h, .{ .encoding = frame.charset }) catch h; } diff --git a/src/browser/EventManager.zig b/src/browser/EventManager.zig index 69ecfde8d..d4a19cbb4 100644 --- a/src/browser/EventManager.zig +++ b/src/browser/EventManager.zig @@ -792,7 +792,7 @@ const ActivationState = struct { fn findCheckedRadioInGroup(input: *Input, frame: *Frame) !?*Input { const elem = input.asElement(); - const name = elem.getAttributeSafe(comptime .wrap("name")) orelse return null; + const name = elem.getName() orelse return null; if (name.len == 0) { return null; } @@ -819,7 +819,7 @@ const ActivationState = struct { continue; } - const other_name = other_element.getAttributeSafe(comptime .wrap("name")) orelse continue; + const other_name = other_element.getName() orelse continue; if (!std.mem.eql(u8, name, other_name)) { continue; } diff --git a/src/browser/Frame.zig b/src/browser/Frame.zig index 7fe677d54..2408ff511 100644 --- a/src/browser/Frame.zig +++ b/src/browser/Frame.zig @@ -1951,7 +1951,7 @@ pub fn scriptAddedCallback(self: *Frame, comptime from_parser: bool, script: *El log.err(.frame, "frame.scriptAddedCallback", .{ .err = err, .url = self.url, - .src = script.asElement().getAttributeSafe(comptime .wrap("src")), + .src = script.asElement().getAttributeInterned("src"), .type = self._type, }); }; @@ -1977,7 +1977,7 @@ pub fn iframeAddedCallback(self: *Frame, iframe: *IFrame) !void { break :blk "about:srcdoc"; } - var src = iframe.asElement().getAttributeSafe(comptime .wrap("src")) orelse ""; + var src = iframe.asElement().getAttributeInterned("src") orelse ""; if (src.len == 0) { src = "about:blank"; } @@ -2277,7 +2277,7 @@ pub fn getElementByIdFromNode(self: *Frame, node: *Node, id: []const u8) ?*Eleme // exists, so scan it. var tw = TreeWalker.Full.Elements.init(node, .{}); while (tw.next()) |el| { - const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue; + const element_id = el.getId() orelse continue; if (std.mem.eql(u8, element_id, id)) { return el; } @@ -2747,7 +2747,7 @@ pub fn removeNode(self: *Frame, parent: *Node, child: *Node, opts: RemoveNodeOpt // the ID map and invoking disconnectedCallback for custom elements var tw = TreeWalker.Full.Elements.init(child, .{}); while (tw.next()) |el| { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { self.removeElementIdWithMaps(old_id_maps.?, id); } @@ -2790,7 +2790,7 @@ pub fn removeNode(self: *Frame, parent: *Node, child: *Node, opts: RemoveNodeOpt fn unregisterSubtreeIds(self: *Frame, node: *Node, id_maps: ElementIdMaps) void { var tw = TreeWalker.Full.Elements.init(node, .{}); while (tw.next()) |el| { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { self.removeElementIdWithMaps(id_maps, id); } } @@ -2961,7 +2961,7 @@ pub fn _insertNodeRelative(self: *Frame, comptime from_parser: bool, parent: *No // For main document parsing we know nodes are connected (fast path); // for fragment parsing (innerHTML) we check connectivity. if (child.isConnected() or child.isInShadowTree()) { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { try self.addElementId(parent, el, id); } try Element.Html.Custom.enqueueConnectedCallbackOnElement(true, el, self); @@ -3015,7 +3015,7 @@ pub fn _insertNodeRelative(self: *Frame, comptime from_parser: bool, parent: *No // id to the new parent... var tw = TreeWalker.Full.Elements.init(child, .{}); while (tw.next()) |el| { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { try self.addElementIdWithMaps(new_id_maps, el, id); } } @@ -3035,7 +3035,7 @@ pub fn _insertNodeRelative(self: *Frame, comptime from_parser: bool, parent: *No var tw = TreeWalker.Full.Elements.init(child, .{}); while (tw.next()) |el| { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { try self.addElementIdWithMaps(new_id_maps, el, id); } @@ -3533,7 +3533,7 @@ pub fn openBlankTarget(self: *Frame, element: *Element, url: []const u8) !*Frame } fn hasRelToken(element: *Element, token: []const u8) bool { - const rel = element.getAttributeSafe(comptime .wrap("rel")) orelse return false; + const rel = element.getAttributeInterned("rel") orelse return false; var it = std.mem.tokenizeAny(u8, rel, &std.ascii.whitespace); while (it.next()) |t| { if (std.ascii.eqlIgnoreCase(t, token)) { @@ -3547,7 +3547,7 @@ fn findFrameByName(frame: *Frame, name: []const u8) ?*Frame { for (frame.child_frames.items) |f| { if (f.iframe) |iframe| { if (iframe.asNode().isConnected()) { - const frame_name = iframe.asElement().getAttributeSafe(comptime .wrap("name")) orelse ""; + const frame_name = iframe.asElement().getName() orelse ""; if (std.mem.eql(u8, frame_name, name)) { return f; } @@ -3578,7 +3578,7 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For } if (submitter_) |submitter| { - if (submitter.getAttributeSafe(comptime .wrap("disabled")) != null) { + if (submitter.getAttributeInterned("disabled") != null) { return; } } @@ -3600,7 +3600,7 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For break :blk ft; } } - break :blk form_element.getAttributeSafe(comptime .wrap("target")); + break :blk form_element.getAttributeInterned("target"); }; const target: TargetFrame = blk: { @@ -3691,7 +3691,7 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For if (submit_button) |s| { if (s.getAttributeSafe(comptime .wrap("formmethod"))) |fm| break :blk fm; } - break :blk form_element.getAttributeSafe(comptime .wrap("method")); + break :blk form_element.getAttributeInterned("method"); }; const method = Element.Html.Form.normalizeMethod(method_attr, "get"); @@ -3747,7 +3747,7 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For if (submit_button) |s| { if (s.getAttributeSafe(comptime .wrap("formaction"))) |fa| break :blk fa; } - break :blk form_element.getAttributeSafe(comptime .wrap("action")) orelse self.url; + break :blk form_element.getAttributeInterned("action") orelse self.url; }; var opts = NavigateOpts{ diff --git a/src/browser/RenderTree.zig b/src/browser/RenderTree.zig index 451f318d8..d9f2981b8 100644 --- a/src/browser/RenderTree.zig +++ b/src/browser/RenderTree.zig @@ -141,7 +141,7 @@ fn display(self: *const RenderTree, el: *Element, is_slotted: bool) ?StyleManage return .other; }; if (dump_html.shouldStripElement(el, self.strip, self.frame)) return null; - if (!is_slotted and el.getAttributeSafe(comptime .wrap("slot")) != null) return null; + if (!is_slotted and el.getSlot() != null) return null; return d; } @@ -156,7 +156,7 @@ fn visibleDisplay(el: *Element, frame: *Frame) ?StyleManager.Display { if (d == .none) { return null; } - if (el.getAttributeSafe(comptime .wrap("aria-hidden"))) |v| { + if (el.getAttributeInterned("aria-hidden")) |v| { if (std.ascii.eqlIgnoreCase(v, "true")) return null; } return d; diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index 10410d967..524460f40 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -107,7 +107,7 @@ const CorsSettings = struct { // in order to properly set the request_mode and credentials_mode. fn corsSettings(element: ?*Element, is_module: bool) CorsSettings { const mode: enum { no_cors, anonymous, use_credentials } = blk: { - const co = if (element) |e| e.getAttributeSafe(comptime .wrap("crossorigin")) else null; + const co = if (element) |e| e.getAttributeInterned("crossorigin") else null; const value = co orelse { // Missing-value default: No CORS for classic scripts, Anonymous for modules. @@ -229,7 +229,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e } const kind: Script.Extra.FrameExtra.Kind = blk: { - const script_type = element.getAttributeSafe(comptime .wrap("type")) orelse break :blk .javascript; + const script_type = element.getAttributeInterned("type") orelse break :blk .javascript; if (script_type.len == 0) { break :blk .javascript; } @@ -255,7 +255,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e const frame = self.frame; const base_url = frame.base(); - const src = element.getAttributeSafe(comptime .wrap("src")) orelse { + const src = element.getAttributeInterned("src") orelse { return self.addInlineScript(script_element, kind); }; @@ -274,12 +274,12 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e script_element._executed = true; const mode: Script.Extra.FrameExtra.Mode = blk: { - if (element.getAttributeSafe(comptime .wrap("async")) != null) { + if (element.getAttributeInterned("async") != null) { break :blk .async; } // Check for defer or module (before checking dynamic script default) - if (kind == .module or element.getAttributeSafe(comptime .wrap("defer")) != null) { + if (kind == .module or element.getAttributeInterned("defer") != null) { break :blk .@"defer"; } diff --git a/src/browser/SelectorPath.zig b/src/browser/SelectorPath.zig index 0b2cb8515..406b1f9ec 100644 --- a/src/browser/SelectorPath.zig +++ b/src/browser/SelectorPath.zig @@ -90,7 +90,7 @@ fn buildStrictPath(self: SelectorPath, target: *Element) !?[]const u8 { /// else its tag qualified by stable attributes and — when that still matches a /// sibling — a `:has()` distinguisher (preferred) or positional `:nth-of-type`. fn localSegment(self: SelectorPath, el: *Element) ![]const u8 { - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { if (id.len != 0) { const id_sel = try std.fmt.allocPrint(self.arena, "#{s}", .{try CSS.escape(id, self.frame)}); if (self.isFirstMatch(el, id_sel)) return id_sel; diff --git a/src/browser/StyleManager.zig b/src/browser/StyleManager.zig index 4dc3a161c..e25a4afbc 100644 --- a/src/browser/StyleManager.zig +++ b/src/browser/StyleManager.zig @@ -638,7 +638,7 @@ fn matchesUaDisplayNoneRule(el: *Element) bool { const tag = el.getTag(); if (tag.isHiddenByUaStylesheet()) return true; - if (el.hasAttributeSafe(comptime .wrap("hidden"))) return true; + if (el.hasAttributeInterned("hidden")) return true; // input[type="hidden" i] { display: none !important } // _input_type is parsed case-insensitively at attribute-set time. @@ -810,13 +810,13 @@ fn resolve(self: *StyleManager, el: *Element, options: CheckVisibilityOptions, c .frame = self.frame, }; - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { if (self.id_rules.get(id)) |rules| { ctx.checkRules(&rules); } } - if (el.getAttributeSafe(comptime .wrap("class"))) |class_attr| { + if (el.getClassName()) |class_attr| { var it = std.mem.tokenizeAny(u8, class_attr, &std.ascii.whitespace); while (it.next()) |class| { if (self.class_rules.get(class)) |rules| { @@ -916,13 +916,13 @@ fn elementHasPointerEventsNone(self: *StyleManager, el: *Element) bool { } }.check; - if (el.getAttributeSafe(comptime .wrap("id"))) |id| { + if (el.getId()) |id| { if (self.id_rules.get(id)) |rules| { checkRules(&rules, &result, &best_priority, el, frame); } } - if (el.getAttributeSafe(comptime .wrap("class"))) |class_attr| { + if (el.getClassName()) |class_attr| { var it = std.mem.tokenizeAny(u8, class_attr, &std.ascii.whitespace); while (it.next()) |class| { if (self.class_rules.get(class)) |rules| { @@ -1246,7 +1246,7 @@ fn inlineValue(el: *Element, property_name: String, comptime access: InlineAcces return styleValue(style, property_name); } // No JS-set style object and no style attribute -> nothing inline to read. - const attr = el.getAttributeSafe(comptime .wrap("style")) orelse return null; + const attr = el.getAttributeInterned("style") orelse return null; switch (access) { .materialize => { const style = el.getOrCreateStyle(frame) catch |err| { diff --git a/src/browser/dump.zig b/src/browser/dump.zig index f3382a537..3f547f1ed 100644 --- a/src/browser/dump.zig +++ b/src/browser/dump.zig @@ -141,7 +141,7 @@ fn _deep(node: *Node, opts: Opts, comptime force_slot: bool, writer: *std.Io.Wri // to render that "active" content, so when we're trying to render // it, we don't want to skip it. if ((comptime force_slot == false) and opts.shadow == .rendered) { - if (el.getAttributeSafe(comptime .wrap("slot"))) |_| { + if (el.getSlot()) |_| { // Skip - will be rendered by the Slot if it's the active container return; } @@ -378,7 +378,7 @@ pub fn shouldStripElement(el: *Node.Element, strip: Opts.Strip, frame: *Frame) b if (el.getAttributeSafe(comptime .wrap("as"))) |as| { if (std.mem.eql(u8, as, "script")) return true; } - if (el.getAttributeSafe(comptime .wrap("rel"))) |rel| { + if (el.getAttributeInterned("rel")) |rel| { if (std.mem.eql(u8, rel, "modulepreload") or std.mem.eql(u8, rel, "preload")) { if (el.getAttributeSafe(comptime .wrap("as"))) |as| { if (std.mem.eql(u8, as, "script")) return true; @@ -392,7 +392,7 @@ pub fn shouldStripElement(el: *Node.Element, strip: Opts.Strip, frame: *Frame) b if (std.mem.eql(u8, tag_name, "style")) return true; if (std.mem.eql(u8, tag_name, "link")) { - if (el.getAttributeSafe(comptime .wrap("rel"))) |rel| { + if (el.getAttributeInterned("rel")) |rel| { if (std.mem.eql(u8, rel, "stylesheet")) return true; } } diff --git a/src/browser/forms.zig b/src/browser/forms.zig index 858382bfd..e352f1427 100644 --- a/src/browser/forms.zig +++ b/src/browser/forms.zig @@ -169,7 +169,7 @@ pub fn collectForms( const fields = try collectFormFields(arena, form, frame); if (fields.len == 0) continue; - const action_attr = el.getAttributeSafe(comptime .wrap("action")); + const action_attr = el.getAttributeInterned("action"); const method_str = form.getMethod(); try forms.append(arena, .{ @@ -204,12 +204,12 @@ fn collectFormFields( try fields.append(arena, .{ .node = node, .tag_name = "input", - .name = el.getAttributeSafe(comptime .wrap("name")), + .name = el.getName(), .input_type = input._input_type.toString(), - .required = el.getAttributeSafe(comptime .wrap("required")) != null, + .required = el.getAttributeInterned("required") != null, .disabled = is_disabled, .value = input.getRedactedValue(), - .placeholder = el.getAttributeSafe(comptime .wrap("placeholder")), + .placeholder = el.getAttributeInterned("placeholder"), .options = &.{}, }); continue; @@ -219,12 +219,12 @@ fn collectFormFields( try fields.append(arena, .{ .node = node, .tag_name = "textarea", - .name = el.getAttributeSafe(comptime .wrap("name")), + .name = el.getName(), .input_type = null, - .required = el.getAttributeSafe(comptime .wrap("required")) != null, + .required = el.getAttributeInterned("required") != null, .disabled = is_disabled, .value = textarea.getValue(), - .placeholder = el.getAttributeSafe(comptime .wrap("placeholder")), + .placeholder = el.getAttributeInterned("placeholder"), .options = &.{}, }); continue; @@ -236,9 +236,9 @@ fn collectFormFields( try fields.append(arena, .{ .node = node, .tag_name = "select", - .name = el.getAttributeSafe(comptime .wrap("name")), + .name = el.getName(), .input_type = null, - .required = el.getAttributeSafe(comptime .wrap("required")) != null, + .required = el.getAttributeInterned("required") != null, .disabled = is_disabled, .value = select.getValue(frame), .placeholder = null, diff --git a/src/browser/frame/node_factory.zig b/src/browser/frame/node_factory.zig index 6d0e23737..bb0e2b3c5 100644 --- a/src/browser/frame/node_factory.zig +++ b/src/browser/frame/node_factory.zig @@ -411,7 +411,7 @@ pub fn createElementNS(frame: *Frame, namespace: Element.Namespace, name: []cons // If frames's base url is not already set, fill it with // the base tag. if (frame.base_url == null) { - if (n.as(Element).getAttributeSafe(comptime .wrap("href"))) |href| { + if (n.as(Element).getAttributeInterned("href")) |href| { frame.base_url = try URL.resolve(frame.arena, frame.url, href, .{}); } } diff --git a/src/browser/frame/user_input.zig b/src/browser/frame/user_input.zig index 58f75decb..70889bb85 100644 --- a/src/browser/frame/user_input.zig +++ b/src/browser/frame/user_input.zig @@ -331,7 +331,7 @@ fn hasClickActivationBehavior(node: *Node) bool { }; return switch (html_element._type) { - .anchor => element.getAttributeSafe(comptime .wrap("href")) != null, + .anchor => element.getAttributeInterned("href") != null, .input, .button, .select, .textarea, .label => true, .generic => html_element.subtype(Element.Html.Generic)._tag == .summary, else => false, @@ -340,7 +340,7 @@ fn hasClickActivationBehavior(node: *Node) bool { // SVG 2 links via `href`; xlink:href is the deprecated SVG 1.1 spelling. fn svgAnchorHref(element: *Element) ?[]const u8 { - return element.getAttributeSafe(comptime .wrap("href")) orelse element.getAttributeSafe(comptime .wrap("xlink:href")); + return element.getAttributeInterned("href") orelse element.getAttributeSafe(comptime .wrap("xlink:href")); } // Clicks on editable content are for editing: they don't activate the @@ -462,7 +462,7 @@ pub fn handleClick(frame: *Frame, target: *Node, event_target: *Node) !void { if (element.is(Element.Svg.Graphics.A) != null) { const href = svgAnchorHref(element) orelse return; - const target_name = element.getAttributeSafe(comptime .wrap("target")) orelse ""; + const target_name = element.getAttributeInterned("target") orelse ""; return followLink(frame, target, element, href, target_name); } @@ -471,7 +471,7 @@ pub fn handleClick(frame: *Frame, target: *Node, event_target: *Node) !void { switch (html_element._type) { .anchor => { const anchor = html_element.subtype(Element.Html.Anchor); - const href = element.getAttributeSafe(comptime .wrap("href")) orelse return; + const href = element.getAttributeInterned("href") orelse return; return followLink(frame, target, element, href, anchor.getTarget()); }, .input => { @@ -794,7 +794,7 @@ fn enterActivates(element: *Element) bool { return true; } if (html_element._type == .anchor) { - return element.getAttributeSafe(comptime .wrap("href")) != null; + return element.getAttributeInterned("href") != null; } if (element.is(Element.Html.Input)) |input| { return switch (input._input_type) { @@ -861,7 +861,7 @@ fn moveFocus(frame: *Frame, forward: bool) !void { } const candidate_tab_index = blk: { - if (candidate.getAttributeSafe(comptime .wrap("tabindex"))) |attr| { + if (candidate.getAttributeInterned("tabindex")) |attr| { if (Element.Html.parseInteger(attr)) |tab_index| { if (tab_index < 0) { continue; @@ -875,7 +875,7 @@ fn moveFocus(frame: *Frame, forward: bool) !void { const focusable = switch (candidate.getTag()) { .button, .select, .textarea, .iframe => true, .input => candidate.as(Element.Html.Input)._input_type != .hidden, - .anchor, .area => candidate.getAttributeSafe(comptime .wrap("href")) != null, + .anchor, .area => candidate.getAttributeInterned("href") != null, else => false, }; if (focusable == false) { diff --git a/src/browser/interactive.zig b/src/browser/interactive.zig index ba47dc493..af5748baf 100644 --- a/src/browser/interactive.zig +++ b/src/browser/interactive.zig @@ -242,16 +242,16 @@ fn walkInteractive( .listener_types = listener_types, .disabled = el.isDisabled(), .tab_index = html_el.getTabIndex(), - .id = el.getAttributeSafe(comptime .wrap("id")), - .class = el.getAttributeSafe(comptime .wrap("class")), - .href = if (el.getAttributeSafe(comptime .wrap("href"))) |href| + .id = el.getId(), + .class = el.getClassName(), + .href = if (el.getAttributeInterned("href")) |href| URL.resolve(arena, frame.base(), href, .{ .encoding = frame.charset }) catch href else null, .input_type = getInputType(el), .value = getInputValue(el), - .element_name = el.getAttributeSafe(comptime .wrap("name")), - .placeholder = el.getAttributeSafe(comptime .wrap("placeholder")), + .element_name = el.getName(), + .placeholder = el.getAttributeInterned("placeholder"), }); if (filter.max) |m| { @@ -306,7 +306,7 @@ pub fn classifyInteractivity( switch (el.getTag()) { .button, .summary, .details, .select, .textarea => return .native, .anchor, .area => { - if (el.getAttributeSafe(comptime .wrap("href")) != null) return .native; + if (el.getAttributeInterned("href") != null) return .native; }, .input => { if (el.is(Element.Html.Input)) |input| { @@ -334,7 +334,7 @@ pub fn classifyInteractivity( // Only count elements with an EXPLICIT tabindex attribute, // since getTabIndex() returns 0 for all interactive tags by default // (including anchors without href and hidden inputs). - if (el.getAttributeSafe(comptime .wrap("tabindex"))) |_| { + if (el.getAttributeInterned("tabindex")) |_| { if (html_el.getTabIndex() >= 0) return .focusable; } @@ -391,7 +391,7 @@ pub fn isContentRole(role: []const u8) bool { // ARIA `role` is a space-separated fallback list; the first token wins. pub fn explicitRole(el: *Element) ?[]const u8 { - const attr = el.getAttributeSafe(comptime .wrap("role")) orelse return null; + const attr = el.getAttributeInterned("role") orelse return null; var it = std.mem.tokenizeAny(u8, attr, " \t\n\r"); return it.next(); } diff --git a/src/browser/markdown.zig b/src/browser/markdown.zig index 017070b0f..9f6ba9e97 100644 --- a/src/browser/markdown.zig +++ b/src/browser/markdown.zig @@ -62,7 +62,7 @@ fn shouldAddSpacing(tag: Element.Tag) bool { } fn getAnchorLabel(el: *Element) ?[]const u8 { - return el.getAttributeSafe(comptime .wrap("aria-label")) orelse el.getAttributeSafe(comptime .wrap("title")); + return el.getAttributeInterned("aria-label") orelse el.getAttributeInterned("title"); } const Context = struct { @@ -230,11 +230,11 @@ const Context = struct { }, .img => { try self.writer.writeAll("!["); - if (el.getAttributeSafe(comptime .wrap("alt"))) |alt| { + if (el.getAttributeInterned("alt")) |alt| { try self.escape(alt); } try self.writer.writeAll("]("); - if (el.getAttributeSafe(comptime .wrap("src"))) |src| { + if (el.getAttributeInterned("src")) |src| { const frame = self.frame; const absolute_src = URL.resolve(frame.call_arena, frame.base(), src, .{ .encoding = frame.charset }) catch src; try self.writer.writeAll(absolute_src); @@ -247,7 +247,7 @@ const Context = struct { const frame = self.frame; const info = RenderTree.analyzeContent(el.asNode(), frame); const label = getAnchorLabel(el); - const href_raw = el.getAttributeSafe(comptime .wrap("href")); + const href_raw = el.getAttributeInterned("href"); if (!info.has_visible and label == null and href_raw == null) return; @@ -291,9 +291,9 @@ const Context = struct { return; }, .input => { - const type_attr = el.getAttributeSafe(comptime .wrap("type")) orelse return; + const type_attr = el.getAttributeInterned("type") orelse return; if (std.ascii.eqlIgnoreCase(type_attr, "checkbox")) { - const checked = el.getAttributeSafe(comptime .wrap("checked")) != null; + const checked = el.getAttributeInterned("checked") != null; try self.writer.writeAll(if (checked) "[x] " else "[ ] "); self.state.last_char_was_newline = false; } diff --git a/src/browser/screenshot.zig b/src/browser/screenshot.zig index 8ec0fd523..fc41efdb5 100644 --- a/src/browser/screenshot.zig +++ b/src/browser/screenshot.zig @@ -886,7 +886,7 @@ const Builder = struct { return; }, .img => { - const alt = el.getAttributeSafe(comptime .wrap("alt")) orelse return; + const alt = el.getAttributeInterned("alt") orelse return; if (isAllWhitespace(alt)) return; self.italic += 1; self.muted += 1; @@ -896,17 +896,17 @@ const Builder = struct { return; }, .input => { - const type_attr = el.getAttributeSafe(comptime .wrap("type")) orelse return; + const type_attr = el.getAttributeInterned("type") orelse return; if (std.ascii.eqlIgnoreCase(type_attr, "checkbox")) { - const checked = el.getAttributeSafe(comptime .wrap("checked")) != null; + const checked = el.getAttributeInterned("checked") != null; try self.appendWord(if (checked) "☑" else "☐"); self.pending_space = true; } return; }, .anchor => { - const href = el.getAttributeSafe(comptime .wrap("href")); - const label = el.getAttributeSafe(comptime .wrap("aria-label")) orelse el.getAttributeSafe(comptime .wrap("title")); + const href = el.getAttributeInterned("href"); + const label = el.getAttributeInterned("aria-label") orelse el.getAttributeInterned("title"); const info = RenderTree.analyzeContent(el.asNode(), self.frame); if (!info.has_visible and label == null) return; diff --git a/src/browser/structured_data.zig b/src/browser/structured_data.zig index 0090f81eb..af647a7ef 100644 --- a/src/browser/structured_data.zig +++ b/src/browser/structured_data.zig @@ -173,7 +173,7 @@ pub fn collectStructuredData( // Extract language from the root element. if (root.is(Element)) |root_el| { - if (root_el.getAttributeSafe(comptime .wrap("lang"))) |lang| { + if (root_el.getAttributeInterned("lang")) |lang| { try meta.append(arena, .{ .key = "language", .value = lang }); } } else { @@ -182,7 +182,7 @@ pub fn collectStructuredData( while (children.next()) |child| { const el = child.is(Element) orelse continue; if (el.getTag() == .html) { - if (el.getAttributeSafe(comptime .wrap("lang"))) |lang| { + if (el.getAttributeInterned("lang")) |lang| { try meta.append(arena, .{ .key = "language", .value = lang }); } break; @@ -368,7 +368,7 @@ fn collectJsonLd( arena: Allocator, json_ld: *std.ArrayList([]const u8), ) !void { - const type_attr = el.getAttributeSafe(comptime .wrap("type")) orelse return; + const type_attr = el.getAttributeInterned("type") orelse return; if (!std.ascii.eqlIgnoreCase(type_attr, "application/ld+json")) return; var buf: std.Io.Writer.Allocating = .init(arena); @@ -387,11 +387,11 @@ fn collectMeta( arena: Allocator, ) !void { // charset: (no content attribute needed). - if (el.getAttributeSafe(comptime .wrap("charset"))) |charset| { + if (el.getAttributeInterned("charset")) |charset| { try meta.append(arena, .{ .key = "charset", .value = charset }); } - const content = el.getAttributeSafe(comptime .wrap("content")) orelse return; + const content = el.getAttributeInterned("content") orelse return; // Open Graph: if (el.getAttributeSafe(comptime .wrap("property"))) |property| { @@ -412,7 +412,7 @@ fn collectMeta( } // Twitter Cards: - if (el.getAttributeSafe(comptime .wrap("name"))) |name| { + if (el.getName()) |name| { if (std.mem.startsWith(u8, name, "twitter:")) { try twitter_card.append(arena, .{ .key = name[8..], .value = content }); return; @@ -457,16 +457,16 @@ fn collectLink( links: *std.ArrayList(Property), alternate: *std.ArrayList(AlternateLink), ) !void { - const rel = el.getAttributeSafe(comptime .wrap("rel")) orelse return; - const raw_href = el.getAttributeSafe(comptime .wrap("href")) orelse return; + const rel = el.getAttributeInterned("rel") orelse return; + const raw_href = el.getAttributeInterned("href") orelse return; const href = URL.resolve(arena, frame.base(), raw_href, .{ .encoding = frame.charset }) catch raw_href; if (std.ascii.eqlIgnoreCase(rel, "alternate")) { try alternate.append(arena, .{ .href = href, .hreflang = el.getAttributeSafe(comptime .wrap("hreflang")), - .type = el.getAttributeSafe(comptime .wrap("type")), - .title = el.getAttributeSafe(comptime .wrap("title")), + .type = el.getAttributeInterned("type"), + .title = el.getAttributeInterned("title"), }); return; } diff --git a/src/browser/tests/element/attributes.html b/src/browser/tests/element/attributes.html index 0929a3d9e..68652e5ef 100644 --- a/src/browser/tests/element/attributes.html +++ b/src/browser/tests/element/attributes.html @@ -281,3 +281,41 @@ testing.expectEqual('', nsa.getAttribute('arr')); } + + diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index 0a6310de7..81385c763 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -454,7 +454,7 @@ pub fn getElementById(self: *Document, id: []const u8, frame: *Frame) ?*Element if (self._removed_ids.remove(id)) { var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{}); while (tw.next()) |el| { - const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue; + const element_id = el.getId() orelse continue; if (std.mem.eql(u8, element_id, id)) { // we ignore this error to keep getElementById easy to call // if it really failed, then we're out of memory and nothing's diff --git a/src/browser/webapi/DocumentFragment.zig b/src/browser/webapi/DocumentFragment.zig index 2c0f431ea..a726a0af4 100644 --- a/src/browser/webapi/DocumentFragment.zig +++ b/src/browser/webapi/DocumentFragment.zig @@ -76,7 +76,7 @@ pub fn getElementById(self: *DocumentFragment, id: []const u8) ?*Element { var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{}); while (tw.next()) |el| { - if (el.getAttributeSafe(comptime .wrap("id"))) |element_id| { + if (el.getId()) |element_id| { if (std.mem.eql(u8, element_id, id)) { return el; } diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index b2837d9bc..7788a08be 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -630,32 +630,43 @@ pub fn setHTMLUnsafe(self: *Element, html: []const u8, frame: *Frame) !void { return parent.setHTML(html, .{ .allow_declarative_shadow = true }, frame); } -pub fn getId(self: *const Element) []const u8 { - return self.getAttributeInterned("id") orelse ""; +pub fn getId(self: *const Element) ?[]const u8 { + return self.getAttributeInterned("id"); } pub fn setId(self: *Element, value: []const u8, frame: *Frame) !void { return self.setAttributeSafe(comptime .wrap("id"), .wrap(value), frame); } -pub fn getSlot(self: *const Element) []const u8 { - return self.getAttributeSafe(comptime .wrap("slot")) orelse ""; +// ** INTERN ONL **. Unlike other getters, e.g. getClassName, getSlot, this +// isn't a WebApi (some individual types DO have a name getter, but not Element). +// BUT, enough code internally needs this, that the helper exists. +pub fn getName(self: *const Element) ?[]const u8 { + return self.getAttributeInterned("name"); +} + +pub fn hasName(self: *const Element) bool { + return self.hasAttributeInterned("name"); +} + +pub fn getSlot(self: *const Element) ?[]const u8 { + return self.getAttributeSafe(comptime .wrap("slot")); } pub fn setSlot(self: *Element, value: []const u8, frame: *Frame) !void { return self.setAttributeSafe(comptime .wrap("slot"), .wrap(value), frame); } -pub fn getDir(self: *const Element) []const u8 { - return self.getAttributeInterned("dir") orelse ""; +pub fn getDir(self: *const Element) ?[]const u8 { + return self.getAttributeInterned("dir"); } pub fn setDir(self: *Element, value: []const u8, frame: *Frame) !void { return self.setAttributeSafe(comptime .wrap("dir"), .wrap(value), frame); } -pub fn getClassName(self: *const Element) []const u8 { - return self.getAttributeInterned("class") orelse ""; +pub fn getClassName(self: *const Element) ?[]const u8 { + return self.getAttributeInterned("class"); } pub fn setClassName(self: *Element, value: []const u8, frame: *Frame) !void { @@ -752,7 +763,7 @@ pub fn isDisabled(self: *const Element) bool { return false; } - if (self.getAttributeSafe(comptime .wrap("disabled")) != null) { + if (self.getAttributeInterned("disabled") != null) { return true; } @@ -764,7 +775,7 @@ pub fn isDisabled(self: *const Element) bool { if (self.asConstNode()._parent) |parent_node| { if (parent_node.is(Element)) |parent_el| { if (parent_el.getTag() == .optgroup and - parent_el.getAttributeSafe(comptime .wrap("disabled")) != null) + parent_el.getAttributeInterned("disabled") != null) { return true; } @@ -779,7 +790,7 @@ pub fn isDisabled(self: *const Element) bool { current = node._parent; const ancestor = node.is(Element) orelse continue; - if (ancestor.getTag() == .fieldset and ancestor.getAttributeSafe(comptime .wrap("disabled")) != null) { + if (ancestor.getTag() == .fieldset and ancestor.getAttributeInterned("disabled") != null) { var child = ancestor.firstElementChild(); while (child) |c| { if (c.getTag() == .legend) { @@ -2405,8 +2416,16 @@ pub const JsApi = struct { } pub const localName = bridge.accessor(Element.getLocalName, null, .{}); - pub const id = bridge.accessor(Element.getId, Element.setId, .{ .ce_reactions = true }); - pub const slot = bridge.accessor(Element.getSlot, Element.setSlot, .{ .ce_reactions = true }); + pub const id = bridge.accessor(struct { + fn wrap(self: *const Element) []const u8 { + return self.getId() orelse ""; + } + }.wrap, Element.setId, .{ .ce_reactions = true }); + pub const slot = bridge.accessor(struct { + fn wrap(self: *const Element) []const u8 { + return self.getSlot() orelse ""; + } + }.wrap, Element.setSlot, .{ .ce_reactions = true }); pub const role = ariaAccessor("role"); pub const ariaAtomic = ariaAccessor("aria-atomic"); pub const ariaAutoComplete = ariaAccessor("aria-autocomplete"); @@ -2451,8 +2470,16 @@ pub const JsApi = struct { pub const ariaValueMin = ariaAccessor("aria-valuemin"); pub const ariaValueNow = ariaAccessor("aria-valuenow"); pub const ariaValueText = ariaAccessor("aria-valuetext"); - pub const dir = bridge.accessor(Element.getDir, Element.setDir, .{ .ce_reactions = true }); - pub const className = bridge.accessor(Element.getClassName, Element.setClassName, .{ .ce_reactions = true }); + pub const dir = bridge.accessor(struct { + fn wrap(self: *const Element) []const u8 { + return self.getDir() orelse ""; + } + }.wrap, Element.setDir, .{ .ce_reactions = true }); + pub const className = bridge.accessor(struct { + fn wrap(self: *const Element) []const u8 { + return self.getClassName() orelse ""; + } + }.wrap, Element.setClassName, .{ .ce_reactions = true }); pub const classList = bridge.accessor(Element.getClassList, Element.setClassList, .{ .ce_reactions = true }); pub const part = bridge.accessor(Element.getPartList, null, .{}); pub const dataset = bridge.accessor(Element.getDataset, null, .{}); diff --git a/src/browser/webapi/ShadowRoot.zig b/src/browser/webapi/ShadowRoot.zig index 83f633b89..1ef07999f 100644 --- a/src/browser/webapi/ShadowRoot.zig +++ b/src/browser/webapi/ShadowRoot.zig @@ -162,7 +162,7 @@ pub fn getElementById(self: *ShadowRoot, id: []const u8, frame: *Frame) ?*Elemen // Do a tree walk to find another element with this ID var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{}); while (tw.next()) |el| { - const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue; + const element_id = el.getId() orelse continue; if (std.mem.eql(u8, element_id, id)) { // we ignore this error to keep getElementById easy to call // if it really failed, then we're out of memory and nothing's diff --git a/src/browser/webapi/collections/HTMLAllCollection.zig b/src/browser/webapi/collections/HTMLAllCollection.zig index 559553813..42c38999c 100644 --- a/src/browser/webapi/collections/HTMLAllCollection.zig +++ b/src/browser/webapi/collections/HTMLAllCollection.zig @@ -57,7 +57,7 @@ pub fn getByName(self: *HTMLAllCollection, name: []const u8, frame: *Frame) ?*El if (!isAllNamed(el)) { continue; } - if (el.getAttributeSafe(comptime .wrap("name"))) |attr_name| { + if (el.getName()) |attr_name| { if (std.mem.eql(u8, attr_name, name)) { return el; } diff --git a/src/browser/webapi/collections/HTMLCollection.zig b/src/browser/webapi/collections/HTMLCollection.zig index b203ae5b8..19840795f 100644 --- a/src/browser/webapi/collections/HTMLCollection.zig +++ b/src/browser/webapi/collections/HTMLCollection.zig @@ -291,13 +291,13 @@ pub const JsApi = struct { const len = self.length(frame); for (0..len) |i| { const element = self.getAtIndex(i, frame) orelse break; - if (element.getAttributeSafe(comptime .wrap("id"))) |id| { + if (element.getId()) |id| { if (id.len > 0 and !contains(names.items, id)) { try names.append(arena, id); } } if (element._namespace == .html) { - if (element.getAttributeSafe(comptime .wrap("name"))) |name| { + if (element.getName()) |name| { if (name.len > 0 and !contains(names.items, name)) { try names.append(arena, name); } diff --git a/src/browser/webapi/collections/HTMLFormControlsCollection.zig b/src/browser/webapi/collections/HTMLFormControlsCollection.zig index bf0c60677..a71070ad4 100644 --- a/src/browser/webapi/collections/HTMLFormControlsCollection.zig +++ b/src/browser/webapi/collections/HTMLFormControlsCollection.zig @@ -75,12 +75,12 @@ pub fn namedItem(self: *HTMLFormControlsCollection, name: []const u8, frame: *Fr var it = try self.iterator(); while (it.next()) |element| { const is_match = blk: { - if (element.getAttributeSafe(comptime .wrap("id"))) |id| { + if (element.getId()) |id| { if (std.mem.eql(u8, id, name)) { break :blk true; } } - if (element.getAttributeSafe(comptime .wrap("name"))) |elem_name| { + if (element.getName()) |elem_name| { if (std.mem.eql(u8, elem_name, name)) { break :blk true; } diff --git a/src/browser/webapi/collections/RadioNodeList.zig b/src/browser/webapi/collections/RadioNodeList.zig index 1a202721f..cfcfb6b1e 100644 --- a/src/browser/webapi/collections/RadioNodeList.zig +++ b/src/browser/webapi/collections/RadioNodeList.zig @@ -73,7 +73,7 @@ pub fn getValue(self: *RadioNodeList) ![]const u8 { if (!input.getChecked()) { continue; } - return element.getAttributeSafe(comptime .wrap("value")) orelse "on"; + return element.getAttributeInterned("value") orelse "on"; } return ""; } @@ -86,7 +86,7 @@ pub fn setValue(self: *RadioNodeList, value: []const u8, frame: *Frame) !void { continue; } - const input_value = element.getAttributeSafe(comptime .wrap("value")); + const input_value = element.getAttributeInterned("value"); const matches_value = blk: { if (std.mem.eql(u8, value, "on")) { break :blk input_value == null or (input_value != null and std.mem.eql(u8, input_value.?, "on")); @@ -103,12 +103,12 @@ pub fn setValue(self: *RadioNodeList, value: []const u8, frame: *Frame) !void { } fn matches(self: *const RadioNodeList, element: *Element) bool { - if (element.getAttributeSafe(comptime .wrap("id"))) |id| { + if (element.getId()) |id| { if (std.mem.eql(u8, id, self._name)) { return true; } } - if (element.getAttributeSafe(comptime .wrap("name"))) |elem_name| { + if (element.getName()) |elem_name| { if (std.mem.eql(u8, elem_name, self._name)) { return true; } diff --git a/src/browser/webapi/collections/node_live.zig b/src/browser/webapi/collections/node_live.zig index 1a649787b..2c0619fb9 100644 --- a/src/browser/webapi/collections/node_live.zig +++ b/src/browser/webapi/collections/node_live.zig @@ -239,7 +239,7 @@ pub fn NodeLive(comptime mode: Mode) type { if (element._namespace != .html) { continue; } - const element_name = element.getAttributeSafe(comptime .wrap("name")) orelse continue; + const element_name = element.getName() orelse continue; if (std.mem.eql(u8, element_name, name)) { return element; } @@ -321,7 +321,7 @@ pub fn NodeLive(comptime mode: Mode) type { const el = node.is(Element) orelse return false; // getElementsByName only considers HTML elements. if (el._namespace != .html) return false; - const name_attr = el.getAttributeInterned("name") orelse return false; + const name_attr = el.getName() orelse return false; return std.mem.eql(u8, name_attr, self._filter); }, .all_elements => return node._type == .element, @@ -361,14 +361,14 @@ pub fn NodeLive(comptime mode: Mode) type { const el = node.is(Element) orelse return false; const Anchor = Element.Html.Anchor; if (el.is(Anchor) == null) return false; - return el.hasAttributeSafe(comptime .wrap("href")); + return el.hasAttributeInterned("href"); }, .anchors => { // Anchors are elements with name attribute const el = node.is(Element) orelse return false; const Anchor = Element.Html.Anchor; if (el.is(Anchor) == null) return false; - return el.hasAttributeSafe(comptime .wrap("name")); + return el.hasName(); }, .form => { const el = node.is(Element) orelse return false; diff --git a/src/browser/webapi/css/CSSStyleDeclaration.zig b/src/browser/webapi/css/CSSStyleDeclaration.zig index b40b3635d..5ebc10a13 100644 --- a/src/browser/webapi/css/CSSStyleDeclaration.zig +++ b/src/browser/webapi/css/CSSStyleDeclaration.zig @@ -44,7 +44,7 @@ pub fn parseInlineStyle(self: *CSSStyleDeclaration, frame: *Frame) !void { return; } const el = self._element orelse return; - const attr_value = el.getAttributeSafe(comptime .wrap("style")) orelse return; + const attr_value = el.getAttributeInterned("style") orelse return; try self.applyDeclarations(attr_value, frame); } diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index cc7c8863e..5ec8cfc51 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -441,7 +441,7 @@ pub fn click(self: *HtmlElement, frame: *Frame) !void { // TODO: Per spec, hidden is a tristate: true | false | "until-found". // We only support boolean for now; "until-found" would need bridge union support. pub fn getHidden(self: *HtmlElement) bool { - return self.asElement().getAttributeSafe(comptime .wrap("hidden")) != null; + return self.asElement().getAttributeInterned("hidden") != null; } pub fn setHidden(self: *HtmlElement, hidden: bool, frame: *Frame) !void { @@ -479,7 +479,7 @@ pub fn setTranslate(self: *HtmlElement, translate: bool, frame: *Frame) !void { // auto state, which defaults to true only for and with an href. // https://html.spec.whatwg.org/multipage/dnd.html#the-draggable-attribute pub fn getDraggable(self: *HtmlElement) bool { - if (self.asElement().getAttributeSafe(comptime .wrap("draggable"))) |value| { + if (self.asElement().getAttributeInterned("draggable")) |value| { if (std.ascii.eqlIgnoreCase(value, "true")) { return true; } @@ -489,7 +489,7 @@ pub fn getDraggable(self: *HtmlElement) bool { } return switch (self._type) { .img => true, - .anchor => self.asElement().getAttributeSafe(comptime .wrap("href")) != null, + .anchor => self.asElement().getAttributeInterned("href") != null, else => false, }; } @@ -536,7 +536,7 @@ pub fn togglePopover(self: *HtmlElement, force: ?bool, frame: *Frame) !bool { } pub fn getTabIndex(self: *HtmlElement) i32 { - if (self.asElement().getAttributeSafe(comptime .wrap("tabindex"))) |attr| { + if (self.asElement().getAttributeInterned("tabindex")) |attr| { if (parseInteger(attr)) |tab_index| { return tab_index; } @@ -555,7 +555,7 @@ pub fn setTabIndex(self: *HtmlElement, value: i32, frame: *Frame) !void { } pub fn getDir(self: *HtmlElement) []const u8 { - return reflection.enumeratedValue(self.asElement().getAttributeSafe(comptime .wrap("dir")), &.{ "ltr", "rtl", "auto" }, "", "").?; + return reflection.enumeratedValue(self.asElement().getDir(), &.{ "ltr", "rtl", "auto" }, "", "").?; } pub fn getAccessKey(self: *HtmlElement) []const u8 { @@ -567,7 +567,7 @@ pub fn setAccessKey(self: *HtmlElement, value: []const u8, frame: *Frame) !void } pub fn getAutofocus(self: *HtmlElement) bool { - return self.asElement().getAttributeSafe(comptime .wrap("autofocus")) != null; + return self.asElement().getAttributeInterned("autofocus") != null; } pub fn setAutofocus(self: *HtmlElement, autofocus: bool, frame: *Frame) !void { @@ -587,7 +587,7 @@ pub fn setNonce(self: *HtmlElement, value: []const u8, frame: *Frame) !void { } pub fn getLang(self: *HtmlElement) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("lang")) orelse ""; + return self.asElement().getAttributeInterned("lang") orelse ""; } pub fn setLang(self: *HtmlElement, value: []const u8, frame: *Frame) !void { @@ -595,7 +595,7 @@ pub fn setLang(self: *HtmlElement, value: []const u8, frame: *Frame) !void { } pub fn getTitle(self: *HtmlElement) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("title")) orelse ""; + return self.asElement().getAttributeInterned("title") orelse ""; } pub fn setTitle(self: *HtmlElement, value: []const u8, frame: *Frame) !void { diff --git a/src/browser/webapi/element/html/Anchor.zig b/src/browser/webapi/element/html/Anchor.zig index da93cc409..b15196b24 100644 --- a/src/browser/webapi/element/html/Anchor.zig +++ b/src/browser/webapi/element/html/Anchor.zig @@ -44,7 +44,7 @@ pub fn asNode(self: *Anchor) *Node { } pub fn getHref(self: *Anchor, frame: *Frame) ![]const u8 { - const href = self.asElement().getAttributeSafe(comptime .wrap("href")) orelse return ""; + const href = self.asElement().getAttributeInterned("href") orelse return ""; if (href.len == 0) { return ""; } @@ -197,7 +197,7 @@ pub fn setText(self: *Anchor, value: []const u8, frame: *Frame) !void { } fn getResolvedHref(self: *Anchor, frame: *Frame) !?[:0]const u8 { - const href = self.asElement().getAttributeSafe(comptime .wrap("href")) orelse return null; + const href = self.asElement().getAttributeInterned("href") orelse return null; if (href.len == 0) { return null; } @@ -210,7 +210,7 @@ fn getResolvedHref(self: *Anchor, frame: *Frame) !?[:0]const u8 { } pub fn getTarget(self: *Anchor) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("target")) orelse ""; + return self.asElement().getAttributeInterned("target") orelse ""; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Area.zig b/src/browser/webapi/element/html/Area.zig index 679d937b6..bf7362149 100644 --- a/src/browser/webapi/element/html/Area.zig +++ b/src/browser/webapi/element/html/Area.zig @@ -44,7 +44,7 @@ pub fn asNode(self: *Area) *Node { } pub fn getHref(self: *Area, frame: *Frame) ![]const u8 { - const href = self.asElement().getAttributeSafe(comptime .wrap("href")) orelse return ""; + const href = self.asElement().getAttributeInterned("href") orelse return ""; if (href.len == 0) { return ""; } @@ -198,7 +198,7 @@ pub fn getRelList(self: *Area, frame: *Frame) !?*DOMTokenList { } fn getResolvedHref(self: *Area, frame: *Frame) !?[:0]const u8 { - const href = self.asElement().getAttributeSafe(comptime .wrap("href")) orelse return null; + const href = self.asElement().getAttributeInterned("href") orelse return null; if (href.len == 0) { return null; } diff --git a/src/browser/webapi/element/html/Base.zig b/src/browser/webapi/element/html/Base.zig index 1870c30d5..8a2d89725 100644 --- a/src/browser/webapi/element/html/Base.zig +++ b/src/browser/webapi/element/html/Base.zig @@ -24,7 +24,7 @@ pub fn asNode(self: *Base) *Node { pub fn getHref(self: *Base, frame: *Frame) ![]const u8 { const element = self.asElement(); - const href = element.getAttributeSafe(comptime .wrap("href")) orelse return ""; + const href = element.getAttributeInterned("href") orelse return ""; if (href.len == 0) { return ""; } @@ -50,7 +50,7 @@ pub fn setHref(self: *Base, value: []const u8, frame: *Frame) !void { owner.base_url = null; return; }; - const href = first.getAttributeSafe(comptime .wrap("href")) orelse { + const href = first.getAttributeInterned("href") orelse { owner.base_url = null; return; }; diff --git a/src/browser/webapi/element/html/Button.zig b/src/browser/webapi/element/html/Button.zig index 994420565..dda3e3632 100644 --- a/src/browser/webapi/element/html/Button.zig +++ b/src/browser/webapi/element/html/Button.zig @@ -52,7 +52,7 @@ pub fn asNode(self: *Button) *Node { } pub fn getType(self: *const Button) []const u8 { - return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "submit"; + return self.asConstElement().getAttributeInterned("type") orelse "submit"; } pub fn getForm(self: *Button, frame: *Frame) ?*Form { @@ -208,11 +208,11 @@ pub fn setPopoverTargetAction(self: *Button, value: []const u8, frame: *Frame) ! } pub fn getDisabled(self: *const Button) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null; + return self.asConstElement().getAttributeInterned("disabled") != null; } pub fn getValue(self: *const Button) []const u8 { - return self.asConstElement().getAttributeSafe(comptime .wrap("value")) orelse ""; + return self.asConstElement().getAttributeInterned("value") orelse ""; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Canvas.zig b/src/browser/webapi/element/html/Canvas.zig index fb92bfcd8..6be6588e7 100644 --- a/src/browser/webapi/element/html/Canvas.zig +++ b/src/browser/webapi/element/html/Canvas.zig @@ -54,12 +54,12 @@ pub fn asNode(self: *Canvas) *Node { } pub fn getWidth(self: *const Canvas) u32 { - const attr = self.asConstElement().getAttributeSafe(comptime .wrap("width")) orelse return 300; + const attr = self.asConstElement().getAttributeInterned("width") orelse return 300; return std.fmt.parseUnsigned(u32, attr, 10) catch 300; } pub fn getHeight(self: *const Canvas) u32 { - const attr = self.asConstElement().getAttributeSafe(comptime .wrap("height")) orelse return 150; + const attr = self.asConstElement().getAttributeInterned("height") orelse return 150; return std.fmt.parseUnsigned(u32, attr, 10) catch 150; } diff --git a/src/browser/webapi/element/html/Embed.zig b/src/browser/webapi/element/html/Embed.zig index 04981bcb4..4971d2ebd 100644 --- a/src/browser/webapi/element/html/Embed.zig +++ b/src/browser/webapi/element/html/Embed.zig @@ -42,7 +42,7 @@ pub fn asNode(self: *Embed) *Node { pub fn getSrc(self: *const Embed, frame: *Frame) ![]const u8 { const element = self.asConstElement(); - const src = element.getAttributeSafe(comptime .wrap("src")) orelse return ""; + const src = element.getAttributeInterned("src") orelse return ""; if (src.len == 0) { return ""; } diff --git a/src/browser/webapi/element/html/Form.zig b/src/browser/webapi/element/html/Form.zig index 81b7652dc..def859a8e 100644 --- a/src/browser/webapi/element/html/Form.zig +++ b/src/browser/webapi/element/html/Form.zig @@ -83,7 +83,7 @@ pub fn normalizeEnctype(attr: ?[]const u8, missing_default: []const u8) []const } pub fn getMethod(self: *const Form) []const u8 { - return normalizeMethod(self.asConstElement().getAttributeSafe(comptime .wrap("method")), "get"); + return normalizeMethod(self.asConstElement().getAttributeInterned("method"), "get"); } pub fn setMethod(self: *Form, method: []const u8, frame: *Frame) !void { @@ -101,7 +101,7 @@ pub fn getElements(self: *Form, frame: *Frame) !*collections.HTMLFormControlsCol } pub fn iterator(self: *Form, frame: *Frame) collections.NodeLive(.form) { - const form_id = self.asElement().getAttributeSafe(comptime .wrap("id")); + const form_id = self.asElement().getId(); const root = if (form_id != null) self.asNode().getRootNode(.{}) // Has ID: walk entire document to find form=ID controls else @@ -113,7 +113,7 @@ pub fn iterator(self: *Form, frame: *Frame) collections.NodeLive(.form) { pub fn getAction(self: *Form, frame: *Frame) ![]const u8 { const element = self.asElement(); const owner_url = element.ownerFrame(frame).url; - const action = element.getAttributeSafe(comptime .wrap("action")) orelse return owner_url; + const action = element.getAttributeInterned("action") orelse return owner_url; if (action.len == 0) { return owner_url; } @@ -218,7 +218,7 @@ fn checkElementValidity(element: *Element, frame: *Frame) !bool { } pub fn getNoValidate(self: *const Form) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("novalidate")) != null; + return self.asConstElement().getAttributeInterned("novalidate") != null; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/IFrame.zig b/src/browser/webapi/element/html/IFrame.zig index c3797f107..cf0f37675 100644 --- a/src/browser/webapi/element/html/IFrame.zig +++ b/src/browser/webapi/element/html/IFrame.zig @@ -59,7 +59,7 @@ pub fn getContentDocument(self: *const IFrame) ?*Document { // loading=lazy iframes are still but don't delay the page's "load" event pub fn isLazyLoading(self: *IFrame) bool { - const loading = self.asElement().getAttributeSafe(comptime .wrap("loading")) orelse return false; + const loading = self.asElement().getAttributeInterned("loading") orelse return false; return std.ascii.eqlIgnoreCase(loading, "lazy"); } @@ -71,7 +71,7 @@ pub fn getSrc(self: *IFrame, frame: *Frame) ![]const u8 { pub fn setSrc(self: *IFrame, src: []const u8, frame: *Frame) !void { const element = self.asElement(); try element.setAttributeSafe(comptime .wrap("src"), .wrap(src), frame); - self._src = element.getAttributeSafe(comptime .wrap("src")) orelse unreachable; + self._src = element.getAttributeInterned("src") orelse unreachable; if (element.asNode().isConnected()) { // unlike script, an iframe is reloaded every time the src is set // even if it's set to the same URL. @@ -134,7 +134,7 @@ pub const Build = struct { pub fn complete(node: *Node, _: *Frame) !void { const self = node.as(IFrame); const element = self.asElement(); - self._src = element.getAttributeSafe(comptime .wrap("src")) orelse ""; + self._src = element.getAttributeInterned("src") orelse ""; } pub fn attributeChange(element: *Element, name: String, _: String, frame: *Frame) !void { diff --git a/src/browser/webapi/element/html/Image.zig b/src/browser/webapi/element/html/Image.zig index c27453a56..bda840912 100644 --- a/src/browser/webapi/element/html/Image.zig +++ b/src/browser/webapi/element/html/Image.zig @@ -47,7 +47,7 @@ pub fn asNode(self: *Image) *Node { pub fn getSrc(self: *const Image, frame: *Frame) ![]const u8 { const element = self.asConstElement(); - const src = element.getAttributeSafe(comptime .wrap("src")) orelse return ""; + const src = element.getAttributeInterned("src") orelse return ""; if (src.len == 0) { return ""; } @@ -59,7 +59,7 @@ pub fn setSrc(self: *Image, value: []const u8, frame: *Frame) !void { } pub fn getLoading(self: *const Image) []const u8 { - return self.asConstElement().getAttributeSafe(comptime .wrap("loading")) orelse "eager"; + return self.asConstElement().getAttributeInterned("loading") orelse "eager"; } pub fn setLoading(self: *Image, value: []const u8, frame: *Frame) !void { @@ -102,7 +102,7 @@ pub fn imageAddedCallback(self: *Image, frame: *Frame) !void { const element = self.asElement(); // Exit if src not set. - const src = element.getAttributeSafe(comptime .wrap("src")) orelse return; + const src = element.getAttributeInterned("src") orelse return; if (src.len == 0) return; // If image loading not desired, we just do fake "load" event. diff --git a/src/browser/webapi/element/html/Input.zig b/src/browser/webapi/element/html/Input.zig index a01008c18..2f605324d 100644 --- a/src/browser/webapi/element/html/Input.zig +++ b/src/browser/webapi/element/html/Input.zig @@ -501,7 +501,7 @@ const RadioGroupIterator = struct { const other_element = node.is(Element) orelse continue; const other_input = other_element.is(Input) orelse continue; if (other_input._input_type != .radio) continue; - const other_name = other_element.getAttributeSafe(comptime .wrap("name")) orelse continue; + const other_name = other_element.getName() orelse continue; if (!std.mem.eql(u8, self.name, other_name)) continue; return other_input; } @@ -515,7 +515,7 @@ const RadioGroupIterator = struct { /// because nothing in the iteration mutates the tree. fn radioGroupIterator(self: *const Input) ?RadioGroupIterator { const element = self.asConstElement(); - const name = element.getAttributeSafe(comptime .wrap("name")) orelse return null; + const name = element.getName() orelse return null; if (name.len == 0) return null; const root = @constCast(element.asConstNode()).getRootNode(.{}); return .{ @@ -589,7 +589,7 @@ fn codepointCount(value: []const u8) usize { } pub fn getDisabled(self: *const Input) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null; + return self.asConstElement().getAttributeInterned("disabled") != null; } pub fn setDisabled(self: *Input, disabled: bool, frame: *Frame) !void { @@ -609,7 +609,7 @@ pub fn getMinLength(self: *const Input) i32 { } pub fn getSrc(self: *const Input, frame: *Frame) ![]const u8 { - const src = self.asConstElement().getAttributeSafe(comptime .wrap("src")) orelse return ""; + const src = self.asConstElement().getAttributeInterned("src") orelse return ""; return self.asConstElement().asConstNode().resolveURLReflect(src, frame, .{}); } @@ -777,7 +777,7 @@ fn sanitizeValue(self: *Input, comptime dupe: bool, value: []const u8, frame: *F .@"datetime-local" => return try sanitizeDatetimeLocal(dupe, value, frame.arena), .number => return if (isValidFloatingPoint(value)) if (comptime dupe) try frame.dupeString(value) else value else "", .range => { - const value_attr = self.asConstElement().getAttributeSafe(comptime .wrap("value")) orelse ""; + const value_attr = self.asConstElement().getAttributeInterned("value") orelse ""; return try sanitizeRange(dupe, value, self.getMin(), self.getMax(), self.getStep(), value_attr, frame); }, .color => { @@ -895,7 +895,7 @@ fn stepBy(self: *Input, n: i32, frame: *Frame) !void { fn stepBase(self: *const Input) f64 { const typ = self._input_type; if (valueToNumber(typ, self.getMin())) |min| return min; - if (valueToNumber(typ, self.asConstElement().getAttributeSafe(comptime .wrap("value")) orelse "")) |v| return v; + if (valueToNumber(typ, self.asConstElement().getAttributeInterned("value") orelse "")) |v| return v; return if (typ == .week) -259_200_000 else 0; } @@ -1434,7 +1434,7 @@ pub fn getMin(self: *const Input) []const u8 { } pub fn getRequired(self: *const Input) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null; + return self.asConstElement().getAttributeInterned("required") != null; } pub fn getStep(self: *const Input) []const u8 { @@ -1522,12 +1522,12 @@ pub const Build = struct { const element = self.asElement(); // Store initial values from attributes - self._default_value = element.getAttributeSafe(comptime .wrap("value")); - self._default_checked = element.getAttributeSafe(comptime .wrap("checked")) != null; + self._default_value = element.getAttributeInterned("value"); + self._default_checked = element.getAttributeInterned("checked") != null; self._checked = self._default_checked; - self._input_type = if (element.getAttributeSafe(comptime .wrap("type"))) |type_attr| + self._input_type = if (element.getAttributeInterned("type")) |type_attr| Type.fromString(type_attr) else .text; diff --git a/src/browser/webapi/element/html/Label.zig b/src/browser/webapi/element/html/Label.zig index e1468ddd0..2511b6e3a 100644 --- a/src/browser/webapi/element/html/Label.zig +++ b/src/browser/webapi/element/html/Label.zig @@ -23,7 +23,7 @@ pub fn asNode(self: *Label) *Node { } pub fn getControl(self: *Label, frame: *Frame) ?*Element { - if (self.asElement().getAttributeSafe(comptime .wrap("for"))) |id| { + if (self.asElement().getAttributeInterned("for")) |id| { const el = frame.getElementByIdFromNode(self.asElement().asNode(), id) orelse return null; if (!isLabelable(el)) { return null; @@ -72,7 +72,7 @@ pub const LabelByForIndex = struct { var it = TreeWalker.Full.Elements.init(root, .{}); while (it.next()) |el| { if (el.getTag() != .label) continue; - const for_attr = el.getAttributeSafe(comptime .wrap("for")) orelse continue; + const for_attr = el.getAttributeInterned("for") orelse continue; if (for_attr.len == 0) continue; const gop = try self.map.getOrPut(allocator, for_attr); if (!gop.found_existing) gop.value_ptr.* = el; @@ -92,14 +92,14 @@ pub fn getControlLabels(control: *Element, frame: *Frame) !js.Array { var arr = local.newArray(0); var idx: u32 = 0; - if (control.getAttributeSafe(comptime .wrap("id"))) |id_value| { + if (control.getId()) |id_value| { if (id_value.len > 0) { const doc = control.asNode().ownerDocument(frame); const search_root: *Node = if (doc) |d| d.asNode() else control.asNode(); var it = TreeWalker.Full.Elements.init(search_root, .{}); while (it.next()) |el| { if (el.getTag() != .label) continue; - const for_attr = el.getAttributeSafe(comptime .wrap("for")) orelse continue; + const for_attr = el.getAttributeInterned("for") orelse continue; if (!std.mem.eql(u8, for_attr, id_value)) continue; _ = try arr.set(idx, el, .{}); idx += 1; diff --git a/src/browser/webapi/element/html/Link.zig b/src/browser/webapi/element/html/Link.zig index 558df7d24..36f4f4c7e 100644 --- a/src/browser/webapi/element/html/Link.zig +++ b/src/browser/webapi/element/html/Link.zig @@ -51,7 +51,7 @@ pub fn asNode(self: *Link) *Node { pub fn getHref(self: *Link, frame: *Frame) ![]const u8 { const element = self.asElement(); - const href = element.getAttributeSafe(comptime .wrap("href")) orelse return ""; + const href = element.getAttributeInterned("href") orelse return ""; if (href.len == 0) { return ""; } @@ -68,7 +68,7 @@ pub fn setHref(self: *Link, value: []const u8, frame: *Frame) !void { } pub fn getRel(self: *Link) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("rel")) orelse return ""; + return self.asElement().getAttributeInterned("rel") orelse return ""; } pub fn setRel(self: *Link, value: []const u8, frame: *Frame) !void { @@ -76,7 +76,7 @@ pub fn setRel(self: *Link, value: []const u8, frame: *Frame) !void { } pub fn getMedia(self: *Link) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("media")) orelse return ""; + return self.asElement().getAttributeInterned("media") orelse return ""; } pub fn setMedia(self: *Link, value: []const u8, frame: *Frame) !void { @@ -108,12 +108,12 @@ pub fn linkAddedCallback(self: *Link, frame: *Frame) !void { const element = self.asElement(); - const href = element.getAttributeSafe(comptime .wrap("href")) orelse return; + const href = element.getAttributeInterned("href") orelse return; if (href.len == 0) { return; } - const rel = element.getAttributeSafe(comptime .wrap("rel")) orelse return; + const rel = element.getAttributeInterned("rel") orelse return; // Opt-in fetch for `rel="stylesheet"` — drives `frame.loadExternalStylesheet`, // which fires the load/error event itself. diff --git a/src/browser/webapi/element/html/Media.zig b/src/browser/webapi/element/html/Media.zig index 01068032b..b77ea2663 100644 --- a/src/browser/webapi/element/html/Media.zig +++ b/src/browser/webapi/element/html/Media.zig @@ -250,7 +250,7 @@ pub fn setCurrentTime(self: *Media, value: f64) void { pub fn getSrc(self: *const Media, frame: *Frame) ![]const u8 { const element = self.asConstElement(); - const src = element.getAttributeSafe(comptime .wrap("src")) orelse return ""; + const src = element.getAttributeInterned("src") orelse return ""; if (src.len == 0) { return ""; } diff --git a/src/browser/webapi/element/html/Meta.zig b/src/browser/webapi/element/html/Meta.zig index e71dc2755..e6c6e16dc 100644 --- a/src/browser/webapi/element/html/Meta.zig +++ b/src/browser/webapi/element/html/Meta.zig @@ -48,7 +48,7 @@ pub fn asNode(self: *Meta) *Node { } pub fn getName(self: *Meta) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("name")) orelse return ""; + return self.asElement().getName() orelse ""; } pub fn setName(self: *Meta, value: []const u8, frame: *Frame) !void { @@ -64,7 +64,7 @@ pub fn setHttpEquiv(self: *Meta, value: []const u8, frame: *Frame) !void { } pub fn getContent(self: *Meta) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("content")) orelse return ""; + return self.asElement().getAttributeInterned("content") orelse return ""; } pub fn setContent(self: *Meta, value: []const u8, frame: *Frame) !void { @@ -72,7 +72,7 @@ pub fn setContent(self: *Meta, value: []const u8, frame: *Frame) !void { } pub fn getMedia(self: *Meta) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("media")) orelse return ""; + return self.asElement().getAttributeInterned("media") orelse return ""; } pub fn setMedia(self: *Meta, value: []const u8, frame: *Frame) !void { @@ -165,9 +165,9 @@ pub const Build = struct { const el = self.asElement(); // sets the document's referrer policy. - if (el.getAttributeSafe(comptime .wrap("name"))) |name| { + if (el.getName()) |name| { if (std.ascii.eqlIgnoreCase(name, "referrer")) { - if (el.getAttributeSafe(comptime .wrap("content"))) |content| { + if (el.getAttributeInterned("content")) |content| { if (referrer.parseMeta(content)) |rp| { frame.referrer_policy = rp; } diff --git a/src/browser/webapi/element/html/OL.zig b/src/browser/webapi/element/html/OL.zig index 07412f4f3..b07352a41 100644 --- a/src/browser/webapi/element/html/OL.zig +++ b/src/browser/webapi/element/html/OL.zig @@ -38,7 +38,7 @@ pub fn asNode(self: *OL) *Node { } pub fn getType(self: *OL) []const u8 { - return self.asElement().getAttributeSafe(comptime .wrap("type")) orelse "1"; + return self.asElement().getAttributeInterned("type") orelse "1"; } pub fn setType(self: *OL, value: []const u8, frame: *Frame) !void { diff --git a/src/browser/webapi/element/html/Option.zig b/src/browser/webapi/element/html/Option.zig index 56978ba68..7c50a733f 100644 --- a/src/browser/webapi/element/html/Option.zig +++ b/src/browser/webapi/element/html/Option.zig @@ -104,7 +104,7 @@ fn ownerSelect(self: *Option) ?*Select { } pub fn getDefaultSelected(self: *const Option) bool { - return self.asConstElement().hasAttributeSafe(comptime .wrap("selected")); + return self.asConstElement().hasAttributeInterned("selected"); } pub fn setDefaultSelected(self: *Option, value: bool, frame: *Frame) !void { @@ -153,10 +153,10 @@ pub const Build = struct { const element = self.asElement(); // Check for value attribute - self._value = element.getAttributeSafe(comptime .wrap("value")); + self._value = element.getAttributeInterned("value"); // Check for selected attribute - self._default_selected = element.getAttributeSafe(comptime .wrap("selected")) != null; + self._default_selected = element.getAttributeInterned("selected") != null; self._selected = self._default_selected; } @@ -166,7 +166,7 @@ pub const Build = struct { switch (attribute) { // `value` is passed by value; for <= 12 bytes, str() points into our // own parameter copy, so we have to re-read the owned bytes. - .value => self._value = element.getAttributeSafe(comptime .wrap("value")), + .value => self._value = element.getAttributeInterned("value"), .selected => { self._default_selected = true; self._selected = true; diff --git a/src/browser/webapi/element/html/Script.zig b/src/browser/webapi/element/html/Script.zig index e196fa2aa..e70cc1233 100644 --- a/src/browser/webapi/element/html/Script.zig +++ b/src/browser/webapi/element/html/Script.zig @@ -59,7 +59,7 @@ pub fn setSrc(self: *Script, src: []const u8, frame: *Frame) !void { } pub fn getAsync(self: *const Script) bool { - return self._force_async or self.asConstElement().getAttributeSafe(comptime .wrap("async")) != null; + return self._force_async or self.asConstElement().getAttributeInterned("async") != null; } pub fn setAsync(self: *Script, value: bool, frame: *Frame) !void { @@ -127,7 +127,7 @@ pub const Build = struct { pub fn complete(node: *Node, _: *Frame) !void { const self = node.as(Script); const element = self.asElement(); - self._src = element.getAttributeSafe(comptime .wrap("src")) orelse ""; + self._src = element.getAttributeInterned("src") orelse ""; } pub fn attributeChange(element: *Element, name: String, _: String, frame: *Frame) !void { @@ -136,7 +136,7 @@ pub const Build = struct { } const self = element.as(Script); - self._src = element.getAttributeSafe(comptime .wrap("src")) orelse ""; + self._src = element.getAttributeInterned("src") orelse ""; if (self._src.len > 0 and element.asNode().isConnected()) { try frame.scriptAddedCallback(false, self); } diff --git a/src/browser/webapi/element/html/Select.zig b/src/browser/webapi/element/html/Select.zig index caf2754fd..0031048d4 100644 --- a/src/browser/webapi/element/html/Select.zig +++ b/src/browser/webapi/element/html/Select.zig @@ -373,15 +373,15 @@ pub fn suffersValueMissing(self: *const Select) bool { } pub fn getDisabled(self: *const Select) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null; + return self.asConstElement().getAttributeInterned("disabled") != null; } pub fn getMultiple(self: *const Select) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("multiple")) != null; + return self.asConstElement().getAttributeInterned("multiple") != null; } pub fn getRequired(self: *const Select) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null; + return self.asConstElement().getAttributeInterned("required") != null; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Slot.zig b/src/browser/webapi/element/html/Slot.zig index 9e041ee07..33a6e9742 100644 --- a/src/browser/webapi/element/html/Slot.zig +++ b/src/browser/webapi/element/html/Slot.zig @@ -150,7 +150,7 @@ pub fn assign(self: *Slot, values: []const js.Value, frame: *Frame) !void { } pub fn getName(self: *const Slot) []const u8 { - return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse ""; + return self.asConstElement().getName() orelse ""; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/Source.zig b/src/browser/webapi/element/html/Source.zig index be26556f9..fcccee00a 100644 --- a/src/browser/webapi/element/html/Source.zig +++ b/src/browser/webapi/element/html/Source.zig @@ -25,7 +25,7 @@ pub fn asNode(self: *Source) *Node { pub fn getSrc(self: *const Source, frame: *Frame) ![]const u8 { const element = self.asConstElement(); - const src = element.getAttributeSafe(comptime .wrap("src")) orelse return ""; + const src = element.getAttributeInterned("src") orelse return ""; if (src.len == 0) { return ""; } diff --git a/src/browser/webapi/element/html/Style.zig b/src/browser/webapi/element/html/Style.zig index 6327d990e..65d982bb4 100644 --- a/src/browser/webapi/element/html/Style.zig +++ b/src/browser/webapi/element/html/Style.zig @@ -86,7 +86,7 @@ pub fn styleAddedCallback(self: *Style, frame: *Frame) !void { } pub fn getType(self: *const Style) []const u8 { - return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse ""; + return self.asConstElement().getAttributeInterned("type") orelse ""; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/html/TextArea.zig b/src/browser/webapi/element/html/TextArea.zig index 596f84a00..9133faec8 100644 --- a/src/browser/webapi/element/html/TextArea.zig +++ b/src/browser/webapi/element/html/TextArea.zig @@ -265,11 +265,11 @@ pub fn suffersTooShort(self: *const TextArea) bool { } pub fn getDisabled(self: *const TextArea) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null; + return self.asConstElement().getAttributeInterned("disabled") != null; } pub fn getRequired(self: *const TextArea) bool { - return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null; + return self.asConstElement().getAttributeInterned("required") != null; } pub const JsApi = struct { diff --git a/src/browser/webapi/element/slotting.zig b/src/browser/webapi/element/slotting.zig index 2a18a0d28..a1ffbb820 100644 --- a/src/browser/webapi/element/slotting.zig +++ b/src/browser/webapi/element/slotting.zig @@ -59,7 +59,7 @@ pub fn findSlot(slottable: *Node, comptime open_only: bool, frame: *Frame) ?*Slo const slottable_name = blk: { const el = slottable.is(Element) orelse break :blk ""; - break :blk el.getAttributeSafe(comptime .wrap("slot")) orelse ""; + break :blk el.getSlot() orelse ""; }; return findNamedSlot(shadow_node, slottable_name); } diff --git a/src/browser/webapi/element/svg/Svg.zig b/src/browser/webapi/element/svg/Svg.zig index 4e2f4f467..834fa29c3 100644 --- a/src/browser/webapi/element/svg/Svg.zig +++ b/src/browser/webapi/element/svg/Svg.zig @@ -58,7 +58,7 @@ pub fn getElementById(self: *Svg, id: []const u8) ?*Element { var tw = TreeWalker.Full.Elements.init(self.asNode(), .{}); while (tw.next()) |el| { - const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue; + const element_id = el.getId() orelse continue; if (std.mem.eql(u8, element_id, id)) { return el; } diff --git a/src/browser/webapi/net/FormData.zig b/src/browser/webapi/net/FormData.zig index 682a51378..0adb92cbe 100644 --- a/src/browser/webapi/net/FormData.zig +++ b/src/browser/webapi/net/FormData.zig @@ -811,7 +811,7 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, charset: continue; } - const name = element.getAttributeSafe(comptime .wrap("name")); + const name = element.getName(); const x_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.x", .{n}) else "x"; const y_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.y", .{n}) else "y"; try appendString(&list, arena, x_key, "0"); @@ -820,7 +820,7 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, charset: } } - const name = element.getAttributeSafe(comptime .wrap("name")) orelse continue; + const name = element.getName() orelse continue; const value = blk: { if (element.is(Form.Input)) |input| { const input_type = input._input_type; diff --git a/src/server/cdp/AXNode.zig b/src/server/cdp/AXNode.zig index c4492b11a..d5017fe33 100644 --- a/src/server/cdp/AXNode.zig +++ b/src/server/cdp/AXNode.zig @@ -392,8 +392,8 @@ pub const Writer = struct { try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w); } try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = false } }, w); - try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("readonly")) } }, w); - try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("required")) } }, w); + try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeInterned("readonly") } }, w); + try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeInterned("required") } }, w); }, .button, .submit, .reset, .image => { try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w); @@ -406,7 +406,7 @@ pub const Writer = struct { if (!is_disabled) { try self.writeAXProperty(.{ .name = .focusable, .value = .{ .booleanOrUndefined = true } }, w); } - const is_checked = el.hasAttributeSafe(comptime .wrap("checked")); + const is_checked = el.hasAttributeInterned("checked"); try self.writeAXProperty(.{ .name = .checked, .value = .{ .token = if (is_checked) "true" else "false" } }, w); }, else => {}, @@ -424,8 +424,8 @@ pub const Writer = struct { try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w); } try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = true } }, w); - try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("readonly")) } }, w); - try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("required")) } }, w); + try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeInterned("readonly") } }, w); + try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeInterned("required") } }, w); }, .select => { const is_disabled = el.isDisabled(); @@ -827,7 +827,7 @@ pub const AXRole = enum(u8) { }, .textarea => .textbox, .select => { - if (el.getAttributeSafe(comptime .wrap("multiple")) != null) { + if (el.getAttributeInterned("multiple") != null) { return .listbox; } if (el.getAttributeSafe(comptime .wrap("size"))) |size| { @@ -847,7 +847,7 @@ pub const AXRole = enum(u8) { // Interactive Elements .anchor, .area => { - if (el.getAttributeSafe(comptime .wrap("href")) == null) { + if (el.getAttributeInterned("href") == null) { return .none; } @@ -1030,7 +1030,7 @@ fn writeName( } } - if (el.getAttributeSafe(comptime .wrap("aria-label"))) |aria_label| { + if (el.getAttributeInterned("aria-label")) |aria_label| { try w.write(aria_label); return .aria_label; } @@ -1041,7 +1041,7 @@ fn writeName( } } - if (el.getAttributeSafe(comptime .wrap("alt"))) |alt| { + if (el.getAttributeInterned("alt")) |alt| { try w.write(alt); return .alt; } @@ -1090,12 +1090,12 @@ fn writeName( } } - if (el.getAttributeSafe(comptime .wrap("title"))) |title| { + if (el.getAttributeInterned("title")) |title| { try w.write(title); return .title; } - if (el.getAttributeSafe(comptime .wrap("placeholder"))) |placeholder| { + if (el.getAttributeInterned("placeholder")) |placeholder| { try w.write(placeholder); return .placeholder; } @@ -1154,7 +1154,7 @@ fn writeAccessibleNameFallback(node: *DOMNode, writer: *std.Io.Writer, frame: *F } fn hasAriaHiddenTrue(elt: *DOMNode.Element) bool { - if (elt.getAttributeSafe(comptime .wrap("aria-hidden"))) |value| { + if (elt.getAttributeInterned("aria-hidden")) |value| { return std.mem.eql(u8, value, "true"); } return false; @@ -1242,7 +1242,7 @@ fn writeLabelName( label_index: *Label.LabelByForIndex, w: anytype, ) !?AXSource { - if (el.getAttributeSafe(comptime .wrap("id"))) |id_value| { + if (el.getId()) |id_value| { if (id_value.len > 0) { if (node.ownerDocument(frame)) |doc| { if (try label_index.lookup(doc.asNode(), id_value, frame.call_arena)) |label_el| { @@ -1281,13 +1281,13 @@ fn scratchAllocator(temp_arena: ?*lp.Arena, frame: *Frame) std.mem.Allocator { } fn isHidden(elt: *DOMNode.Element, frame: *Frame, cache: *DOMNode.Element.VisibilityCache) bool { - if (elt.getAttributeSafe(comptime .wrap("aria-hidden"))) |value| { + if (elt.getAttributeInterned("aria-hidden")) |value| { if (std.mem.eql(u8, value, "true")) { return true; } } - if (elt.hasAttributeSafe(comptime .wrap("hidden"))) { + if (elt.hasAttributeInterned("hidden")) { return true; } @@ -1367,7 +1367,7 @@ fn isIgnore(self: AXNode, frame: *Frame, cache: *DOMNode.Element.VisibilityCache // zig fmt: on .img => { // Check for empty decorative images - const alt_ = elt.getAttributeSafe(comptime .wrap("alt")); + const alt_ = elt.getAttributeInterned("alt"); if (alt_ == null or alt_.?.len == 0) { return true; } @@ -1398,8 +1398,8 @@ fn isIgnore(self: AXNode, frame: *Frame, cache: *DOMNode.Element.VisibilityCache // Generic containers with no semantic value if (tag == .div or tag == .span) { - const has_role = elt.hasAttributeSafe(comptime .wrap("role")); - const has_aria_label = elt.hasAttributeSafe(comptime .wrap("aria-label")); + const has_role = elt.hasAttributeInterned("role"); + const has_aria_label = elt.hasAttributeInterned("aria-label"); const has_aria_labelledby = elt.hasAttributeSafe(.wrap("aria-labelledby")); if (!has_role and !has_aria_label and !has_aria_labelledby) {