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

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

Issue 2967443002: [DevTools] Add ARIA semantics for AXBreadcrumbs (Closed)
Patch Set: Add JSDoc for _children Created 3 years, 5 months 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 Accessibility.AXBreadcrumbsPane = class extends Accessibility.AccessibilitySubPa ne { 5 Accessibility.AXBreadcrumbsPane = class extends Accessibility.AccessibilitySubPa ne {
6 /** 6 /**
7 * @param {!Accessibility.AccessibilitySidebarView} axSidebarView 7 * @param {!Accessibility.AccessibilitySidebarView} axSidebarView
8 */ 8 */
9 constructor(axSidebarView) { 9 constructor(axSidebarView) {
10 super(Common.UIString('Accessibility Tree')); 10 super(Common.UIString('Accessibility Tree'));
11 11
12 this.element.classList.add('ax-subpane'); 12 this.element.classList.add('ax-subpane');
13 UI.ARIAUtils.markAsTree(this.element);
13 14
14 this._axSidebarView = axSidebarView; 15 this._axSidebarView = axSidebarView;
15 16
16 /** @type {?Accessibility.AXBreadcrumb} */ 17 /** @type {?Accessibility.AXBreadcrumb} */
17 this._preselectedBreadcrumb = null; 18 this._preselectedBreadcrumb = null;
18 19
19 this._selectedByUser = true; 20 this._selectedByUser = true;
20 21
21 this._hoveredBreadcrumb = null; 22 this._hoveredBreadcrumb = null;
22 this._rootElement = this.element.createChild('div', 'ax-breadcrumbs'); 23 this._rootElement = this.element.createChild('div', 'ax-breadcrumbs');
(...skipping 23 matching lines...) Expand all
46 var ancestorChain = []; 47 var ancestorChain = [];
47 var ancestor = axNode; 48 var ancestor = axNode;
48 while (ancestor) { 49 while (ancestor) {
49 ancestorChain.push(ancestor); 50 ancestorChain.push(ancestor);
50 ancestor = ancestor.parentNode(); 51 ancestor = ancestor.parentNode();
51 } 52 }
52 ancestorChain.reverse(); 53 ancestorChain.reverse();
53 54
54 var depth = 0; 55 var depth = 0;
55 var breadcrumb = null; 56 var breadcrumb = null;
57 var parent = null;
56 for (ancestor of ancestorChain) { 58 for (ancestor of ancestorChain) {
57 breadcrumb = new Accessibility.AXBreadcrumb(ancestor, depth, (ancestor === axNode)); 59 breadcrumb = new Accessibility.AXBreadcrumb(ancestor, depth, (ancestor === axNode));
58 if (ancestor.children().length) 60 if (parent)
59 breadcrumb.element().classList.add('parent'); 61 parent.appendChild(breadcrumb);
60 this._rootElement.appendChild(breadcrumb.element()); 62 else
63 this._rootElement.appendChild(breadcrumb.element());
64 parent = breadcrumb;
61 depth++; 65 depth++;
62 } 66 }
63 67
64 var inspectedNodeBreadcrumb = breadcrumb; 68 var inspectedNodeBreadcrumb = breadcrumb;
65 inspectedNodeBreadcrumb.setPreselected(true, this._selectedByUser); 69 inspectedNodeBreadcrumb.setPreselected(true, this._selectedByUser);
66 70
67 this._setPreselectedBreadcrumb(inspectedNodeBreadcrumb); 71 this._setPreselectedBreadcrumb(inspectedNodeBreadcrumb);
68 72
69 for (var child of axNode.children()) { 73 for (var child of axNode.children()) {
70 var childBreadcrumb = new Accessibility.AXBreadcrumb(child, depth, false); 74 var childBreadcrumb = new Accessibility.AXBreadcrumb(child, depth, false);
71 this._rootElement.appendChild(childBreadcrumb.element()); 75 inspectedNodeBreadcrumb.appendChild(childBreadcrumb);
72 } 76 }
73 77
74 this._selectedByUser = false; 78 this._selectedByUser = false;
75 } 79 }
76 80
77 /** 81 /**
78 * @override 82 * @override
79 */ 83 */
80 wasShown() { 84 wasShown() {
81 this._selectedByUser = true; 85 this._selectedByUser = true;
(...skipping 26 matching lines...) Expand all
108 handled = this._inspectDOMNode(this._preselectedBreadcrumb.axNode()); 112 handled = this._inspectDOMNode(this._preselectedBreadcrumb.axNode());
109 113
110 if (handled) 114 if (handled)
111 event.consume(true); 115 event.consume(true);
112 } 116 }
113 117
114 /** 118 /**
115 * @return {boolean} 119 * @return {boolean}
116 */ 120 */
117 _preselectPrevious() { 121 _preselectPrevious() {
118 var previousElement = this._preselectedBreadcrumb.element().previousSibling; 122 var previousBreadcrumb = this._preselectedBreadcrumb.previousBreadcrumb();
119 if (!previousElement) 123 if (!previousBreadcrumb)
120 return false; 124 return false;
121 this._selectedByUser = true; 125 this._selectedByUser = true;
122 this._setPreselectedBreadcrumb(previousElement.breadcrumb); 126 this._setPreselectedBreadcrumb(previousBreadcrumb);
123 return true; 127 return true;
124 } 128 }
125 129
126 /** 130 /**
127 * @return {boolean} 131 * @return {boolean}
128 */ 132 */
129 _preselectNext() { 133 _preselectNext() {
130 var nextElement = this._preselectedBreadcrumb.element().nextSibling; 134 var nextBreadcrumb = this._preselectedBreadcrumb.nextBreadcrumb();
131 if (!nextElement) 135 if (!nextBreadcrumb)
132 return false; 136 return false;
133 this._selectedByUser = true; 137 this._selectedByUser = true;
134 this._setPreselectedBreadcrumb(nextElement.breadcrumb); 138 this._setPreselectedBreadcrumb(nextBreadcrumb);
135 return true; 139 return true;
136 } 140 }
137 141
138 /** 142 /**
139 * @param {?Accessibility.AXBreadcrumb} breadcrumb 143 * @param {?Accessibility.AXBreadcrumb} breadcrumb
140 */ 144 */
141 _setPreselectedBreadcrumb(breadcrumb) { 145 _setPreselectedBreadcrumb(breadcrumb) {
142 if (breadcrumb === this._preselectedBreadcrumb) 146 if (breadcrumb === this._preselectedBreadcrumb)
143 return; 147 return;
144 if (this._preselectedBreadcrumb) 148 if (this._preselectedBreadcrumb)
145 this._preselectedBreadcrumb.setPreselected(false, this._selectedByUser); 149 this._preselectedBreadcrumb.setPreselected(false, this._selectedByUser);
146 this._preselectedBreadcrumb = breadcrumb; 150 this._preselectedBreadcrumb = breadcrumb;
147 if (this._preselectedBreadcrumb) 151 if (this._preselectedBreadcrumb)
148 this._preselectedBreadcrumb.setPreselected(true, this._selectedByUser); 152 this._preselectedBreadcrumb.setPreselected(true, this._selectedByUser);
149 else if (this._selectedByUser) 153 else if (this._selectedByUser)
150 SDK.OverlayModel.hideDOMNodeHighlight(); 154 SDK.OverlayModel.hideDOMNodeHighlight();
151 } 155 }
152 156
153 /** 157 /**
154 * @param {!Event} event 158 * @param {!Event} event
155 */ 159 */
156 _onMouseLeave(event) { 160 _onMouseLeave(event) {
157 this._setHoveredBreadcrumb(null); 161 this._setHoveredBreadcrumb(null);
158 } 162 }
159 163
160 /** 164 /**
161 * @param {!Event} event 165 * @param {!Event} event
162 */ 166 */
163 _onMouseMove(event) { 167 _onMouseMove(event) {
164 var breadcrumbElement = event.target.enclosingNodeOrSelfWithClass('ax-node') ; 168 var breadcrumbElement = event.target.enclosingNodeOrSelfWithClass('ax-breadc rumb');
165 if (!breadcrumbElement) { 169 if (!breadcrumbElement) {
166 this._setHoveredBreadcrumb(null); 170 this._setHoveredBreadcrumb(null);
167 return; 171 return;
168 } 172 }
169 var breadcrumb = breadcrumbElement.breadcrumb; 173 var breadcrumb = breadcrumbElement.breadcrumb;
170 if (breadcrumb.preselected() || breadcrumb.inspected() || !breadcrumb.isDOMN ode()) 174 if (breadcrumb.preselected() || breadcrumb.inspected() || !breadcrumb.isDOMN ode())
171 return; 175 return;
172 this._setHoveredBreadcrumb(breadcrumb); 176 this._setHoveredBreadcrumb(breadcrumb);
173 } 177 }
174 178
175 /** 179 /**
176 * @param {!Event} event 180 * @param {!Event} event
177 */ 181 */
178 _onClick(event) { 182 _onClick(event) {
179 var breadcrumbElement = event.target.enclosingNodeOrSelfWithClass('ax-node') ; 183 var breadcrumbElement = event.target.enclosingNodeOrSelfWithClass('ax-breadc rumb');
180 if (!breadcrumbElement) { 184 if (!breadcrumbElement) {
181 this._setHoveredBreadcrumb(null); 185 this._setHoveredBreadcrumb(null);
182 return; 186 return;
183 } 187 }
184 var breadcrumb = breadcrumbElement.breadcrumb; 188 var breadcrumb = breadcrumbElement.breadcrumb;
185 if (breadcrumb.inspected()) { 189 if (breadcrumb.inspected()) {
186 // If the user is clicking the inspected breadcrumb, they probably want to 190 // If the user is clicking the inspected breadcrumb, they probably want to
187 // focus it. 191 // focus it.
188 breadcrumb.element().focus(); 192 breadcrumb.element().focus();
189 return; 193 return;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 Accessibility.AXBreadcrumb = class { 271 Accessibility.AXBreadcrumb = class {
268 /** 272 /**
269 * @param {!Accessibility.AccessibilityNode} axNode 273 * @param {!Accessibility.AccessibilityNode} axNode
270 * @param {number} depth 274 * @param {number} depth
271 * @param {boolean} inspected 275 * @param {boolean} inspected
272 */ 276 */
273 constructor(axNode, depth, inspected) { 277 constructor(axNode, depth, inspected) {
274 /** @type {!Accessibility.AccessibilityNode} */ 278 /** @type {!Accessibility.AccessibilityNode} */
275 this._axNode = axNode; 279 this._axNode = axNode;
276 280
277 this._element = createElementWithClass('div', 'ax-node'); 281 this._element = createElementWithClass('div', 'ax-breadcrumb');
282 UI.ARIAUtils.markAsTreeitem(this._element);
278 this._element.breadcrumb = this; 283 this._element.breadcrumb = this;
279 284
285 this._nodeElement = createElementWithClass('div', 'ax-node');
286 this._element.appendChild(this._nodeElement);
287 this._nodeWrapper = createElementWithClass('div', 'wrapper');
288 this._nodeElement.appendChild(this._nodeWrapper);
289
280 this._selectionElement = createElementWithClass('div', 'selection fill'); 290 this._selectionElement = createElementWithClass('div', 'selection fill');
281 this._element.appendChild(this._selectionElement); 291 this._nodeElement.appendChild(this._selectionElement);
282 292
283 this._nodeWrapper = createElementWithClass('span', 'wrapper'); 293 this._childrenGroupElement = createElementWithClass('div', 'children');
284 this._element.appendChild(this._nodeWrapper); 294 UI.ARIAUtils.markAsGroup(this._childrenGroupElement);
295 this._element.appendChild(this._childrenGroupElement);
285 296
297 /** @type !Array<!Accessibility.AXBreadcrumb> */
298 this._children = [];
286 this._hovered = false; 299 this._hovered = false;
287 this._preselected = false; 300 this._preselected = false;
301 this._parent = null;
288 302
289 this._inspected = inspected; 303 this._inspected = inspected;
290 this.element().classList.toggle('inspected', inspected); 304 this._nodeElement.classList.toggle('inspected', inspected);
291 305
292 this._element.style.paddingLeft = (16 * depth + 4) + 'px'; 306 this._nodeElement.style.paddingLeft = (16 * depth + 4) + 'px';
293 307
294 if (this._axNode.ignored()) { 308 if (this._axNode.ignored()) {
295 this._appendIgnoredNodeElement(); 309 this._appendIgnoredNodeElement();
296 } else { 310 } else {
297 this._appendRoleElement(this._axNode.role()); 311 this._appendRoleElement(this._axNode.role());
298 if (this._axNode.name() && this._axNode.name().value) { 312 if (this._axNode.name() && this._axNode.name().value) {
299 this._nodeWrapper.createChild('span', 'separator').textContent = '\u00A0 '; 313 this._nodeWrapper.createChild('span', 'separator').textContent = '\u00A0 ';
300 this._appendNameElement(/** @type {string} */ (this._axNode.name().value )); 314 this._appendNameElement(/** @type {string} */ (this._axNode.name().value ));
301 } 315 }
302 } 316 }
303 317
304 if (this._axNode.hasOnlyUnloadedChildren()) 318 if (this._axNode.hasOnlyUnloadedChildren())
305 this._element.classList.add('children-unloaded'); 319 this._nodeElement.classList.add('children-unloaded');
306 320
307 if (!this._axNode.isDOMNode()) 321 if (!this._axNode.isDOMNode())
308 this._element.classList.add('no-dom-node'); 322 this._nodeElement.classList.add('no-dom-node');
309 } 323 }
310 324
311 /** 325 /**
312 * @return {!Element} 326 * @return {!Element}
313 */ 327 */
314 element() { 328 element() {
315 return this._element; 329 return this._element;
316 } 330 }
317 331
318 /** 332 /**
333 * @param {!Accessibility.AXBreadcrumb} breadcrumb
334 */
335 appendChild(breadcrumb) {
336 this._children.push(breadcrumb);
337 breadcrumb.setParent(this);
338 this._nodeElement.classList.add('parent');
339 UI.ARIAUtils.setExpanded(this._element, true);
340 this._childrenGroupElement.appendChild(breadcrumb.element());
341 }
342
343 /**
344 * @param {!Accessibility.AXBreadcrumb} breadcrumb
345 */
346 setParent(breadcrumb) {
347 this._parent = breadcrumb;
348 }
349
350 /**
319 * @return {boolean} 351 * @return {boolean}
320 */ 352 */
321 preselected() { 353 preselected() {
322 return this._preselected; 354 return this._preselected;
323 } 355 }
324 356
325 /** 357 /**
326 * @param {boolean} preselected 358 * @param {boolean} preselected
327 * @param {boolean} selectedByUser 359 * @param {boolean} selectedByUser
328 */ 360 */
329 setPreselected(preselected, selectedByUser) { 361 setPreselected(preselected, selectedByUser) {
330 if (this._preselected === preselected) 362 if (this._preselected === preselected)
331 return; 363 return;
332 this._preselected = preselected; 364 this._preselected = preselected;
333 this.element().classList.toggle('preselected', preselected); 365 this._nodeElement.classList.toggle('preselected', preselected);
334 if (preselected) 366 if (preselected)
335 this.element().setAttribute('tabIndex', 0); 367 this._nodeElement.setAttribute('tabIndex', 0);
336 else 368 else
337 this.element().removeAttribute('tabIndex'); 369 this._nodeElement.removeAttribute('tabIndex');
338 if (this._preselected) { 370 if (this._preselected) {
339 if (selectedByUser) 371 if (selectedByUser)
340 this.element().focus(); 372 this._nodeElement.focus();
341 if (!this._inspected) 373 if (!this._inspected)
342 this._axNode.highlightDOMNode(); 374 this._axNode.highlightDOMNode();
343 else 375 else
344 SDK.OverlayModel.hideDOMNodeHighlight(); 376 SDK.OverlayModel.hideDOMNodeHighlight();
345 } 377 }
346 } 378 }
347 379
348 /** 380 /**
349 * @param {boolean} hovered 381 * @param {boolean} hovered
350 */ 382 */
351 setHovered(hovered) { 383 setHovered(hovered) {
352 if (this._hovered === hovered) 384 if (this._hovered === hovered)
353 return; 385 return;
354 this._hovered = hovered; 386 this._hovered = hovered;
355 this.element().classList.toggle('hovered', hovered); 387 this._nodeElement.classList.toggle('hovered', hovered);
356 if (this._hovered) { 388 if (this._hovered) {
357 this.element().classList.toggle('hovered', true); 389 this._nodeElement.classList.toggle('hovered', true);
358 this._axNode.highlightDOMNode(); 390 this._axNode.highlightDOMNode();
359 } 391 }
360 } 392 }
361 393
362 /** 394 /**
363 * @return {!Accessibility.AccessibilityNode} 395 * @return {!Accessibility.AccessibilityNode}
364 */ 396 */
365 axNode() { 397 axNode() {
366 return this._axNode; 398 return this._axNode;
367 } 399 }
368 400
369 /** 401 /**
370 * @return {boolean} 402 * @return {boolean}
371 */ 403 */
372 inspected() { 404 inspected() {
373 return this._inspected; 405 return this._inspected;
374 } 406 }
375 407
376 /** 408 /**
377 * @return {boolean} 409 * @return {boolean}
378 */ 410 */
379 isDOMNode() { 411 isDOMNode() {
380 return this._axNode.isDOMNode(); 412 return this._axNode.isDOMNode();
381 } 413 }
382 414
383 /** 415 /**
416 * @return {?Accessibility.AXBreadcrumb}
417 */
418 nextBreadcrumb() {
419 if (this._children.length)
420 return this._children[0];
421 var nextSibling = this.element().nextSibling;
422 if (nextSibling)
423 return nextSibling.breadcrumb;
424 return null;
425 }
426
427 /**
428 * @return {?Accessibility.AXBreadcrumb}
429 */
430 previousBreadcrumb() {
431 var previousSibling = this.element().previousSibling;
432 if (previousSibling)
433 return previousSibling.breadcrumb;
434
435 return this._parent;
436 }
437
438 /**
384 * @param {string} name 439 * @param {string} name
385 */ 440 */
386 _appendNameElement(name) { 441 _appendNameElement(name) {
387 var nameElement = createElement('span'); 442 var nameElement = createElement('span');
388 nameElement.textContent = '"' + name + '"'; 443 nameElement.textContent = '"' + name + '"';
389 nameElement.classList.add('ax-readable-string'); 444 nameElement.classList.add('ax-readable-string');
390 this._nodeWrapper.appendChild(nameElement); 445 this._nodeWrapper.appendChild(nameElement);
391 } 446 }
392 447
393 /** 448 /**
(...skipping 16 matching lines...) Expand all
410 ignoredNodeElement.classList.add('ax-breadcrumbs-ignored-node'); 465 ignoredNodeElement.classList.add('ax-breadcrumbs-ignored-node');
411 this._nodeWrapper.appendChild(ignoredNodeElement); 466 this._nodeWrapper.appendChild(ignoredNodeElement);
412 } 467 }
413 }; 468 };
414 469
415 /** @type {!Object<string, string>} */ 470 /** @type {!Object<string, string>} */
416 Accessibility.AXBreadcrumb.RoleStyles = { 471 Accessibility.AXBreadcrumb.RoleStyles = {
417 internalRole: 'ax-internal-role', 472 internalRole: 'ax-internal-role',
418 role: 'ax-role', 473 role: 'ax-role',
419 }; 474 };
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698