Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(384)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/accessibility/AXTreePane.js

Issue 2390783006: [DevTools] Accessibility: Show siblings and children of selected node (Closed)
Patch Set: Rebase tests again and be consistent about backendDOMNodeId Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 /** 4 /**
5 * @unrestricted 5 * @unrestricted
6 */ 6 */
7 WebInspector.AXTreePane = class extends WebInspector.AccessibilitySubPane { 7 WebInspector.AXTreePane = class extends WebInspector.AccessibilitySubPane {
8 constructor() { 8 constructor() {
9 super(WebInspector.UIString('Accessibility Tree')); 9 super(WebInspector.UIString('Accessibility Tree'));
10 10
11 this._treeOutline = this.createTreeOutline(); 11 this._treeOutline = this.createTreeOutline();
12 12
13 this.element.classList.add('accessibility-computed'); 13 this.element.classList.add('accessibility-computed');
14
15 this._expandedNodes = new Set();
14 } 16 }
15 17
16 /** 18 /**
17 * @param {!Array<!WebInspector.AccessibilityNode>} nodes 19 * @param {?WebInspector.AccessibilityNode} axNode
20 * @override
18 */ 21 */
19 setAXNodeAndAncestors(nodes) { 22 setAXNode(axNode) {
20 this._nodes = nodes; 23 this._axNode = axNode;
21 24
22 var target = this.node().target();
23 var treeOutline = this._treeOutline; 25 var treeOutline = this._treeOutline;
24 treeOutline.removeChildren(); 26 treeOutline.removeChildren();
27
28 // TODO(aboxhall): show no node UI
29 if (!axNode)
30 return;
31
25 treeOutline.element.classList.remove('hidden'); 32 treeOutline.element.classList.remove('hidden');
26 var previous = treeOutline.rootElement(); 33 var previousTreeElement = treeOutline.rootElement();
27 while (nodes.length) { 34 var inspectedNodeTreeElement = new WebInspector.AXNodeTreeElement(axNode, th is);
28 var ancestor = nodes.pop(); 35 inspectedNodeTreeElement.setInspected(true);
29 var ancestorTreeElement = new WebInspector.AXNodeTreeElement(ancestor, tar get); 36
30 previous.appendChild(ancestorTreeElement); 37 var parent = axNode.parentNode();
31 previous.expand(); 38 if (parent) {
32 previous = ancestorTreeElement; 39 this.setExpanded(parent.backendDOMNodeId(), false);
40
41 var chain = [];
42 var ancestor = parent.parentNode();
43 while (ancestor) {
44 chain.unshift(ancestor);
45 ancestor = ancestor.parentNode();
46 }
47 for (var ancestorNode of chain) {
48 var ancestorTreeElement = new WebInspector.AXNodeTreeElement(ancestorNod e, this);
49 previousTreeElement.appendChild(ancestorTreeElement);
50 previousTreeElement.expand();
51 previousTreeElement = ancestorTreeElement;
52 }
53 var parentTreeElement = new WebInspector.AXNodeTreeParentElement(parent, i nspectedNodeTreeElement, this);
54 previousTreeElement.appendChild(parentTreeElement);
55 if (this.isExpanded(parent.backendDOMNodeId()))
56 parentTreeElement.appendSiblings();
57 else
58 parentTreeElement.appendChild(inspectedNodeTreeElement);
59 previousTreeElement.expand();
60 previousTreeElement = parentTreeElement;
61 } else {
62 previousTreeElement.appendChild(inspectedNodeTreeElement);
33 } 63 }
34 previous.selectable = true; 64
35 previous.select(true /* omitFocus */); 65 previousTreeElement.expand();
66
67 for (var child of axNode.children()) {
68 var childTreeElement = new WebInspector.AXNodeTreeElement(child, this);
69 inspectedNodeTreeElement.appendChild(childTreeElement);
70 }
71
72 inspectedNodeTreeElement.selectable = true;
73 inspectedNodeTreeElement.select(!this._selectedByUser /* omitFocus */, false );
74 if (this.isExpanded(axNode.backendDOMNodeId()))
75 inspectedNodeTreeElement.expand();
76 this.clearSelectedByUser();
77 }
78
79 /**
80 * @param {boolean} selectedByUser
81 */
82 setSelectedByUser(selectedByUser) {
83 this._selectedByUser = true;
84 }
85
86 clearSelectedByUser() {
87 delete this._selectedByUser;
88 }
89
90 /**
91 * @return {!WebInspector.Target}
92 */
93 target() {
94 return this.node().target();
95 }
96
97 /**
98 * @param {?number} backendDOMNodeId
99 * @param {boolean} expanded
100 */
101 setExpanded(backendDOMNodeId, expanded) {
102 if (!backendDOMNodeId)
103 return;
104 if (expanded)
105 this._expandedNodes.add(backendDOMNodeId);
106 else
107 this._expandedNodes.delete(backendDOMNodeId);
108 }
109
110 /**
111 * @param {?number} backendDOMNodeId
112 * @return {boolean}
113 */
114 isExpanded(backendDOMNodeId) {
115 if (!backendDOMNodeId)
116 return false;
117
118 return this._expandedNodes.has(backendDOMNodeId);
36 } 119 }
37 }; 120 };
38 121
122 WebInspector.InspectNodeButton = class {
123 /**
124 * @param {!WebInspector.AccessibilityNode} axNode
125 * @param {!WebInspector.AXTreePane} treePane
126 */
127 constructor(axNode, treePane) {
128 this._axNode = axNode;
129 this._treePane = treePane;
130
131 this.element = createElementWithClass('button', 'inspect-dom-node');
132 this.element.addEventListener('mousedown', this._handleMouseDown.bind(this)) ;
133 }
134
135 /**
136 * @param {!Event} event
137 */
138 _handleMouseDown(event) {
139 this._treePane.setSelectedByUser(true);
140 WebInspector.Revealer.reveal(this._axNode.deferredDOMNode());
141 }
142 };
143
39 /** 144 /**
40 * @unrestricted 145 * @unrestricted
41 */ 146 */
42 WebInspector.AXNodeTreeElement = class extends TreeElement { 147 WebInspector.AXNodeTreeElement = class extends TreeElement {
43 /** 148 /**
44 * @param {!WebInspector.AccessibilityNode} axNode 149 * @param {!WebInspector.AccessibilityNode} axNode
45 * @param {!WebInspector.Target} target 150 * @param {!WebInspector.AXTreePane} treePane
46 */ 151 */
47 constructor(axNode, target) { 152 constructor(axNode, treePane) {
48 // Pass an empty title, the title gets made later in onattach. 153 // Pass an empty title, the title gets made later in onattach.
49 super(''); 154 super('');
50 155
51 /** @type {!WebInspector.AccessibilityNode} */ 156 /** @type {!WebInspector.AccessibilityNode} */
52 this._axNode = axNode; 157 this._axNode = axNode;
53 158
54 /** @type {!WebInspector.Target} */ 159 /** @type {!WebInspector.AXTreePane} */
55 this._target = target; 160 this._treePane = treePane;
56 161
57 this.selectable = false; 162 this.selectable = true;
163
164 this._inspectNodeButton =
165 new WebInspector.InspectNodeButton(axNode, treePane);
58 } 166 }
59 167
60 /** 168 /**
169 * @return {!WebInspector.AccessibilityNode}
170 */
171 axNode() {
172 return this._axNode;
173 }
174
175 /**
176 * @param {boolean} inspected
177 */
178 setInspected(inspected) {
179 this._inspected = inspected;
180 this.listItemElement.classList.toggle('inspected', this._inspected);
181 }
182
183 /**
184 * @override
185 * @return {boolean}
186 */
187 onenter() {
188 this.inspectDOMNode();
189 return true;
190 }
191
192 /**
193 * @override
194 * @param {!Event} event
195 * @return {boolean}
196 */
197 ondblclick(event) {
198 this.inspectDOMNode();
199 return true;
200 }
201
202 inspectDOMNode() {
203 this._treePane.setSelectedByUser(true);
204 WebInspector.Revealer.reveal(this._axNode.deferredDOMNode());
205 }
206
207 /**
61 * @override 208 * @override
62 */ 209 */
63 onattach() { 210 onattach() {
64 this._update(); 211 this._update();
65 } 212 }
66 213
67 _update() { 214 _update() {
68 this.listItemElement.removeChildren(); 215 this.listItemElement.removeChildren();
69 216
70 if (this._axNode.ignored()) { 217 if (this._axNode.ignored()) {
71 this._appendIgnoredNodeElement(); 218 this._appendIgnoredNodeElement();
72 } else { 219 } else {
73 this._appendRoleElement(this._axNode.role()); 220 this._appendRoleElement(this._axNode.role());
74 if ('name' in this._axNode && this._axNode.name().value) { 221 if (this._axNode.name().value) {
75 this.listItemElement.createChild('span', 'separator').textContent = '\u0 0A0'; 222 this.listItemElement.createChild('span', 'separator').textContent = '\u0 0A0';
76 this._appendNameElement(/** @type {string} */ (this._axNode.name().value )); 223 this._appendNameElement(/** @type {string} */ (this._axNode.name().value ));
77 } 224 }
78 } 225 }
226
227 if (this._axNode.hasOnlyUnloadedChildren()) {
228 this.listItemElement.classList.add('children-unloaded');
229 this.setExpandable(true);
230 } else {
231 this.setExpandable(!!this._axNode.numChildren());
232 }
233
234 if (!this._axNode.isDOMNode())
235 this.listItemElement.classList.add('no-dom-node');
236 this.listItemElement.appendChild(this._inspectNodeButton.element);
79 } 237 }
80 238
81 /** 239 /**
240 * @override
241 */
242 expand() {
243 if (!this._axNode || this._axNode.hasOnlyUnloadedChildren())
244 return;
245
246 this._treePane.setExpanded(this._axNode.backendDOMNodeId(), true);
247 super.expand();
248 }
249
250 /**
251 * @override
252 */
253 collapse() {
254 if (!this._axNode || this._axNode.hasOnlyUnloadedChildren())
255 return;
256
257 if (this._treePane)
258 this._treePane.setExpanded(this._axNode.backendDOMNodeId(), false);
259 super.collapse();
260 }
261
262 /**
82 * @param {string} name 263 * @param {string} name
83 */ 264 */
84 _appendNameElement(name) { 265 _appendNameElement(name) {
85 var nameElement = createElement('span'); 266 var nameElement = createElement('span');
86 nameElement.textContent = '"' + name + '"'; 267 nameElement.textContent = '"' + name + '"';
87 nameElement.classList.add('ax-readable-string'); 268 nameElement.classList.add('ax-readable-string');
88 this.listItemElement.appendChild(nameElement); 269 this.listItemElement.appendChild(nameElement);
89 } 270 }
90 271
91 /** 272 /**
92 * @param {?Protocol.Accessibility.AXValue} role 273 * @param {?Protocol.Accessibility.AXValue} role
93 */ 274 */
94 _appendRoleElement(role) { 275 _appendRoleElement(role) {
95 if (!role) 276 if (!role)
96 return; 277 return;
97 278
98 var roleElement = createElementWithClass('span', 'monospace'); 279 var roleElement = createElementWithClass('span', 'monospace');
99 roleElement.classList.add(WebInspector.AXNodeTreeElement.RoleStyles[role.typ e]); 280 roleElement.classList.add(WebInspector.AXNodeTreeElement.RoleStyles[role.typ e]);
100 roleElement.setTextContentTruncatedIfNeeded(role.value || ''); 281 roleElement.setTextContentTruncatedIfNeeded(role.value || '');
101 282
102 this.listItemElement.appendChild(roleElement); 283 this.listItemElement.appendChild(roleElement);
103 } 284 }
104 285
105 _appendIgnoredNodeElement() { 286 _appendIgnoredNodeElement() {
106 var ignoredNodeElement = createElementWithClass('span', 'monospace'); 287 var ignoredNodeElement = createElementWithClass('span', 'monospace');
107 ignoredNodeElement.textContent = WebInspector.UIString('Ignored'); 288 ignoredNodeElement.textContent = WebInspector.UIString('Ignored');
108 ignoredNodeElement.classList.add('ax-tree-ignored-node'); 289 ignoredNodeElement.classList.add('ax-tree-ignored-node');
109 this.listItemElement.appendChild(ignoredNodeElement); 290 this.listItemElement.appendChild(ignoredNodeElement);
110 } 291 }
292
293 /**
294 * @param {boolean=} omitFocus
295 * @param {boolean=} selectedByUser
296 * @return {boolean}
297 * @override
298 */
299 select(omitFocus, selectedByUser) {
300 this._treePane.setSelectedByUser(!!selectedByUser);
301
302 return super.select(omitFocus, selectedByUser);
303 }
111 }; 304 };
112 305
113 /** @type {!Object<string, string>} */ 306 /** @type {!Object<string, string>} */
114 WebInspector.AXNodeTreeElement.RoleStyles = { 307 WebInspector.AXNodeTreeElement.RoleStyles = {
115 internalRole: 'ax-internal-role', 308 internalRole: 'ax-internal-role',
116 role: 'ax-role', 309 role: 'ax-role',
117 }; 310 };
311
312 /**
313 * @unrestricted
314 */
315 WebInspector.ExpandSiblingsButton = class {
316 /**
317 * @param {!WebInspector.AXNodeTreeParentElement} treeElement
318 * @param {number} numSiblings
319 */
320 constructor(treeElement, numSiblings) {
321 this._treeElement = treeElement;
322
323 this.element = createElementWithClass('button', 'expand-siblings');
324 this.element.textContent = WebInspector.UIString(
325 (numSiblings === 1 ? '+ %d node' : '+ %d nodes'), numSiblings);
326 this.element.addEventListener('mousedown', this._handleMouseDown.bind(this)) ;
327 }
328
329 /**
330 * @param {!Event} event
331 */
332 _handleMouseDown(event) {
333 this._treeElement.expandSiblings();
334 event.consume();
335 }
336 };
337
338 /**
339 * @unrestricted
340 */
341 WebInspector.AXNodeTreeParentElement = class extends WebInspector.AXNodeTreeElem ent {
342 /**
343 * @param {!WebInspector.AccessibilityNode} axNode
344 * @param {!WebInspector.AXNodeTreeElement} inspectedNodeTreeElement
345 * @param {!WebInspector.AXTreePane} treePane
346 */
347 constructor(axNode, inspectedNodeTreeElement, treePane) {
348 super(axNode, treePane);
349
350 this._inspectedNodeTreeElement = inspectedNodeTreeElement;
351 var numSiblings = axNode.children().length - 1;
352 this._expandSiblingsButton = new WebInspector.ExpandSiblingsButton(this, num Siblings);
353 this._partiallyExpanded = false;
354 }
355
356 /**
357 * @override
358 */
359 onattach() {
360 super.onattach();
361 if (this._treePane.isExpanded(this._axNode.backendDOMNodeId()))
362 this._listItemNode.classList.add('siblings-expanded');
363 if (this._axNode.numChildren() > 1) {
364 this._listItemNode.insertBefore(this._expandSiblingsButton.element,
365 this._inspectNodeButton.element);
366 }
367 }
368
369 /**
370 * @param {boolean} altKey
371 * @return {boolean}
372 * @override
373 */
374 descendOrExpand(altKey) {
375 if (!this.expanded || !this._partiallyExpanded)
376 return super.descendOrExpand(altKey);
377
378 this.expandSiblings();
379 if (altKey)
380 this.expandRecursively();
381 return true;
382 }
383
384 /**
385 * @override
386 */
387 expand() {
388 super.expand();
389 this._partiallyExpanded = true;
390 }
391
392 expandSiblings() {
393 this._listItemNode.classList.add('siblings-expanded');
394 this.appendSiblings();
395 this.expanded = true;
396 this._partiallyExpanded = false;
397 this._treePane.setExpanded(this._axNode.backendDOMNodeId(), true);
398 }
399
400 appendSiblings() {
401 var inspectedAXNode = this._inspectedNodeTreeElement.axNode();
402 var nextIndex = 0;
403 var foundInspectedNode = false;
404 for (var sibling of this._axNode.children()) {
405 var siblingTreeElement = null;
406 if (sibling === inspectedAXNode) {
407 foundInspectedNode = true;
408 continue;
409 }
410 siblingTreeElement = new WebInspector.AXNodeTreeElement(sibling, this._tre ePane);
411 if (foundInspectedNode)
412 this.appendChild(siblingTreeElement);
413 else
414 this.insertChild(siblingTreeElement, nextIndex++);
415 }
416 }
417 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698