aria-api 0.7.0 → 0.8.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/README.md +3 -3
- package/dist/aria.js +1213 -1245
- package/index.js +4 -18
- package/lib/atree.js +5 -12
- package/lib/attrs.js +9 -11
- package/lib/constants.js +15 -15
- package/lib/name.js +31 -26
- package/lib/query.js +6 -13
- package/package.json +4 -5
package/index.js
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
getRole: query.getRole,
|
|
7
|
-
getAttribute: query.getAttribute,
|
|
8
|
-
getName: name.getName,
|
|
9
|
-
getDescription: name.getDescription,
|
|
10
|
-
|
|
11
|
-
matches: query.matches,
|
|
12
|
-
querySelector: query.querySelector,
|
|
13
|
-
querySelectorAll: query.querySelectorAll,
|
|
14
|
-
closest: query.closest,
|
|
15
|
-
|
|
16
|
-
getParentNode: atree.getParentNode,
|
|
17
|
-
getChildNodes: atree.getChildNodes,
|
|
18
|
-
};
|
|
1
|
+
export { getParentNode, getChildNodes } from './lib/atree.js';
|
|
2
|
+
export { getRole, getAttribute } from './lib/attrs.js';
|
|
3
|
+
export { matches, querySelector, querySelectorAll, closest } from './lib/query.js';
|
|
4
|
+
export { getName, getDescription } from './lib/name.js';
|
package/lib/atree.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import * as attrs from './attrs';
|
|
2
2
|
|
|
3
3
|
const _getOwner = function(node, owners) {
|
|
4
4
|
if (node.nodeType === node.ELEMENT_NODE && node.id) {
|
|
@@ -36,7 +36,7 @@ const getOwner = function(node, owners) {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const getParentNode = function(node, owners) {
|
|
39
|
+
export const getParentNode = function(node, owners) {
|
|
40
40
|
return getOwner(node, owners) || node.parentNode;
|
|
41
41
|
};
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ const isHidden = function(node) {
|
|
|
44
44
|
return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const getChildNodes = function(node, owners) {
|
|
47
|
+
export const getChildNodes = function(node, owners) {
|
|
48
48
|
const childNodes = [];
|
|
49
49
|
|
|
50
50
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
@@ -68,7 +68,7 @@ const getChildNodes = function(node, owners) {
|
|
|
68
68
|
return childNodes;
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
const walk = function(root, fn) {
|
|
71
|
+
export const walk = function(root, fn) {
|
|
72
72
|
const owners = document.querySelectorAll('[aria-owns]');
|
|
73
73
|
let queue = [root];
|
|
74
74
|
while (queue.length) {
|
|
@@ -78,7 +78,7 @@ const walk = function(root, fn) {
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
const searchUp = function(node, test) {
|
|
81
|
+
export const searchUp = function(node, test) {
|
|
82
82
|
const candidate = getParentNode(node);
|
|
83
83
|
if (candidate) {
|
|
84
84
|
if (test(candidate)) {
|
|
@@ -88,10 +88,3 @@ const searchUp = function(node, test) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
|
-
|
|
92
|
-
module.exports = {
|
|
93
|
-
'getParentNode': getParentNode,
|
|
94
|
-
'getChildNodes': getChildNodes,
|
|
95
|
-
'walk': walk,
|
|
96
|
-
'searchUp': searchUp,
|
|
97
|
-
};
|
package/lib/attrs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import * as constants from './constants.js';
|
|
2
2
|
|
|
3
3
|
var unique = function(arr) {
|
|
4
4
|
return arr.filter((a, i) => arr.indexOf(a) === i);
|
|
@@ -17,7 +17,7 @@ var normalizeRoles = function(roles, includeAbstract) {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
// candidates can be passed for performance optimization
|
|
20
|
-
const
|
|
20
|
+
const getRoleRaw = function(el, candidates) {
|
|
21
21
|
// TODO: filter out any invalid roles (e.g. name or context required)
|
|
22
22
|
const roles = normalizeRoles(
|
|
23
23
|
(el.getAttribute('role') || '').toLowerCase().split(/\s+/)
|
|
@@ -41,14 +41,18 @@ const getRole = function(el, candidates) {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
const
|
|
44
|
+
export const getRole = function(el) {
|
|
45
|
+
return getRoleRaw(el);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const hasRole = function(el, roles) {
|
|
45
49
|
const subRoles = normalizeRoles(roles, true).map(role => {
|
|
46
50
|
return constants.roles[role].subRoles || [role];
|
|
47
51
|
});
|
|
48
|
-
return !!
|
|
52
|
+
return !!getRoleRaw(el, unique(flatten(subRoles)));
|
|
49
53
|
};
|
|
50
54
|
|
|
51
|
-
const getAttribute = function(el, key) {
|
|
55
|
+
export const getAttribute = function(el, key) {
|
|
52
56
|
if (constants.attributeStrongMapping.hasOwnProperty(key)) {
|
|
53
57
|
const value = el[constants.attributeStrongMapping[key]];
|
|
54
58
|
if (value) {
|
|
@@ -124,9 +128,3 @@ const getAttribute = function(el, key) {
|
|
|
124
128
|
return false;
|
|
125
129
|
}
|
|
126
130
|
};
|
|
127
|
-
|
|
128
|
-
module.exports = {
|
|
129
|
-
getRole: getRole,
|
|
130
|
-
hasRole: hasRole,
|
|
131
|
-
getAttribute: getAttribute,
|
|
132
|
-
};
|
package/lib/constants.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// https://www.w3.org/TR/wai-aria/#state_prop_def
|
|
2
|
-
|
|
2
|
+
export const attributes = {
|
|
3
3
|
'activedescendant': 'id',
|
|
4
4
|
'atomic': 'bool',
|
|
5
5
|
'autocomplete': 'token',
|
|
@@ -55,14 +55,14 @@ exports.attributes = {
|
|
|
55
55
|
'valuetext': 'string',
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
export const attributeStrongMapping = {
|
|
59
59
|
'disabled': 'disabled',
|
|
60
60
|
'placeholder': 'placeholder',
|
|
61
61
|
'readonly': 'readOnly',
|
|
62
62
|
'required': 'required',
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
export const attributeWeakMapping = {
|
|
66
66
|
'checked': 'checked',
|
|
67
67
|
'colspan': 'colSpan',
|
|
68
68
|
'expanded': 'open',
|
|
@@ -89,7 +89,7 @@ const svgSelectors = function(selector) {
|
|
|
89
89
|
|
|
90
90
|
// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
|
|
91
91
|
// https://www.w3.org/TR/wai-aria/roles
|
|
92
|
-
|
|
92
|
+
export const roles = {
|
|
93
93
|
alert: {
|
|
94
94
|
childRoles: ['alertdialog'],
|
|
95
95
|
defaults: {
|
|
@@ -387,7 +387,7 @@ exports.roles = {
|
|
|
387
387
|
],
|
|
388
388
|
},
|
|
389
389
|
link: {
|
|
390
|
-
selectors: ['a[*|href]', 'area[href]'],
|
|
390
|
+
selectors: ['a[*|href]', 'area[*|href]'],
|
|
391
391
|
childRoles: ['doc-backlink', 'doc-biblioref', 'doc-glossref', 'doc-noteref'],
|
|
392
392
|
nameFromContents: true,
|
|
393
393
|
},
|
|
@@ -732,7 +732,7 @@ exports.roles = {
|
|
|
732
732
|
};
|
|
733
733
|
|
|
734
734
|
const getSubRoles = function(role) {
|
|
735
|
-
const children = (
|
|
735
|
+
const children = (roles[role]).childRoles || [];
|
|
736
736
|
const descendents = children.map(getSubRoles);
|
|
737
737
|
|
|
738
738
|
const result = [role];
|
|
@@ -748,30 +748,30 @@ const getSubRoles = function(role) {
|
|
|
748
748
|
return result;
|
|
749
749
|
};
|
|
750
750
|
|
|
751
|
-
|
|
751
|
+
export const attrsWithDefaults = [];
|
|
752
752
|
|
|
753
|
-
for (const role in
|
|
754
|
-
|
|
755
|
-
for (const key in
|
|
756
|
-
if (!
|
|
757
|
-
|
|
753
|
+
for (const role in roles) {
|
|
754
|
+
roles[role].subRoles = getSubRoles(role);
|
|
755
|
+
for (const key in roles[role].defaults) {
|
|
756
|
+
if (!attrsWithDefaults.includes(key)) {
|
|
757
|
+
attrsWithDefaults.push(key);
|
|
758
758
|
}
|
|
759
759
|
}
|
|
760
760
|
}
|
|
761
761
|
|
|
762
|
-
|
|
762
|
+
export const aliases = {
|
|
763
763
|
'presentation': 'none',
|
|
764
764
|
'directory': 'list',
|
|
765
765
|
'img': 'image',
|
|
766
766
|
};
|
|
767
767
|
|
|
768
|
-
|
|
768
|
+
export const nameFromDescendant = {
|
|
769
769
|
'figure': 'figcaption',
|
|
770
770
|
'table': 'caption',
|
|
771
771
|
'fieldset': 'legend',
|
|
772
772
|
};
|
|
773
773
|
|
|
774
|
-
|
|
774
|
+
export const nameDefaults = {
|
|
775
775
|
'input[type="submit"]': 'Submit',
|
|
776
776
|
'input[type="reset"]': 'Reset',
|
|
777
777
|
'summary': 'Details',
|
package/lib/name.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as constants from './constants.js';
|
|
2
|
+
import * as atree from './atree.js';
|
|
3
|
+
import * as attrs from './attrs.js';
|
|
4
|
+
import * as query from './query.js';
|
|
4
5
|
|
|
5
6
|
const addSpaces = function(text, el, pseudoSelector) {
|
|
6
7
|
// https://github.com/w3c/accname/issues/3
|
|
@@ -16,17 +17,17 @@ const getPseudoContent = function(el, pseudoSelector) {
|
|
|
16
17
|
|
|
17
18
|
let match;
|
|
18
19
|
while (tail.length) {
|
|
19
|
-
if (match = tail.match(/^"([^"]*)"/)) {
|
|
20
|
+
if ((match = tail.match(/^"([^"]*)"/))) {
|
|
20
21
|
ret.push(match[1]);
|
|
21
|
-
} else if (match = tail.match(/^([a-z-]+)\(([^)]*)\)/)) {
|
|
22
|
+
} else if ((match = tail.match(/^([a-z-]+)\(([^)]*)\)/))) {
|
|
22
23
|
if (match[1] === 'attr') {
|
|
23
24
|
ret.push(el.getAttribute(match[2]) || '');
|
|
24
25
|
}
|
|
25
|
-
} else if (match = tail.match(/^([a-z-]+)/)) {
|
|
26
|
+
} else if ((match = tail.match(/^([a-z-]+)/))) {
|
|
26
27
|
if (match[1] === 'open-quote' || match[1] === 'close-quote') {
|
|
27
28
|
ret.push('"');
|
|
28
29
|
}
|
|
29
|
-
} else if (match = tail.match(/^\//)) {
|
|
30
|
+
} else if ((match = tail.match(/^\//))) {
|
|
30
31
|
ret = [];
|
|
31
32
|
} else {
|
|
32
33
|
// invalid content, ignore
|
|
@@ -45,12 +46,21 @@ const getContent = function(root, ongoingLabelledBy, visited) {
|
|
|
45
46
|
for (let i = 0; i < children.length; i++) {
|
|
46
47
|
const node = children[i];
|
|
47
48
|
if (node.nodeType === node.TEXT_NODE) {
|
|
48
|
-
|
|
49
|
+
const styles = window.getComputedStyle(node.parentElement);
|
|
50
|
+
if (styles.textTransform === 'uppercase') {
|
|
51
|
+
ret += node.textContent.toUpperCase();
|
|
52
|
+
} else if (styles.textTransform === 'lowercase') {
|
|
53
|
+
ret += node.textContent.toLowerCase();
|
|
54
|
+
} else if (styles.textTransform === 'capitalize') {
|
|
55
|
+
ret += node.textContent.replace(/\b\w/g, c => c.toUpperCase());
|
|
56
|
+
} else {
|
|
57
|
+
ret += node.textContent;
|
|
58
|
+
}
|
|
49
59
|
} else if (node.nodeType === node.ELEMENT_NODE) {
|
|
50
60
|
if (node.tagName.toLowerCase() === 'br') {
|
|
51
61
|
ret += '\n';
|
|
52
62
|
} else {
|
|
53
|
-
ret +=
|
|
63
|
+
ret += getNameRaw(node, true, ongoingLabelledBy, visited);
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
}
|
|
@@ -59,13 +69,13 @@ const getContent = function(root, ongoingLabelledBy, visited) {
|
|
|
59
69
|
};
|
|
60
70
|
|
|
61
71
|
const allowNameFromContent = function(el) {
|
|
62
|
-
const role =
|
|
72
|
+
const role = attrs.getRole(el);
|
|
63
73
|
if (role) {
|
|
64
74
|
return constants.roles[role].nameFromContents;
|
|
65
75
|
}
|
|
66
76
|
};
|
|
67
77
|
|
|
68
|
-
const
|
|
78
|
+
const getNameRaw = function(el, recursive, ongoingLabelledBy, visited, directReference) {
|
|
69
79
|
let ret = '';
|
|
70
80
|
|
|
71
81
|
visited = visited || [];
|
|
@@ -85,7 +95,7 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
|
|
|
85
95
|
const ids = el.getAttribute('aria-labelledby').split(/\s+/);
|
|
86
96
|
const strings = ids.map(id => {
|
|
87
97
|
const label = document.getElementById(id);
|
|
88
|
-
return label ?
|
|
98
|
+
return label ? getNameRaw(label, true, true, visited, true) : '';
|
|
89
99
|
});
|
|
90
100
|
ret = strings.join(' ');
|
|
91
101
|
}
|
|
@@ -97,12 +107,12 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
|
|
|
97
107
|
} else if (query.matches(el, 'combobox,listbox')) {
|
|
98
108
|
const selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
|
|
99
109
|
if (selected) {
|
|
100
|
-
ret =
|
|
110
|
+
ret = getNameRaw(selected, recursive, ongoingLabelledBy, visited);
|
|
101
111
|
} else {
|
|
102
112
|
ret = el.value || '';
|
|
103
113
|
}
|
|
104
114
|
} else if (query.matches(el, 'range')) {
|
|
105
|
-
ret = '' + (
|
|
115
|
+
ret = '' + (attrs.getAttribute(el, 'valuetext') || attrs.getAttribute(el, 'valuenow') || el.value);
|
|
106
116
|
}
|
|
107
117
|
}
|
|
108
118
|
|
|
@@ -115,7 +125,7 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
|
|
|
115
125
|
// D
|
|
116
126
|
if (!ret.trim() && !recursive && el.labels) {
|
|
117
127
|
const strings = Array.prototype.map.call(el.labels, label => {
|
|
118
|
-
return
|
|
128
|
+
return getNameRaw(label, true, ongoingLabelledBy, visited);
|
|
119
129
|
});
|
|
120
130
|
ret = strings.join(' ');
|
|
121
131
|
}
|
|
@@ -130,7 +140,7 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
|
|
|
130
140
|
if (el.matches(selector)) {
|
|
131
141
|
const descendant = el.querySelector(constants.nameFromDescendant[selector]);
|
|
132
142
|
if (descendant) {
|
|
133
|
-
ret =
|
|
143
|
+
ret = getNameRaw(descendant, true, ongoingLabelledBy, visited);
|
|
134
144
|
}
|
|
135
145
|
}
|
|
136
146
|
}
|
|
@@ -182,21 +192,21 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
|
|
|
182
192
|
return addSpaces(before + ret + after, el);
|
|
183
193
|
};
|
|
184
194
|
|
|
185
|
-
const
|
|
186
|
-
return
|
|
195
|
+
export const getName = function(el) {
|
|
196
|
+
return getNameRaw(el)
|
|
187
197
|
.replace(/[ \n\r\t\f]+/g, ' ')
|
|
188
198
|
.replace(/^ /, '')
|
|
189
199
|
.replace(/ $/, '');
|
|
190
200
|
};
|
|
191
201
|
|
|
192
|
-
const getDescription = function(el) {
|
|
202
|
+
export const getDescription = function(el) {
|
|
193
203
|
let ret = '';
|
|
194
204
|
|
|
195
205
|
if (el.matches('[aria-describedby]')) {
|
|
196
206
|
const ids = el.getAttribute('aria-describedby').split(/\s+/);
|
|
197
207
|
const strings = ids.map(id => {
|
|
198
208
|
const label = document.getElementById(id);
|
|
199
|
-
return label ?
|
|
209
|
+
return label ? getNameRaw(label, true, true) : '';
|
|
200
210
|
});
|
|
201
211
|
ret = strings.join(' ');
|
|
202
212
|
} else if (el.matches('[aria-description]')) {
|
|
@@ -215,14 +225,9 @@ const getDescription = function(el) {
|
|
|
215
225
|
|
|
216
226
|
ret = (ret || '').trim().replace(/\s+/g, ' ');
|
|
217
227
|
|
|
218
|
-
if (ret ===
|
|
228
|
+
if (ret === getName(el)) {
|
|
219
229
|
ret = '';
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
return ret;
|
|
223
233
|
};
|
|
224
|
-
|
|
225
|
-
module.exports = {
|
|
226
|
-
getName: getNameTrimmed,
|
|
227
|
-
getDescription: getDescription,
|
|
228
|
-
};
|
package/lib/query.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as attrs from './attrs.js';
|
|
2
|
+
import * as atree from './atree.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const matches = function(el, selector) {
|
|
4
|
+
export const matches = function(el, selector) {
|
|
6
5
|
if (selector.substr(0, 1) === ':') {
|
|
7
6
|
const attr = selector.substr(1);
|
|
8
7
|
return attrs.getAttribute(el, attr);
|
|
@@ -40,7 +39,7 @@ const _querySelector = function(all) {
|
|
|
40
39
|
};
|
|
41
40
|
};
|
|
42
41
|
|
|
43
|
-
const closest = function(el, selector) {
|
|
42
|
+
export const closest = function(el, selector) {
|
|
44
43
|
return atree.searchUp(el, candidate => {
|
|
45
44
|
if (candidate.nodeType === candidate.ELEMENT_NODE) {
|
|
46
45
|
return matches(candidate, selector);
|
|
@@ -48,11 +47,5 @@ const closest = function(el, selector) {
|
|
|
48
47
|
});
|
|
49
48
|
};
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
getAttribute: attrs.getAttribute,
|
|
54
|
-
matches: matches,
|
|
55
|
-
querySelector: _querySelector(),
|
|
56
|
-
querySelectorAll: _querySelector(true),
|
|
57
|
-
closest: closest,
|
|
58
|
-
};
|
|
50
|
+
export const querySelector = _querySelector();
|
|
51
|
+
export const querySelectorAll = _querySelector(true);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aria-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Access ARIA information from JavaScript",
|
|
5
|
-
"
|
|
5
|
+
"module": "index.js",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"aria",
|
|
8
8
|
"accessibility",
|
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
"author": "Tobias Bengfort <tobias.bengfort@posteo.de>",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"brfs": "^2.0.0",
|
|
15
|
-
"browserify": "^17.0.0",
|
|
16
14
|
"expect": "^1.20.2",
|
|
17
15
|
"mocha": "^10.2.0",
|
|
18
|
-
"mocha-headless-chrome": "^4.0.0"
|
|
16
|
+
"mocha-headless-chrome": "^4.0.0",
|
|
17
|
+
"rollup": "^4.24.3"
|
|
19
18
|
},
|
|
20
19
|
"files": [
|
|
21
20
|
"index.js",
|