| Index: third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
|
| index 9de87bb1eb8510475b4c2b11902734ca78af7ab8..3e3e482df56b3f7ddae93cd688fd118b07f58114 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js
|
| @@ -11,28 +11,133 @@ WebInspector.AXTreePane = class extends WebInspector.AccessibilitySubPane {
|
| this._treeOutline = this.createTreeOutline();
|
|
|
| this.element.classList.add('accessibility-computed');
|
| +
|
| + this._expandedNodes = new Set();
|
| }
|
|
|
| /**
|
| - * @param {!Array<!WebInspector.AccessibilityNode>} nodes
|
| + * @param {?WebInspector.AccessibilityNode} axNode
|
| + * @override
|
| */
|
| - setAXNodeAndAncestors(nodes) {
|
| - this._nodes = nodes;
|
| + setAXNode(axNode) {
|
| + this._axNode = axNode;
|
|
|
| - var target = this.node().target();
|
| var treeOutline = this._treeOutline;
|
| treeOutline.removeChildren();
|
| +
|
| + // TODO(aboxhall): show no node UI
|
| + if (!axNode)
|
| + return;
|
| +
|
| treeOutline.element.classList.remove('hidden');
|
| - var previous = treeOutline.rootElement();
|
| - while (nodes.length) {
|
| - var ancestor = nodes.pop();
|
| - var ancestorTreeElement = new WebInspector.AXNodeTreeElement(ancestor, target);
|
| - previous.appendChild(ancestorTreeElement);
|
| - previous.expand();
|
| - previous = ancestorTreeElement;
|
| + var previousTreeElement = treeOutline.rootElement();
|
| + var inspectedNodeTreeElement = new WebInspector.AXNodeTreeElement(axNode, this);
|
| + inspectedNodeTreeElement.setInspected(true);
|
| +
|
| + var parent = axNode.parentNode();
|
| + if (parent) {
|
| + this.setExpanded(parent.backendDOMNodeId(), false);
|
| +
|
| + var chain = [];
|
| + var ancestor = parent.parentNode();
|
| + while (ancestor) {
|
| + chain.unshift(ancestor);
|
| + ancestor = ancestor.parentNode();
|
| + }
|
| + for (var ancestorNode of chain) {
|
| + var ancestorTreeElement = new WebInspector.AXNodeTreeElement(ancestorNode, this);
|
| + previousTreeElement.appendChild(ancestorTreeElement);
|
| + previousTreeElement.expand();
|
| + previousTreeElement = ancestorTreeElement;
|
| + }
|
| + var parentTreeElement = new WebInspector.AXNodeTreeParentElement(parent, inspectedNodeTreeElement, this);
|
| + previousTreeElement.appendChild(parentTreeElement);
|
| + if (this.isExpanded(parent.backendDOMNodeId()))
|
| + parentTreeElement.appendSiblings();
|
| + else
|
| + parentTreeElement.appendChild(inspectedNodeTreeElement);
|
| + previousTreeElement.expand();
|
| + previousTreeElement = parentTreeElement;
|
| + } else {
|
| + previousTreeElement.appendChild(inspectedNodeTreeElement);
|
| + }
|
| +
|
| + previousTreeElement.expand();
|
| +
|
| + for (var child of axNode.children()) {
|
| + var childTreeElement = new WebInspector.AXNodeTreeElement(child, this);
|
| + inspectedNodeTreeElement.appendChild(childTreeElement);
|
| }
|
| - previous.selectable = true;
|
| - previous.select(true /* omitFocus */);
|
| +
|
| + inspectedNodeTreeElement.selectable = true;
|
| + inspectedNodeTreeElement.select(!this._selectedByUser /* omitFocus */, false);
|
| + if (this.isExpanded(axNode.backendDOMNodeId()))
|
| + inspectedNodeTreeElement.expand();
|
| + this.clearSelectedByUser();
|
| + }
|
| +
|
| + /**
|
| + * @param {boolean} selectedByUser
|
| + */
|
| + setSelectedByUser(selectedByUser) {
|
| + this._selectedByUser = true;
|
| + }
|
| +
|
| + clearSelectedByUser() {
|
| + delete this._selectedByUser;
|
| + }
|
| +
|
| + /**
|
| + * @return {!WebInspector.Target}
|
| + */
|
| + target() {
|
| + return this.node().target();
|
| + }
|
| +
|
| + /**
|
| + * @param {?number} backendDOMNodeId
|
| + * @param {boolean} expanded
|
| + */
|
| + setExpanded(backendDOMNodeId, expanded) {
|
| + if (!backendDOMNodeId)
|
| + return;
|
| + if (expanded)
|
| + this._expandedNodes.add(backendDOMNodeId);
|
| + else
|
| + this._expandedNodes.delete(backendDOMNodeId);
|
| + }
|
| +
|
| + /**
|
| + * @param {?number} backendDOMNodeId
|
| + * @return {boolean}
|
| + */
|
| + isExpanded(backendDOMNodeId) {
|
| + if (!backendDOMNodeId)
|
| + return false;
|
| +
|
| + return this._expandedNodes.has(backendDOMNodeId);
|
| + }
|
| +};
|
| +
|
| +WebInspector.InspectNodeButton = class {
|
| + /**
|
| + * @param {!WebInspector.AccessibilityNode} axNode
|
| + * @param {!WebInspector.AXTreePane} treePane
|
| + */
|
| + constructor(axNode, treePane) {
|
| + this._axNode = axNode;
|
| + this._treePane = treePane;
|
| +
|
| + this.element = createElementWithClass('button', 'inspect-dom-node');
|
| + this.element.addEventListener('mousedown', this._handleMouseDown.bind(this));
|
| + }
|
| +
|
| + /**
|
| + * @param {!Event} event
|
| + */
|
| + _handleMouseDown(event) {
|
| + this._treePane.setSelectedByUser(true);
|
| + WebInspector.Revealer.reveal(this._axNode.deferredDOMNode());
|
| }
|
| };
|
|
|
| @@ -42,19 +147,61 @@ WebInspector.AXTreePane = class extends WebInspector.AccessibilitySubPane {
|
| WebInspector.AXNodeTreeElement = class extends TreeElement {
|
| /**
|
| * @param {!WebInspector.AccessibilityNode} axNode
|
| - * @param {!WebInspector.Target} target
|
| + * @param {!WebInspector.AXTreePane} treePane
|
| */
|
| - constructor(axNode, target) {
|
| + constructor(axNode, treePane) {
|
| // Pass an empty title, the title gets made later in onattach.
|
| super('');
|
|
|
| /** @type {!WebInspector.AccessibilityNode} */
|
| this._axNode = axNode;
|
|
|
| - /** @type {!WebInspector.Target} */
|
| - this._target = target;
|
| + /** @type {!WebInspector.AXTreePane} */
|
| + this._treePane = treePane;
|
|
|
| - this.selectable = false;
|
| + this.selectable = true;
|
| +
|
| + this._inspectNodeButton =
|
| + new WebInspector.InspectNodeButton(axNode, treePane);
|
| + }
|
| +
|
| + /**
|
| + * @return {!WebInspector.AccessibilityNode}
|
| + */
|
| + axNode() {
|
| + return this._axNode;
|
| + }
|
| +
|
| + /**
|
| + * @param {boolean} inspected
|
| + */
|
| + setInspected(inspected) {
|
| + this._inspected = inspected;
|
| + this.listItemElement.classList.toggle('inspected', this._inspected);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {boolean}
|
| + */
|
| + onenter() {
|
| + this.inspectDOMNode();
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {!Event} event
|
| + * @return {boolean}
|
| + */
|
| + ondblclick(event) {
|
| + this.inspectDOMNode();
|
| + return true;
|
| + }
|
| +
|
| + inspectDOMNode() {
|
| + this._treePane.setSelectedByUser(true);
|
| + WebInspector.Revealer.reveal(this._axNode.deferredDOMNode());
|
| }
|
|
|
| /**
|
| @@ -71,11 +218,45 @@ WebInspector.AXNodeTreeElement = class extends TreeElement {
|
| this._appendIgnoredNodeElement();
|
| } else {
|
| this._appendRoleElement(this._axNode.role());
|
| - if ('name' in this._axNode && this._axNode.name().value) {
|
| + if (this._axNode.name().value) {
|
| this.listItemElement.createChild('span', 'separator').textContent = '\u00A0';
|
| this._appendNameElement(/** @type {string} */ (this._axNode.name().value));
|
| }
|
| }
|
| +
|
| + if (this._axNode.hasOnlyUnloadedChildren()) {
|
| + this.listItemElement.classList.add('children-unloaded');
|
| + this.setExpandable(true);
|
| + } else {
|
| + this.setExpandable(!!this._axNode.numChildren());
|
| + }
|
| +
|
| + if (!this._axNode.isDOMNode())
|
| + this.listItemElement.classList.add('no-dom-node');
|
| + this.listItemElement.appendChild(this._inspectNodeButton.element);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + expand() {
|
| + if (!this._axNode || this._axNode.hasOnlyUnloadedChildren())
|
| + return;
|
| +
|
| + this._treePane.setExpanded(this._axNode.backendDOMNodeId(), true);
|
| + super.expand();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + collapse() {
|
| + if (!this._axNode || this._axNode.hasOnlyUnloadedChildren())
|
| + return;
|
| +
|
| + if (this._treePane)
|
| + this._treePane.setExpanded(this._axNode.backendDOMNodeId(), false);
|
| + super.collapse();
|
| }
|
|
|
| /**
|
| @@ -108,6 +289,18 @@ WebInspector.AXNodeTreeElement = class extends TreeElement {
|
| ignoredNodeElement.classList.add('ax-tree-ignored-node');
|
| this.listItemElement.appendChild(ignoredNodeElement);
|
| }
|
| +
|
| + /**
|
| + * @param {boolean=} omitFocus
|
| + * @param {boolean=} selectedByUser
|
| + * @return {boolean}
|
| + * @override
|
| + */
|
| + select(omitFocus, selectedByUser) {
|
| + this._treePane.setSelectedByUser(!!selectedByUser);
|
| +
|
| + return super.select(omitFocus, selectedByUser);
|
| + }
|
| };
|
|
|
| /** @type {!Object<string, string>} */
|
| @@ -115,3 +308,110 @@ WebInspector.AXNodeTreeElement.RoleStyles = {
|
| internalRole: 'ax-internal-role',
|
| role: 'ax-role',
|
| };
|
| +
|
| +/**
|
| + * @unrestricted
|
| + */
|
| +WebInspector.ExpandSiblingsButton = class {
|
| + /**
|
| + * @param {!WebInspector.AXNodeTreeParentElement} treeElement
|
| + * @param {number} numSiblings
|
| + */
|
| + constructor(treeElement, numSiblings) {
|
| + this._treeElement = treeElement;
|
| +
|
| + this.element = createElementWithClass('button', 'expand-siblings');
|
| + this.element.textContent = WebInspector.UIString(
|
| + (numSiblings === 1 ? '+ %d node' : '+ %d nodes'), numSiblings);
|
| + this.element.addEventListener('mousedown', this._handleMouseDown.bind(this));
|
| + }
|
| +
|
| + /**
|
| + * @param {!Event} event
|
| + */
|
| + _handleMouseDown(event) {
|
| + this._treeElement.expandSiblings();
|
| + event.consume();
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * @unrestricted
|
| + */
|
| +WebInspector.AXNodeTreeParentElement = class extends WebInspector.AXNodeTreeElement {
|
| + /**
|
| + * @param {!WebInspector.AccessibilityNode} axNode
|
| + * @param {!WebInspector.AXNodeTreeElement} inspectedNodeTreeElement
|
| + * @param {!WebInspector.AXTreePane} treePane
|
| + */
|
| + constructor(axNode, inspectedNodeTreeElement, treePane) {
|
| + super(axNode, treePane);
|
| +
|
| + this._inspectedNodeTreeElement = inspectedNodeTreeElement;
|
| + var numSiblings = axNode.children().length - 1;
|
| + this._expandSiblingsButton = new WebInspector.ExpandSiblingsButton(this, numSiblings);
|
| + this._partiallyExpanded = false;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + onattach() {
|
| + super.onattach();
|
| + if (this._treePane.isExpanded(this._axNode.backendDOMNodeId()))
|
| + this._listItemNode.classList.add('siblings-expanded');
|
| + if (this._axNode.numChildren() > 1) {
|
| + this._listItemNode.insertBefore(this._expandSiblingsButton.element,
|
| + this._inspectNodeButton.element);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {boolean} altKey
|
| + * @return {boolean}
|
| + * @override
|
| + */
|
| + descendOrExpand(altKey) {
|
| + if (!this.expanded || !this._partiallyExpanded)
|
| + return super.descendOrExpand(altKey);
|
| +
|
| + this.expandSiblings();
|
| + if (altKey)
|
| + this.expandRecursively();
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + expand() {
|
| + super.expand();
|
| + this._partiallyExpanded = true;
|
| + }
|
| +
|
| + expandSiblings() {
|
| + this._listItemNode.classList.add('siblings-expanded');
|
| + this.appendSiblings();
|
| + this.expanded = true;
|
| + this._partiallyExpanded = false;
|
| + this._treePane.setExpanded(this._axNode.backendDOMNodeId(), true);
|
| + }
|
| +
|
| + appendSiblings() {
|
| + var inspectedAXNode = this._inspectedNodeTreeElement.axNode();
|
| + var nextIndex = 0;
|
| + var foundInspectedNode = false;
|
| + for (var sibling of this._axNode.children()) {
|
| + var siblingTreeElement = null;
|
| + if (sibling === inspectedAXNode) {
|
| + foundInspectedNode = true;
|
| + continue;
|
| + }
|
| + siblingTreeElement = new WebInspector.AXNodeTreeElement(sibling, this._treePane);
|
| + if (foundInspectedNode)
|
| + this.appendChild(siblingTreeElement);
|
| + else
|
| + this.insertChild(siblingTreeElement, nextIndex++);
|
| + }
|
| + }
|
| +};
|
|
|