mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-31 17:39:46 +00:00
Merge pull request #2048 from lightpanda-io/feature/semantic-tree-checked-state
SemanticTree: add checked state to node data and output
This commit is contained in:
@@ -95,10 +95,11 @@ const NodeData = struct {
|
|||||||
name: ?[]const u8,
|
name: ?[]const u8,
|
||||||
value: ?[]const u8,
|
value: ?[]const u8,
|
||||||
options: ?[]OptionData = null,
|
options: ?[]OptionData = null,
|
||||||
|
checked: ?bool = null,
|
||||||
xpath: []const u8,
|
xpath: []const u8,
|
||||||
is_interactive: bool,
|
interactive: bool,
|
||||||
is_disabled: bool,
|
disabled: bool,
|
||||||
node_name: []const u8,
|
tag_name: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const WalkContext = struct {
|
const WalkContext = struct {
|
||||||
@@ -152,13 +153,17 @@ fn walk(
|
|||||||
var is_disabled = false;
|
var is_disabled = false;
|
||||||
var value: ?[]const u8 = null;
|
var value: ?[]const u8 = null;
|
||||||
var options: ?[]OptionData = null;
|
var options: ?[]OptionData = null;
|
||||||
var node_name: []const u8 = "text";
|
var checked: ?bool = null;
|
||||||
|
var tag_name: []const u8 = "text";
|
||||||
|
|
||||||
if (node.is(Element)) |el| {
|
if (node.is(Element)) |el| {
|
||||||
node_name = el.getTagNameLower();
|
tag_name = el.getTagNameLower();
|
||||||
|
|
||||||
if (el.is(Element.Html.Input)) |input| {
|
if (el.is(Element.Html.Input)) |input| {
|
||||||
value = input.getValue();
|
value = input.getValue();
|
||||||
|
if (input._input_type == .checkbox or input._input_type == .radio) {
|
||||||
|
checked = input.getChecked();
|
||||||
|
}
|
||||||
if (el.getAttributeSafe(comptime .wrap("list"))) |list_id| {
|
if (el.getAttributeSafe(comptime .wrap("list"))) |list_id| {
|
||||||
options = try extractDataListOptions(list_id, self.page, self.arena);
|
options = try extractDataListOptions(list_id, self.page, self.arena);
|
||||||
}
|
}
|
||||||
@@ -177,7 +182,7 @@ fn walk(
|
|||||||
|
|
||||||
is_disabled = el.isDisabled();
|
is_disabled = el.isDisabled();
|
||||||
} else if (node._type == .document or node._type == .document_fragment) {
|
} else if (node._type == .document or node._type == .document_fragment) {
|
||||||
node_name = "root";
|
tag_name = "root";
|
||||||
}
|
}
|
||||||
|
|
||||||
const initial_xpath_len = ctx.xpath_buffer.items.len;
|
const initial_xpath_len = ctx.xpath_buffer.items.len;
|
||||||
@@ -238,10 +243,11 @@ fn walk(
|
|||||||
.name = name,
|
.name = name,
|
||||||
.value = value,
|
.value = value,
|
||||||
.options = options,
|
.options = options,
|
||||||
|
.checked = checked,
|
||||||
.xpath = xpath,
|
.xpath = xpath,
|
||||||
.is_interactive = is_interactive,
|
.interactive = is_interactive,
|
||||||
.is_disabled = is_disabled,
|
.disabled = is_disabled,
|
||||||
.node_name = node_name,
|
.tag_name = tag_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (should_visit) {
|
if (should_visit) {
|
||||||
@@ -340,7 +346,7 @@ const JsonVisitor = struct {
|
|||||||
try self.jw.write(data.id);
|
try self.jw.write(data.id);
|
||||||
|
|
||||||
try self.jw.objectField("nodeName");
|
try self.jw.objectField("nodeName");
|
||||||
try self.jw.write(data.node_name);
|
try self.jw.write(data.tag_name);
|
||||||
|
|
||||||
try self.jw.objectField("xpath");
|
try self.jw.objectField("xpath");
|
||||||
try self.jw.write(data.xpath);
|
try self.jw.write(data.xpath);
|
||||||
@@ -350,9 +356,9 @@ const JsonVisitor = struct {
|
|||||||
try self.jw.write(1);
|
try self.jw.write(1);
|
||||||
|
|
||||||
try self.jw.objectField("isInteractive");
|
try self.jw.objectField("isInteractive");
|
||||||
try self.jw.write(data.is_interactive);
|
try self.jw.write(data.interactive);
|
||||||
|
|
||||||
if (data.is_disabled) {
|
if (data.disabled) {
|
||||||
try self.jw.objectField("isDisabled");
|
try self.jw.objectField("isDisabled");
|
||||||
try self.jw.write(true);
|
try self.jw.write(true);
|
||||||
}
|
}
|
||||||
@@ -383,6 +389,11 @@ const JsonVisitor = struct {
|
|||||||
try self.jw.endObject();
|
try self.jw.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.checked) |checked| {
|
||||||
|
try self.jw.objectField("checked");
|
||||||
|
try self.jw.write(checked);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.options) |options| {
|
if (data.options) |options| {
|
||||||
try self.jw.objectField("options");
|
try self.jw.objectField("options");
|
||||||
try self.jw.beginArray();
|
try self.jw.beginArray();
|
||||||
@@ -469,8 +480,8 @@ const TextVisitor = struct {
|
|||||||
const is_text_only = std.mem.eql(u8, data.role, "StaticText") or std.mem.eql(u8, data.role, "none") or std.mem.eql(u8, data.role, "generic");
|
const is_text_only = std.mem.eql(u8, data.role, "StaticText") or std.mem.eql(u8, data.role, "none") or std.mem.eql(u8, data.role, "generic");
|
||||||
|
|
||||||
try self.writer.print("{d}", .{data.id});
|
try self.writer.print("{d}", .{data.id});
|
||||||
if (data.is_interactive) {
|
if (data.interactive) {
|
||||||
try self.writer.writeAll(if (data.is_disabled) " [i:disabled]" else " [i]");
|
try self.writer.writeAll(if (data.disabled) " [i:disabled]" else " [i]");
|
||||||
}
|
}
|
||||||
if (!is_text_only) {
|
if (!is_text_only) {
|
||||||
try self.writer.print(" {s}", .{data.role});
|
try self.writer.print(" {s}", .{data.role});
|
||||||
@@ -485,6 +496,14 @@ const TextVisitor = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.checked) |c| {
|
||||||
|
if (c) {
|
||||||
|
try self.writer.writeAll(" [checked]");
|
||||||
|
} else {
|
||||||
|
try self.writer.writeAll(" [unchecked]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data.options) |options| {
|
if (data.options) |options| {
|
||||||
try self.writer.writeAll(" options=[");
|
try self.writer.writeAll(" options=[");
|
||||||
for (options, 0..) |opt, i| {
|
for (options, 0..) |opt, i| {
|
||||||
@@ -527,8 +546,8 @@ pub const NodeDetails = struct {
|
|||||||
tag_name: []const u8,
|
tag_name: []const u8,
|
||||||
role: []const u8,
|
role: []const u8,
|
||||||
name: ?[]const u8,
|
name: ?[]const u8,
|
||||||
is_interactive: bool,
|
interactive: bool,
|
||||||
is_disabled: bool,
|
disabled: bool,
|
||||||
value: ?[]const u8 = null,
|
value: ?[]const u8 = null,
|
||||||
input_type: ?[]const u8 = null,
|
input_type: ?[]const u8 = null,
|
||||||
placeholder: ?[]const u8 = null,
|
placeholder: ?[]const u8 = null,
|
||||||
@@ -556,9 +575,9 @@ pub const NodeDetails = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try jw.objectField("isInteractive");
|
try jw.objectField("isInteractive");
|
||||||
try jw.write(self.is_interactive);
|
try jw.write(self.interactive);
|
||||||
|
|
||||||
if (self.is_disabled) {
|
if (self.disabled) {
|
||||||
try jw.objectField("isDisabled");
|
try jw.objectField("isDisabled");
|
||||||
try jw.write(true);
|
try jw.write(true);
|
||||||
}
|
}
|
||||||
@@ -620,13 +639,18 @@ pub const NodeDetails = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getNodeDetails(node: *Node, registry: *CDPNode.Registry, page: *Page, arena: std.mem.Allocator) !NodeDetails {
|
pub fn getNodeDetails(
|
||||||
|
node: *Node,
|
||||||
|
registry: *CDPNode.Registry,
|
||||||
|
page: *Page,
|
||||||
|
arena: std.mem.Allocator,
|
||||||
|
) !NodeDetails {
|
||||||
const cdp_node = try registry.register(node);
|
const cdp_node = try registry.register(node);
|
||||||
const axn = AXNode.fromNode(node);
|
const axn = AXNode.fromNode(node);
|
||||||
const role = try axn.getRole();
|
const role = try axn.getRole();
|
||||||
const name = try axn.getName(page, arena);
|
const name = try axn.getName(page, arena);
|
||||||
|
|
||||||
var is_interactive_val = false;
|
var is_interactive = false;
|
||||||
var is_disabled = false;
|
var is_disabled = false;
|
||||||
var tag_name: []const u8 = "text";
|
var tag_name: []const u8 = "text";
|
||||||
var value: ?[]const u8 = null;
|
var value: ?[]const u8 = null;
|
||||||
@@ -670,7 +694,7 @@ pub fn getNodeDetails(node: *Node, registry: *CDPNode.Registry, page: *Page, are
|
|||||||
const listener_targets = try interactive.buildListenerTargetMap(page, arena);
|
const listener_targets = try interactive.buildListenerTargetMap(page, arena);
|
||||||
var pointer_events_cache: Element.PointerEventsCache = .empty;
|
var pointer_events_cache: Element.PointerEventsCache = .empty;
|
||||||
if (interactive.classifyInteractivity(page, el, html_el, listener_targets, &pointer_events_cache) != null) {
|
if (interactive.classifyInteractivity(page, el, html_el, listener_targets, &pointer_events_cache) != null) {
|
||||||
is_interactive_val = true;
|
is_interactive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -680,8 +704,8 @@ pub fn getNodeDetails(node: *Node, registry: *CDPNode.Registry, page: *Page, are
|
|||||||
.tag_name = tag_name,
|
.tag_name = tag_name,
|
||||||
.role = role,
|
.role = role,
|
||||||
.name = name,
|
.name = name,
|
||||||
.is_interactive = is_interactive_val,
|
.interactive = is_interactive,
|
||||||
.is_disabled = is_disabled,
|
.disabled = is_disabled,
|
||||||
.value = value,
|
.value = value,
|
||||||
.input_type = input_type,
|
.input_type = input_type,
|
||||||
.placeholder = placeholder,
|
.placeholder = placeholder,
|
||||||
|
|||||||
Reference in New Issue
Block a user