Chromium Code Reviews| 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 e7da83a0d7a79eec8967ef9a6cbe45e95efbd1f1..66c9d8be80fd84fe673b329ffde4bd2adc060f25 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js |
| @@ -13,31 +13,119 @@ WebInspector.AXTreePane = function() |
| this._treeOutline = this.createTreeOutline(); |
| this.element.classList.add("accessibility-computed"); |
| + |
| + this._expandedNodes = new Set(); |
| }; |
| WebInspector.AXTreePane.prototype = { |
| /** |
| - * @param {!Array<!WebInspector.AccessibilityNode>} nodes |
| + * @param {?WebInspector.AccessibilityNode} axNode |
| + * @override |
| */ |
| - setAXNodeAndAncestors: function(nodes) |
| + setAXNode : function(axNode) |
| { |
| - this._nodes = nodes; |
| + 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.domNode(), 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); |
| + if (this.isExpanded(parent.domNode())) |
| + parentTreeElement.appendSiblings(); |
| + else |
| + parentTreeElement.appendChild(inspectedNodeTreeElement); |
| + previousTreeElement.appendChild(parentTreeElement); |
| + previousTreeElement.expand(); |
| + previousTreeElement = parentTreeElement; |
| + } else { |
| + previousTreeElement.appendChild(inspectedNodeTreeElement); |
| } |
| - previous.selectable = true; |
| - previous.select(true /* omitFocus */); |
| + |
| + previousTreeElement.expand(); |
| + |
| + for (var child of axNode.children()) { |
| + var childTreeElement = new WebInspector.AXNodeTreeElement(child, this); |
| + inspectedNodeTreeElement.appendChild(childTreeElement); |
| + } |
| + |
| + inspectedNodeTreeElement.selectable = true; |
| + inspectedNodeTreeElement.select(!this._selectedByUser /* omitFocus */, false); |
| + if (this.isExpanded(axNode.domNode())) |
| + inspectedNodeTreeElement.expand(); |
| + this.clearSelectedByUser(); |
| + }, |
| + |
| + /** |
| + * @param {boolean} selectedByUser |
| + */ |
| + setSelectedByUser: function(selectedByUser) |
| + { |
| + this._selectedByUser = true; |
| + }, |
| + |
| + clearSelectedByUser: function() |
| + { |
| + delete this._selectedByUser; |
| + }, |
| + |
| + /** |
| + * @return {!WebInspector.Target} |
| + */ |
| + target: function() |
| + { |
| + return this.node().target(); |
| + }, |
| + |
| + /** |
| + * @param {?WebInspector.DOMNode} domNode |
| + * @param {boolean} expanded |
| + */ |
| + setExpanded: function(domNode, expanded) |
| + { |
| + if (!domNode) |
| + return; |
| + if (expanded) |
| + this._expandedNodes.add(domNode.id); |
| + else |
| + this._expandedNodes.delete(domNode.id); |
| + }, |
| + |
| + /** |
| + * @param {?WebInspector.DOMNode} domNode |
| + * @return {boolean} |
| + */ |
| + isExpanded: function(domNode) |
| + { |
| + if (!domNode) |
| + return false; |
| + |
| + return this._expandedNodes.has(domNode.id); |
| }, |
| __proto__: WebInspector.AccessibilitySubPane.prototype |
| @@ -47,9 +135,9 @@ WebInspector.AXTreePane.prototype = { |
| * @constructor |
| * @extends {TreeElement} |
| * @param {!WebInspector.AccessibilityNode} axNode |
| - * @param {!WebInspector.Target} target |
| + * @param {!WebInspector.AXTreePane} treePane |
| */ |
| -WebInspector.AXNodeTreeElement = function(axNode, target) |
| +WebInspector.AXNodeTreeElement = function(axNode, treePane) |
| { |
| // Pass an empty title, the title gets made later in onattach. |
| TreeElement.call(this, ""); |
| @@ -57,8 +145,8 @@ WebInspector.AXNodeTreeElement = function(axNode, target) |
| /** @type {!WebInspector.AccessibilityNode} */ |
| this._axNode = axNode; |
| - /** @type {!WebInspector.Target} */ |
| - this._target = target; |
| + /** @type {!WebInspector.AXTreePane} */ |
| + this._treePane = treePane; |
| this.selectable = false; |
| }; |
| @@ -71,6 +159,52 @@ WebInspector.AXNodeTreeElement.RoleStyles = { |
| WebInspector.AXNodeTreeElement.prototype = { |
| /** |
| + * @return {!WebInspector.AccessibilityNode} |
| + */ |
| + axNode: function() |
| + { |
| + return this._axNode; |
| + }, |
| + |
| + /** |
| + * @param {boolean} inspected |
| + */ |
| + setInspected: function(inspected) |
| + { |
| + if (inspected) |
| + this.listItemElement.classList.add("inspected"); |
| + else |
| + this.listItemElement.classList.remove("inspected"); |
| + }, |
| + |
| + /** |
| + * @override |
| + * @return {boolean} |
| + */ |
| + onenter: function() |
| + { |
| + this.inspectDOMNode(); |
| + return true; |
| + }, |
| + |
| + /** |
| + * @override |
| + * @param {!Event} event |
| + * @return {boolean} |
| + */ |
| + ondblclick: function(event) |
| + { |
| + this.inspectDOMNode(); |
| + return true; |
| + }, |
| + |
| + inspectDOMNode: function() |
| + { |
| + this._treePane.setSelectedByUser(true); |
| + WebInspector.Revealer.reveal(this._axNode.domNode()); |
| + }, |
| + |
| + /** |
| * @override |
| */ |
| onattach: function() |
| @@ -86,11 +220,44 @@ WebInspector.AXNodeTreeElement.prototype = { |
| this._appendIgnoredNodeElement(); |
| } else { |
| this._appendRoleElement(this._axNode.role()); |
| - if ("name" in this._axNode && this._axNode.name().value) { |
| + if (this._axNode && this._axNode.name().value) { |
| this.listItemElement.createChild("span", "separator").textContent = "\u00A0"; |
| this._appendNameElement(/** @type {string} */ (this._axNode.name().value)); |
| } |
| } |
| + |
| + if (this._axNode.hasOnlyUnloadedChildren()) { |
| + this._hasOnlyUnloadedChildren = true; |
| + this.listItemElement.classList.add("children-unloaded"); |
| + this.setExpandable(true); |
| + } else { |
| + this.setExpandable(!!this._axNode.numChildren()); |
| + } |
| + }, |
| + |
| + /** |
| + * @override |
| + */ |
| + expand: function() |
| + { |
| + if (this._hasOnlyUnloadedChildren) |
| + return; |
| + |
| + this._treePane.setExpanded(this._axNode.domNode(), true); |
| + TreeElement.prototype.expand.call(this); |
| + }, |
| + |
| + /** |
| + * @override |
| + */ |
| + collapse: function() |
| + { |
| + if (this._hasOnlyUnloadedChildren) |
| + return; |
| + |
| + if (this._treePane) |
| + this._treePane.setExpanded(this._axNode.domNode(), false); |
| + TreeElement.prototype.collapse.call(this); |
| }, |
| /** |
| @@ -127,5 +294,126 @@ WebInspector.AXNodeTreeElement.prototype = { |
| this.listItemElement.appendChild(ignoredNodeElement); |
| }, |
| + /** |
| + * @param {boolean=} omitFocus |
| + * @param {boolean=} selectedByUser |
| + * @return {boolean} |
| + * @override |
| + */ |
| + select: function(omitFocus, selectedByUser) |
| + { |
| + this._ensureSelection(); |
| + |
| + this._treePane.setSelectedByUser(!!selectedByUser); |
| + if (selectedByUser) |
| + WebInspector.context.setFlavor(WebInspector.AccessibilityNode, this._axNode); |
|
dgozman
2016/10/31 21:36:30
Where is this flavor being used?
aboxhall
2016/10/31 22:45:15
Ah, thanks for catching - I was using it earlier b
|
| + |
| + return TreeElement.prototype.select.call(this, omitFocus, selectedByUser); |
| + }, |
| + |
| __proto__: TreeElement.prototype |
| }; |
| + |
| +/** |
| + * @constructor |
| + * @param {!WebInspector.AXNodeTreeParentElement} treeElement |
| + */ |
| +WebInspector.ExpandSiblingsButton = function(treeElement) |
| +{ |
| + this._treeElement = treeElement; |
| + |
| + this.element = createElementWithClass("button", "expand-siblings"); |
| + this.element.addEventListener("mousedown", this._handleMouseDown.bind(this)); |
| +}; |
| + |
| +WebInspector.ExpandSiblingsButton.prototype = { |
| + _handleMouseDown: function(event) { |
|
dgozman
2016/10/31 21:36:30
style: { on next line (here and below)
aboxhall
2016/10/31 22:45:15
Done.
|
| + this._treeElement.expandSiblings(); |
| + event.consume(); |
| + } |
| +}; |
| + |
| + |
| +/** |
| + * @constructor |
| + * @extends {WebInspector.AXNodeTreeElement} |
| + * @param {!WebInspector.AccessibilityNode} axNode |
| + * @param {!WebInspector.AXNodeTreeElement} inspectedNodeTreeElement |
| + * @param {!WebInspector.AXTreePane} treePane |
| + */ |
| +WebInspector.AXNodeTreeParentElement = function(axNode, inspectedNodeTreeElement, treePane) |
| +{ |
| + WebInspector.AXNodeTreeElement.call(this, axNode, treePane); |
| + |
| + this._inspectedNodeTreeElement = inspectedNodeTreeElement; |
| + this._expandSibingsButton = new WebInspector.ExpandSiblingsButton(this); |
| + this._partiallyExpanded = false; |
| +}; |
| + |
| +WebInspector.AXNodeTreeParentElement.prototype = { |
| + /** |
| + * @override |
| + */ |
| + onattach: function(){ |
| + WebInspector.AXNodeTreeElement.prototype.onattach.call(this); |
| + if (this._treePane.isExpanded(this._axNode.domNode())) |
| + this._listItemNode.classList.add("siblings-expanded"); |
| + if (this._axNode.numChildren() > 1) |
| + this._listItemNode.appendChild(this._expandSibingsButton.element); |
| + }, |
| + |
| + /** |
| + * @param {boolean} altKey |
| + * @return {boolean} |
| + * @override |
| + */ |
| + descendOrExpand: function(altKey) |
| + { |
| + if (!this.expanded || !this._partiallyExpanded) |
| + return TreeElement.prototype.descendOrExpand.call(this, altKey); |
| + |
| + this.expandSiblings(); |
| + if (altKey) |
| + this.expandRecursively(); |
| + return true; |
| + }, |
| + |
| + /** |
| + * @override |
| + */ |
| + expand: function() |
| + { |
| + TreeElement.prototype.expand.call(this); |
| + this._partiallyExpanded = true; |
| + }, |
| + |
| + expandSiblings: function() |
| + { |
| + this._listItemNode.classList.add("siblings-expanded"); |
| + this.appendSiblings(); |
| + this.expanded = true; |
| + this._partiallyExpanded = false; |
| + this._treePane.setExpanded(this._axNode.domNode(), true); |
| + }, |
| + |
| + appendSiblings: function() |
| + { |
| + 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++); |
| + } |
| + }, |
| + |
| + __proto__: WebInspector.AXNodeTreeElement.prototype |
| +}; |