mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-11-06 21:29:31 +08:00
They are not needed now we use Lit static tags. Bug: 1153077 Change-Id: Ic5a7971e9e0dfc788d774b84d99c2538f6a3eadb Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2896897 Commit-Queue: Jack Franklin <jacktfranklin@chromium.org> Auto-Submit: Jack Franklin <jacktfranklin@chromium.org> Reviewed-by: Tim van der Lippe <tvanderlippe@chromium.org>
154 lines
6.1 KiB
TypeScript
154 lines
6.1 KiB
TypeScript
// Copyright 2020 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import * as Common from '../../core/common/common.js';
|
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
import * as TreeOutline from '../../ui/components/tree_outline/tree_outline.js';
|
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
import type * as LitHtml from '../../ui/lit-html/lit-html.js';
|
|
|
|
import * as ElementsComponents from './components/components.js';
|
|
|
|
export class AccessibilityTreeView extends UI.Widget.VBox {
|
|
private readonly accessibilityTreeComponent =
|
|
new TreeOutline.TreeOutline.TreeOutline<SDK.AccessibilityModel.AccessibilityNode>();
|
|
private treeData: ElementsComponents.AccessibilityTreeUtils.AXTreeNode[] = [];
|
|
private readonly toggleButton: HTMLButtonElement;
|
|
private accessibilityModel: SDK.AccessibilityModel.AccessibilityModel|null = null;
|
|
private rootAXNode: SDK.AccessibilityModel.AccessibilityNode|null = null;
|
|
private selectedTreeNode: ElementsComponents.AccessibilityTreeUtils.AXTreeNode|null = null;
|
|
private inspectedDOMNode: SDK.DOMModel.DOMNode|null = null;
|
|
|
|
constructor(toggleButton: HTMLButtonElement) {
|
|
super();
|
|
// toggleButton is bound to a click handler on ElementsPanel to switch between the DOM tree
|
|
// and accessibility tree views.
|
|
this.toggleButton = toggleButton;
|
|
this.contentElement.appendChild(this.toggleButton);
|
|
this.contentElement.appendChild(this.accessibilityTreeComponent);
|
|
|
|
// The DOM tree and accessibility are kept in sync as much as possible, so
|
|
// on node selection, update the currently inspected node and reveal in the
|
|
// DOM tree.
|
|
this.accessibilityTreeComponent.addEventListener('itemselected', (event: Event) => {
|
|
const evt = event as TreeOutline.TreeOutline.ItemSelectedEvent<SDK.AccessibilityModel.AccessibilityNode>;
|
|
const axNode = evt.data.node.treeNodeData;
|
|
if (!axNode.isDOMNode()) {
|
|
return;
|
|
}
|
|
const deferredNode = axNode.deferredDOMNode();
|
|
if (deferredNode) {
|
|
deferredNode.resolve(domNode => {
|
|
if (domNode && domNode.nodeName() === '#document') {
|
|
return;
|
|
}
|
|
Common.Revealer.reveal(domNode, true /* omitFocus */);
|
|
});
|
|
}
|
|
|
|
// Highlight the node as well, for keyboard navigation.
|
|
evt.data.node.treeNodeData.highlightDOMNode();
|
|
});
|
|
|
|
this.accessibilityTreeComponent.addEventListener('itemmouseover', (event: Event) => {
|
|
const evt = event as TreeOutline.TreeOutline.ItemMouseOverEvent<SDK.AccessibilityModel.AccessibilityNode>;
|
|
evt.data.node.treeNodeData.highlightDOMNode();
|
|
});
|
|
|
|
this.accessibilityTreeComponent.addEventListener('itemmouseout', () => {
|
|
SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
|
|
});
|
|
}
|
|
|
|
wasShown(): void {
|
|
if (this.selectedTreeNode) {
|
|
this.accessibilityTreeComponent.expandToAndSelectTreeNode(this.selectedTreeNode);
|
|
}
|
|
}
|
|
|
|
setAccessibilityModel(model: SDK.AccessibilityModel.AccessibilityModel|null): void {
|
|
this.accessibilityModel = model;
|
|
this.refreshAccessibilityTree();
|
|
}
|
|
|
|
async refreshAccessibilityTree(): Promise<void> {
|
|
if (!this.accessibilityModel) {
|
|
return;
|
|
}
|
|
|
|
const root = await this.accessibilityModel.requestRootNode();
|
|
if (!root) {
|
|
return;
|
|
}
|
|
|
|
this.rootAXNode = root;
|
|
this.treeData = [ElementsComponents.AccessibilityTreeUtils.sdkNodeToAXTreeNode(this.rootAXNode)];
|
|
|
|
this.accessibilityTreeComponent.data = {
|
|
defaultRenderer: (node): LitHtml.TemplateResult =>
|
|
ElementsComponents.AccessibilityTreeUtils.accessibilityNodeRenderer(node),
|
|
tree: this.treeData,
|
|
};
|
|
|
|
this.accessibilityTreeComponent.expandRecursively(2);
|
|
this.selectedTreeNode = this.treeData[0];
|
|
}
|
|
|
|
// Given a selected DOM node, asks the model to load the missing subtree from the root to the
|
|
// selected node and then re-renders the tree.
|
|
async loadSubTreeIntoAccessibilityModel(selectedNode: SDK.DOMModel.DOMNode): Promise<void> {
|
|
if (!this.accessibilityModel) {
|
|
return;
|
|
}
|
|
|
|
this.inspectedDOMNode = selectedNode;
|
|
|
|
// If this node has been loaded previously, the accessibility tree will return it's cached node.
|
|
// Eventually we'll need some mechanism for forcing it to fetch a new node when we are subscribing
|
|
// for updates, but TBD later.
|
|
// EG for a backend tree like:
|
|
//
|
|
// A*
|
|
// B
|
|
// C
|
|
// D
|
|
// E
|
|
// Where only A is already loaded into the model, calling requestAndLoadSubTreeToNode(C) will
|
|
// load [A, B, D, C] into the model, and return C.
|
|
const inspectedAXNode = await this.accessibilityModel.requestAndLoadSubTreeToNode(selectedNode);
|
|
if (!inspectedAXNode) {
|
|
return;
|
|
}
|
|
|
|
this.accessibilityTreeComponent.data = {
|
|
defaultRenderer: (node): LitHtml.TemplateResult =>
|
|
ElementsComponents.AccessibilityTreeUtils.accessibilityNodeRenderer(node),
|
|
tree: this.treeData,
|
|
};
|
|
|
|
// These nodes require a special case, as they don't have an unignored node in the
|
|
// accessibility tree. Someone inspecting these in the DOM is probably expecting to
|
|
// be focused on the root WebArea of the accessibility tree.
|
|
// TODO(meredithl): Fix for when the inspected node is ingored in the accessibility
|
|
// tree. Eg, inspecting <head> in the DOM tree.
|
|
if (selectedNode.nodeName() === 'BODY' || selectedNode.nodeName() === 'HTML') {
|
|
this.accessibilityTreeComponent.expandToAndSelectTreeNode(this.treeData[0]);
|
|
this.selectedTreeNode = this.treeData[0];
|
|
return;
|
|
}
|
|
|
|
this.selectedTreeNode = ElementsComponents.AccessibilityTreeUtils.sdkNodeToAXTreeNode(inspectedAXNode);
|
|
this.accessibilityTreeComponent.expandToAndSelectTreeNode(this.selectedTreeNode);
|
|
}
|
|
|
|
// Selected node in the DOM has changed, and the corresponding accessibility node may be
|
|
// unloaded. We probably only want to do this when the AccessibilityTree is visible.
|
|
async selectedNodeChanged(inspectedNode: SDK.DOMModel.DOMNode): Promise<void> {
|
|
if (inspectedNode === this.inspectedDOMNode) {
|
|
return;
|
|
}
|
|
await this.loadSubTreeIntoAccessibilityModel(inspectedNode);
|
|
}
|
|
}
|