aria-api 0.4.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +4 -4
- package/dist/aria.js +367 -170
- package/lib/atree.js +24 -24
- package/lib/attrs.js +47 -28
- package/lib/constants.js +218 -48
- package/lib/name.js +66 -56
- package/lib/query.js +12 -14
- package/package.json +3 -3
package/lib/name.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
const constants = require('./constants.js');
|
|
2
|
+
const atree = require('./atree.js');
|
|
3
|
+
const query = require('./query.js');
|
|
4
|
+
|
|
5
|
+
const getPseudoContent = function(node, selector) {
|
|
6
|
+
const styles = window.getComputedStyle(node, selector);
|
|
7
|
+
const ret = styles.getPropertyValue('content');
|
|
8
|
+
const inline = styles.display.substr(0, 6) === 'inline';
|
|
9
9
|
if (!ret) {
|
|
10
10
|
return '';
|
|
11
11
|
}
|
|
@@ -20,12 +20,12 @@ var getPseudoContent = function(node, selector) {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const getContent = function(root, visited) {
|
|
24
|
+
const children = atree.getChildNodes(root);
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
for (
|
|
28
|
-
|
|
26
|
+
let ret = '';
|
|
27
|
+
for (let i = 0; i < children.length; i++) {
|
|
28
|
+
const node = children[i];
|
|
29
29
|
if (node.nodeType === node.TEXT_NODE) {
|
|
30
30
|
ret += node.textContent;
|
|
31
31
|
} else if (node.nodeType === node.ELEMENT_NODE) {
|
|
@@ -44,18 +44,15 @@ var getContent = function(root, visited) {
|
|
|
44
44
|
return ret;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
var isInLabelForOtherWidget = function(el) {
|
|
53
|
-
var label = el.parentElement.closest('label');
|
|
54
|
-
return label && (!el.labels || !Array.prototype.includes.call(el.labels, label));
|
|
47
|
+
const allowNameFromContent = function(el) {
|
|
48
|
+
const role = query.getRole(el);
|
|
49
|
+
if (role) {
|
|
50
|
+
return constants.roles[role].nameFromContents;
|
|
51
|
+
}
|
|
55
52
|
};
|
|
56
53
|
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const getName = function(el, recursive, visited, directReference) {
|
|
55
|
+
let ret = '';
|
|
59
56
|
|
|
60
57
|
visited = visited || [];
|
|
61
58
|
if (visited.includes(el)) {
|
|
@@ -71,14 +68,30 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
71
68
|
|
|
72
69
|
// B
|
|
73
70
|
if (!recursive && el.matches('[aria-labelledby]')) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
const ids = el.getAttribute('aria-labelledby').split(/\s+/);
|
|
72
|
+
const strings = ids.map(id => {
|
|
73
|
+
const label = document.getElementById(id);
|
|
77
74
|
return label ? getName(label, true, visited, true) : '';
|
|
78
75
|
});
|
|
79
76
|
ret = strings.join(' ');
|
|
80
77
|
}
|
|
81
78
|
|
|
79
|
+
// E (the current draft has this at this high priority)
|
|
80
|
+
if (!ret.trim() && recursive) {
|
|
81
|
+
if (query.matches(el, 'textbox,button')) {
|
|
82
|
+
ret = el.value || el.textContent;
|
|
83
|
+
} else if (query.matches(el, 'combobox,listbox')) {
|
|
84
|
+
const selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
|
|
85
|
+
if (selected) {
|
|
86
|
+
ret = getName(selected, recursive, visited);
|
|
87
|
+
} else {
|
|
88
|
+
ret = el.value || '';
|
|
89
|
+
}
|
|
90
|
+
} else if (query.matches(el, 'range')) {
|
|
91
|
+
ret = '' + (query.getAttribute(el, 'valuetext') || query.getAttribute(el, 'valuenow') || el.value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
82
95
|
// C
|
|
83
96
|
if (!ret.trim() && el.matches('[aria-label]')) {
|
|
84
97
|
// FIXME: may skip to 2E
|
|
@@ -87,7 +100,7 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
87
100
|
|
|
88
101
|
// D
|
|
89
102
|
if (!ret.trim() && !recursive && el.labels) {
|
|
90
|
-
|
|
103
|
+
const strings = Array.prototype.map.call(el.labels, label => {
|
|
91
104
|
return getName(label, true, visited);
|
|
92
105
|
});
|
|
93
106
|
ret = strings.join(' ');
|
|
@@ -102,31 +115,19 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
102
115
|
ret = el.title;
|
|
103
116
|
}
|
|
104
117
|
if (!ret.trim()) {
|
|
105
|
-
for (
|
|
118
|
+
for (const selector in constants.nameFromDescendant) {
|
|
106
119
|
if (el.matches(selector)) {
|
|
107
|
-
|
|
120
|
+
const descendant = el.querySelector(constants.nameFromDescendant[selector]);
|
|
108
121
|
if (descendant) {
|
|
109
122
|
ret = getName(descendant, true, visited);
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (query.matches(el, 'textbox,button')) {
|
|
119
|
-
ret = el.value || el.textContent;
|
|
120
|
-
} else if (query.matches(el, 'combobox,listbox')) {
|
|
121
|
-
var selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
|
|
122
|
-
if (selected) {
|
|
123
|
-
ret = getName(selected, recursive, visited);
|
|
124
|
-
} else {
|
|
125
|
-
ret = el.value || '';
|
|
126
|
-
}
|
|
127
|
-
} else if (query.matches(el, 'range')) {
|
|
128
|
-
ret = '' + (query.getAttribute(el, 'valuetext') || query.getAttribute(el, 'valuenow') || el.value);
|
|
129
|
-
}
|
|
127
|
+
if (!ret.trim() && el.matches('svg *')) {
|
|
128
|
+
const svgTitle = el.querySelector('title');
|
|
129
|
+
if (svgTitle && svgTitle.parentElement === el) {
|
|
130
|
+
ret = svgTitle.textContent;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -136,8 +137,12 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
136
137
|
ret = getContent(el, visited);
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
if (!ret.trim() && query.matches(el, 'button')) {
|
|
141
|
+
ret = el.value || '';
|
|
142
|
+
}
|
|
143
|
+
|
|
139
144
|
if (!ret.trim()) {
|
|
140
|
-
for (
|
|
145
|
+
for (const selector in constants.nameDefaults) {
|
|
141
146
|
if (el.matches(selector)) {
|
|
142
147
|
ret = constants.nameDefaults[selector];
|
|
143
148
|
}
|
|
@@ -159,29 +164,34 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
159
164
|
ret = ' ';
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
const before = getPseudoContent(el, ':before');
|
|
168
|
+
const after = getPseudoContent(el, ':after');
|
|
164
169
|
return before + ret + after;
|
|
165
170
|
};
|
|
166
171
|
|
|
167
|
-
|
|
172
|
+
const getNameTrimmed = function(el) {
|
|
168
173
|
return getName(el).replace(/\s+/g, ' ').trim();
|
|
169
174
|
};
|
|
170
175
|
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
const getDescription = function(el) {
|
|
177
|
+
let ret = '';
|
|
173
178
|
|
|
174
179
|
if (el.matches('[aria-describedby]')) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
const ids = el.getAttribute('aria-describedby').split(/\s+/);
|
|
181
|
+
const strings = ids.map(id => {
|
|
182
|
+
const label = document.getElementById(id);
|
|
178
183
|
return label ? getName(label, true) : '';
|
|
179
184
|
});
|
|
180
185
|
ret = strings.join(' ');
|
|
186
|
+
} else if (el.matches('[aria-description]')) {
|
|
187
|
+
ret = el.getAttribute('aria-description');
|
|
188
|
+
} else if (el.matches('svg *')) {
|
|
189
|
+
const svgDesc = el.querySelector('desc');
|
|
190
|
+
if (svgDesc && svgDesc.parentElement === el) {
|
|
191
|
+
ret = svgDesc.textContent;
|
|
192
|
+
}
|
|
181
193
|
} else if (el.title) {
|
|
182
194
|
ret = el.title;
|
|
183
|
-
} else if (el.placeholder) {
|
|
184
|
-
ret = el.placeholder;
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
ret = (ret || '').trim().replace(/\s+/g, ' ');
|
package/lib/query.js
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const attrs = require('./attrs.js');
|
|
2
|
+
const atree = require('./atree.js');
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
var actual;
|
|
7
|
-
|
|
5
|
+
const matches = function(el, selector) {
|
|
8
6
|
if (selector.substr(0, 1) === ':') {
|
|
9
|
-
|
|
7
|
+
const attr = selector.substr(1);
|
|
10
8
|
return attrs.getAttribute(el, attr);
|
|
11
9
|
} else if (selector.substr(0, 1) === '[') {
|
|
12
|
-
|
|
13
|
-
actual = attrs.getAttribute(el, match[1]);
|
|
14
|
-
|
|
10
|
+
const match = /\[([a-z]+)="(.*)"\]/.exec(selector);
|
|
11
|
+
const actual = attrs.getAttribute(el, match[1]);
|
|
12
|
+
const rawValue = match[2];
|
|
15
13
|
return actual.toString() === rawValue;
|
|
16
14
|
} else {
|
|
17
15
|
return attrs.hasRole(el, selector.split(','));
|
|
18
16
|
}
|
|
19
17
|
};
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
return function(root,
|
|
23
|
-
|
|
19
|
+
const _querySelector = function(all) {
|
|
20
|
+
return function(root, selector) {
|
|
21
|
+
const results = [];
|
|
24
22
|
try {
|
|
25
23
|
atree.walk(root, node => {
|
|
26
24
|
if (node.nodeType === node.ELEMENT_NODE) {
|
|
27
25
|
// FIXME: skip hidden elements
|
|
28
|
-
if (matches(node,
|
|
26
|
+
if (matches(node, selector)) {
|
|
29
27
|
results.push(node);
|
|
30
28
|
if (!all) {
|
|
31
29
|
throw 'StopIteration';
|
|
@@ -42,7 +40,7 @@ var _querySelector = function(all) {
|
|
|
42
40
|
};
|
|
43
41
|
};
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
const closest = function(el, selector) {
|
|
46
44
|
return atree.searchUp(el, candidate => {
|
|
47
45
|
if (candidate.nodeType === candidate.ELEMENT_NODE) {
|
|
48
46
|
return matches(candidate, selector);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aria-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Access ARIA information from JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"brfs": "^2.0.0",
|
|
15
15
|
"browserify": "^17.0.0",
|
|
16
16
|
"expect": "^1.20.2",
|
|
17
|
-
"mocha": "^
|
|
18
|
-
"mocha-headless-chrome": "^
|
|
17
|
+
"mocha": "^10.2.0",
|
|
18
|
+
"mocha-headless-chrome": "^4.0.0"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"index.js",
|