blob: 97b2029e996a03a62385b2f7c5614237bed1d16f [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Tim van der Lippe6d1e03c2020-01-22 14:05:584
Tim van der Lippe8f15c8d2020-02-13 14:59:415import * as Common from '../common/common.js';
6import * as SDK from '../sdk/sdk.js';
7import * as UI from '../ui/ui.js';
8
Peter Marshall14e5fbd2020-09-01 11:04:129import {AccessibilityNode, CoreAxPropertyName, CoreOrProtocolAxProperty} from './AccessibilityModel.js'; // eslint-disable-line no-unused-vars
Tim van der Lippe6d1e03c2020-01-22 14:05:5810import {AXAttributes, AXNativeSourceTypes, AXSourceTypes} from './AccessibilityStrings.js';
11import {AccessibilitySubPane} from './AccessibilitySubPane.js';
12
Blink Reformat4c46d092018-04-07 15:32:3713/**
14 * @unrestricted
15 */
Tim van der Lippe6d1e03c2020-01-22 14:05:5816export class AXNodeSubPane extends AccessibilitySubPane {
Blink Reformat4c46d092018-04-07 15:32:3717 constructor() {
18 super(ls`Computed Properties`);
19
Tim van der Lippe6d1e03c2020-01-22 14:05:5820 /**
21 * @protected
22 * @suppress {accessControls}
Peter Marshall7e33f4d2020-09-02 08:59:0923 * @type {?AccessibilityNode}
Tim van der Lippe6d1e03c2020-01-22 14:05:5824 */
25 this._axNode = null;
26
Blink Reformat4c46d092018-04-07 15:32:3727 this.contentElement.classList.add('ax-subpane');
28
29 this._noNodeInfo = this.createInfo(ls`No accessibility node`);
30 this._ignoredInfo = this.createInfo(ls`Accessibility node not exposed`, 'ax-ignored-info hidden');
31
32 this._treeOutline = this.createTreeOutline();
33 this._ignoredReasonsTree = this.createTreeOutline();
34
35 this.element.classList.add('accessibility-computed');
Jack Franklin71519f82020-11-03 12:08:5936 this.registerRequiredCSS('accessibility/accessibilityNode.css', {enableLegacyPatching: true});
Rob Paveza84d41442019-10-10 23:01:0937 this._treeOutline.setFocusable(true);
Blink Reformat4c46d092018-04-07 15:32:3738 }
39
40 /**
Tim van der Lippe6d1e03c2020-01-22 14:05:5841 * @param {?AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:3742 * @override
43 */
44 setAXNode(axNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3445 if (this._axNode === axNode) {
Blink Reformat4c46d092018-04-07 15:32:3746 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3447 }
Blink Reformat4c46d092018-04-07 15:32:3748 this._axNode = axNode;
49
50 const treeOutline = this._treeOutline;
51 treeOutline.removeChildren();
52 const ignoredReasons = this._ignoredReasonsTree;
53 ignoredReasons.removeChildren();
54
55 if (!axNode) {
56 treeOutline.element.classList.add('hidden');
57 this._ignoredInfo.classList.add('hidden');
58 ignoredReasons.element.classList.add('hidden');
59
60 this._noNodeInfo.classList.remove('hidden');
61 this.element.classList.add('ax-ignored-node-pane');
62
63 return;
64 }
65
66 if (axNode.ignored()) {
67 this._noNodeInfo.classList.add('hidden');
68 treeOutline.element.classList.add('hidden');
69 this.element.classList.add('ax-ignored-node-pane');
70
71 this._ignoredInfo.classList.remove('hidden');
72 ignoredReasons.element.classList.remove('hidden');
73 /**
74 * @param {!Protocol.Accessibility.AXProperty} property
75 */
76 function addIgnoredReason(property) {
Tim van der Lippe6d1e03c2020-01-22 14:05:5877 ignoredReasons.appendChild(
78 new AXNodeIgnoredReasonTreeElement(property, /** @type {!AccessibilityNode} */ (axNode)));
Blink Reformat4c46d092018-04-07 15:32:3779 }
80 const ignoredReasonsArray = /** @type {!Array<!Protocol.Accessibility.AXProperty>} */ (axNode.ignoredReasons());
Tim van der Lippe1d6e57a2019-09-30 11:55:3481 for (const reason of ignoredReasonsArray) {
Blink Reformat4c46d092018-04-07 15:32:3782 addIgnoredReason(reason);
Tim van der Lippe1d6e57a2019-09-30 11:55:3483 }
84 if (!ignoredReasons.firstChild()) {
Blink Reformat4c46d092018-04-07 15:32:3785 ignoredReasons.element.classList.add('hidden');
Tim van der Lippe1d6e57a2019-09-30 11:55:3486 }
Blink Reformat4c46d092018-04-07 15:32:3787 return;
88 }
89 this.element.classList.remove('ax-ignored-node-pane');
90
91 this._ignoredInfo.classList.add('hidden');
92 ignoredReasons.element.classList.add('hidden');
93 this._noNodeInfo.classList.add('hidden');
94
95 treeOutline.element.classList.remove('hidden');
96
97 /**
Peter Marshall14e5fbd2020-09-01 11:04:1298 * @param {!CoreOrProtocolAxProperty} property
Blink Reformat4c46d092018-04-07 15:32:3799 */
100 function addProperty(property) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58101 treeOutline.appendChild(
102 new AXNodePropertyTreePropertyElement(property, /** @type {!AccessibilityNode} */ (axNode)));
Blink Reformat4c46d092018-04-07 15:32:37103 }
104
Tim van der Lippe1d6e57a2019-09-30 11:55:34105 for (const property of axNode.coreProperties()) {
Blink Reformat4c46d092018-04-07 15:32:37106 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:34107 }
Blink Reformat4c46d092018-04-07 15:32:37108
Peter Marshall14e5fbd2020-09-01 11:04:12109 const role = axNode.role();
110 if (role) {
111 /** @type {!CoreOrProtocolAxProperty} */
112 const roleProperty = {name: CoreAxPropertyName.Role, value: role};
113 addProperty(roleProperty);
114 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34115 for (const property of /** @type {!Array.<!Protocol.Accessibility.AXProperty>} */ (axNode.properties())) {
Blink Reformat4c46d092018-04-07 15:32:37116 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:34117 }
Rob Paveza84d41442019-10-10 23:01:09118
119 const firstNode = treeOutline.firstChild();
120 if (firstNode) {
121 firstNode.select(/* omitFocus= */ true, /* selectedByUser= */ false);
122 }
Blink Reformat4c46d092018-04-07 15:32:37123 }
124
125 /**
126 * @override
Tim van der Lippe8f15c8d2020-02-13 14:59:41127 * @param {?SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37128 */
129 setNode(node) {
130 super.setNode(node);
131 this._axNode = null;
132 }
Paul Lewisf16142c2019-11-07 15:56:04133}
Blink Reformat4c46d092018-04-07 15:32:37134
135/**
136 * @unrestricted
137 */
Tim van der Lippe8f15c8d2020-02-13 14:59:41138export class AXNodePropertyTreeElement extends UI.TreeOutline.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37139 /**
Tim van der Lippe6d1e03c2020-01-22 14:05:58140 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37141 */
142 constructor(axNode) {
143 // Pass an empty title, the title gets made later in onattach.
144 super('');
145 this._axNode = axNode;
146 }
147
148 /**
149 * @param {?Protocol.Accessibility.AXValueType} type
150 * @param {string} value
151 * @return {!Element}
152 */
153 static createSimpleValueElement(type, value) {
154 let valueElement;
155 const AXValueType = Protocol.Accessibility.AXValueType;
Tim van der Lippe1d6e57a2019-09-30 11:55:34156 if (!type || type === AXValueType.ValueUndefined || type === AXValueType.ComputedString) {
Peter Marshall7e33f4d2020-09-02 08:59:09157 valueElement = document.createElement('span');
Tim van der Lippe1d6e57a2019-09-30 11:55:34158 } else {
Tim van der Lippef49e2322020-05-01 15:03:09159 valueElement = document.createElement('span');
160 valueElement.classList.add('monospace');
Tim van der Lippe1d6e57a2019-09-30 11:55:34161 }
Blink Reformat4c46d092018-04-07 15:32:37162 let valueText;
Tim van der Lippe6d1e03c2020-01-22 14:05:58163 const isStringProperty = type && StringProperties.has(type);
Blink Reformat4c46d092018-04-07 15:32:37164 if (isStringProperty) {
165 // Render \n as a nice unicode cr symbol.
166 valueText = '"' + value.replace(/\n/g, '\u21B5') + '"';
Blink Reformat4c46d092018-04-07 15:32:37167 } else {
168 valueText = String(value);
169 }
170
Tim van der Lippe6d1e03c2020-01-22 14:05:58171 if (type && type in TypeStyles) {
172 valueElement.classList.add(TypeStyles[type]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34173 }
Blink Reformat4c46d092018-04-07 15:32:37174
175 valueElement.setTextContentTruncatedIfNeeded(valueText || '');
176
177 valueElement.title = String(value) || '';
178
179 return valueElement;
180 }
181
182 /**
183 * @param {string} tooltip
184 * @return {!Element}
185 */
186 static createExclamationMark(tooltip) {
Peter Marshall7e33f4d2020-09-02 08:59:09187 const exclamationElement =
188 /** @type {!UI.UIUtils.DevToolsIconLabel} */ (document.createElement('span', {is: 'dt-icon-label'}));
Blink Reformat4c46d092018-04-07 15:32:37189 exclamationElement.type = 'smallicon-warning';
190 exclamationElement.title = tooltip;
191 return exclamationElement;
192 }
193
194 /**
195 * @param {string} name
196 */
197 appendNameElement(name) {
Peter Marshall7e33f4d2020-09-02 08:59:09198 const nameElement = document.createElement('span');
Blink Reformat4c46d092018-04-07 15:32:37199 if (name in AXAttributes) {
Peter Marshall7e33f4d2020-09-02 08:59:09200 // @ts-ignore TS can't cast name here but we checked it's valid.
201 const attribute = AXAttributes[name];
202 nameElement.textContent = attribute.name;
203 nameElement.title = attribute.description;
Blink Reformat4c46d092018-04-07 15:32:37204 nameElement.classList.add('ax-readable-name');
205 } else {
206 nameElement.textContent = name;
207 nameElement.classList.add('ax-name');
208 nameElement.classList.add('monospace');
209 }
210 this.listItemElement.appendChild(nameElement);
211 }
212
213 /**
214 * @param {!Protocol.Accessibility.AXValue} value
215 */
216 appendValueElement(value) {
217 const AXValueType = Protocol.Accessibility.AXValueType;
218 if (value.type === AXValueType.Idref || value.type === AXValueType.Node || value.type === AXValueType.IdrefList ||
219 value.type === AXValueType.NodeList) {
220 this.appendRelatedNodeListValueElement(value);
221 return;
Mathias Bynensf06e8c02020-02-28 13:58:28222 }
223 if (value.sources) {
Blink Reformat4c46d092018-04-07 15:32:37224 const sources = value.sources;
225 for (let i = 0; i < sources.length; i++) {
226 const source = sources[i];
Tim van der Lippe6d1e03c2020-01-22 14:05:58227 const child = new AXValueSourceTreeElement(source, this._axNode);
Blink Reformat4c46d092018-04-07 15:32:37228 this.appendChild(child);
229 }
230 this.expand();
231 }
Tim van der Lippe6d1e03c2020-01-22 14:05:58232 const element = AXNodePropertyTreeElement.createSimpleValueElement(value.type, String(value.value));
Blink Reformat4c46d092018-04-07 15:32:37233 this.listItemElement.appendChild(element);
234 }
235
236 /**
237 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
238 * @param {number} index
239 */
240 appendRelatedNode(relatedNode, index) {
241 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41242 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Peter Marshall7e33f4d2020-09-02 08:59:09243 const nodeTreeElement =
244 new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode, idref: undefined}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37245 this.appendChild(nodeTreeElement);
246 }
247
248 /**
249 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
250 */
251 appendRelatedNodeInline(relatedNode) {
252 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41253 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Peter Marshall7e33f4d2020-09-02 08:59:09254 const linkedNode = new AXRelatedNodeElement({deferredNode: deferredNode, idref: undefined}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37255 this.listItemElement.appendChild(linkedNode.render());
256 }
257
258 /**
259 * @param {!Protocol.Accessibility.AXValue} value
260 */
261 appendRelatedNodeListValueElement(value) {
Peter Marshall7e33f4d2020-09-02 08:59:09262 if (value.relatedNodes && value.relatedNodes.length === 1 && !value.value) {
Blink Reformat4c46d092018-04-07 15:32:37263 this.appendRelatedNodeInline(value.relatedNodes[0]);
264 return;
265 }
266
Peter Marshall7e33f4d2020-09-02 08:59:09267 if (value.relatedNodes) {
268 value.relatedNodes.forEach(this.appendRelatedNode, this);
269 }
270 if (value.relatedNodes && value.relatedNodes.length <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37271 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34272 } else {
Blink Reformat4c46d092018-04-07 15:32:37273 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34274 }
Blink Reformat4c46d092018-04-07 15:32:37275 }
Paul Lewisf16142c2019-11-07 15:56:04276}
Blink Reformat4c46d092018-04-07 15:32:37277
278/** @type {!Object<string, string>} */
Paul Lewisf16142c2019-11-07 15:56:04279export const TypeStyles = {
Blink Reformat4c46d092018-04-07 15:32:37280 attribute: 'ax-value-string',
281 boolean: 'object-value-boolean',
282 booleanOrUndefined: 'object-value-boolean',
283 computedString: 'ax-readable-string',
284 idref: 'ax-value-string',
285 idrefList: 'ax-value-string',
286 integer: 'object-value-number',
287 internalRole: 'ax-internal-role',
288 number: 'ax-value-number',
289 role: 'ax-role',
290 string: 'ax-value-string',
291 tristate: 'object-value-boolean',
292 valueUndefined: 'ax-value-undefined'
293};
294
295/** @type {!Set.<!Protocol.Accessibility.AXValueType>} */
Paul Lewisf16142c2019-11-07 15:56:04296export const StringProperties = new Set([
Blink Reformat4c46d092018-04-07 15:32:37297 Protocol.Accessibility.AXValueType.String, Protocol.Accessibility.AXValueType.ComputedString,
298 Protocol.Accessibility.AXValueType.IdrefList, Protocol.Accessibility.AXValueType.Idref
299]);
300
301/**
302 * @unrestricted
303 */
Paul Lewisf16142c2019-11-07 15:56:04304export class AXNodePropertyTreePropertyElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37305 /**
Peter Marshall14e5fbd2020-09-01 11:04:12306 * @param {!CoreOrProtocolAxProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58307 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37308 */
309 constructor(property, axNode) {
310 super(axNode);
311
312 this._property = property;
313 this.toggleOnClick = true;
Blink Reformat4c46d092018-04-07 15:32:37314
315 this.listItemElement.classList.add('property');
316 }
317
318 /**
319 * @override
320 */
321 onattach() {
322 this._update();
323 }
324
325 _update() {
326 this.listItemElement.removeChildren();
327
328 this.appendNameElement(this._property.name);
329
Mathias Bynens7d8cd342019-09-17 13:32:10330 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37331
332 this.appendValueElement(this._property.value);
333 }
Paul Lewisf16142c2019-11-07 15:56:04334}
Blink Reformat4c46d092018-04-07 15:32:37335
336/**
337 * @unrestricted
338 */
Paul Lewisf16142c2019-11-07 15:56:04339export class AXValueSourceTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37340 /**
341 * @param {!Protocol.Accessibility.AXValueSource} source
Tim van der Lippe6d1e03c2020-01-22 14:05:58342 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37343 */
344 constructor(source, axNode) {
345 super(axNode);
346 this._source = source;
Blink Reformat4c46d092018-04-07 15:32:37347 }
348
349 /**
350 * @override
351 */
352 onattach() {
353 this._update();
354 }
355
356 /**
357 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
Blink Reformat4c46d092018-04-07 15:32:37358 * @param {string} idref
359 */
Meredith Lane4be4e9a2020-02-05 06:07:02360 appendRelatedNodeWithIdref(relatedNode, idref) {
Blink Reformat4c46d092018-04-07 15:32:37361 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41362 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58363 const nodeTreeElement = new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode, idref: idref}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37364 this.appendChild(nodeTreeElement);
365 }
366
367 /**
368 * @param {!Protocol.Accessibility.AXValue} value
369 */
370 appendIDRefValueElement(value) {
Meredith Lane4be4e9a2020-02-05 06:07:02371 if (value.value === null) {
372 return;
373 }
374
375 const relatedNodes = value.relatedNodes || [];
376
377 // Content attribute is empty, but if the relationship was set via the IDL
378 // then there may be related nodes.
379 if (value.value === '') {
380 for (const node of relatedNodes) {
381 const idref = node.idref || '';
382 this.appendRelatedNodeWithIdref(node, idref);
383 }
384 return;
385 }
Blink Reformat4c46d092018-04-07 15:32:37386
387 const idrefs = value.value.trim().split(/\s+/);
Meredith Lane4be4e9a2020-02-05 06:07:02388 for (const idref of idrefs) {
Blink Reformat4c46d092018-04-07 15:32:37389 const matchingNode = relatedNodes.find(node => node.idref === idref);
Blink Reformat4c46d092018-04-07 15:32:37390
Meredith Lane4be4e9a2020-02-05 06:07:02391 // If there is exactly one related node, it is rendered on the same line
392 // of the label. If there are more, they are each rendered on their own
393 // line below the label.
Blink Reformat4c46d092018-04-07 15:32:37394 // TODO(aboxhall): exclamation mark if not idreflist type
Meredith Lane4be4e9a2020-02-05 06:07:02395 if (matchingNode) {
396 this.appendRelatedNodeWithIdref(matchingNode, idref);
397 } else if (idrefs.length === 1) {
Peter Marshall7e33f4d2020-09-02 08:59:09398 this.listItemElement.appendChild(new AXRelatedNodeElement({deferredNode: undefined, idref: idref}).render());
Meredith Lane4be4e9a2020-02-05 06:07:02399 } else {
Peter Marshall7e33f4d2020-09-02 08:59:09400 this.appendChild(new AXRelatedNodeSourceTreeElement({deferredNode: undefined, idref: idref}));
Blink Reformat4c46d092018-04-07 15:32:37401 }
402 }
403 }
404
405 /**
406 * @param {!Protocol.Accessibility.AXValue} value
407 * @override
408 */
409 appendRelatedNodeListValueElement(value) {
410 const relatedNodes = value.relatedNodes;
Peter Marshall7e33f4d2020-09-02 08:59:09411 const numNodes = relatedNodes ? relatedNodes.length : 0;
Blink Reformat4c46d092018-04-07 15:32:37412
413 if (value.type === Protocol.Accessibility.AXValueType.IdrefList ||
Tim van der Lippe1d6e57a2019-09-30 11:55:34414 value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37415 this.appendIDRefValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34416 } else {
Blink Reformat4c46d092018-04-07 15:32:37417 super.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34418 }
Blink Reformat4c46d092018-04-07 15:32:37419
420
Tim van der Lippe1d6e57a2019-09-30 11:55:34421 if (numNodes <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37422 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34423 } else {
Blink Reformat4c46d092018-04-07 15:32:37424 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34425 }
Blink Reformat4c46d092018-04-07 15:32:37426 }
427
428 /**
429 * @param {!Protocol.Accessibility.AXValueSource} source
430 */
431 appendSourceNameElement(source) {
Peter Marshall7e33f4d2020-09-02 08:59:09432 const nameElement = document.createElement('span');
Blink Reformat4c46d092018-04-07 15:32:37433 const AXValueSourceType = Protocol.Accessibility.AXValueSourceType;
434 const type = source.type;
435 switch (type) {
436 case AXValueSourceType.Attribute:
437 case AXValueSourceType.Placeholder:
438 case AXValueSourceType.RelatedElement:
439 if (source.nativeSource) {
Blink Reformat4c46d092018-04-07 15:32:37440 const nativeSource = source.nativeSource;
Mandy Chenba6de382019-06-07 21:38:50441 nameElement.textContent = AXNativeSourceTypes[nativeSource].name;
442 nameElement.title = AXNativeSourceTypes[nativeSource].description;
Blink Reformat4c46d092018-04-07 15:32:37443 nameElement.classList.add('ax-readable-name');
444 break;
445 }
Peter Marshall7e33f4d2020-09-02 08:59:09446 nameElement.textContent = source.attribute || null;
Blink Reformat4c46d092018-04-07 15:32:37447 nameElement.classList.add('ax-name');
448 nameElement.classList.add('monospace');
449 break;
450 default:
Blink Reformat4c46d092018-04-07 15:32:37451 if (type in AXSourceTypes) {
Mandy Chenba6de382019-06-07 21:38:50452 nameElement.textContent = AXSourceTypes[type].name;
453 nameElement.title = AXSourceTypes[type].description;
Blink Reformat4c46d092018-04-07 15:32:37454 nameElement.classList.add('ax-readable-name');
455 } else {
456 console.warn(type, 'not in AXSourceTypes');
Mandy Chenba6de382019-06-07 21:38:50457 nameElement.textContent = type;
Blink Reformat4c46d092018-04-07 15:32:37458 }
459 }
460 this.listItemElement.appendChild(nameElement);
461 }
462
463 _update() {
464 this.listItemElement.removeChildren();
465
466 if (this._source.invalid) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58467 const exclamationMark = AXNodePropertyTreeElement.createExclamationMark(ls`Invalid source.`);
Blink Reformat4c46d092018-04-07 15:32:37468 this.listItemElement.appendChild(exclamationMark);
469 this.listItemElement.classList.add('ax-value-source-invalid');
470 } else if (this._source.superseded) {
471 this.listItemElement.classList.add('ax-value-source-unused');
472 }
473
474 this.appendSourceNameElement(this._source);
475
Mathias Bynens7d8cd342019-09-17 13:32:10476 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37477
478 if (this._source.attributeValue) {
479 this.appendValueElement(this._source.attributeValue);
Sigurd Schneider23c52972020-10-13 09:31:14480 UI.UIUtils.createTextChild(this.listItemElement, '\xA0');
Blink Reformat4c46d092018-04-07 15:32:37481 } else if (this._source.nativeSourceValue) {
482 this.appendValueElement(this._source.nativeSourceValue);
Sigurd Schneider23c52972020-10-13 09:31:14483 UI.UIUtils.createTextChild(this.listItemElement, '\xA0');
Tim van der Lippe1d6e57a2019-09-30 11:55:34484 if (this._source.value) {
Blink Reformat4c46d092018-04-07 15:32:37485 this.appendValueElement(this._source.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34486 }
Blink Reformat4c46d092018-04-07 15:32:37487 } else if (this._source.value) {
488 this.appendValueElement(this._source.value);
489 } else {
Tim van der Lippe6d1e03c2020-01-22 14:05:58490 const valueElement = AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37491 Protocol.Accessibility.AXValueType.ValueUndefined, ls`Not specified`);
492 this.listItemElement.appendChild(valueElement);
493 this.listItemElement.classList.add('ax-value-source-unused');
494 }
495
Tim van der Lippe1d6e57a2019-09-30 11:55:34496 if (this._source.value && this._source.superseded) {
Blink Reformat4c46d092018-04-07 15:32:37497 this.listItemElement.classList.add('ax-value-source-superseded');
Tim van der Lippe1d6e57a2019-09-30 11:55:34498 }
Blink Reformat4c46d092018-04-07 15:32:37499 }
Paul Lewisf16142c2019-11-07 15:56:04500}
Blink Reformat4c46d092018-04-07 15:32:37501
502/**
503 * @unrestricted
504 */
Tim van der Lippe8f15c8d2020-02-13 14:59:41505export class AXRelatedNodeSourceTreeElement extends UI.TreeOutline.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37506 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41507 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37508 * @param {!Protocol.Accessibility.AXRelatedNode=} value
509 */
510 constructor(node, value) {
511 super('');
512
513 this._value = value;
Tim van der Lippe6d1e03c2020-01-22 14:05:58514 this._axRelatedNodeElement = new AXRelatedNodeElement(node, value);
Rob Paveza84d41442019-10-10 23:01:09515 this.selectable = true;
Blink Reformat4c46d092018-04-07 15:32:37516 }
517
518 /**
519 * @override
520 */
521 onattach() {
522 this.listItemElement.appendChild(this._axRelatedNodeElement.render());
Tim van der Lippe1d6e57a2019-09-30 11:55:34523 if (!this._value) {
Blink Reformat4c46d092018-04-07 15:32:37524 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34525 }
Blink Reformat4c46d092018-04-07 15:32:37526
527 if (this._value.text) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58528 this.listItemElement.appendChild(AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37529 Protocol.Accessibility.AXValueType.ComputedString, this._value.text));
530 }
531 }
Rob Paveza84d41442019-10-10 23:01:09532
533 /**
534 * @override
535 */
536 onenter() {
537 this._axRelatedNodeElement.revealNode();
538 return true;
539 }
Paul Lewisf16142c2019-11-07 15:56:04540}
Blink Reformat4c46d092018-04-07 15:32:37541
542/**
543 * @unrestricted
544 */
Paul Lewisf16142c2019-11-07 15:56:04545export class AXRelatedNodeElement {
Blink Reformat4c46d092018-04-07 15:32:37546 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41547 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37548 * @param {!Protocol.Accessibility.AXRelatedNode=} value
549 */
550 constructor(node, value) {
551 this._deferredNode = node.deferredNode;
552 this._idref = node.idref;
553 this._value = value;
554 }
555
556 /**
557 * @return {!Element}
558 */
559 render() {
Peter Marshall7e33f4d2020-09-02 08:59:09560 const element = document.createElement('span');
Blink Reformat4c46d092018-04-07 15:32:37561
562 if (this._deferredNode) {
Peter Marshall7e33f4d2020-09-02 08:59:09563 const valueElement = document.createElement('span');
Blink Reformat4c46d092018-04-07 15:32:37564 element.appendChild(valueElement);
Alice Boxhall6ac43432018-11-22 08:24:18565 this._deferredNode.resolvePromise().then(node => {
Peter Marshall7e33f4d2020-09-02 08:59:09566 Common.Linkifier.Linkifier.linkify(node, {tooltip: undefined, preventKeyboardFocus: true})
Jeff Fisher3f5f19c2019-08-28 19:10:02567 .then(linkfied => valueElement.appendChild(linkfied));
Alice Boxhall6ac43432018-11-22 08:24:18568 });
Blink Reformat4c46d092018-04-07 15:32:37569 } else if (this._idref) {
570 element.classList.add('invalid');
Peter Marshall7e33f4d2020-09-02 08:59:09571 const valueElement = AXNodePropertyTreeElement.createExclamationMark(ls`No node with this ID.`);
Sigurd Schneider23c52972020-10-13 09:31:14572 UI.UIUtils.createTextChild(valueElement, this._idref);
Blink Reformat4c46d092018-04-07 15:32:37573 element.appendChild(valueElement);
574 }
575
576 return element;
577 }
Rob Paveza84d41442019-10-10 23:01:09578
579 /**
580 * Attempts to cause the node referred to by the related node to be selected in the tree.
581 */
582 revealNode() {
Peter Marshall7e33f4d2020-09-02 08:59:09583 if (this._deferredNode) {
584 this._deferredNode.resolvePromise().then(node => Common.Revealer.reveal(node));
585 }
Rob Paveza84d41442019-10-10 23:01:09586 }
Paul Lewisf16142c2019-11-07 15:56:04587}
Blink Reformat4c46d092018-04-07 15:32:37588
589/**
590 * @unrestricted
591 */
Paul Lewisf16142c2019-11-07 15:56:04592export class AXNodeIgnoredReasonTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37593 /**
594 * @param {!Protocol.Accessibility.AXProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58595 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37596 */
597 constructor(property, axNode) {
598 super(axNode);
599 this._property = property;
600 this._axNode = axNode;
601 this.toggleOnClick = true;
602 this.selectable = false;
603 }
604
605 /**
606 * @param {?string} reason
Tim van der Lippe6d1e03c2020-01-22 14:05:58607 * @param {?AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37608 * @return {?Element}
609 */
610 static createReasonElement(reason, axNode) {
611 let reasonElement = null;
612 switch (reason) {
613 case 'activeModalDialog':
Tim van der Lippe8f15c8d2020-02-13 14:59:41614 reasonElement = UI.UIUtils.formatLocalized('Element is hidden by active modal dialog:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37615 break;
616 case 'ancestorIsLeafNode':
Tim van der Lippe8f15c8d2020-02-13 14:59:41617 reasonElement = UI.UIUtils.formatLocalized('Ancestor\'s children are all presentational:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37618 break;
619 case 'ariaHiddenElement': {
Peter Marshall7e33f4d2020-09-02 08:59:09620 const ariaHiddenSpan = document.createElement('span', {is: 'source-code'}).textContent = 'aria-hidden';
Tim van der Lippe8f15c8d2020-02-13 14:59:41621 reasonElement = UI.UIUtils.formatLocalized('Element is %s.', [ariaHiddenSpan]);
Blink Reformat4c46d092018-04-07 15:32:37622 break;
623 }
624 case 'ariaHiddenSubtree': {
Peter Marshall7e33f4d2020-09-02 08:59:09625 const ariaHiddenSpan = document.createElement('span', {is: 'source-code'}).textContent = 'aria-hidden';
626 const trueSpan = document.createElement('span', {is: 'source-code'}).textContent = 'true';
Tim van der Lippe8f15c8d2020-02-13 14:59:41627 reasonElement = UI.UIUtils.formatLocalized('%s is %s on ancestor:\xA0', [ariaHiddenSpan, trueSpan]);
Blink Reformat4c46d092018-04-07 15:32:37628 break;
629 }
630 case 'emptyAlt':
Tim van der Lippe8f15c8d2020-02-13 14:59:41631 reasonElement = UI.UIUtils.formatLocalized('Element has empty alt text.', []);
Blink Reformat4c46d092018-04-07 15:32:37632 break;
633 case 'emptyText':
Tim van der Lippe8f15c8d2020-02-13 14:59:41634 reasonElement = UI.UIUtils.formatLocalized('No text content.', []);
Blink Reformat4c46d092018-04-07 15:32:37635 break;
636 case 'inertElement':
Tim van der Lippe8f15c8d2020-02-13 14:59:41637 reasonElement = UI.UIUtils.formatLocalized('Element is inert.', []);
Blink Reformat4c46d092018-04-07 15:32:37638 break;
639 case 'inertSubtree':
Tim van der Lippe8f15c8d2020-02-13 14:59:41640 reasonElement = UI.UIUtils.formatLocalized('Element is in an inert subtree from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37641 break;
642 case 'inheritsPresentation':
Tim van der Lippe8f15c8d2020-02-13 14:59:41643 reasonElement = UI.UIUtils.formatLocalized('Element inherits presentational role from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37644 break;
645 case 'labelContainer':
Tim van der Lippe8f15c8d2020-02-13 14:59:41646 reasonElement = UI.UIUtils.formatLocalized('Part of label element:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37647 break;
648 case 'labelFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41649 reasonElement = UI.UIUtils.formatLocalized('Label for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37650 break;
651 case 'notRendered':
Tim van der Lippe8f15c8d2020-02-13 14:59:41652 reasonElement = UI.UIUtils.formatLocalized('Element is not rendered.', []);
Blink Reformat4c46d092018-04-07 15:32:37653 break;
654 case 'notVisible':
Tim van der Lippe8f15c8d2020-02-13 14:59:41655 reasonElement = UI.UIUtils.formatLocalized('Element is not visible.', []);
Blink Reformat4c46d092018-04-07 15:32:37656 break;
657 case 'presentationalRole': {
Peter Marshall7e33f4d2020-09-02 08:59:09658 const role = axNode && axNode.role() || '';
659 const rolePresentationSpan = document.createElement('span', {is: 'source-code'}).textContent = 'role=' + role;
Tim van der Lippe8f15c8d2020-02-13 14:59:41660 reasonElement = UI.UIUtils.formatLocalized('Element has %s.', [rolePresentationSpan]);
Blink Reformat4c46d092018-04-07 15:32:37661 break;
662 }
663 case 'probablyPresentational':
Tim van der Lippe8f15c8d2020-02-13 14:59:41664 reasonElement = UI.UIUtils.formatLocalized('Element is presentational.', []);
Blink Reformat4c46d092018-04-07 15:32:37665 break;
666 case 'staticTextUsedAsNameFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41667 reasonElement = UI.UIUtils.formatLocalized('Static text node is used as name for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37668 break;
669 case 'uninteresting':
Tim van der Lippe8f15c8d2020-02-13 14:59:41670 reasonElement = UI.UIUtils.formatLocalized('Element not interesting for accessibility.', []);
Blink Reformat4c46d092018-04-07 15:32:37671 break;
672 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34673 if (reasonElement) {
Blink Reformat4c46d092018-04-07 15:32:37674 reasonElement.classList.add('ax-reason');
Tim van der Lippe1d6e57a2019-09-30 11:55:34675 }
Blink Reformat4c46d092018-04-07 15:32:37676 return reasonElement;
677 }
678
679 /**
680 * @override
681 */
682 onattach() {
683 this.listItemElement.removeChildren();
684
Tim van der Lippe6d1e03c2020-01-22 14:05:58685 this._reasonElement = AXNodeIgnoredReasonTreeElement.createReasonElement(this._property.name, this._axNode);
Changhao Hanc1817b22020-09-07 09:04:18686 if (this._reasonElement) {
687 this.listItemElement.appendChild(this._reasonElement);
688 }
Blink Reformat4c46d092018-04-07 15:32:37689
690 const value = this._property.value;
Tim van der Lippe1d6e57a2019-09-30 11:55:34691 if (value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37692 this.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34693 }
Blink Reformat4c46d092018-04-07 15:32:37694 }
Paul Lewisf16142c2019-11-07 15:56:04695}