Skip to content

Commit 2aeeb14

Browse files
authored
Merge pull request #1043 from lightpanda-io/html_slot_assigned_elements
add assignedElements to HTMLSlotElement
2 parents e5e57ab + b7fb0ef commit 2aeeb14

File tree

2 files changed

+67
-46
lines changed

2 files changed

+67
-46
lines changed

src/browser/html/elements.zig

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,68 +1042,84 @@ pub const HTMLSlotElement = struct {
10421042
flatten: bool = false,
10431043
};
10441044
pub fn _assignedNodes(self: *parser.Slot, opts_: ?AssignedNodesOpts, page: *Page) ![]NodeUnion {
1045-
const opts = opts_ orelse AssignedNodesOpts{ .flatten = false };
1046-
1047-
if (try findAssignedSlotNodes(self, opts, page)) |nodes| {
1048-
return nodes;
1049-
}
1050-
1051-
if (!opts.flatten) {
1052-
return &.{};
1053-
}
1054-
1055-
const node: *parser.Node = @ptrCast(@alignCast(self));
1056-
const nl = try parser.nodeGetChildNodes(node);
1057-
const len = try parser.nodeListLength(nl);
1058-
if (len == 0) {
1059-
return &.{};
1060-
}
1045+
return findAssignedSlotNodes(self, opts_, false, page);
1046+
}
10611047

1062-
var assigned = try page.call_arena.alloc(NodeUnion, len);
1063-
var i: usize = 0;
1064-
while (true) : (i += 1) {
1065-
const child = try parser.nodeListItem(nl, @intCast(i)) orelse break;
1066-
assigned[i] = try Node.toInterface(child);
1067-
}
1068-
return assigned[0..i];
1048+
// This should return Union, instead of NodeUnion, but we want to re-use
1049+
// findAssignedSlotNodes. Returning NodeUnion is fine, as long as every element
1050+
// within is an Element. This could be more efficient
1051+
pub fn _assignedElements(self: *parser.Slot, opts_: ?AssignedNodesOpts, page: *Page) ![]NodeUnion {
1052+
return findAssignedSlotNodes(self, opts_, true, page);
10691053
}
10701054

1071-
fn findAssignedSlotNodes(self: *parser.Slot, opts: AssignedNodesOpts, page: *Page) !?[]NodeUnion {
1055+
fn findAssignedSlotNodes(self: *parser.Slot, opts_: ?AssignedNodesOpts, element_only: bool, page: *Page) ![]NodeUnion {
1056+
const opts = opts_ orelse AssignedNodesOpts{ .flatten = false };
1057+
10721058
if (opts.flatten) {
10731059
log.debug(.web_api, "not implemented", .{ .feature = "HTMLSlotElement flatten assignedNodes" });
10741060
}
10751061

1076-
const slot_name = try parser.elementGetAttribute(@ptrCast(@alignCast(self)), "name");
10771062
const node: *parser.Node = @ptrCast(@alignCast(self));
1078-
var root = try parser.nodeGetRootNode(node);
1079-
if (page.getNodeState(root)) |state| {
1080-
if (state.shadow_root) |sr| {
1081-
root = @ptrCast(@alignCast(sr.host));
1063+
1064+
// First we look for any explicitly assigned nodes (via the slot attribute)
1065+
{
1066+
const slot_name = try parser.elementGetAttribute(@ptrCast(@alignCast(self)), "name");
1067+
var root = try parser.nodeGetRootNode(node);
1068+
if (page.getNodeState(root)) |state| {
1069+
if (state.shadow_root) |sr| {
1070+
root = @ptrCast(@alignCast(sr.host));
1071+
}
10821072
}
1083-
}
10841073

1085-
var arr: std.ArrayList(NodeUnion) = .empty;
1086-
const w = @import("../dom/walker.zig").WalkerChildren{};
1087-
var next: ?*parser.Node = null;
1088-
while (true) {
1089-
next = try w.get_next(root, next) orelse break;
1090-
if (try parser.nodeType(next.?) != .element) {
1091-
if (slot_name == null) {
1092-
// default slot (with no name), takes everything
1074+
var arr: std.ArrayList(NodeUnion) = .empty;
1075+
const w = @import("../dom/walker.zig").WalkerChildren{};
1076+
var next: ?*parser.Node = null;
1077+
while (true) {
1078+
next = try w.get_next(root, next) orelse break;
1079+
if (try parser.nodeType(next.?) != .element) {
1080+
if (slot_name == null and !element_only) {
1081+
// default slot (with no name), takes everything
1082+
try arr.append(page.call_arena, try Node.toInterface(next.?));
1083+
}
1084+
continue;
1085+
}
1086+
const el: *parser.Element = @ptrCast(@alignCast(next.?));
1087+
const element_slot = try parser.elementGetAttribute(el, "slot");
1088+
1089+
if (nullableStringsAreEqual(slot_name, element_slot)) {
1090+
// either they're the same string or they are both null
10931091
try arr.append(page.call_arena, try Node.toInterface(next.?));
1092+
continue;
10941093
}
1095-
continue;
10961094
}
1097-
const el: *parser.Element = @ptrCast(@alignCast(next.?));
1098-
const element_slot = try parser.elementGetAttribute(el, "slot");
1095+
if (arr.items.len > 0) {
1096+
return arr.items;
1097+
}
10991098

1100-
if (nullableStringsAreEqual(slot_name, element_slot)) {
1101-
// either they're the same string or they are both null
1102-
try arr.append(page.call_arena, try Node.toInterface(next.?));
1103-
continue;
1099+
if (!opts.flatten) {
1100+
return &.{};
1101+
}
1102+
}
1103+
1104+
// Since, we have no explicitly assigned nodes and flatten == false,
1105+
// we'll collect the children of the slot - the defaults.
1106+
{
1107+
const nl = try parser.nodeGetChildNodes(node);
1108+
const len = try parser.nodeListLength(nl);
1109+
if (len == 0) {
1110+
return &.{};
1111+
}
1112+
1113+
var assigned = try page.call_arena.alloc(NodeUnion, len);
1114+
var i: usize = 0;
1115+
while (true) : (i += 1) {
1116+
const child = try parser.nodeListItem(nl, @intCast(i)) orelse break;
1117+
if (!element_only or try parser.nodeType(child) == .element) {
1118+
assigned[i] = try Node.toInterface(child);
1119+
}
11041120
}
1121+
return assigned[0..i];
11051122
}
1106-
return if (arr.items.len == 0) null else arr.items;
11071123
}
11081124

11091125
fn nullableStringsAreEqual(a: ?[]const u8, b: ?[]const u8) bool {

src/tests/html/slot.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,9 @@
6363
assertNodes(['default2'], s6[0].assignedNodes({flatten: true}));
6464
assertNodes(['More ', ' ', '!!'], s6[1].assignedNodes({}));
6565
assertNodes(['More ', ' ', '!!'], s6[1].assignedNodes({flatten: true}));
66+
67+
assertNodes(['default2'], s6[0].assignedElements({}));
68+
assertNodes(['default2'], s6[0].assignedElements({flatten: true}));
69+
assertNodes(['!!'], s6[1].assignedElements({}));
70+
assertNodes(['!!'], s6[1].assignedElements({flatten: true}));
6671
</script>

0 commit comments

Comments
 (0)