-
Notifications
You must be signed in to change notification settings - Fork 286
Add support for CDP's DOM.requestChildNodes #888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -201,49 +201,69 @@ pub const Search = struct { | |||||
| // (For now, we only support direct children) | ||||||
|
|
||||||
| pub const Writer = struct { | ||||||
| opts: Opts, | ||||||
| node: *const Node, | ||||||
| depth: i32, | ||||||
| exclude_root: bool, | ||||||
| root: *const Node, | ||||||
| registry: *Registry, | ||||||
|
|
||||||
| pub const Opts = struct {}; | ||||||
| pub const Opts = struct { | ||||||
| depth: i32 = 0, | ||||||
| exclude_root: bool = false, | ||||||
| }; | ||||||
|
|
||||||
| pub fn jsonStringify(self: *const Writer, w: anytype) !void { | ||||||
sjorsdonkers marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| self.toJSON(w) catch |err| { | ||||||
| // The only error our jsonStringify method can return is | ||||||
| // @TypeOf(w).Error. In other words, our code can't return its own | ||||||
| // error, we can only return a writer error. Kinda sucks. | ||||||
| log.err(.cdp, "json stringify", .{ .err = err }); | ||||||
| return error.OutOfMemory; | ||||||
| }; | ||||||
| if (self.exclude_root) { | ||||||
| _ = self.writeChildren(self.root, 1, w) catch |err| { | ||||||
| log.err(.cdp, "node writeChildren", .{ .err = err }); | ||||||
| return error.OutOfMemory; | ||||||
| }; | ||||||
| } else { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assume that the meaning of the depth value 1, 2, 3 has been confirmed for both cases |
||||||
| self.toJSON(self.root, 0, w) catch |err| { | ||||||
| // The only error our jsonStringify method can return is | ||||||
| // @TypeOf(w).Error. In other words, our code can't return its own | ||||||
| // error, we can only return a writer error. Kinda sucks. | ||||||
| log.err(.cdp, "node toJSON stringify", .{ .err = err }); | ||||||
| return error.OutOfMemory; | ||||||
| }; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn toJSON(self: *const Writer, w: anytype) !void { | ||||||
| fn toJSON(self: *const Writer, node: *const Node, depth: usize, w: anytype) !void { | ||||||
| try w.beginObject(); | ||||||
| try self.writeCommon(self.node, false, w); | ||||||
| try self.writeCommon(node, false, w); | ||||||
|
|
||||||
| { | ||||||
| var registry = self.registry; | ||||||
| const child_nodes = try parser.nodeGetChildNodes(self.node._node); | ||||||
| const child_count = try parser.nodeListLength(child_nodes); | ||||||
| try w.objectField("children"); | ||||||
| const child_count = try self.writeChildren(node, depth, w); | ||||||
| try w.objectField("childNodeCount"); | ||||||
| try w.write(child_count); | ||||||
|
|
||||||
| var i: usize = 0; | ||||||
| try w.objectField("children"); | ||||||
| try w.beginArray(); | ||||||
| for (0..child_count) |_| { | ||||||
| const child = (try parser.nodeListItem(child_nodes, @intCast(i))) orelse break; | ||||||
| const child_node = try registry.register(child); | ||||||
| try w.endObject(); | ||||||
| } | ||||||
|
|
||||||
| fn writeChildren(self: *const Writer, node: *const Node, depth: usize, w: anytype) anyerror!usize { | ||||||
| var registry = self.registry; | ||||||
| const child_nodes = try parser.nodeGetChildNodes(node._node); | ||||||
| const child_count = try parser.nodeListLength(child_nodes); | ||||||
| const full_child = self.depth < 0 or self.depth < depth; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
My understanding is that if In the I would not be surpised if I'm off by one tho. |
||||||
|
|
||||||
| var i: usize = 0; | ||||||
| try w.beginArray(); | ||||||
| for (0..child_count) |_| { | ||||||
| const child = (try parser.nodeListItem(child_nodes, @intCast(i))) orelse break; | ||||||
| const child_node = try registry.register(child); | ||||||
| if (full_child) { | ||||||
| try self.toJSON(child_node, depth + 1, w); | ||||||
| } else { | ||||||
| try w.beginObject(); | ||||||
| try self.writeCommon(child_node, true, w); | ||||||
| try w.endObject(); | ||||||
| i += 1; | ||||||
| } | ||||||
| try w.endArray(); | ||||||
|
|
||||||
| try w.objectField("childNodeCount"); | ||||||
| try w.write(i); | ||||||
| i += 1; | ||||||
| } | ||||||
| try w.endArray(); | ||||||
|
|
||||||
| try w.endObject(); | ||||||
| return i; | ||||||
| } | ||||||
|
|
||||||
| fn writeCommon(self: *const Writer, node: *const Node, include_child_count: bool, w: anytype) !void { | ||||||
|
|
@@ -400,14 +420,15 @@ test "cdp Node: Writer" { | |||||
| var registry = Registry.init(testing.allocator); | ||||||
| defer registry.deinit(); | ||||||
|
|
||||||
| var doc = try testing.Document.init("<a id=a1></a><a id=a2></a>"); | ||||||
| var doc = try testing.Document.init("<a id=a1></a><div id=d2><a id=a2></a></div>"); | ||||||
| defer doc.deinit(); | ||||||
|
|
||||||
| { | ||||||
| const node = try registry.register(doc.asNode()); | ||||||
| const json = try std.json.stringifyAlloc(testing.allocator, Writer{ | ||||||
| .node = node, | ||||||
| .opts = .{}, | ||||||
| .root = node, | ||||||
| .depth = 0, | ||||||
| .exclude_root = false, | ||||||
| .registry = ®istry, | ||||||
| }, .{}); | ||||||
| defer testing.allocator.free(json); | ||||||
|
|
@@ -445,8 +466,9 @@ test "cdp Node: Writer" { | |||||
| { | ||||||
| const node = registry.lookup_by_id.get(1).?; | ||||||
| const json = try std.json.stringifyAlloc(testing.allocator, Writer{ | ||||||
| .node = node, | ||||||
| .opts = .{}, | ||||||
| .root = node, | ||||||
| .depth = 1, | ||||||
| .exclude_root = false, | ||||||
| .registry = ®istry, | ||||||
| }, .{}); | ||||||
| defer testing.allocator.free(json); | ||||||
|
|
@@ -495,4 +517,61 @@ test "cdp Node: Writer" { | |||||
| } }, | ||||||
| }, json); | ||||||
| } | ||||||
|
|
||||||
| { | ||||||
| const node = registry.lookup_by_id.get(1).?; | ||||||
| const json = try std.json.stringifyAlloc(testing.allocator, Writer{ | ||||||
| .root = node, | ||||||
| .depth = -1, | ||||||
| .exclude_root = true, | ||||||
| .registry = ®istry, | ||||||
| }, .{}); | ||||||
| defer testing.allocator.free(json); | ||||||
|
|
||||||
| try testing.expectJson(&.{ .{ | ||||||
| .nodeId = 2, | ||||||
| .backendNodeId = 2, | ||||||
| .nodeType = 1, | ||||||
| .nodeName = "HEAD", | ||||||
| .localName = "head", | ||||||
| .nodeValue = "", | ||||||
| .childNodeCount = 0, | ||||||
| .documentURL = null, | ||||||
| .baseURL = null, | ||||||
| .xmlVersion = "", | ||||||
| .compatibilityMode = "NoQuirksMode", | ||||||
| .isScrollable = false, | ||||||
| .parentId = 1, | ||||||
| }, .{ | ||||||
| .nodeId = 3, | ||||||
| .backendNodeId = 3, | ||||||
| .nodeType = 1, | ||||||
| .nodeName = "BODY", | ||||||
| .localName = "body", | ||||||
| .nodeValue = "", | ||||||
| .childNodeCount = 2, | ||||||
| .documentURL = null, | ||||||
| .baseURL = null, | ||||||
| .xmlVersion = "", | ||||||
| .compatibilityMode = "NoQuirksMode", | ||||||
| .isScrollable = false, | ||||||
| .children = &.{ .{ | ||||||
| .nodeId = 4, | ||||||
| .localName = "a", | ||||||
| .childNodeCount = 0, | ||||||
| .parentId = 3, | ||||||
| }, .{ | ||||||
| .nodeId = 5, | ||||||
| .localName = "div", | ||||||
| .childNodeCount = 1, | ||||||
| .parentId = 3, | ||||||
| .children = &.{ .{ | ||||||
| .nodeId = 6, | ||||||
| .localName = "a", | ||||||
| .childNodeCount = 0, | ||||||
| .parentId = 5, | ||||||
| }} | ||||||
| } | ||||||
| } } }, json); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ pub fn processMessage(cmd: anytype) !void { | |
| scrollIntoViewIfNeeded, | ||
| getContentQuads, | ||
| getBoxModel, | ||
| requestChildNodes, | ||
| }, cmd.input.action) orelse return error.UnknownMethod; | ||
|
|
||
| switch (action) { | ||
|
|
@@ -53,6 +54,7 @@ pub fn processMessage(cmd: anytype) !void { | |
| .scrollIntoViewIfNeeded => return scrollIntoViewIfNeeded(cmd), | ||
| .getContentQuads => return getContentQuads(cmd), | ||
| .getBoxModel => return getBoxModel(cmd), | ||
| .requestChildNodes => return requestChildNodes(cmd), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -433,6 +435,30 @@ fn getBoxModel(cmd: anytype) !void { | |
| } }, .{}); | ||
| } | ||
|
|
||
| fn requestChildNodes(cmd: anytype) !void { | ||
| const params = (try cmd.params(struct { | ||
| nodeId: Node.Id, | ||
| depth: i32 = 1, | ||
| pierce: bool = false, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May want to warn or so when pierce is set to true that this is not implemented yet |
||
| })) orelse return error.InvalidParams; | ||
|
|
||
| if (params.depth == 0) return error.InvalidParams; | ||
| const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; | ||
| const session_id = bc.session_id orelse return error.SessionIdNotLoaded; | ||
| const node = bc.node_registry.lookup_by_id.get(params.nodeId) orelse { | ||
| return error.InvalidNode; | ||
| }; | ||
|
|
||
| try cmd.sendEvent("DOM.setChildNodes", .{ | ||
| .parentId = node.id, | ||
| .nodes = bc.nodeWriter(node, .{.depth = params.depth, .exclude_root = true}), | ||
| }, .{ | ||
| .session_id = session_id, | ||
| }); | ||
|
|
||
| return cmd.sendResult(null, .{}); | ||
| } | ||
|
|
||
| const testing = @import("../testing.zig"); | ||
|
|
||
| test "cdp.dom: getSearchResults unknown search id" { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DOM.getDocumentI believe uses the undocumented value3by default. So may be good to update the other users in this pr as well, and connect the parameters.For
DOM.describeNodethe default is1, however it would be good to wire it in.performSearchandquerySelectormost likely use the default, but I did not check to confirm