blob: 99f951e7717155a0c719d6e751b7357e958313d1 [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
Tim van der Lippe6d1e03c2020-01-22 14:05:589import {AccessibilityNode} from './AccessibilityModel.js'; // eslint-disable-line no-unused-vars
10import {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}
23 */
24 this._axNode = null;
25
Blink Reformat4c46d092018-04-07 15:32:3726 this.contentElement.classList.add('ax-subpane');
27
28 this._noNodeInfo = this.createInfo(ls`No accessibility node`);
29 this._ignoredInfo = this.createInfo(ls`Accessibility node not exposed`, 'ax-ignored-info hidden');
30
31 this._treeOutline = this.createTreeOutline();
32 this._ignoredReasonsTree = this.createTreeOutline();
33
34 this.element.classList.add('accessibility-computed');
35 this.registerRequiredCSS('accessibility/accessibilityNode.css');
Rob Paveza84d41442019-10-10 23:01:0936 this._treeOutline.setFocusable(true);
Blink Reformat4c46d092018-04-07 15:32:3737 }
38
39 /**
Tim van der Lippe6d1e03c2020-01-22 14:05:5840 * @param {?AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:3741 * @override
42 */
43 setAXNode(axNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3444 if (this._axNode === axNode) {
Blink Reformat4c46d092018-04-07 15:32:3745 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3446 }
Blink Reformat4c46d092018-04-07 15:32:3747 this._axNode = axNode;
48
49 const treeOutline = this._treeOutline;
50 treeOutline.removeChildren();
51 const ignoredReasons = this._ignoredReasonsTree;
52 ignoredReasons.removeChildren();
53
54 if (!axNode) {
55 treeOutline.element.classList.add('hidden');
56 this._ignoredInfo.classList.add('hidden');
57 ignoredReasons.element.classList.add('hidden');
58
59 this._noNodeInfo.classList.remove('hidden');
60 this.element.classList.add('ax-ignored-node-pane');
61
62 return;
63 }
64
65 if (axNode.ignored()) {
66 this._noNodeInfo.classList.add('hidden');
67 treeOutline.element.classList.add('hidden');
68 this.element.classList.add('ax-ignored-node-pane');
69
70 this._ignoredInfo.classList.remove('hidden');
71 ignoredReasons.element.classList.remove('hidden');
72 /**
73 * @param {!Protocol.Accessibility.AXProperty} property
74 */
75 function addIgnoredReason(property) {
Tim van der Lippe6d1e03c2020-01-22 14:05:5876 ignoredReasons.appendChild(
77 new AXNodeIgnoredReasonTreeElement(property, /** @type {!AccessibilityNode} */ (axNode)));
Blink Reformat4c46d092018-04-07 15:32:3778 }
79 const ignoredReasonsArray = /** @type {!Array<!Protocol.Accessibility.AXProperty>} */ (axNode.ignoredReasons());
Tim van der Lippe1d6e57a2019-09-30 11:55:3480 for (const reason of ignoredReasonsArray) {
Blink Reformat4c46d092018-04-07 15:32:3781 addIgnoredReason(reason);
Tim van der Lippe1d6e57a2019-09-30 11:55:3482 }
83 if (!ignoredReasons.firstChild()) {
Blink Reformat4c46d092018-04-07 15:32:3784 ignoredReasons.element.classList.add('hidden');
Tim van der Lippe1d6e57a2019-09-30 11:55:3485 }
Blink Reformat4c46d092018-04-07 15:32:3786 return;
87 }
88 this.element.classList.remove('ax-ignored-node-pane');
89
90 this._ignoredInfo.classList.add('hidden');
91 ignoredReasons.element.classList.add('hidden');
92 this._noNodeInfo.classList.add('hidden');
93
94 treeOutline.element.classList.remove('hidden');
95
96 /**
97 * @param {!Protocol.Accessibility.AXProperty} property
98 */
99 function addProperty(property) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58100 treeOutline.appendChild(
101 new AXNodePropertyTreePropertyElement(property, /** @type {!AccessibilityNode} */ (axNode)));
Blink Reformat4c46d092018-04-07 15:32:37102 }
103
Tim van der Lippe1d6e57a2019-09-30 11:55:34104 for (const property of axNode.coreProperties()) {
Blink Reformat4c46d092018-04-07 15:32:37105 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:34106 }
Blink Reformat4c46d092018-04-07 15:32:37107
108 const roleProperty = /** @type {!Protocol.Accessibility.AXProperty} */ ({name: 'role', value: axNode.role()});
109 addProperty(roleProperty);
Tim van der Lippe1d6e57a2019-09-30 11:55:34110 for (const property of /** @type {!Array.<!Protocol.Accessibility.AXProperty>} */ (axNode.properties())) {
Blink Reformat4c46d092018-04-07 15:32:37111 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:34112 }
Rob Paveza84d41442019-10-10 23:01:09113
114 const firstNode = treeOutline.firstChild();
115 if (firstNode) {
116 firstNode.select(/* omitFocus= */ true, /* selectedByUser= */ false);
117 }
Blink Reformat4c46d092018-04-07 15:32:37118 }
119
120 /**
121 * @override
Tim van der Lippe8f15c8d2020-02-13 14:59:41122 * @param {?SDK.DOMModel.DOMNode} node
Blink Reformat4c46d092018-04-07 15:32:37123 */
124 setNode(node) {
125 super.setNode(node);
126 this._axNode = null;
127 }
Paul Lewisf16142c2019-11-07 15:56:04128}
Blink Reformat4c46d092018-04-07 15:32:37129
130/**
131 * @unrestricted
132 */
Tim van der Lippe8f15c8d2020-02-13 14:59:41133export class AXNodePropertyTreeElement extends UI.TreeOutline.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37134 /**
Tim van der Lippe6d1e03c2020-01-22 14:05:58135 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37136 */
137 constructor(axNode) {
138 // Pass an empty title, the title gets made later in onattach.
139 super('');
140 this._axNode = axNode;
141 }
142
143 /**
144 * @param {?Protocol.Accessibility.AXValueType} type
145 * @param {string} value
146 * @return {!Element}
147 */
148 static createSimpleValueElement(type, value) {
149 let valueElement;
150 const AXValueType = Protocol.Accessibility.AXValueType;
Tim van der Lippe1d6e57a2019-09-30 11:55:34151 if (!type || type === AXValueType.ValueUndefined || type === AXValueType.ComputedString) {
Blink Reformat4c46d092018-04-07 15:32:37152 valueElement = createElement('span');
Tim van der Lippe1d6e57a2019-09-30 11:55:34153 } else {
Blink Reformat4c46d092018-04-07 15:32:37154 valueElement = createElementWithClass('span', 'monospace');
Tim van der Lippe1d6e57a2019-09-30 11:55:34155 }
Blink Reformat4c46d092018-04-07 15:32:37156 let valueText;
Tim van der Lippe6d1e03c2020-01-22 14:05:58157 const isStringProperty = type && StringProperties.has(type);
Blink Reformat4c46d092018-04-07 15:32:37158 if (isStringProperty) {
159 // Render \n as a nice unicode cr symbol.
160 valueText = '"' + value.replace(/\n/g, '\u21B5') + '"';
161 valueElement._originalTextContent = value;
162 } else {
163 valueText = String(value);
164 }
165
Tim van der Lippe6d1e03c2020-01-22 14:05:58166 if (type && type in TypeStyles) {
167 valueElement.classList.add(TypeStyles[type]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 }
Blink Reformat4c46d092018-04-07 15:32:37169
170 valueElement.setTextContentTruncatedIfNeeded(valueText || '');
171
172 valueElement.title = String(value) || '';
173
174 return valueElement;
175 }
176
177 /**
178 * @param {string} tooltip
179 * @return {!Element}
180 */
181 static createExclamationMark(tooltip) {
Joel Einbinder7fbe24c2019-01-24 05:19:01182 const exclamationElement = createElement('span', 'dt-icon-label');
Blink Reformat4c46d092018-04-07 15:32:37183 exclamationElement.type = 'smallicon-warning';
184 exclamationElement.title = tooltip;
185 return exclamationElement;
186 }
187
188 /**
189 * @param {string} name
190 */
191 appendNameElement(name) {
192 const nameElement = createElement('span');
Blink Reformat4c46d092018-04-07 15:32:37193 if (name in AXAttributes) {
Mandy Chenba6de382019-06-07 21:38:50194 nameElement.textContent = AXAttributes[name].name;
Blink Reformat4c46d092018-04-07 15:32:37195 nameElement.title = AXAttributes[name].description;
196 nameElement.classList.add('ax-readable-name');
197 } else {
198 nameElement.textContent = name;
199 nameElement.classList.add('ax-name');
200 nameElement.classList.add('monospace');
201 }
202 this.listItemElement.appendChild(nameElement);
203 }
204
205 /**
206 * @param {!Protocol.Accessibility.AXValue} value
207 */
208 appendValueElement(value) {
209 const AXValueType = Protocol.Accessibility.AXValueType;
210 if (value.type === AXValueType.Idref || value.type === AXValueType.Node || value.type === AXValueType.IdrefList ||
211 value.type === AXValueType.NodeList) {
212 this.appendRelatedNodeListValueElement(value);
213 return;
214 } else if (value.sources) {
215 const sources = value.sources;
216 for (let i = 0; i < sources.length; i++) {
217 const source = sources[i];
Tim van der Lippe6d1e03c2020-01-22 14:05:58218 const child = new AXValueSourceTreeElement(source, this._axNode);
Blink Reformat4c46d092018-04-07 15:32:37219 this.appendChild(child);
220 }
221 this.expand();
222 }
Tim van der Lippe6d1e03c2020-01-22 14:05:58223 const element = AXNodePropertyTreeElement.createSimpleValueElement(value.type, String(value.value));
Blink Reformat4c46d092018-04-07 15:32:37224 this.listItemElement.appendChild(element);
225 }
226
227 /**
228 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
229 * @param {number} index
230 */
231 appendRelatedNode(relatedNode, index) {
232 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41233 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58234 const nodeTreeElement = new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37235 this.appendChild(nodeTreeElement);
236 }
237
238 /**
239 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
240 */
241 appendRelatedNodeInline(relatedNode) {
242 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41243 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58244 const linkedNode = new AXRelatedNodeElement({deferredNode: deferredNode}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37245 this.listItemElement.appendChild(linkedNode.render());
246 }
247
248 /**
249 * @param {!Protocol.Accessibility.AXValue} value
250 */
251 appendRelatedNodeListValueElement(value) {
252 if (value.relatedNodes.length === 1 && !value.value) {
253 this.appendRelatedNodeInline(value.relatedNodes[0]);
254 return;
255 }
256
257 value.relatedNodes.forEach(this.appendRelatedNode, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34258 if (value.relatedNodes.length <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37259 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34260 } else {
Blink Reformat4c46d092018-04-07 15:32:37261 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34262 }
Blink Reformat4c46d092018-04-07 15:32:37263 }
Paul Lewisf16142c2019-11-07 15:56:04264}
Blink Reformat4c46d092018-04-07 15:32:37265
266/** @type {!Object<string, string>} */
Paul Lewisf16142c2019-11-07 15:56:04267export const TypeStyles = {
Blink Reformat4c46d092018-04-07 15:32:37268 attribute: 'ax-value-string',
269 boolean: 'object-value-boolean',
270 booleanOrUndefined: 'object-value-boolean',
271 computedString: 'ax-readable-string',
272 idref: 'ax-value-string',
273 idrefList: 'ax-value-string',
274 integer: 'object-value-number',
275 internalRole: 'ax-internal-role',
276 number: 'ax-value-number',
277 role: 'ax-role',
278 string: 'ax-value-string',
279 tristate: 'object-value-boolean',
280 valueUndefined: 'ax-value-undefined'
281};
282
283/** @type {!Set.<!Protocol.Accessibility.AXValueType>} */
Paul Lewisf16142c2019-11-07 15:56:04284export const StringProperties = new Set([
Blink Reformat4c46d092018-04-07 15:32:37285 Protocol.Accessibility.AXValueType.String, Protocol.Accessibility.AXValueType.ComputedString,
286 Protocol.Accessibility.AXValueType.IdrefList, Protocol.Accessibility.AXValueType.Idref
287]);
288
289/**
290 * @unrestricted
291 */
Paul Lewisf16142c2019-11-07 15:56:04292export class AXNodePropertyTreePropertyElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37293 /**
294 * @param {!Protocol.Accessibility.AXProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58295 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37296 */
297 constructor(property, axNode) {
298 super(axNode);
299
300 this._property = property;
301 this.toggleOnClick = true;
Blink Reformat4c46d092018-04-07 15:32:37302
303 this.listItemElement.classList.add('property');
304 }
305
306 /**
307 * @override
308 */
309 onattach() {
310 this._update();
311 }
312
313 _update() {
314 this.listItemElement.removeChildren();
315
316 this.appendNameElement(this._property.name);
317
Mathias Bynens7d8cd342019-09-17 13:32:10318 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37319
320 this.appendValueElement(this._property.value);
321 }
Paul Lewisf16142c2019-11-07 15:56:04322}
Blink Reformat4c46d092018-04-07 15:32:37323
324/**
325 * @unrestricted
326 */
Paul Lewisf16142c2019-11-07 15:56:04327export class AXValueSourceTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37328 /**
329 * @param {!Protocol.Accessibility.AXValueSource} source
Tim van der Lippe6d1e03c2020-01-22 14:05:58330 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37331 */
332 constructor(source, axNode) {
333 super(axNode);
334 this._source = source;
Blink Reformat4c46d092018-04-07 15:32:37335 }
336
337 /**
338 * @override
339 */
340 onattach() {
341 this._update();
342 }
343
344 /**
345 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
Blink Reformat4c46d092018-04-07 15:32:37346 * @param {string} idref
347 */
Meredith Lane4be4e9a2020-02-05 06:07:02348 appendRelatedNodeWithIdref(relatedNode, idref) {
Blink Reformat4c46d092018-04-07 15:32:37349 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41350 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58351 const nodeTreeElement = new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode, idref: idref}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37352 this.appendChild(nodeTreeElement);
353 }
354
355 /**
356 * @param {!Protocol.Accessibility.AXValue} value
357 */
358 appendIDRefValueElement(value) {
Meredith Lane4be4e9a2020-02-05 06:07:02359 if (value.value === null) {
360 return;
361 }
362
363 const relatedNodes = value.relatedNodes || [];
364
365 // Content attribute is empty, but if the relationship was set via the IDL
366 // then there may be related nodes.
367 if (value.value === '') {
368 for (const node of relatedNodes) {
369 const idref = node.idref || '';
370 this.appendRelatedNodeWithIdref(node, idref);
371 }
372 return;
373 }
Blink Reformat4c46d092018-04-07 15:32:37374
375 const idrefs = value.value.trim().split(/\s+/);
Meredith Lane4be4e9a2020-02-05 06:07:02376 for (const idref of idrefs) {
Blink Reformat4c46d092018-04-07 15:32:37377 const matchingNode = relatedNodes.find(node => node.idref === idref);
Blink Reformat4c46d092018-04-07 15:32:37378
Meredith Lane4be4e9a2020-02-05 06:07:02379 // If there is exactly one related node, it is rendered on the same line
380 // of the label. If there are more, they are each rendered on their own
381 // line below the label.
Blink Reformat4c46d092018-04-07 15:32:37382 // TODO(aboxhall): exclamation mark if not idreflist type
Meredith Lane4be4e9a2020-02-05 06:07:02383 if (matchingNode) {
384 this.appendRelatedNodeWithIdref(matchingNode, idref);
385 } else if (idrefs.length === 1) {
386 this.listItemElement.appendChild(new Accessibility.AXRelatedNodeElement({idref: idref}).render());
387 } else {
388 this.appendChild(new Accessibility.AXRelatedNodeSourceTreeElement({idref: idref}));
Blink Reformat4c46d092018-04-07 15:32:37389 }
390 }
391 }
392
393 /**
394 * @param {!Protocol.Accessibility.AXValue} value
395 * @override
396 */
397 appendRelatedNodeListValueElement(value) {
398 const relatedNodes = value.relatedNodes;
399 const numNodes = relatedNodes.length;
400
401 if (value.type === Protocol.Accessibility.AXValueType.IdrefList ||
Tim van der Lippe1d6e57a2019-09-30 11:55:34402 value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37403 this.appendIDRefValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34404 } else {
Blink Reformat4c46d092018-04-07 15:32:37405 super.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 }
Blink Reformat4c46d092018-04-07 15:32:37407
408
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 if (numNodes <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37410 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34411 } else {
Blink Reformat4c46d092018-04-07 15:32:37412 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34413 }
Blink Reformat4c46d092018-04-07 15:32:37414 }
415
416 /**
417 * @param {!Protocol.Accessibility.AXValueSource} source
418 */
419 appendSourceNameElement(source) {
420 const nameElement = createElement('span');
421 const AXValueSourceType = Protocol.Accessibility.AXValueSourceType;
422 const type = source.type;
423 switch (type) {
424 case AXValueSourceType.Attribute:
425 case AXValueSourceType.Placeholder:
426 case AXValueSourceType.RelatedElement:
427 if (source.nativeSource) {
Blink Reformat4c46d092018-04-07 15:32:37428 const nativeSource = source.nativeSource;
Mandy Chenba6de382019-06-07 21:38:50429 nameElement.textContent = AXNativeSourceTypes[nativeSource].name;
430 nameElement.title = AXNativeSourceTypes[nativeSource].description;
Blink Reformat4c46d092018-04-07 15:32:37431 nameElement.classList.add('ax-readable-name');
432 break;
433 }
434 nameElement.textContent = source.attribute;
435 nameElement.classList.add('ax-name');
436 nameElement.classList.add('monospace');
437 break;
438 default:
Blink Reformat4c46d092018-04-07 15:32:37439 if (type in AXSourceTypes) {
Mandy Chenba6de382019-06-07 21:38:50440 nameElement.textContent = AXSourceTypes[type].name;
441 nameElement.title = AXSourceTypes[type].description;
Blink Reformat4c46d092018-04-07 15:32:37442 nameElement.classList.add('ax-readable-name');
443 } else {
444 console.warn(type, 'not in AXSourceTypes');
Mandy Chenba6de382019-06-07 21:38:50445 nameElement.textContent = type;
Blink Reformat4c46d092018-04-07 15:32:37446 }
447 }
448 this.listItemElement.appendChild(nameElement);
449 }
450
451 _update() {
452 this.listItemElement.removeChildren();
453
454 if (this._source.invalid) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58455 const exclamationMark = AXNodePropertyTreeElement.createExclamationMark(ls`Invalid source.`);
Blink Reformat4c46d092018-04-07 15:32:37456 this.listItemElement.appendChild(exclamationMark);
457 this.listItemElement.classList.add('ax-value-source-invalid');
458 } else if (this._source.superseded) {
459 this.listItemElement.classList.add('ax-value-source-unused');
460 }
461
462 this.appendSourceNameElement(this._source);
463
Mathias Bynens7d8cd342019-09-17 13:32:10464 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37465
466 if (this._source.attributeValue) {
467 this.appendValueElement(this._source.attributeValue);
Mathias Bynens7d8cd342019-09-17 13:32:10468 this.listItemElement.createTextChild('\xA0');
Blink Reformat4c46d092018-04-07 15:32:37469 } else if (this._source.nativeSourceValue) {
470 this.appendValueElement(this._source.nativeSourceValue);
Mathias Bynens7d8cd342019-09-17 13:32:10471 this.listItemElement.createTextChild('\xA0');
Tim van der Lippe1d6e57a2019-09-30 11:55:34472 if (this._source.value) {
Blink Reformat4c46d092018-04-07 15:32:37473 this.appendValueElement(this._source.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34474 }
Blink Reformat4c46d092018-04-07 15:32:37475 } else if (this._source.value) {
476 this.appendValueElement(this._source.value);
477 } else {
Tim van der Lippe6d1e03c2020-01-22 14:05:58478 const valueElement = AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37479 Protocol.Accessibility.AXValueType.ValueUndefined, ls`Not specified`);
480 this.listItemElement.appendChild(valueElement);
481 this.listItemElement.classList.add('ax-value-source-unused');
482 }
483
Tim van der Lippe1d6e57a2019-09-30 11:55:34484 if (this._source.value && this._source.superseded) {
Blink Reformat4c46d092018-04-07 15:32:37485 this.listItemElement.classList.add('ax-value-source-superseded');
Tim van der Lippe1d6e57a2019-09-30 11:55:34486 }
Blink Reformat4c46d092018-04-07 15:32:37487 }
Paul Lewisf16142c2019-11-07 15:56:04488}
Blink Reformat4c46d092018-04-07 15:32:37489
490/**
491 * @unrestricted
492 */
Tim van der Lippe8f15c8d2020-02-13 14:59:41493export class AXRelatedNodeSourceTreeElement extends UI.TreeOutline.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37494 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41495 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37496 * @param {!Protocol.Accessibility.AXRelatedNode=} value
497 */
498 constructor(node, value) {
499 super('');
500
501 this._value = value;
Tim van der Lippe6d1e03c2020-01-22 14:05:58502 this._axRelatedNodeElement = new AXRelatedNodeElement(node, value);
Rob Paveza84d41442019-10-10 23:01:09503 this.selectable = true;
Blink Reformat4c46d092018-04-07 15:32:37504 }
505
506 /**
507 * @override
508 */
509 onattach() {
510 this.listItemElement.appendChild(this._axRelatedNodeElement.render());
Tim van der Lippe1d6e57a2019-09-30 11:55:34511 if (!this._value) {
Blink Reformat4c46d092018-04-07 15:32:37512 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34513 }
Blink Reformat4c46d092018-04-07 15:32:37514
515 if (this._value.text) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58516 this.listItemElement.appendChild(AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37517 Protocol.Accessibility.AXValueType.ComputedString, this._value.text));
518 }
519 }
Rob Paveza84d41442019-10-10 23:01:09520
521 /**
522 * @override
523 */
524 onenter() {
525 this._axRelatedNodeElement.revealNode();
526 return true;
527 }
Paul Lewisf16142c2019-11-07 15:56:04528}
Blink Reformat4c46d092018-04-07 15:32:37529
530/**
531 * @unrestricted
532 */
Paul Lewisf16142c2019-11-07 15:56:04533export class AXRelatedNodeElement {
Blink Reformat4c46d092018-04-07 15:32:37534 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41535 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37536 * @param {!Protocol.Accessibility.AXRelatedNode=} value
537 */
538 constructor(node, value) {
539 this._deferredNode = node.deferredNode;
540 this._idref = node.idref;
541 this._value = value;
542 }
543
544 /**
545 * @return {!Element}
546 */
547 render() {
548 const element = createElement('span');
549 let valueElement;
550
551 if (this._deferredNode) {
552 valueElement = createElement('span');
553 element.appendChild(valueElement);
Alice Boxhall6ac43432018-11-22 08:24:18554 this._deferredNode.resolvePromise().then(node => {
Tim van der Lippe8f15c8d2020-02-13 14:59:41555 Common.Linkifier.Linkifier.linkify(node, {preventKeyboardFocus: true})
Jeff Fisher3f5f19c2019-08-28 19:10:02556 .then(linkfied => valueElement.appendChild(linkfied));
Alice Boxhall6ac43432018-11-22 08:24:18557 });
Blink Reformat4c46d092018-04-07 15:32:37558 } else if (this._idref) {
559 element.classList.add('invalid');
Tim van der Lippe6d1e03c2020-01-22 14:05:58560 valueElement = AXNodePropertyTreeElement.createExclamationMark(ls`No node with this ID.`);
Blink Reformat4c46d092018-04-07 15:32:37561 valueElement.createTextChild(this._idref);
562 element.appendChild(valueElement);
563 }
564
565 return element;
566 }
Rob Paveza84d41442019-10-10 23:01:09567
568 /**
569 * Attempts to cause the node referred to by the related node to be selected in the tree.
570 */
571 revealNode() {
572 this._deferredNode.resolvePromise().then(node => Common.Revealer.reveal(node));
573 }
Paul Lewisf16142c2019-11-07 15:56:04574}
Blink Reformat4c46d092018-04-07 15:32:37575
576/**
577 * @unrestricted
578 */
Paul Lewisf16142c2019-11-07 15:56:04579export class AXNodeIgnoredReasonTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37580 /**
581 * @param {!Protocol.Accessibility.AXProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58582 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37583 */
584 constructor(property, axNode) {
585 super(axNode);
586 this._property = property;
587 this._axNode = axNode;
588 this.toggleOnClick = true;
589 this.selectable = false;
590 }
591
592 /**
593 * @param {?string} reason
Tim van der Lippe6d1e03c2020-01-22 14:05:58594 * @param {?AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37595 * @return {?Element}
596 */
597 static createReasonElement(reason, axNode) {
598 let reasonElement = null;
599 switch (reason) {
600 case 'activeModalDialog':
Tim van der Lippe8f15c8d2020-02-13 14:59:41601 reasonElement = UI.UIUtils.formatLocalized('Element is hidden by active modal dialog:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37602 break;
603 case 'ancestorIsLeafNode':
Tim van der Lippe8f15c8d2020-02-13 14:59:41604 reasonElement = UI.UIUtils.formatLocalized('Ancestor\'s children are all presentational:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37605 break;
606 case 'ariaHiddenElement': {
607 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
Tim van der Lippe8f15c8d2020-02-13 14:59:41608 reasonElement = UI.UIUtils.formatLocalized('Element is %s.', [ariaHiddenSpan]);
Blink Reformat4c46d092018-04-07 15:32:37609 break;
610 }
611 case 'ariaHiddenSubtree': {
612 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
613 const trueSpan = createElement('span', 'source-code').textContent = 'true';
Tim van der Lippe8f15c8d2020-02-13 14:59:41614 reasonElement = UI.UIUtils.formatLocalized('%s is %s on ancestor:\xA0', [ariaHiddenSpan, trueSpan]);
Blink Reformat4c46d092018-04-07 15:32:37615 break;
616 }
617 case 'emptyAlt':
Tim van der Lippe8f15c8d2020-02-13 14:59:41618 reasonElement = UI.UIUtils.formatLocalized('Element has empty alt text.', []);
Blink Reformat4c46d092018-04-07 15:32:37619 break;
620 case 'emptyText':
Tim van der Lippe8f15c8d2020-02-13 14:59:41621 reasonElement = UI.UIUtils.formatLocalized('No text content.', []);
Blink Reformat4c46d092018-04-07 15:32:37622 break;
623 case 'inertElement':
Tim van der Lippe8f15c8d2020-02-13 14:59:41624 reasonElement = UI.UIUtils.formatLocalized('Element is inert.', []);
Blink Reformat4c46d092018-04-07 15:32:37625 break;
626 case 'inertSubtree':
Tim van der Lippe8f15c8d2020-02-13 14:59:41627 reasonElement = UI.UIUtils.formatLocalized('Element is in an inert subtree from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37628 break;
629 case 'inheritsPresentation':
Tim van der Lippe8f15c8d2020-02-13 14:59:41630 reasonElement = UI.UIUtils.formatLocalized('Element inherits presentational role from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37631 break;
632 case 'labelContainer':
Tim van der Lippe8f15c8d2020-02-13 14:59:41633 reasonElement = UI.UIUtils.formatLocalized('Part of label element:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37634 break;
635 case 'labelFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41636 reasonElement = UI.UIUtils.formatLocalized('Label for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37637 break;
638 case 'notRendered':
Tim van der Lippe8f15c8d2020-02-13 14:59:41639 reasonElement = UI.UIUtils.formatLocalized('Element is not rendered.', []);
Blink Reformat4c46d092018-04-07 15:32:37640 break;
641 case 'notVisible':
Tim van der Lippe8f15c8d2020-02-13 14:59:41642 reasonElement = UI.UIUtils.formatLocalized('Element is not visible.', []);
Blink Reformat4c46d092018-04-07 15:32:37643 break;
644 case 'presentationalRole': {
645 const rolePresentationSpan = createElement('span', 'source-code').textContent = 'role=' + axNode.role().value;
Tim van der Lippe8f15c8d2020-02-13 14:59:41646 reasonElement = UI.UIUtils.formatLocalized('Element has %s.', [rolePresentationSpan]);
Blink Reformat4c46d092018-04-07 15:32:37647 break;
648 }
649 case 'probablyPresentational':
Tim van der Lippe8f15c8d2020-02-13 14:59:41650 reasonElement = UI.UIUtils.formatLocalized('Element is presentational.', []);
Blink Reformat4c46d092018-04-07 15:32:37651 break;
652 case 'staticTextUsedAsNameFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41653 reasonElement = UI.UIUtils.formatLocalized('Static text node is used as name for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37654 break;
655 case 'uninteresting':
Tim van der Lippe8f15c8d2020-02-13 14:59:41656 reasonElement = UI.UIUtils.formatLocalized('Element not interesting for accessibility.', []);
Blink Reformat4c46d092018-04-07 15:32:37657 break;
658 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34659 if (reasonElement) {
Blink Reformat4c46d092018-04-07 15:32:37660 reasonElement.classList.add('ax-reason');
Tim van der Lippe1d6e57a2019-09-30 11:55:34661 }
Blink Reformat4c46d092018-04-07 15:32:37662 return reasonElement;
663 }
664
665 /**
666 * @override
667 */
668 onattach() {
669 this.listItemElement.removeChildren();
670
Tim van der Lippe6d1e03c2020-01-22 14:05:58671 this._reasonElement = AXNodeIgnoredReasonTreeElement.createReasonElement(this._property.name, this._axNode);
Blink Reformat4c46d092018-04-07 15:32:37672 this.listItemElement.appendChild(this._reasonElement);
673
674 const value = this._property.value;
Tim van der Lippe1d6e57a2019-09-30 11:55:34675 if (value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37676 this.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34677 }
Blink Reformat4c46d092018-04-07 15:32:37678 }
Paul Lewisf16142c2019-11-07 15:56:04679}