blob: 67dcd58aaf7aa241f3abe31626fd310e665387de [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;
Mathias Bynensf06e8c02020-02-28 13:58:28214 }
215 if (value.sources) {
Blink Reformat4c46d092018-04-07 15:32:37216 const sources = value.sources;
217 for (let i = 0; i < sources.length; i++) {
218 const source = sources[i];
Tim van der Lippe6d1e03c2020-01-22 14:05:58219 const child = new AXValueSourceTreeElement(source, this._axNode);
Blink Reformat4c46d092018-04-07 15:32:37220 this.appendChild(child);
221 }
222 this.expand();
223 }
Tim van der Lippe6d1e03c2020-01-22 14:05:58224 const element = AXNodePropertyTreeElement.createSimpleValueElement(value.type, String(value.value));
Blink Reformat4c46d092018-04-07 15:32:37225 this.listItemElement.appendChild(element);
226 }
227
228 /**
229 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
230 * @param {number} index
231 */
232 appendRelatedNode(relatedNode, index) {
233 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41234 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58235 const nodeTreeElement = new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37236 this.appendChild(nodeTreeElement);
237 }
238
239 /**
240 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
241 */
242 appendRelatedNodeInline(relatedNode) {
243 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41244 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58245 const linkedNode = new AXRelatedNodeElement({deferredNode: deferredNode}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37246 this.listItemElement.appendChild(linkedNode.render());
247 }
248
249 /**
250 * @param {!Protocol.Accessibility.AXValue} value
251 */
252 appendRelatedNodeListValueElement(value) {
253 if (value.relatedNodes.length === 1 && !value.value) {
254 this.appendRelatedNodeInline(value.relatedNodes[0]);
255 return;
256 }
257
258 value.relatedNodes.forEach(this.appendRelatedNode, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34259 if (value.relatedNodes.length <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37260 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 } else {
Blink Reformat4c46d092018-04-07 15:32:37262 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34263 }
Blink Reformat4c46d092018-04-07 15:32:37264 }
Paul Lewisf16142c2019-11-07 15:56:04265}
Blink Reformat4c46d092018-04-07 15:32:37266
267/** @type {!Object<string, string>} */
Paul Lewisf16142c2019-11-07 15:56:04268export const TypeStyles = {
Blink Reformat4c46d092018-04-07 15:32:37269 attribute: 'ax-value-string',
270 boolean: 'object-value-boolean',
271 booleanOrUndefined: 'object-value-boolean',
272 computedString: 'ax-readable-string',
273 idref: 'ax-value-string',
274 idrefList: 'ax-value-string',
275 integer: 'object-value-number',
276 internalRole: 'ax-internal-role',
277 number: 'ax-value-number',
278 role: 'ax-role',
279 string: 'ax-value-string',
280 tristate: 'object-value-boolean',
281 valueUndefined: 'ax-value-undefined'
282};
283
284/** @type {!Set.<!Protocol.Accessibility.AXValueType>} */
Paul Lewisf16142c2019-11-07 15:56:04285export const StringProperties = new Set([
Blink Reformat4c46d092018-04-07 15:32:37286 Protocol.Accessibility.AXValueType.String, Protocol.Accessibility.AXValueType.ComputedString,
287 Protocol.Accessibility.AXValueType.IdrefList, Protocol.Accessibility.AXValueType.Idref
288]);
289
290/**
291 * @unrestricted
292 */
Paul Lewisf16142c2019-11-07 15:56:04293export class AXNodePropertyTreePropertyElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37294 /**
295 * @param {!Protocol.Accessibility.AXProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58296 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37297 */
298 constructor(property, axNode) {
299 super(axNode);
300
301 this._property = property;
302 this.toggleOnClick = true;
Blink Reformat4c46d092018-04-07 15:32:37303
304 this.listItemElement.classList.add('property');
305 }
306
307 /**
308 * @override
309 */
310 onattach() {
311 this._update();
312 }
313
314 _update() {
315 this.listItemElement.removeChildren();
316
317 this.appendNameElement(this._property.name);
318
Mathias Bynens7d8cd342019-09-17 13:32:10319 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37320
321 this.appendValueElement(this._property.value);
322 }
Paul Lewisf16142c2019-11-07 15:56:04323}
Blink Reformat4c46d092018-04-07 15:32:37324
325/**
326 * @unrestricted
327 */
Paul Lewisf16142c2019-11-07 15:56:04328export class AXValueSourceTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37329 /**
330 * @param {!Protocol.Accessibility.AXValueSource} source
Tim van der Lippe6d1e03c2020-01-22 14:05:58331 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37332 */
333 constructor(source, axNode) {
334 super(axNode);
335 this._source = source;
Blink Reformat4c46d092018-04-07 15:32:37336 }
337
338 /**
339 * @override
340 */
341 onattach() {
342 this._update();
343 }
344
345 /**
346 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
Blink Reformat4c46d092018-04-07 15:32:37347 * @param {string} idref
348 */
Meredith Lane4be4e9a2020-02-05 06:07:02349 appendRelatedNodeWithIdref(relatedNode, idref) {
Blink Reformat4c46d092018-04-07 15:32:37350 const deferredNode =
Tim van der Lippe8f15c8d2020-02-13 14:59:41351 new SDK.DOMModel.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
Tim van der Lippe6d1e03c2020-01-22 14:05:58352 const nodeTreeElement = new AXRelatedNodeSourceTreeElement({deferredNode: deferredNode, idref: idref}, relatedNode);
Blink Reformat4c46d092018-04-07 15:32:37353 this.appendChild(nodeTreeElement);
354 }
355
356 /**
357 * @param {!Protocol.Accessibility.AXValue} value
358 */
359 appendIDRefValueElement(value) {
Meredith Lane4be4e9a2020-02-05 06:07:02360 if (value.value === null) {
361 return;
362 }
363
364 const relatedNodes = value.relatedNodes || [];
365
366 // Content attribute is empty, but if the relationship was set via the IDL
367 // then there may be related nodes.
368 if (value.value === '') {
369 for (const node of relatedNodes) {
370 const idref = node.idref || '';
371 this.appendRelatedNodeWithIdref(node, idref);
372 }
373 return;
374 }
Blink Reformat4c46d092018-04-07 15:32:37375
376 const idrefs = value.value.trim().split(/\s+/);
Meredith Lane4be4e9a2020-02-05 06:07:02377 for (const idref of idrefs) {
Blink Reformat4c46d092018-04-07 15:32:37378 const matchingNode = relatedNodes.find(node => node.idref === idref);
Blink Reformat4c46d092018-04-07 15:32:37379
Meredith Lane4be4e9a2020-02-05 06:07:02380 // If there is exactly one related node, it is rendered on the same line
381 // of the label. If there are more, they are each rendered on their own
382 // line below the label.
Blink Reformat4c46d092018-04-07 15:32:37383 // TODO(aboxhall): exclamation mark if not idreflist type
Meredith Lane4be4e9a2020-02-05 06:07:02384 if (matchingNode) {
385 this.appendRelatedNodeWithIdref(matchingNode, idref);
386 } else if (idrefs.length === 1) {
387 this.listItemElement.appendChild(new Accessibility.AXRelatedNodeElement({idref: idref}).render());
388 } else {
389 this.appendChild(new Accessibility.AXRelatedNodeSourceTreeElement({idref: idref}));
Blink Reformat4c46d092018-04-07 15:32:37390 }
391 }
392 }
393
394 /**
395 * @param {!Protocol.Accessibility.AXValue} value
396 * @override
397 */
398 appendRelatedNodeListValueElement(value) {
399 const relatedNodes = value.relatedNodes;
400 const numNodes = relatedNodes.length;
401
402 if (value.type === Protocol.Accessibility.AXValueType.IdrefList ||
Tim van der Lippe1d6e57a2019-09-30 11:55:34403 value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37404 this.appendIDRefValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34405 } else {
Blink Reformat4c46d092018-04-07 15:32:37406 super.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 }
Blink Reformat4c46d092018-04-07 15:32:37408
409
Tim van der Lippe1d6e57a2019-09-30 11:55:34410 if (numNodes <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37411 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34412 } else {
Blink Reformat4c46d092018-04-07 15:32:37413 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34414 }
Blink Reformat4c46d092018-04-07 15:32:37415 }
416
417 /**
418 * @param {!Protocol.Accessibility.AXValueSource} source
419 */
420 appendSourceNameElement(source) {
421 const nameElement = createElement('span');
422 const AXValueSourceType = Protocol.Accessibility.AXValueSourceType;
423 const type = source.type;
424 switch (type) {
425 case AXValueSourceType.Attribute:
426 case AXValueSourceType.Placeholder:
427 case AXValueSourceType.RelatedElement:
428 if (source.nativeSource) {
Blink Reformat4c46d092018-04-07 15:32:37429 const nativeSource = source.nativeSource;
Mandy Chenba6de382019-06-07 21:38:50430 nameElement.textContent = AXNativeSourceTypes[nativeSource].name;
431 nameElement.title = AXNativeSourceTypes[nativeSource].description;
Blink Reformat4c46d092018-04-07 15:32:37432 nameElement.classList.add('ax-readable-name');
433 break;
434 }
435 nameElement.textContent = source.attribute;
436 nameElement.classList.add('ax-name');
437 nameElement.classList.add('monospace');
438 break;
439 default:
Blink Reformat4c46d092018-04-07 15:32:37440 if (type in AXSourceTypes) {
Mandy Chenba6de382019-06-07 21:38:50441 nameElement.textContent = AXSourceTypes[type].name;
442 nameElement.title = AXSourceTypes[type].description;
Blink Reformat4c46d092018-04-07 15:32:37443 nameElement.classList.add('ax-readable-name');
444 } else {
445 console.warn(type, 'not in AXSourceTypes');
Mandy Chenba6de382019-06-07 21:38:50446 nameElement.textContent = type;
Blink Reformat4c46d092018-04-07 15:32:37447 }
448 }
449 this.listItemElement.appendChild(nameElement);
450 }
451
452 _update() {
453 this.listItemElement.removeChildren();
454
455 if (this._source.invalid) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58456 const exclamationMark = AXNodePropertyTreeElement.createExclamationMark(ls`Invalid source.`);
Blink Reformat4c46d092018-04-07 15:32:37457 this.listItemElement.appendChild(exclamationMark);
458 this.listItemElement.classList.add('ax-value-source-invalid');
459 } else if (this._source.superseded) {
460 this.listItemElement.classList.add('ax-value-source-unused');
461 }
462
463 this.appendSourceNameElement(this._source);
464
Mathias Bynens7d8cd342019-09-17 13:32:10465 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37466
467 if (this._source.attributeValue) {
468 this.appendValueElement(this._source.attributeValue);
Mathias Bynens7d8cd342019-09-17 13:32:10469 this.listItemElement.createTextChild('\xA0');
Blink Reformat4c46d092018-04-07 15:32:37470 } else if (this._source.nativeSourceValue) {
471 this.appendValueElement(this._source.nativeSourceValue);
Mathias Bynens7d8cd342019-09-17 13:32:10472 this.listItemElement.createTextChild('\xA0');
Tim van der Lippe1d6e57a2019-09-30 11:55:34473 if (this._source.value) {
Blink Reformat4c46d092018-04-07 15:32:37474 this.appendValueElement(this._source.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34475 }
Blink Reformat4c46d092018-04-07 15:32:37476 } else if (this._source.value) {
477 this.appendValueElement(this._source.value);
478 } else {
Tim van der Lippe6d1e03c2020-01-22 14:05:58479 const valueElement = AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37480 Protocol.Accessibility.AXValueType.ValueUndefined, ls`Not specified`);
481 this.listItemElement.appendChild(valueElement);
482 this.listItemElement.classList.add('ax-value-source-unused');
483 }
484
Tim van der Lippe1d6e57a2019-09-30 11:55:34485 if (this._source.value && this._source.superseded) {
Blink Reformat4c46d092018-04-07 15:32:37486 this.listItemElement.classList.add('ax-value-source-superseded');
Tim van der Lippe1d6e57a2019-09-30 11:55:34487 }
Blink Reformat4c46d092018-04-07 15:32:37488 }
Paul Lewisf16142c2019-11-07 15:56:04489}
Blink Reformat4c46d092018-04-07 15:32:37490
491/**
492 * @unrestricted
493 */
Tim van der Lippe8f15c8d2020-02-13 14:59:41494export class AXRelatedNodeSourceTreeElement extends UI.TreeOutline.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37495 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41496 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37497 * @param {!Protocol.Accessibility.AXRelatedNode=} value
498 */
499 constructor(node, value) {
500 super('');
501
502 this._value = value;
Tim van der Lippe6d1e03c2020-01-22 14:05:58503 this._axRelatedNodeElement = new AXRelatedNodeElement(node, value);
Rob Paveza84d41442019-10-10 23:01:09504 this.selectable = true;
Blink Reformat4c46d092018-04-07 15:32:37505 }
506
507 /**
508 * @override
509 */
510 onattach() {
511 this.listItemElement.appendChild(this._axRelatedNodeElement.render());
Tim van der Lippe1d6e57a2019-09-30 11:55:34512 if (!this._value) {
Blink Reformat4c46d092018-04-07 15:32:37513 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34514 }
Blink Reformat4c46d092018-04-07 15:32:37515
516 if (this._value.text) {
Tim van der Lippe6d1e03c2020-01-22 14:05:58517 this.listItemElement.appendChild(AXNodePropertyTreeElement.createSimpleValueElement(
Blink Reformat4c46d092018-04-07 15:32:37518 Protocol.Accessibility.AXValueType.ComputedString, this._value.text));
519 }
520 }
Rob Paveza84d41442019-10-10 23:01:09521
522 /**
523 * @override
524 */
525 onenter() {
526 this._axRelatedNodeElement.revealNode();
527 return true;
528 }
Paul Lewisf16142c2019-11-07 15:56:04529}
Blink Reformat4c46d092018-04-07 15:32:37530
531/**
532 * @unrestricted
533 */
Paul Lewisf16142c2019-11-07 15:56:04534export class AXRelatedNodeElement {
Blink Reformat4c46d092018-04-07 15:32:37535 /**
Tim van der Lippe8f15c8d2020-02-13 14:59:41536 * @param {{deferredNode: (!SDK.DOMModel.DeferredDOMNode|undefined), idref: (string|undefined)}} node
Blink Reformat4c46d092018-04-07 15:32:37537 * @param {!Protocol.Accessibility.AXRelatedNode=} value
538 */
539 constructor(node, value) {
540 this._deferredNode = node.deferredNode;
541 this._idref = node.idref;
542 this._value = value;
543 }
544
545 /**
546 * @return {!Element}
547 */
548 render() {
549 const element = createElement('span');
550 let valueElement;
551
552 if (this._deferredNode) {
553 valueElement = createElement('span');
554 element.appendChild(valueElement);
Alice Boxhall6ac43432018-11-22 08:24:18555 this._deferredNode.resolvePromise().then(node => {
Tim van der Lippe8f15c8d2020-02-13 14:59:41556 Common.Linkifier.Linkifier.linkify(node, {preventKeyboardFocus: true})
Jeff Fisher3f5f19c2019-08-28 19:10:02557 .then(linkfied => valueElement.appendChild(linkfied));
Alice Boxhall6ac43432018-11-22 08:24:18558 });
Blink Reformat4c46d092018-04-07 15:32:37559 } else if (this._idref) {
560 element.classList.add('invalid');
Tim van der Lippe6d1e03c2020-01-22 14:05:58561 valueElement = AXNodePropertyTreeElement.createExclamationMark(ls`No node with this ID.`);
Blink Reformat4c46d092018-04-07 15:32:37562 valueElement.createTextChild(this._idref);
563 element.appendChild(valueElement);
564 }
565
566 return element;
567 }
Rob Paveza84d41442019-10-10 23:01:09568
569 /**
570 * Attempts to cause the node referred to by the related node to be selected in the tree.
571 */
572 revealNode() {
573 this._deferredNode.resolvePromise().then(node => Common.Revealer.reveal(node));
574 }
Paul Lewisf16142c2019-11-07 15:56:04575}
Blink Reformat4c46d092018-04-07 15:32:37576
577/**
578 * @unrestricted
579 */
Paul Lewisf16142c2019-11-07 15:56:04580export class AXNodeIgnoredReasonTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37581 /**
582 * @param {!Protocol.Accessibility.AXProperty} property
Tim van der Lippe6d1e03c2020-01-22 14:05:58583 * @param {!AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37584 */
585 constructor(property, axNode) {
586 super(axNode);
587 this._property = property;
588 this._axNode = axNode;
589 this.toggleOnClick = true;
590 this.selectable = false;
591 }
592
593 /**
594 * @param {?string} reason
Tim van der Lippe6d1e03c2020-01-22 14:05:58595 * @param {?AccessibilityNode} axNode
Blink Reformat4c46d092018-04-07 15:32:37596 * @return {?Element}
597 */
598 static createReasonElement(reason, axNode) {
599 let reasonElement = null;
600 switch (reason) {
601 case 'activeModalDialog':
Tim van der Lippe8f15c8d2020-02-13 14:59:41602 reasonElement = UI.UIUtils.formatLocalized('Element is hidden by active modal dialog:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37603 break;
604 case 'ancestorIsLeafNode':
Tim van der Lippe8f15c8d2020-02-13 14:59:41605 reasonElement = UI.UIUtils.formatLocalized('Ancestor\'s children are all presentational:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37606 break;
607 case 'ariaHiddenElement': {
608 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
Tim van der Lippe8f15c8d2020-02-13 14:59:41609 reasonElement = UI.UIUtils.formatLocalized('Element is %s.', [ariaHiddenSpan]);
Blink Reformat4c46d092018-04-07 15:32:37610 break;
611 }
612 case 'ariaHiddenSubtree': {
613 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
614 const trueSpan = createElement('span', 'source-code').textContent = 'true';
Tim van der Lippe8f15c8d2020-02-13 14:59:41615 reasonElement = UI.UIUtils.formatLocalized('%s is %s on ancestor:\xA0', [ariaHiddenSpan, trueSpan]);
Blink Reformat4c46d092018-04-07 15:32:37616 break;
617 }
618 case 'emptyAlt':
Tim van der Lippe8f15c8d2020-02-13 14:59:41619 reasonElement = UI.UIUtils.formatLocalized('Element has empty alt text.', []);
Blink Reformat4c46d092018-04-07 15:32:37620 break;
621 case 'emptyText':
Tim van der Lippe8f15c8d2020-02-13 14:59:41622 reasonElement = UI.UIUtils.formatLocalized('No text content.', []);
Blink Reformat4c46d092018-04-07 15:32:37623 break;
624 case 'inertElement':
Tim van der Lippe8f15c8d2020-02-13 14:59:41625 reasonElement = UI.UIUtils.formatLocalized('Element is inert.', []);
Blink Reformat4c46d092018-04-07 15:32:37626 break;
627 case 'inertSubtree':
Tim van der Lippe8f15c8d2020-02-13 14:59:41628 reasonElement = UI.UIUtils.formatLocalized('Element is in an inert subtree from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37629 break;
630 case 'inheritsPresentation':
Tim van der Lippe8f15c8d2020-02-13 14:59:41631 reasonElement = UI.UIUtils.formatLocalized('Element inherits presentational role from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37632 break;
633 case 'labelContainer':
Tim van der Lippe8f15c8d2020-02-13 14:59:41634 reasonElement = UI.UIUtils.formatLocalized('Part of label element:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37635 break;
636 case 'labelFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41637 reasonElement = UI.UIUtils.formatLocalized('Label for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37638 break;
639 case 'notRendered':
Tim van der Lippe8f15c8d2020-02-13 14:59:41640 reasonElement = UI.UIUtils.formatLocalized('Element is not rendered.', []);
Blink Reformat4c46d092018-04-07 15:32:37641 break;
642 case 'notVisible':
Tim van der Lippe8f15c8d2020-02-13 14:59:41643 reasonElement = UI.UIUtils.formatLocalized('Element is not visible.', []);
Blink Reformat4c46d092018-04-07 15:32:37644 break;
645 case 'presentationalRole': {
646 const rolePresentationSpan = createElement('span', 'source-code').textContent = 'role=' + axNode.role().value;
Tim van der Lippe8f15c8d2020-02-13 14:59:41647 reasonElement = UI.UIUtils.formatLocalized('Element has %s.', [rolePresentationSpan]);
Blink Reformat4c46d092018-04-07 15:32:37648 break;
649 }
650 case 'probablyPresentational':
Tim van der Lippe8f15c8d2020-02-13 14:59:41651 reasonElement = UI.UIUtils.formatLocalized('Element is presentational.', []);
Blink Reformat4c46d092018-04-07 15:32:37652 break;
653 case 'staticTextUsedAsNameFor':
Tim van der Lippe8f15c8d2020-02-13 14:59:41654 reasonElement = UI.UIUtils.formatLocalized('Static text node is used as name for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37655 break;
656 case 'uninteresting':
Tim van der Lippe8f15c8d2020-02-13 14:59:41657 reasonElement = UI.UIUtils.formatLocalized('Element not interesting for accessibility.', []);
Blink Reformat4c46d092018-04-07 15:32:37658 break;
659 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34660 if (reasonElement) {
Blink Reformat4c46d092018-04-07 15:32:37661 reasonElement.classList.add('ax-reason');
Tim van der Lippe1d6e57a2019-09-30 11:55:34662 }
Blink Reformat4c46d092018-04-07 15:32:37663 return reasonElement;
664 }
665
666 /**
667 * @override
668 */
669 onattach() {
670 this.listItemElement.removeChildren();
671
Tim van der Lippe6d1e03c2020-01-22 14:05:58672 this._reasonElement = AXNodeIgnoredReasonTreeElement.createReasonElement(this._property.name, this._axNode);
Blink Reformat4c46d092018-04-07 15:32:37673 this.listItemElement.appendChild(this._reasonElement);
674
675 const value = this._property.value;
Tim van der Lippe1d6e57a2019-09-30 11:55:34676 if (value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37677 this.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34678 }
Blink Reformat4c46d092018-04-07 15:32:37679 }
Paul Lewisf16142c2019-11-07 15:56:04680}