@@ -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 {
0 commit comments