mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #888 from lightpanda-io/cdp_dom_requestChildNodes
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Add support for CDP's DOM.requestChildNodes
This commit is contained in:
143
src/cdp/Node.zig
143
src/cdp/Node.zig
@@ -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 {
|
||||
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 {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,10 +406,11 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
return &self.isolated_world.?;
|
||||
}
|
||||
|
||||
pub fn nodeWriter(self: *Self, node: *const Node, opts: Node.Writer.Opts) Node.Writer {
|
||||
pub fn nodeWriter(self: *Self, root: *const Node, opts: Node.Writer.Opts) Node.Writer {
|
||||
return .{
|
||||
.node = node,
|
||||
.opts = opts,
|
||||
.root = root,
|
||||
.depth = opts.depth,
|
||||
.exclude_root = opts.exclude_root,
|
||||
.registry = &self.node_registry,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})) 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" {
|
||||
|
||||
Reference in New Issue
Block a user