@@ -78,29 +78,86 @@ fn performSearch(cmd: anytype) !void {
7878
7979 // dispatch setChildNodesEvents to inform the client of the subpart of node
8080 // tree covering the results.
81- for (list .nodes .items ) | n | {
82- // retrieve the node's parent
83- if (try parser .nodeParentNode (n )) | p | {
84- // Register the parent and send the node.
85- const parent_node = try bc .node_registry .register (p );
86- const node = bc .node_registry .lookup_by_node .get (n ) orelse unreachable ;
87- // Should-we return one DOM.setChildNodes event per parentId
88- // containing all its children in the nodes array?
89- try cmd .sendEvent ("DOM.setChildNodes" , .{
90- .parentId = parent_node .id ,
91- .nodes = .{bc .nodeWriter (node , .{})},
92- }, .{
93- .session_id = bc .session_id .? ,
94- });
95- }
96- }
81+ try dispatchSetChildNodes (cmd , list .nodes .items );
9782
9883 return cmd .sendResult (.{
9984 .searchId = search .name ,
10085 .resultCount = @as (u32 , @intCast (search .node_ids .len )),
10186 }, .{});
10287}
10388
89+ // dispatchSetChildNodes send the setChildNodes event for the whole DOM tree
90+ // hierarchy of each nodes.
91+ // If a parent has already been registred, we don't re-send a setChildNodes
92+ // event anymore.
93+ // We dispatch event in the reverse order: from the top level to the direct parents.
94+ fn dispatchSetChildNodes (cmd : anytype , nodes : []* parser.Node ) ! void {
95+ const arena = cmd .arena ;
96+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
97+
98+ var parents : std .ArrayListUnmanaged (* parser .Node ) = .{};
99+ for (nodes ) | _n | {
100+ var n = _n ;
101+ while (true ) {
102+ const p = try parser .nodeParentNode (n ) orelse break ;
103+ // If the parent exists in he registry, don't send the event.
104+ // In this case we stop browsing the tree, b/c parents must have
105+ // been sent already.
106+ if (bc .node_registry .lookup_by_node .contains (p )) {
107+ break ;
108+ }
109+ try parents .append (arena , p );
110+
111+ n = p ;
112+ }
113+ }
114+
115+ const plen = parents .items .len ;
116+ if (plen == 0 ) return ;
117+
118+ var i : usize = plen ;
119+ while (i > 0 ) {
120+ i -= 1 ;
121+ const n = parents .items [i ];
122+ // If the parent exists in he registry, don't send the event.
123+ // Indeed the parent can be twice in the array.
124+ if (bc .node_registry .lookup_by_node .contains (n )) {
125+ continue ;
126+ }
127+
128+ // If the node has no parent, it's the root node.
129+ // We don't dispatch event for it because we assume the root node is
130+ // dispatched via the DOM.getDocument command.
131+ const p = try parser .nodeParentNode (n ) orelse break ;
132+ // Register the node.
133+ const node = try bc .node_registry .register (n );
134+ // Retrieve the parent from the registry.
135+ const parent_node = bc .node_registry .lookup_by_node .get (p ) orelse unreachable ;
136+
137+ try cmd .sendEvent ("DOM.setChildNodes" , .{
138+ .parentId = parent_node .id ,
139+ .nodes = .{bc .nodeWriter (node , .{})},
140+ }, .{
141+ .session_id = bc .session_id .? ,
142+ });
143+ }
144+
145+ // now dispatch the event for the node list.
146+ for (nodes ) | n | {
147+ const node = bc .node_registry .lookup_by_node .get (n ) orelse unreachable ;
148+ const p = try parser .nodeParentNode (n ) orelse continue ;
149+ // Retrieve the parent from the registry.
150+ const parent_node = bc .node_registry .lookup_by_node .get (p ) orelse unreachable ;
151+
152+ try cmd .sendEvent ("DOM.setChildNodes" , .{
153+ .parentId = parent_node .id ,
154+ .nodes = .{bc .nodeWriter (node , .{})},
155+ }, .{
156+ .session_id = bc .session_id .? ,
157+ });
158+ }
159+ }
160+
104161// https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-discardSearchResults
105162fn discardSearchResults (cmd : anytype ) ! void {
106163 const params = (try cmd .params (struct {
0 commit comments