OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 }; |
OLD | NEW |