mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-08-02 10:47:15 -04:00
webapi: DOMTokenList-reflected attributes on area, output, iframe, link
Fixes 4 failing tests in WPT /dom/lists/DOMTokenList-coverage-for-attributes.html (135/140 -> 139/140): area.relList, output.htmlFor, iframe.sandbox and link.sizes must be DOMTokenList attributes reflecting their content attributes. Element gains a generic getTokenList lookup (keyed by element and attribute) alongside the existing class/rel dedicated ones, and the four elements expose the accessors following the Anchor/Link relList pattern (undefined outside the HTML namespace). The remaining failure needs an SVGAElement interface (relList on SVG <a> elements), which doesn't exist yet — SVG elements are all generic. Coverage: /dom/lists/DOMTokenList-coverage-for-attributes.html 135/140 -> 139/140. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Karl Seguin
parent
0740f7d113
commit
0a7e24fa2f
@@ -134,6 +134,7 @@ _element_computed_styles: Element.StyleLookup = .empty,
|
||||
_element_datasets: Element.DatasetLookup = .empty,
|
||||
_element_class_lists: Element.ClassListLookup = .empty,
|
||||
_element_rel_lists: Element.RelListLookup = .empty,
|
||||
_element_token_lists: Element.TokenListLookup = .empty,
|
||||
_element_shadow_roots: Element.ShadowRootLookup = .empty,
|
||||
_node_owner_documents: Node.OwnerDocumentLookup = .empty,
|
||||
_element_scroll_positions: Element.ScrollPositionLookup = .empty,
|
||||
|
||||
@@ -885,6 +885,23 @@ pub fn getRelList(self: *Element, frame: *Frame) !*collections.DOMTokenList {
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
|
||||
// The other DOMTokenList-reflected attributes (class and rel have dedicated
|
||||
// lookups above).
|
||||
pub const TokenListAttribute = enum { sizes, sandbox, @"for" };
|
||||
pub const TokenListKey = struct { element: *Element, attribute: TokenListAttribute };
|
||||
pub const TokenListLookup = std.AutoHashMapUnmanaged(TokenListKey, *collections.DOMTokenList);
|
||||
|
||||
pub fn getTokenList(self: *Element, comptime attribute: TokenListAttribute, frame: *Frame) !*collections.DOMTokenList {
|
||||
const gop = try frame._element_token_lists.getOrPut(frame.arena, .{ .element = self, .attribute = attribute });
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = try frame._factory.create(collections.DOMTokenList{
|
||||
._element = self,
|
||||
._attribute_name = comptime .wrap(@tagName(attribute)),
|
||||
});
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
|
||||
pub fn getDataset(self: *Element, frame: *Frame) !*DOMStringMap {
|
||||
const gop = try frame._element_datasets.getOrPut(frame.arena, self);
|
||||
if (!gop.found_existing) {
|
||||
|
||||
@@ -290,12 +290,11 @@ pub const JsApi = struct {
|
||||
pub const referrerPolicy = bridge.accessor(Area.getReferrerPolicy, Area.setReferrerPolicy, .{ .ce_reactions = true });
|
||||
pub const relList = bridge.accessor(_getRelList, null, .{ .null_as_undefined = true });
|
||||
pub const toString = bridge.function(Area.getHref, .{});
|
||||
|
||||
pub const relList = bridge.accessor(_getRelList, null, .{ .null_as_undefined = true });
|
||||
fn _getRelList(self: *Area, frame: *Frame) !?*@import("../../collections.zig").DOMTokenList {
|
||||
const element = self.asElement();
|
||||
// relList is only valid for HTML and SVG <area> elements
|
||||
const namespace = element._namespace;
|
||||
if (namespace != .html and namespace != .svg) {
|
||||
// relList is only valid for HTML <area> elements
|
||||
if (element._namespace != .html) {
|
||||
return null;
|
||||
}
|
||||
return element.getRelList(frame);
|
||||
|
||||
@@ -93,6 +93,15 @@ pub const JsApi = struct {
|
||||
pub const name = bridge.accessor(IFrame.getName, IFrame.setName, .{ .ce_reactions = true });
|
||||
pub const contentWindow = bridge.accessor(IFrame.getContentWindow, null, .{});
|
||||
pub const contentDocument = bridge.accessor(IFrame.getContentDocument, null, .{});
|
||||
pub const sandbox = bridge.accessor(_getSandbox, null, .{ .null_as_undefined = true });
|
||||
|
||||
fn _getSandbox(self: *IFrame, frame: *Frame) !?*@import("../../collections.zig").DOMTokenList {
|
||||
const element = self.asElement();
|
||||
if (element._namespace != .html) {
|
||||
return null;
|
||||
}
|
||||
return element.getTokenList(.sandbox, frame);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Build = struct {
|
||||
|
||||
@@ -256,6 +256,15 @@ pub const JsApi = struct {
|
||||
pub const rev = bridge.accessor(Link.getRev, Link.setRev, .{ .ce_reactions = true });
|
||||
pub const target = bridge.accessor(Link.getTarget, Link.setTarget, .{ .ce_reactions = true });
|
||||
pub const relList = bridge.accessor(_getRelList, null, .{ .null_as_undefined = true });
|
||||
pub const sizes = bridge.accessor(_getSizes, null, .{ .null_as_undefined = true });
|
||||
|
||||
fn _getSizes(self: *Link, frame: *Frame) !?*@import("../../collections.zig").DOMTokenList {
|
||||
const element = self.asElement();
|
||||
if (element._namespace != .html) {
|
||||
return null;
|
||||
}
|
||||
return element.getTokenList(.sizes, frame);
|
||||
}
|
||||
|
||||
fn _getRelList(self: *Link, frame: *Frame) !?*@import("../../collections.zig").DOMTokenList {
|
||||
const element = self.asElement();
|
||||
|
||||
@@ -29,4 +29,13 @@ pub const JsApi = struct {
|
||||
};
|
||||
|
||||
pub const labels = bridge.accessor(Output.getLabels, null, .{});
|
||||
pub const htmlFor = bridge.accessor(_getHtmlFor, null, .{ .null_as_undefined = true });
|
||||
|
||||
fn _getHtmlFor(self: *Output, frame: *Frame) !?*@import("../../collections.zig").DOMTokenList {
|
||||
const element = self.asElement();
|
||||
if (element._namespace != .html) {
|
||||
return null;
|
||||
}
|
||||
return element.getTokenList(.@"for", frame);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user