blob: 8882b947d5b83cf6238760499dc211deed27e8d1 [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.
4/**
5 * @unrestricted
6 */
Paul Lewisf16142c2019-11-07 15:56:047export class AXNodeSubPane extends Accessibility.AccessibilitySubPane {
Blink Reformat4c46d092018-04-07 15:32:378 constructor() {
9 super(ls`Computed Properties`);
10
11 this.contentElement.classList.add('ax-subpane');
12
13 this._noNodeInfo = this.createInfo(ls`No accessibility node`);
14 this._ignoredInfo = this.createInfo(ls`Accessibility node not exposed`, 'ax-ignored-info hidden');
15
16 this._treeOutline = this.createTreeOutline();
17 this._ignoredReasonsTree = this.createTreeOutline();
18
19 this.element.classList.add('accessibility-computed');
20 this.registerRequiredCSS('accessibility/accessibilityNode.css');
Rob Paveza84d41442019-10-10 23:01:0921 this._treeOutline.setFocusable(true);
Blink Reformat4c46d092018-04-07 15:32:3722 }
23
24 /**
25 * @param {?Accessibility.AccessibilityNode} axNode
26 * @override
27 */
28 setAXNode(axNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3429 if (this._axNode === axNode) {
Blink Reformat4c46d092018-04-07 15:32:3730 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:3431 }
Blink Reformat4c46d092018-04-07 15:32:3732 this._axNode = axNode;
33
34 const treeOutline = this._treeOutline;
35 treeOutline.removeChildren();
36 const ignoredReasons = this._ignoredReasonsTree;
37 ignoredReasons.removeChildren();
38
39 if (!axNode) {
40 treeOutline.element.classList.add('hidden');
41 this._ignoredInfo.classList.add('hidden');
42 ignoredReasons.element.classList.add('hidden');
43
44 this._noNodeInfo.classList.remove('hidden');
45 this.element.classList.add('ax-ignored-node-pane');
46
47 return;
48 }
49
50 if (axNode.ignored()) {
51 this._noNodeInfo.classList.add('hidden');
52 treeOutline.element.classList.add('hidden');
53 this.element.classList.add('ax-ignored-node-pane');
54
55 this._ignoredInfo.classList.remove('hidden');
56 ignoredReasons.element.classList.remove('hidden');
57 /**
58 * @param {!Protocol.Accessibility.AXProperty} property
59 */
60 function addIgnoredReason(property) {
61 ignoredReasons.appendChild(new Accessibility.AXNodeIgnoredReasonTreeElement(
62 property, /** @type {!Accessibility.AccessibilityNode} */ (axNode)));
63 }
64 const ignoredReasonsArray = /** @type {!Array<!Protocol.Accessibility.AXProperty>} */ (axNode.ignoredReasons());
Tim van der Lippe1d6e57a2019-09-30 11:55:3465 for (const reason of ignoredReasonsArray) {
Blink Reformat4c46d092018-04-07 15:32:3766 addIgnoredReason(reason);
Tim van der Lippe1d6e57a2019-09-30 11:55:3467 }
68 if (!ignoredReasons.firstChild()) {
Blink Reformat4c46d092018-04-07 15:32:3769 ignoredReasons.element.classList.add('hidden');
Tim van der Lippe1d6e57a2019-09-30 11:55:3470 }
Blink Reformat4c46d092018-04-07 15:32:3771 return;
72 }
73 this.element.classList.remove('ax-ignored-node-pane');
74
75 this._ignoredInfo.classList.add('hidden');
76 ignoredReasons.element.classList.add('hidden');
77 this._noNodeInfo.classList.add('hidden');
78
79 treeOutline.element.classList.remove('hidden');
80
81 /**
82 * @param {!Protocol.Accessibility.AXProperty} property
83 */
84 function addProperty(property) {
85 treeOutline.appendChild(new Accessibility.AXNodePropertyTreePropertyElement(
86 property, /** @type {!Accessibility.AccessibilityNode} */ (axNode)));
87 }
88
Tim van der Lippe1d6e57a2019-09-30 11:55:3489 for (const property of axNode.coreProperties()) {
Blink Reformat4c46d092018-04-07 15:32:3790 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:3491 }
Blink Reformat4c46d092018-04-07 15:32:3792
93 const roleProperty = /** @type {!Protocol.Accessibility.AXProperty} */ ({name: 'role', value: axNode.role()});
94 addProperty(roleProperty);
Tim van der Lippe1d6e57a2019-09-30 11:55:3495 for (const property of /** @type {!Array.<!Protocol.Accessibility.AXProperty>} */ (axNode.properties())) {
Blink Reformat4c46d092018-04-07 15:32:3796 addProperty(property);
Tim van der Lippe1d6e57a2019-09-30 11:55:3497 }
Rob Paveza84d41442019-10-10 23:01:0998
99 const firstNode = treeOutline.firstChild();
100 if (firstNode) {
101 firstNode.select(/* omitFocus= */ true, /* selectedByUser= */ false);
102 }
Blink Reformat4c46d092018-04-07 15:32:37103 }
104
105 /**
106 * @override
107 * @param {?SDK.DOMNode} node
108 */
109 setNode(node) {
110 super.setNode(node);
111 this._axNode = null;
112 }
Paul Lewisf16142c2019-11-07 15:56:04113}
Blink Reformat4c46d092018-04-07 15:32:37114
115/**
116 * @unrestricted
117 */
Paul Lewisf16142c2019-11-07 15:56:04118export class AXNodePropertyTreeElement extends UI.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37119 /**
120 * @param {!Accessibility.AccessibilityNode} axNode
121 */
122 constructor(axNode) {
123 // Pass an empty title, the title gets made later in onattach.
124 super('');
125 this._axNode = axNode;
126 }
127
128 /**
129 * @param {?Protocol.Accessibility.AXValueType} type
130 * @param {string} value
131 * @return {!Element}
132 */
133 static createSimpleValueElement(type, value) {
134 let valueElement;
135 const AXValueType = Protocol.Accessibility.AXValueType;
Tim van der Lippe1d6e57a2019-09-30 11:55:34136 if (!type || type === AXValueType.ValueUndefined || type === AXValueType.ComputedString) {
Blink Reformat4c46d092018-04-07 15:32:37137 valueElement = createElement('span');
Tim van der Lippe1d6e57a2019-09-30 11:55:34138 } else {
Blink Reformat4c46d092018-04-07 15:32:37139 valueElement = createElementWithClass('span', 'monospace');
Tim van der Lippe1d6e57a2019-09-30 11:55:34140 }
Blink Reformat4c46d092018-04-07 15:32:37141 let valueText;
142 const isStringProperty = type && Accessibility.AXNodePropertyTreeElement.StringProperties.has(type);
143 if (isStringProperty) {
144 // Render \n as a nice unicode cr symbol.
145 valueText = '"' + value.replace(/\n/g, '\u21B5') + '"';
146 valueElement._originalTextContent = value;
147 } else {
148 valueText = String(value);
149 }
150
Tim van der Lippe1d6e57a2019-09-30 11:55:34151 if (type && type in Accessibility.AXNodePropertyTreeElement.TypeStyles) {
Blink Reformat4c46d092018-04-07 15:32:37152 valueElement.classList.add(Accessibility.AXNodePropertyTreeElement.TypeStyles[type]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34153 }
Blink Reformat4c46d092018-04-07 15:32:37154
155 valueElement.setTextContentTruncatedIfNeeded(valueText || '');
156
157 valueElement.title = String(value) || '';
158
159 return valueElement;
160 }
161
162 /**
163 * @param {string} tooltip
164 * @return {!Element}
165 */
166 static createExclamationMark(tooltip) {
Joel Einbinder7fbe24c2019-01-24 05:19:01167 const exclamationElement = createElement('span', 'dt-icon-label');
Blink Reformat4c46d092018-04-07 15:32:37168 exclamationElement.type = 'smallicon-warning';
169 exclamationElement.title = tooltip;
170 return exclamationElement;
171 }
172
173 /**
174 * @param {string} name
175 */
176 appendNameElement(name) {
177 const nameElement = createElement('span');
178 const AXAttributes = Accessibility.AccessibilityStrings.AXAttributes;
179 if (name in AXAttributes) {
Mandy Chenba6de382019-06-07 21:38:50180 nameElement.textContent = AXAttributes[name].name;
Blink Reformat4c46d092018-04-07 15:32:37181 nameElement.title = AXAttributes[name].description;
182 nameElement.classList.add('ax-readable-name');
183 } else {
184 nameElement.textContent = name;
185 nameElement.classList.add('ax-name');
186 nameElement.classList.add('monospace');
187 }
188 this.listItemElement.appendChild(nameElement);
189 }
190
191 /**
192 * @param {!Protocol.Accessibility.AXValue} value
193 */
194 appendValueElement(value) {
195 const AXValueType = Protocol.Accessibility.AXValueType;
196 if (value.type === AXValueType.Idref || value.type === AXValueType.Node || value.type === AXValueType.IdrefList ||
197 value.type === AXValueType.NodeList) {
198 this.appendRelatedNodeListValueElement(value);
199 return;
200 } else if (value.sources) {
201 const sources = value.sources;
202 for (let i = 0; i < sources.length; i++) {
203 const source = sources[i];
204 const child = new Accessibility.AXValueSourceTreeElement(source, this._axNode);
205 this.appendChild(child);
206 }
207 this.expand();
208 }
209 const element = Accessibility.AXNodePropertyTreeElement.createSimpleValueElement(value.type, String(value.value));
210 this.listItemElement.appendChild(element);
211 }
212
213 /**
214 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
215 * @param {number} index
216 */
217 appendRelatedNode(relatedNode, index) {
218 const deferredNode =
219 new SDK.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
220 const nodeTreeElement = new Accessibility.AXRelatedNodeSourceTreeElement({deferredNode: deferredNode}, relatedNode);
221 this.appendChild(nodeTreeElement);
222 }
223
224 /**
225 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
226 */
227 appendRelatedNodeInline(relatedNode) {
228 const deferredNode =
229 new SDK.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
230 const linkedNode = new Accessibility.AXRelatedNodeElement({deferredNode: deferredNode}, relatedNode);
231 this.listItemElement.appendChild(linkedNode.render());
232 }
233
234 /**
235 * @param {!Protocol.Accessibility.AXValue} value
236 */
237 appendRelatedNodeListValueElement(value) {
238 if (value.relatedNodes.length === 1 && !value.value) {
239 this.appendRelatedNodeInline(value.relatedNodes[0]);
240 return;
241 }
242
243 value.relatedNodes.forEach(this.appendRelatedNode, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34244 if (value.relatedNodes.length <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37245 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34246 } else {
Blink Reformat4c46d092018-04-07 15:32:37247 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34248 }
Blink Reformat4c46d092018-04-07 15:32:37249 }
Paul Lewisf16142c2019-11-07 15:56:04250}
Blink Reformat4c46d092018-04-07 15:32:37251
252/** @type {!Object<string, string>} */
Paul Lewisf16142c2019-11-07 15:56:04253export const TypeStyles = {
Blink Reformat4c46d092018-04-07 15:32:37254 attribute: 'ax-value-string',
255 boolean: 'object-value-boolean',
256 booleanOrUndefined: 'object-value-boolean',
257 computedString: 'ax-readable-string',
258 idref: 'ax-value-string',
259 idrefList: 'ax-value-string',
260 integer: 'object-value-number',
261 internalRole: 'ax-internal-role',
262 number: 'ax-value-number',
263 role: 'ax-role',
264 string: 'ax-value-string',
265 tristate: 'object-value-boolean',
266 valueUndefined: 'ax-value-undefined'
267};
268
269/** @type {!Set.<!Protocol.Accessibility.AXValueType>} */
Paul Lewisf16142c2019-11-07 15:56:04270export const StringProperties = new Set([
Blink Reformat4c46d092018-04-07 15:32:37271 Protocol.Accessibility.AXValueType.String, Protocol.Accessibility.AXValueType.ComputedString,
272 Protocol.Accessibility.AXValueType.IdrefList, Protocol.Accessibility.AXValueType.Idref
273]);
274
275/**
276 * @unrestricted
277 */
Paul Lewisf16142c2019-11-07 15:56:04278export class AXNodePropertyTreePropertyElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37279 /**
280 * @param {!Protocol.Accessibility.AXProperty} property
281 * @param {!Accessibility.AccessibilityNode} axNode
282 */
283 constructor(property, axNode) {
284 super(axNode);
285
286 this._property = property;
287 this.toggleOnClick = true;
Blink Reformat4c46d092018-04-07 15:32:37288
289 this.listItemElement.classList.add('property');
290 }
291
292 /**
293 * @override
294 */
295 onattach() {
296 this._update();
297 }
298
299 _update() {
300 this.listItemElement.removeChildren();
301
302 this.appendNameElement(this._property.name);
303
Mathias Bynens7d8cd342019-09-17 13:32:10304 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37305
306 this.appendValueElement(this._property.value);
307 }
Paul Lewisf16142c2019-11-07 15:56:04308}
Blink Reformat4c46d092018-04-07 15:32:37309
310/**
311 * @unrestricted
312 */
Paul Lewisf16142c2019-11-07 15:56:04313export class AXValueSourceTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37314 /**
315 * @param {!Protocol.Accessibility.AXValueSource} source
316 * @param {!Accessibility.AccessibilityNode} axNode
317 */
318 constructor(source, axNode) {
319 super(axNode);
320 this._source = source;
Blink Reformat4c46d092018-04-07 15:32:37321 }
322
323 /**
324 * @override
325 */
326 onattach() {
327 this._update();
328 }
329
330 /**
331 * @param {!Protocol.Accessibility.AXRelatedNode} relatedNode
332 * @param {number} index
333 * @param {string} idref
334 */
335 appendRelatedNodeWithIdref(relatedNode, index, idref) {
336 const deferredNode =
337 new SDK.DeferredDOMNode(this._axNode.accessibilityModel().target(), relatedNode.backendDOMNodeId);
338 const nodeTreeElement =
339 new Accessibility.AXRelatedNodeSourceTreeElement({deferredNode: deferredNode, idref: idref}, relatedNode);
340 this.appendChild(nodeTreeElement);
341 }
342
343 /**
344 * @param {!Protocol.Accessibility.AXValue} value
345 */
346 appendIDRefValueElement(value) {
347 const relatedNodes = value.relatedNodes;
348
349 const idrefs = value.value.trim().split(/\s+/);
350 if (idrefs.length === 1) {
351 const idref = idrefs[0];
352 const matchingNode = relatedNodes.find(node => node.idref === idref);
Tim van der Lippe1d6e57a2019-09-30 11:55:34353 if (matchingNode) {
Blink Reformat4c46d092018-04-07 15:32:37354 this.appendRelatedNodeWithIdref(matchingNode, 0, idref);
Tim van der Lippe1d6e57a2019-09-30 11:55:34355 } else {
Blink Reformat4c46d092018-04-07 15:32:37356 this.listItemElement.appendChild(new Accessibility.AXRelatedNodeElement({idref: idref}).render());
Tim van der Lippe1d6e57a2019-09-30 11:55:34357 }
Blink Reformat4c46d092018-04-07 15:32:37358
359 } else {
360 // TODO(aboxhall): exclamation mark if not idreflist type
361 for (let i = 0; i < idrefs.length; ++i) {
362 const idref = idrefs[i];
363 const matchingNode = relatedNodes.find(node => node.idref === idref);
Tim van der Lippe1d6e57a2019-09-30 11:55:34364 if (matchingNode) {
Blink Reformat4c46d092018-04-07 15:32:37365 this.appendRelatedNodeWithIdref(matchingNode, i, idref);
Tim van der Lippe1d6e57a2019-09-30 11:55:34366 } else {
Blink Reformat4c46d092018-04-07 15:32:37367 this.appendChild(new Accessibility.AXRelatedNodeSourceTreeElement({idref: idref}));
Tim van der Lippe1d6e57a2019-09-30 11:55:34368 }
Blink Reformat4c46d092018-04-07 15:32:37369 }
370 }
371 }
372
373 /**
374 * @param {!Protocol.Accessibility.AXValue} value
375 * @override
376 */
377 appendRelatedNodeListValueElement(value) {
378 const relatedNodes = value.relatedNodes;
379 const numNodes = relatedNodes.length;
380
381 if (value.type === Protocol.Accessibility.AXValueType.IdrefList ||
Tim van der Lippe1d6e57a2019-09-30 11:55:34382 value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37383 this.appendIDRefValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34384 } else {
Blink Reformat4c46d092018-04-07 15:32:37385 super.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34386 }
Blink Reformat4c46d092018-04-07 15:32:37387
388
Tim van der Lippe1d6e57a2019-09-30 11:55:34389 if (numNodes <= 3) {
Blink Reformat4c46d092018-04-07 15:32:37390 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34391 } else {
Blink Reformat4c46d092018-04-07 15:32:37392 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34393 }
Blink Reformat4c46d092018-04-07 15:32:37394 }
395
396 /**
397 * @param {!Protocol.Accessibility.AXValueSource} source
398 */
399 appendSourceNameElement(source) {
400 const nameElement = createElement('span');
401 const AXValueSourceType = Protocol.Accessibility.AXValueSourceType;
402 const type = source.type;
403 switch (type) {
404 case AXValueSourceType.Attribute:
405 case AXValueSourceType.Placeholder:
406 case AXValueSourceType.RelatedElement:
407 if (source.nativeSource) {
408 const AXNativeSourceTypes = Accessibility.AccessibilityStrings.AXNativeSourceTypes;
409 const nativeSource = source.nativeSource;
Mandy Chenba6de382019-06-07 21:38:50410 nameElement.textContent = AXNativeSourceTypes[nativeSource].name;
411 nameElement.title = AXNativeSourceTypes[nativeSource].description;
Blink Reformat4c46d092018-04-07 15:32:37412 nameElement.classList.add('ax-readable-name');
413 break;
414 }
415 nameElement.textContent = source.attribute;
416 nameElement.classList.add('ax-name');
417 nameElement.classList.add('monospace');
418 break;
419 default:
420 const AXSourceTypes = Accessibility.AccessibilityStrings.AXSourceTypes;
421 if (type in AXSourceTypes) {
Mandy Chenba6de382019-06-07 21:38:50422 nameElement.textContent = AXSourceTypes[type].name;
423 nameElement.title = AXSourceTypes[type].description;
Blink Reformat4c46d092018-04-07 15:32:37424 nameElement.classList.add('ax-readable-name');
425 } else {
426 console.warn(type, 'not in AXSourceTypes');
Mandy Chenba6de382019-06-07 21:38:50427 nameElement.textContent = type;
Blink Reformat4c46d092018-04-07 15:32:37428 }
429 }
430 this.listItemElement.appendChild(nameElement);
431 }
432
433 _update() {
434 this.listItemElement.removeChildren();
435
436 if (this._source.invalid) {
437 const exclamationMark = Accessibility.AXNodePropertyTreeElement.createExclamationMark(ls`Invalid source.`);
438 this.listItemElement.appendChild(exclamationMark);
439 this.listItemElement.classList.add('ax-value-source-invalid');
440 } else if (this._source.superseded) {
441 this.listItemElement.classList.add('ax-value-source-unused');
442 }
443
444 this.appendSourceNameElement(this._source);
445
Mathias Bynens7d8cd342019-09-17 13:32:10446 this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
Blink Reformat4c46d092018-04-07 15:32:37447
448 if (this._source.attributeValue) {
449 this.appendValueElement(this._source.attributeValue);
Mathias Bynens7d8cd342019-09-17 13:32:10450 this.listItemElement.createTextChild('\xA0');
Blink Reformat4c46d092018-04-07 15:32:37451 } else if (this._source.nativeSourceValue) {
452 this.appendValueElement(this._source.nativeSourceValue);
Mathias Bynens7d8cd342019-09-17 13:32:10453 this.listItemElement.createTextChild('\xA0');
Tim van der Lippe1d6e57a2019-09-30 11:55:34454 if (this._source.value) {
Blink Reformat4c46d092018-04-07 15:32:37455 this.appendValueElement(this._source.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34456 }
Blink Reformat4c46d092018-04-07 15:32:37457 } else if (this._source.value) {
458 this.appendValueElement(this._source.value);
459 } else {
460 const valueElement = Accessibility.AXNodePropertyTreeElement.createSimpleValueElement(
461 Protocol.Accessibility.AXValueType.ValueUndefined, ls`Not specified`);
462 this.listItemElement.appendChild(valueElement);
463 this.listItemElement.classList.add('ax-value-source-unused');
464 }
465
Tim van der Lippe1d6e57a2019-09-30 11:55:34466 if (this._source.value && this._source.superseded) {
Blink Reformat4c46d092018-04-07 15:32:37467 this.listItemElement.classList.add('ax-value-source-superseded');
Tim van der Lippe1d6e57a2019-09-30 11:55:34468 }
Blink Reformat4c46d092018-04-07 15:32:37469 }
Paul Lewisf16142c2019-11-07 15:56:04470}
Blink Reformat4c46d092018-04-07 15:32:37471
472/**
473 * @unrestricted
474 */
Paul Lewisf16142c2019-11-07 15:56:04475export class AXRelatedNodeSourceTreeElement extends UI.TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37476 /**
477 * @param {{deferredNode: (!SDK.DeferredDOMNode|undefined), idref: (string|undefined)}} node
478 * @param {!Protocol.Accessibility.AXRelatedNode=} value
479 */
480 constructor(node, value) {
481 super('');
482
483 this._value = value;
484 this._axRelatedNodeElement = new Accessibility.AXRelatedNodeElement(node, value);
Rob Paveza84d41442019-10-10 23:01:09485 this.selectable = true;
Blink Reformat4c46d092018-04-07 15:32:37486 }
487
488 /**
489 * @override
490 */
491 onattach() {
492 this.listItemElement.appendChild(this._axRelatedNodeElement.render());
Tim van der Lippe1d6e57a2019-09-30 11:55:34493 if (!this._value) {
Blink Reformat4c46d092018-04-07 15:32:37494 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34495 }
Blink Reformat4c46d092018-04-07 15:32:37496
497 if (this._value.text) {
498 this.listItemElement.appendChild(Accessibility.AXNodePropertyTreeElement.createSimpleValueElement(
499 Protocol.Accessibility.AXValueType.ComputedString, this._value.text));
500 }
501 }
Rob Paveza84d41442019-10-10 23:01:09502
503 /**
504 * @override
505 */
506 onenter() {
507 this._axRelatedNodeElement.revealNode();
508 return true;
509 }
Paul Lewisf16142c2019-11-07 15:56:04510}
Blink Reformat4c46d092018-04-07 15:32:37511
512/**
513 * @unrestricted
514 */
Paul Lewisf16142c2019-11-07 15:56:04515export class AXRelatedNodeElement {
Blink Reformat4c46d092018-04-07 15:32:37516 /**
517 * @param {{deferredNode: (!SDK.DeferredDOMNode|undefined), idref: (string|undefined)}} node
518 * @param {!Protocol.Accessibility.AXRelatedNode=} value
519 */
520 constructor(node, value) {
521 this._deferredNode = node.deferredNode;
522 this._idref = node.idref;
523 this._value = value;
524 }
525
526 /**
527 * @return {!Element}
528 */
529 render() {
530 const element = createElement('span');
531 let valueElement;
532
533 if (this._deferredNode) {
534 valueElement = createElement('span');
535 element.appendChild(valueElement);
Alice Boxhall6ac43432018-11-22 08:24:18536 this._deferredNode.resolvePromise().then(node => {
Jeff Fisher3f5f19c2019-08-28 19:10:02537 Common.Linkifier.linkify(node, {preventKeyboardFocus: true})
538 .then(linkfied => valueElement.appendChild(linkfied));
Alice Boxhall6ac43432018-11-22 08:24:18539 });
Blink Reformat4c46d092018-04-07 15:32:37540 } else if (this._idref) {
541 element.classList.add('invalid');
542 valueElement = Accessibility.AXNodePropertyTreeElement.createExclamationMark(ls`No node with this ID.`);
543 valueElement.createTextChild(this._idref);
544 element.appendChild(valueElement);
545 }
546
547 return element;
548 }
Rob Paveza84d41442019-10-10 23:01:09549
550 /**
551 * Attempts to cause the node referred to by the related node to be selected in the tree.
552 */
553 revealNode() {
554 this._deferredNode.resolvePromise().then(node => Common.Revealer.reveal(node));
555 }
Paul Lewisf16142c2019-11-07 15:56:04556}
Blink Reformat4c46d092018-04-07 15:32:37557
558/**
559 * @unrestricted
560 */
Paul Lewisf16142c2019-11-07 15:56:04561export class AXNodeIgnoredReasonTreeElement extends AXNodePropertyTreeElement {
Blink Reformat4c46d092018-04-07 15:32:37562 /**
563 * @param {!Protocol.Accessibility.AXProperty} property
564 * @param {!Accessibility.AccessibilityNode} axNode
565 */
566 constructor(property, axNode) {
567 super(axNode);
568 this._property = property;
569 this._axNode = axNode;
570 this.toggleOnClick = true;
571 this.selectable = false;
572 }
573
574 /**
575 * @param {?string} reason
576 * @param {?Accessibility.AccessibilityNode} axNode
577 * @return {?Element}
578 */
579 static createReasonElement(reason, axNode) {
580 let reasonElement = null;
581 switch (reason) {
582 case 'activeModalDialog':
Mathias Bynens7d8cd342019-09-17 13:32:10583 reasonElement = UI.formatLocalized('Element is hidden by active modal dialog:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37584 break;
585 case 'ancestorIsLeafNode':
Mathias Bynens7d8cd342019-09-17 13:32:10586 reasonElement = UI.formatLocalized('Ancestor\'s children are all presentational:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37587 break;
588 case 'ariaHiddenElement': {
589 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
590 reasonElement = UI.formatLocalized('Element is %s.', [ariaHiddenSpan]);
591 break;
592 }
593 case 'ariaHiddenSubtree': {
594 const ariaHiddenSpan = createElement('span', 'source-code').textContent = 'aria-hidden';
595 const trueSpan = createElement('span', 'source-code').textContent = 'true';
Mathias Bynens7d8cd342019-09-17 13:32:10596 reasonElement = UI.formatLocalized('%s is %s on ancestor:\xA0', [ariaHiddenSpan, trueSpan]);
Blink Reformat4c46d092018-04-07 15:32:37597 break;
598 }
599 case 'emptyAlt':
600 reasonElement = UI.formatLocalized('Element has empty alt text.', []);
601 break;
602 case 'emptyText':
603 reasonElement = UI.formatLocalized('No text content.', []);
604 break;
605 case 'inertElement':
606 reasonElement = UI.formatLocalized('Element is inert.', []);
607 break;
608 case 'inertSubtree':
Mathias Bynens7d8cd342019-09-17 13:32:10609 reasonElement = UI.formatLocalized('Element is in an inert subtree from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37610 break;
611 case 'inheritsPresentation':
Mathias Bynens7d8cd342019-09-17 13:32:10612 reasonElement = UI.formatLocalized('Element inherits presentational role from\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37613 break;
614 case 'labelContainer':
Mathias Bynens7d8cd342019-09-17 13:32:10615 reasonElement = UI.formatLocalized('Part of label element:\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37616 break;
617 case 'labelFor':
Mathias Bynens7d8cd342019-09-17 13:32:10618 reasonElement = UI.formatLocalized('Label for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37619 break;
620 case 'notRendered':
621 reasonElement = UI.formatLocalized('Element is not rendered.', []);
622 break;
623 case 'notVisible':
624 reasonElement = UI.formatLocalized('Element is not visible.', []);
625 break;
626 case 'presentationalRole': {
627 const rolePresentationSpan = createElement('span', 'source-code').textContent = 'role=' + axNode.role().value;
628 reasonElement = UI.formatLocalized('Element has %s.', [rolePresentationSpan]);
629 break;
630 }
631 case 'probablyPresentational':
632 reasonElement = UI.formatLocalized('Element is presentational.', []);
633 break;
634 case 'staticTextUsedAsNameFor':
Mathias Bynens7d8cd342019-09-17 13:32:10635 reasonElement = UI.formatLocalized('Static text node is used as name for\xA0', []);
Blink Reformat4c46d092018-04-07 15:32:37636 break;
637 case 'uninteresting':
638 reasonElement = UI.formatLocalized('Element not interesting for accessibility.', []);
639 break;
640 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34641 if (reasonElement) {
Blink Reformat4c46d092018-04-07 15:32:37642 reasonElement.classList.add('ax-reason');
Tim van der Lippe1d6e57a2019-09-30 11:55:34643 }
Blink Reformat4c46d092018-04-07 15:32:37644 return reasonElement;
645 }
646
647 /**
648 * @override
649 */
650 onattach() {
651 this.listItemElement.removeChildren();
652
653 this._reasonElement =
654 Accessibility.AXNodeIgnoredReasonTreeElement.createReasonElement(this._property.name, this._axNode);
655 this.listItemElement.appendChild(this._reasonElement);
656
657 const value = this._property.value;
Tim van der Lippe1d6e57a2019-09-30 11:55:34658 if (value.type === Protocol.Accessibility.AXValueType.Idref) {
Blink Reformat4c46d092018-04-07 15:32:37659 this.appendRelatedNodeListValueElement(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:34660 }
Blink Reformat4c46d092018-04-07 15:32:37661 }
Paul Lewisf16142c2019-11-07 15:56:04662}
663
664/* Legacy exported object */
665self.Accessibility = self.Accessibility || {};
666
667/* Legacy exported object */
668Accessibility = Accessibility || {};
669
670/**
671 * @constructor
672 */
673Accessibility.AXNodeSubPane = AXNodeSubPane;
674
675/**
676 * @constructor
677 */
678Accessibility.AXNodePropertyTreeElement = AXNodePropertyTreeElement;
679
680/** @type {!Object<string, string>} */
681Accessibility.AXNodePropertyTreeElement.TypeStyles = TypeStyles;
682
683/** @type {!Set.<!Protocol.Accessibility.AXValueType>} */
684Accessibility.AXNodePropertyTreeElement.StringProperties = StringProperties;
685
686/**
687 * @constructor
688 */
689Accessibility.AXNodePropertyTreePropertyElement = AXNodePropertyTreePropertyElement;
690
691/**
692 * @constructor
693 */
694Accessibility.AXValueSourceTreeElement = AXValueSourceTreeElement;
695
696/**
697 * @constructor
698 */
699Accessibility.AXRelatedNodeSourceTreeElement = AXRelatedNodeSourceTreeElement;
700
701/**
702 * @constructor
703 */
704Accessibility.AXRelatedNodeElement = AXRelatedNodeElement;
705
706/**
707 * @constructor
708 */
709Accessibility.AXNodeIgnoredReasonTreeElement = AXNodeIgnoredReasonTreeElement;