aria-api 0.4.5 → 0.4.7
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 +1 -1
- package/dist/aria.js +78 -63
- package/lib/atree.js +32 -25
- package/lib/attrs.js +14 -19
- package/lib/constants.js +19 -10
- package/lib/name.js +10 -4
- package/lib/query.js +3 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ browserify. There is also an UMD build included as `dist/aria.js`.
|
|
|
20
20
|
|
|
21
21
|
var aria = require('aria-api'):
|
|
22
22
|
|
|
23
|
-
aria.querySelector('landmark').forEach(
|
|
23
|
+
aria.querySelector('landmark').forEach(landmark => {
|
|
24
24
|
if (!aria.matches(landmark, ':hidden')) {
|
|
25
25
|
var role = aria.getRole(landmark);
|
|
26
26
|
var name = aria.getName(landmark);
|
package/dist/aria.js
CHANGED
|
@@ -21,52 +21,56 @@ module.exports = {
|
|
|
21
21
|
},{"./lib/atree.js":2,"./lib/name.js":5,"./lib/query.js":6}],2:[function(require,module,exports){
|
|
22
22
|
var attrs = require('./attrs');
|
|
23
23
|
|
|
24
|
-
var _getOwner = function(node) {
|
|
24
|
+
var _getOwner = function(node, owners) {
|
|
25
25
|
if (node.nodeType === node.ELEMENT_NODE && node.id) {
|
|
26
|
-
var
|
|
27
|
-
if (
|
|
28
|
-
|
|
26
|
+
var selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
|
|
27
|
+
if (owners) {
|
|
28
|
+
for (var owner of owners) {
|
|
29
|
+
if (owner.matches(selector)) {
|
|
30
|
+
return owner;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
return document.querySelector(selector);
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
37
|
};
|
|
32
38
|
|
|
33
|
-
var _getParentNode = function(node) {
|
|
34
|
-
return _getOwner(node) || node.parentNode;
|
|
39
|
+
var _getParentNode = function(node, owners) {
|
|
40
|
+
return _getOwner(node, owners) || node.parentNode;
|
|
35
41
|
};
|
|
36
42
|
|
|
37
|
-
var detectLoop = function(node) {
|
|
38
|
-
var seen = [node]
|
|
39
|
-
while ((node = _getParentNode(node))) {
|
|
43
|
+
var detectLoop = function(node, owners) {
|
|
44
|
+
var seen = [node];
|
|
45
|
+
while ((node = _getParentNode(node, owners))) {
|
|
40
46
|
if (seen.includes(node)) {
|
|
41
47
|
return true;
|
|
42
48
|
}
|
|
43
|
-
seen.push(node)
|
|
49
|
+
seen.push(node);
|
|
44
50
|
}
|
|
45
51
|
};
|
|
46
52
|
|
|
47
|
-
var getOwner = function(node) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return owner;
|
|
52
|
-
}
|
|
53
|
+
var getOwner = function(node, owners) {
|
|
54
|
+
var owner = _getOwner(node, owners);
|
|
55
|
+
if (owner && !detectLoop(node, owners)) {
|
|
56
|
+
return owner;
|
|
53
57
|
}
|
|
54
58
|
};
|
|
55
59
|
|
|
56
|
-
var getParentNode = function(node) {
|
|
57
|
-
return getOwner(node) || node.parentNode;
|
|
60
|
+
var getParentNode = function(node, owners) {
|
|
61
|
+
return getOwner(node, owners) || node.parentNode;
|
|
58
62
|
};
|
|
59
63
|
|
|
60
64
|
var isHidden = function(node) {
|
|
61
65
|
return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
|
|
62
66
|
};
|
|
63
67
|
|
|
64
|
-
var getChildNodes = function(node) {
|
|
68
|
+
var getChildNodes = function(node, owners) {
|
|
65
69
|
var childNodes = [];
|
|
66
70
|
|
|
67
71
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
68
72
|
var child = node.childNodes[i];
|
|
69
|
-
if (!getOwner(child) && !isHidden(child)) {
|
|
73
|
+
if (!getOwner(child, owners) && !isHidden(child)) {
|
|
70
74
|
childNodes.push(child);
|
|
71
75
|
}
|
|
72
76
|
}
|
|
@@ -76,7 +80,7 @@ var getChildNodes = function(node) {
|
|
|
76
80
|
for (var i = 0; i < owns.length; i++) {
|
|
77
81
|
var child = document.getElementById(owns[i]);
|
|
78
82
|
// double check with getOwner for consistency
|
|
79
|
-
if (child && getOwner(child) === node && !isHidden(child)) {
|
|
83
|
+
if (child && getOwner(child, owners) === node && !isHidden(child)) {
|
|
80
84
|
childNodes.push(child);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
@@ -86,10 +90,13 @@ var getChildNodes = function(node) {
|
|
|
86
90
|
};
|
|
87
91
|
|
|
88
92
|
var walk = function(root, fn) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
var owners = document.querySelectorAll('[aria-owns]');
|
|
94
|
+
var queue = [root];
|
|
95
|
+
while (queue.length) {
|
|
96
|
+
var item = queue.shift();
|
|
97
|
+
fn(item);
|
|
98
|
+
queue = getChildNodes(item, owners).concat(queue);
|
|
99
|
+
}
|
|
93
100
|
};
|
|
94
101
|
|
|
95
102
|
var searchUp = function(node, test) {
|
|
@@ -116,35 +123,30 @@ var constants = require('./constants.js');
|
|
|
116
123
|
// candidates can be passed for performance optimization
|
|
117
124
|
var getRole = function(el, candidates) {
|
|
118
125
|
if (el.hasAttribute('role')) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for (var role in constants.roles) {
|
|
122
|
-
var selector = (constants.roles[role].selectors || []).join(',');
|
|
123
|
-
if (selector && (!candidates || candidates.includes(role)) && el.matches(selector)) {
|
|
126
|
+
var role = el.getAttribute('role');
|
|
127
|
+
if (!candidates || candidates.includes(role)) {
|
|
124
128
|
return role;
|
|
129
|
+
} else {
|
|
130
|
+
return;
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (el.matches(
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
if (el.matches('footer')) {
|
|
136
|
-
return 'contentinfo';
|
|
133
|
+
var roles = candidates ? candidates : Object.keys(constants.roles);
|
|
134
|
+
for (var role of roles) {
|
|
135
|
+
var r = constants.roles[role];
|
|
136
|
+
if (r) {
|
|
137
|
+
var selector = (r.selectors || []).join(',');
|
|
138
|
+
if (selector && el.matches(selector)) {
|
|
139
|
+
return role;
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
}
|
|
140
143
|
};
|
|
141
144
|
|
|
142
145
|
var hasRole = function(el, roles) {
|
|
143
|
-
var candidates = [].concat.apply([], roles.map(
|
|
146
|
+
var candidates = [].concat.apply([], roles.map(role => {
|
|
144
147
|
return (constants.roles[role] || {}).subRoles || [role];
|
|
145
148
|
}));
|
|
146
|
-
|
|
147
|
-
return candidates.includes(actual);
|
|
149
|
+
return !!getRole(el, candidates);
|
|
148
150
|
};
|
|
149
151
|
|
|
150
152
|
var getAttribute = function(el, key) {
|
|
@@ -163,7 +165,7 @@ var getAttribute = function(el, key) {
|
|
|
163
165
|
if (el.matches('noscript')) {
|
|
164
166
|
return true;
|
|
165
167
|
}
|
|
166
|
-
if (el.matches('details:not([open]) :not(summary)')) {
|
|
168
|
+
if (el.matches('details:not([open]) > :not(summary)')) {
|
|
167
169
|
return true;
|
|
168
170
|
}
|
|
169
171
|
var style = window.getComputedStyle(el);
|
|
@@ -299,6 +301,14 @@ exports.attributeWeakMapping = {
|
|
|
299
301
|
'selected': 'selected',
|
|
300
302
|
};
|
|
301
303
|
|
|
304
|
+
var scoped = [
|
|
305
|
+
'main *',
|
|
306
|
+
// https://www.w3.org/TR/html/dom.html#sectioning-content-2
|
|
307
|
+
'article *', 'aside *', 'nav *', 'section *',
|
|
308
|
+
// https://www.w3.org/TR/html/sections.html#sectioning-roots
|
|
309
|
+
'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
|
|
310
|
+
].join(',');
|
|
311
|
+
|
|
302
312
|
// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
|
|
303
313
|
// https://www.w3.org/TR/wai-aria/roles
|
|
304
314
|
exports.roles = {
|
|
@@ -312,6 +322,9 @@ exports.roles = {
|
|
|
312
322
|
article: {
|
|
313
323
|
selectors: ['article'],
|
|
314
324
|
},
|
|
325
|
+
banner: {
|
|
326
|
+
selectors: ['header:not(' + scoped + ')'],
|
|
327
|
+
},
|
|
315
328
|
button: {
|
|
316
329
|
selectors: [
|
|
317
330
|
'button',
|
|
@@ -366,6 +379,9 @@ exports.roles = {
|
|
|
366
379
|
composite: {
|
|
367
380
|
childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
|
|
368
381
|
},
|
|
382
|
+
contentinfo: {
|
|
383
|
+
selectors: ['footer:not(' + scoped + ')'],
|
|
384
|
+
},
|
|
369
385
|
definition: {
|
|
370
386
|
selectors: ['dd'],
|
|
371
387
|
},
|
|
@@ -528,6 +544,9 @@ exports.roles = {
|
|
|
528
544
|
'selected': 'false',
|
|
529
545
|
},
|
|
530
546
|
},
|
|
547
|
+
presentation: {
|
|
548
|
+
selectors: ['img[alt=""]'],
|
|
549
|
+
},
|
|
531
550
|
progressbar: {
|
|
532
551
|
selectors: ['progress'],
|
|
533
552
|
},
|
|
@@ -728,22 +747,14 @@ exports.roles = {
|
|
|
728
747
|
},
|
|
729
748
|
};
|
|
730
749
|
|
|
731
|
-
exports.scoped = [
|
|
732
|
-
'main *',
|
|
733
|
-
// https://www.w3.org/TR/html/dom.html#sectioning-content-2
|
|
734
|
-
'article *', 'aside *', 'nav *', 'section *',
|
|
735
|
-
// https://www.w3.org/TR/html/sections.html#sectioning-roots
|
|
736
|
-
'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
|
|
737
|
-
].join(',');
|
|
738
|
-
|
|
739
750
|
var getSubRoles = function(role) {
|
|
740
751
|
var children = (exports.roles[role] || {}).childRoles || [];
|
|
741
752
|
var descendents = children.map(getSubRoles);
|
|
742
753
|
|
|
743
754
|
var result = [role];
|
|
744
755
|
|
|
745
|
-
descendents.forEach(
|
|
746
|
-
list.forEach(
|
|
756
|
+
descendents.forEach(list => {
|
|
757
|
+
list.forEach(r => {
|
|
747
758
|
if (!result.includes(r)) {
|
|
748
759
|
result.push(r);
|
|
749
760
|
}
|
|
@@ -855,7 +866,7 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
855
866
|
// B
|
|
856
867
|
if (!recursive && el.matches('[aria-labelledby]')) {
|
|
857
868
|
var ids = el.getAttribute('aria-labelledby').split(/\s+/);
|
|
858
|
-
var strings = ids.map(
|
|
869
|
+
var strings = ids.map(id => {
|
|
859
870
|
var label = document.getElementById(id);
|
|
860
871
|
return label ? getName(label, true, visited, true) : '';
|
|
861
872
|
});
|
|
@@ -870,7 +881,7 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
870
881
|
|
|
871
882
|
// D
|
|
872
883
|
if (!ret.trim() && !recursive && el.labels) {
|
|
873
|
-
var strings = Array.prototype.map.call(el.labels,
|
|
884
|
+
var strings = Array.prototype.map.call(el.labels, label => {
|
|
874
885
|
return getName(label, true, visited);
|
|
875
886
|
});
|
|
876
887
|
ret = strings.join(' ');
|
|
@@ -932,10 +943,16 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
932
943
|
|
|
933
944
|
// I
|
|
934
945
|
// FIXME: presentation not mentioned in the spec
|
|
935
|
-
if (!ret.trim() && !query.matches(el, 'presentation')) {
|
|
946
|
+
if (!ret.trim() && (directReference || !query.matches(el, 'presentation'))) {
|
|
936
947
|
ret = el.title || '';
|
|
937
948
|
}
|
|
938
949
|
|
|
950
|
+
// FIXME: not exactly sure about this, but it reduces the number of failing
|
|
951
|
+
// WPT tests. Whitespace is hard.
|
|
952
|
+
if (!ret.trim()) {
|
|
953
|
+
ret = ' ';
|
|
954
|
+
}
|
|
955
|
+
|
|
939
956
|
var before = getPseudoContent(el, ':before');
|
|
940
957
|
var after = getPseudoContent(el, ':after');
|
|
941
958
|
return before + ret + after;
|
|
@@ -950,7 +967,7 @@ var getDescription = function(el) {
|
|
|
950
967
|
|
|
951
968
|
if (el.matches('[aria-describedby]')) {
|
|
952
969
|
var ids = el.getAttribute('aria-describedby').split(/\s+/);
|
|
953
|
-
var strings = ids.map(
|
|
970
|
+
var strings = ids.map(id => {
|
|
954
971
|
var label = document.getElementById(id);
|
|
955
972
|
return label ? getName(label, true) : '';
|
|
956
973
|
});
|
|
@@ -1000,7 +1017,7 @@ var _querySelector = function(all) {
|
|
|
1000
1017
|
return function(root, role) {
|
|
1001
1018
|
var results = [];
|
|
1002
1019
|
try {
|
|
1003
|
-
atree.walk(root,
|
|
1020
|
+
atree.walk(root, node => {
|
|
1004
1021
|
if (node.nodeType === node.ELEMENT_NODE) {
|
|
1005
1022
|
// FIXME: skip hidden elements
|
|
1006
1023
|
if (matches(node, role)) {
|
|
@@ -1021,7 +1038,7 @@ var _querySelector = function(all) {
|
|
|
1021
1038
|
};
|
|
1022
1039
|
|
|
1023
1040
|
var closest = function(el, selector) {
|
|
1024
|
-
return atree.searchUp(el,
|
|
1041
|
+
return atree.searchUp(el, candidate => {
|
|
1025
1042
|
if (candidate.nodeType === candidate.ELEMENT_NODE) {
|
|
1026
1043
|
return matches(candidate, selector);
|
|
1027
1044
|
}
|
|
@@ -1029,9 +1046,7 @@ var closest = function(el, selector) {
|
|
|
1029
1046
|
};
|
|
1030
1047
|
|
|
1031
1048
|
module.exports = {
|
|
1032
|
-
getRole:
|
|
1033
|
-
return attrs.getRole(el);
|
|
1034
|
-
},
|
|
1049
|
+
getRole: el => attrs.getRole(el),
|
|
1035
1050
|
getAttribute: attrs.getAttribute,
|
|
1036
1051
|
matches: matches,
|
|
1037
1052
|
querySelector: _querySelector(),
|
package/lib/atree.js
CHANGED
|
@@ -1,51 +1,55 @@
|
|
|
1
1
|
var attrs = require('./attrs');
|
|
2
2
|
|
|
3
|
-
var _getOwner = function(node) {
|
|
3
|
+
var _getOwner = function(node, owners) {
|
|
4
4
|
if (node.nodeType === node.ELEMENT_NODE && node.id) {
|
|
5
|
-
var
|
|
6
|
-
if (
|
|
7
|
-
|
|
5
|
+
var selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
|
|
6
|
+
if (owners) {
|
|
7
|
+
for (var owner of owners) {
|
|
8
|
+
if (owner.matches(selector)) {
|
|
9
|
+
return owner;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
return document.querySelector(selector);
|
|
8
14
|
}
|
|
9
15
|
}
|
|
10
16
|
};
|
|
11
17
|
|
|
12
|
-
var _getParentNode = function(node) {
|
|
13
|
-
return _getOwner(node) || node.parentNode;
|
|
18
|
+
var _getParentNode = function(node, owners) {
|
|
19
|
+
return _getOwner(node, owners) || node.parentNode;
|
|
14
20
|
};
|
|
15
21
|
|
|
16
|
-
var detectLoop = function(node) {
|
|
17
|
-
var seen = [node]
|
|
18
|
-
while ((node = _getParentNode(node))) {
|
|
22
|
+
var detectLoop = function(node, owners) {
|
|
23
|
+
var seen = [node];
|
|
24
|
+
while ((node = _getParentNode(node, owners))) {
|
|
19
25
|
if (seen.includes(node)) {
|
|
20
26
|
return true;
|
|
21
27
|
}
|
|
22
|
-
seen.push(node)
|
|
28
|
+
seen.push(node);
|
|
23
29
|
}
|
|
24
30
|
};
|
|
25
31
|
|
|
26
|
-
var getOwner = function(node) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return owner;
|
|
31
|
-
}
|
|
32
|
+
var getOwner = function(node, owners) {
|
|
33
|
+
var owner = _getOwner(node, owners);
|
|
34
|
+
if (owner && !detectLoop(node, owners)) {
|
|
35
|
+
return owner;
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
38
|
|
|
35
|
-
var getParentNode = function(node) {
|
|
36
|
-
return getOwner(node) || node.parentNode;
|
|
39
|
+
var getParentNode = function(node, owners) {
|
|
40
|
+
return getOwner(node, owners) || node.parentNode;
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
var isHidden = function(node) {
|
|
40
44
|
return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
|
|
41
45
|
};
|
|
42
46
|
|
|
43
|
-
var getChildNodes = function(node) {
|
|
47
|
+
var getChildNodes = function(node, owners) {
|
|
44
48
|
var childNodes = [];
|
|
45
49
|
|
|
46
50
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
47
51
|
var child = node.childNodes[i];
|
|
48
|
-
if (!getOwner(child) && !isHidden(child)) {
|
|
52
|
+
if (!getOwner(child, owners) && !isHidden(child)) {
|
|
49
53
|
childNodes.push(child);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
@@ -55,7 +59,7 @@ var getChildNodes = function(node) {
|
|
|
55
59
|
for (var i = 0; i < owns.length; i++) {
|
|
56
60
|
var child = document.getElementById(owns[i]);
|
|
57
61
|
// double check with getOwner for consistency
|
|
58
|
-
if (child && getOwner(child) === node && !isHidden(child)) {
|
|
62
|
+
if (child && getOwner(child, owners) === node && !isHidden(child)) {
|
|
59
63
|
childNodes.push(child);
|
|
60
64
|
}
|
|
61
65
|
}
|
|
@@ -65,10 +69,13 @@ var getChildNodes = function(node) {
|
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
var walk = function(root, fn) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
var owners = document.querySelectorAll('[aria-owns]');
|
|
73
|
+
var queue = [root];
|
|
74
|
+
while (queue.length) {
|
|
75
|
+
var item = queue.shift();
|
|
76
|
+
fn(item);
|
|
77
|
+
queue = getChildNodes(item, owners).concat(queue);
|
|
78
|
+
}
|
|
72
79
|
};
|
|
73
80
|
|
|
74
81
|
var searchUp = function(node, test) {
|
package/lib/attrs.js
CHANGED
|
@@ -3,35 +3,30 @@ var constants = require('./constants.js');
|
|
|
3
3
|
// candidates can be passed for performance optimization
|
|
4
4
|
var getRole = function(el, candidates) {
|
|
5
5
|
if (el.hasAttribute('role')) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (var role in constants.roles) {
|
|
9
|
-
var selector = (constants.roles[role].selectors || []).join(',');
|
|
10
|
-
if (selector && (!candidates || candidates.includes(role)) && el.matches(selector)) {
|
|
6
|
+
var role = el.getAttribute('role');
|
|
7
|
+
if (!candidates || candidates.includes(role)) {
|
|
11
8
|
return role;
|
|
9
|
+
} else {
|
|
10
|
+
return;
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (el.matches(
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
if (el.matches('footer')) {
|
|
23
|
-
return 'contentinfo';
|
|
13
|
+
var roles = candidates ? candidates : Object.keys(constants.roles);
|
|
14
|
+
for (var role of roles) {
|
|
15
|
+
var r = constants.roles[role];
|
|
16
|
+
if (r) {
|
|
17
|
+
var selector = (r.selectors || []).join(',');
|
|
18
|
+
if (selector && el.matches(selector)) {
|
|
19
|
+
return role;
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
23
|
};
|
|
28
24
|
|
|
29
25
|
var hasRole = function(el, roles) {
|
|
30
|
-
var candidates = [].concat.apply([], roles.map(
|
|
26
|
+
var candidates = [].concat.apply([], roles.map(role => {
|
|
31
27
|
return (constants.roles[role] || {}).subRoles || [role];
|
|
32
28
|
}));
|
|
33
|
-
|
|
34
|
-
return candidates.includes(actual);
|
|
29
|
+
return !!getRole(el, candidates);
|
|
35
30
|
};
|
|
36
31
|
|
|
37
32
|
var getAttribute = function(el, key) {
|
|
@@ -50,7 +45,7 @@ var getAttribute = function(el, key) {
|
|
|
50
45
|
if (el.matches('noscript')) {
|
|
51
46
|
return true;
|
|
52
47
|
}
|
|
53
|
-
if (el.matches('details:not([open]) :not(summary)')) {
|
|
48
|
+
if (el.matches('details:not([open]) > :not(summary)')) {
|
|
54
49
|
return true;
|
|
55
50
|
}
|
|
56
51
|
var style = window.getComputedStyle(el);
|
package/lib/constants.js
CHANGED
|
@@ -66,6 +66,14 @@ exports.attributeWeakMapping = {
|
|
|
66
66
|
'selected': 'selected',
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
var scoped = [
|
|
70
|
+
'main *',
|
|
71
|
+
// https://www.w3.org/TR/html/dom.html#sectioning-content-2
|
|
72
|
+
'article *', 'aside *', 'nav *', 'section *',
|
|
73
|
+
// https://www.w3.org/TR/html/sections.html#sectioning-roots
|
|
74
|
+
'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
|
|
75
|
+
].join(',');
|
|
76
|
+
|
|
69
77
|
// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
|
|
70
78
|
// https://www.w3.org/TR/wai-aria/roles
|
|
71
79
|
exports.roles = {
|
|
@@ -79,6 +87,9 @@ exports.roles = {
|
|
|
79
87
|
article: {
|
|
80
88
|
selectors: ['article'],
|
|
81
89
|
},
|
|
90
|
+
banner: {
|
|
91
|
+
selectors: ['header:not(' + scoped + ')'],
|
|
92
|
+
},
|
|
82
93
|
button: {
|
|
83
94
|
selectors: [
|
|
84
95
|
'button',
|
|
@@ -133,6 +144,9 @@ exports.roles = {
|
|
|
133
144
|
composite: {
|
|
134
145
|
childRoles: ['grid', 'select', 'spinbutton', 'tablist'],
|
|
135
146
|
},
|
|
147
|
+
contentinfo: {
|
|
148
|
+
selectors: ['footer:not(' + scoped + ')'],
|
|
149
|
+
},
|
|
136
150
|
definition: {
|
|
137
151
|
selectors: ['dd'],
|
|
138
152
|
},
|
|
@@ -295,6 +309,9 @@ exports.roles = {
|
|
|
295
309
|
'selected': 'false',
|
|
296
310
|
},
|
|
297
311
|
},
|
|
312
|
+
presentation: {
|
|
313
|
+
selectors: ['img[alt=""]'],
|
|
314
|
+
},
|
|
298
315
|
progressbar: {
|
|
299
316
|
selectors: ['progress'],
|
|
300
317
|
},
|
|
@@ -495,22 +512,14 @@ exports.roles = {
|
|
|
495
512
|
},
|
|
496
513
|
};
|
|
497
514
|
|
|
498
|
-
exports.scoped = [
|
|
499
|
-
'main *',
|
|
500
|
-
// https://www.w3.org/TR/html/dom.html#sectioning-content-2
|
|
501
|
-
'article *', 'aside *', 'nav *', 'section *',
|
|
502
|
-
// https://www.w3.org/TR/html/sections.html#sectioning-roots
|
|
503
|
-
'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
|
|
504
|
-
].join(',');
|
|
505
|
-
|
|
506
515
|
var getSubRoles = function(role) {
|
|
507
516
|
var children = (exports.roles[role] || {}).childRoles || [];
|
|
508
517
|
var descendents = children.map(getSubRoles);
|
|
509
518
|
|
|
510
519
|
var result = [role];
|
|
511
520
|
|
|
512
|
-
descendents.forEach(
|
|
513
|
-
list.forEach(
|
|
521
|
+
descendents.forEach(list => {
|
|
522
|
+
list.forEach(r => {
|
|
514
523
|
if (!result.includes(r)) {
|
|
515
524
|
result.push(r);
|
|
516
525
|
}
|
package/lib/name.js
CHANGED
|
@@ -72,7 +72,7 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
72
72
|
// B
|
|
73
73
|
if (!recursive && el.matches('[aria-labelledby]')) {
|
|
74
74
|
var ids = el.getAttribute('aria-labelledby').split(/\s+/);
|
|
75
|
-
var strings = ids.map(
|
|
75
|
+
var strings = ids.map(id => {
|
|
76
76
|
var label = document.getElementById(id);
|
|
77
77
|
return label ? getName(label, true, visited, true) : '';
|
|
78
78
|
});
|
|
@@ -87,7 +87,7 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
87
87
|
|
|
88
88
|
// D
|
|
89
89
|
if (!ret.trim() && !recursive && el.labels) {
|
|
90
|
-
var strings = Array.prototype.map.call(el.labels,
|
|
90
|
+
var strings = Array.prototype.map.call(el.labels, label => {
|
|
91
91
|
return getName(label, true, visited);
|
|
92
92
|
});
|
|
93
93
|
ret = strings.join(' ');
|
|
@@ -149,10 +149,16 @@ var getName = function(el, recursive, visited, directReference) {
|
|
|
149
149
|
|
|
150
150
|
// I
|
|
151
151
|
// FIXME: presentation not mentioned in the spec
|
|
152
|
-
if (!ret.trim() && !query.matches(el, 'presentation')) {
|
|
152
|
+
if (!ret.trim() && (directReference || !query.matches(el, 'presentation'))) {
|
|
153
153
|
ret = el.title || '';
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// FIXME: not exactly sure about this, but it reduces the number of failing
|
|
157
|
+
// WPT tests. Whitespace is hard.
|
|
158
|
+
if (!ret.trim()) {
|
|
159
|
+
ret = ' ';
|
|
160
|
+
}
|
|
161
|
+
|
|
156
162
|
var before = getPseudoContent(el, ':before');
|
|
157
163
|
var after = getPseudoContent(el, ':after');
|
|
158
164
|
return before + ret + after;
|
|
@@ -167,7 +173,7 @@ var getDescription = function(el) {
|
|
|
167
173
|
|
|
168
174
|
if (el.matches('[aria-describedby]')) {
|
|
169
175
|
var ids = el.getAttribute('aria-describedby').split(/\s+/);
|
|
170
|
-
var strings = ids.map(
|
|
176
|
+
var strings = ids.map(id => {
|
|
171
177
|
var label = document.getElementById(id);
|
|
172
178
|
return label ? getName(label, true) : '';
|
|
173
179
|
});
|
package/lib/query.js
CHANGED
|
@@ -22,7 +22,7 @@ var _querySelector = function(all) {
|
|
|
22
22
|
return function(root, role) {
|
|
23
23
|
var results = [];
|
|
24
24
|
try {
|
|
25
|
-
atree.walk(root,
|
|
25
|
+
atree.walk(root, node => {
|
|
26
26
|
if (node.nodeType === node.ELEMENT_NODE) {
|
|
27
27
|
// FIXME: skip hidden elements
|
|
28
28
|
if (matches(node, role)) {
|
|
@@ -43,7 +43,7 @@ var _querySelector = function(all) {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
var closest = function(el, selector) {
|
|
46
|
-
return atree.searchUp(el,
|
|
46
|
+
return atree.searchUp(el, candidate => {
|
|
47
47
|
if (candidate.nodeType === candidate.ELEMENT_NODE) {
|
|
48
48
|
return matches(candidate, selector);
|
|
49
49
|
}
|
|
@@ -51,9 +51,7 @@ var closest = function(el, selector) {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
module.exports = {
|
|
54
|
-
getRole:
|
|
55
|
-
return attrs.getRole(el);
|
|
56
|
-
},
|
|
54
|
+
getRole: el => attrs.getRole(el),
|
|
57
55
|
getAttribute: attrs.getAttribute,
|
|
58
56
|
matches: matches,
|
|
59
57
|
querySelector: _querySelector(),
|