-
Notifications
You must be signed in to change notification settings - Fork 0
/
accname.js
113 lines (98 loc) · 4.33 KB
/
accname.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* Retrieves the accessible name of an HTML element, taking into account ARIA
* attributes and other properties, and returns an object with tested properties.
* @param {HTMLElement} element - The element for which to obtain the accessible name.
* @returns {Object} - An object containing keys for each property tested and their values.
*/
function accName(element) {
// Initialize the result object
const result = {
isVisible: true,
accessibleName: ''
};
// Visibility check: returns an empty object if the element or any of its parents is not visible
if (!element ||
getComputedStyle(element).visibility === 'hidden' ||
getComputedStyle(element).display === 'none' ||
element.closest('[aria-hidden="true"]')) {
result.isVisible = false;
return result; // The element is not visible
}
// Check if the element has the 'aria-labelledby' attribute
const ariaLabelledby = element.getAttribute('aria-labelledby');
if (ariaLabelledby) {
result.ariaLabelledby = ariaLabelledby.split(' ')
.map(id => accName(element.ownerDocument.getElementById(id)).accessibleName)
.filter(Boolean)
.join(', ');
if (result.ariaLabelledby) {
result.accessibleName = result.ariaLabelledby;
}
}
// Check the 'aria-label' attribute
const ariaLabel = element.getAttribute('aria-label')?.trim();
if (ariaLabel) {
result.ariaLabel = ariaLabel;
result.accessibleName = result.accessibleName || ariaLabel;
}
// Check if the element has an ID and get the accessible name of the associated label
const associatedLabel = element.id && accName(element.ownerDocument.querySelector(`label[for="${element.id}"]`));
if (associatedLabel && associatedLabel.accessibleName) {
result.associatedLabel = associatedLabel.accessibleName;
result.accessibleName = result.accessibleName || associatedLabel.accessibleName;
}
// Get the text from the closest label if present
const closestLabelText = element.closest('label')?.textContent.trim();
if (closestLabelText) {
result.closestLabelText = closestLabelText;
result.accessibleName = result.accessibleName || closestLabelText;
}
// Check the 'alt' attribute
const altText = element.hasAttribute('alt') ? element.getAttribute('alt')?.trim() : '';
if (altText) {
result.altText = altText;
result.accessibleName = result.accessibleName || altText;
}
// Get the text from the closest figcaption of a figure
const figcaptionText = element.closest('figure')?.querySelector('figcaption')?.textContent.trim();
if (figcaptionText) {
result.figcaptionText = figcaptionText;
result.accessibleName = result.accessibleName || figcaptionText;
}
// Get the text from the closest caption of a table
const captionText = element.closest('table')?.querySelector('caption')?.textContent.trim();
if (captionText) {
result.captionText = captionText;
result.accessibleName = result.accessibleName || captionText;
}
// Get the text from the closest legend of a fieldset
const legendText = element.closest('fieldset')?.querySelector('legend')?.textContent.trim();
if (legendText) {
result.legendText = legendText;
result.accessibleName = result.accessibleName || legendText;
}
// Check the 'title' attribute
const titleText = element.getAttribute('title')?.trim();
if (titleText) {
result.titleText = titleText;
result.accessibleName = result.accessibleName || titleText;
}
// Check the 'placeholder' attribute
const placeholderText = element.getAttribute('placeholder')?.trim();
if (placeholderText) {
result.placeholderText = placeholderText;
result.accessibleName = result.accessibleName || placeholderText;
}
// Retrieve the visible text content of the element's children
const childrenText = Array.from(element.childNodes)
.map(child => child.nodeType === Node.TEXT_NODE ? child.textContent.trim() : accName(child).accessibleName)
.filter(Boolean)
.join(' ');
if (childrenText) {
result.childrenText = childrenText;
result.accessibleName = result.accessibleName || childrenText;
}
// Set the final accessible name in the result
result.accessibleName = result.accessibleName || '';
return result; // Return the result object with all collected data
}