aria-api 0.6.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 +1215 -1177
- package/index.js +4 -18
- package/lib/atree.js +5 -12
- package/lib/attrs.js +10 -12
- package/lib/constants.js +75 -24
- package/lib/name.js +75 -51
- 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) {
|
|
@@ -68,7 +72,7 @@ const getAttribute = function(el, key) {
|
|
|
68
72
|
return true;
|
|
69
73
|
}
|
|
70
74
|
const style = window.getComputedStyle(el);
|
|
71
|
-
if (style.display === 'none' || style.visibility === 'hidden') {
|
|
75
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.visibility === 'collapse') {
|
|
72
76
|
return true;
|
|
73
77
|
}
|
|
74
78
|
}
|
|
@@ -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,16 +1,20 @@
|
|
|
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',
|
|
6
|
+
'braillelabel': 'string',
|
|
7
|
+
'brailleroledescription': 'string',
|
|
6
8
|
'busy': 'bool',
|
|
7
9
|
'checked': 'tristate',
|
|
8
10
|
'colcount': 'int',
|
|
9
11
|
'colindex': 'int',
|
|
12
|
+
'colindextext': 'string',
|
|
10
13
|
'colspan': 'int',
|
|
11
14
|
'controls': 'id-list',
|
|
12
15
|
'current': 'token',
|
|
13
16
|
'describedby': 'id-list',
|
|
17
|
+
'description': 'string',
|
|
14
18
|
'details': 'id',
|
|
15
19
|
'disabled': 'bool',
|
|
16
20
|
'dropeffect': 'token-list',
|
|
@@ -40,6 +44,7 @@ exports.attributes = {
|
|
|
40
44
|
'roledescription': 'string',
|
|
41
45
|
'rowcount': 'int',
|
|
42
46
|
'rowindex': 'int',
|
|
47
|
+
'rowindextext': 'string',
|
|
43
48
|
'rowspan': 'int',
|
|
44
49
|
'selected': 'bool-undefined',
|
|
45
50
|
'setsize': 'int',
|
|
@@ -50,14 +55,14 @@ exports.attributes = {
|
|
|
50
55
|
'valuetext': 'string',
|
|
51
56
|
};
|
|
52
57
|
|
|
53
|
-
|
|
58
|
+
export const attributeStrongMapping = {
|
|
54
59
|
'disabled': 'disabled',
|
|
55
60
|
'placeholder': 'placeholder',
|
|
56
61
|
'readonly': 'readOnly',
|
|
57
62
|
'required': 'required',
|
|
58
63
|
};
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
export const attributeWeakMapping = {
|
|
61
66
|
'checked': 'checked',
|
|
62
67
|
'colspan': 'colSpan',
|
|
63
68
|
'expanded': 'open',
|
|
@@ -69,9 +74,22 @@ exports.attributeWeakMapping = {
|
|
|
69
74
|
// https://www.w3.org/TR/html/dom.html#sectioning-content-2
|
|
70
75
|
const scoped = ['article *', 'aside *', 'nav *', 'section *'].join(',');
|
|
71
76
|
|
|
77
|
+
const svgSelectors = function(selector) {
|
|
78
|
+
return [
|
|
79
|
+
// `${selector}:has(> title:not(:empty))`,
|
|
80
|
+
// `${selector}:has(> desc:not(:empty))`,
|
|
81
|
+
`${selector}[aria-label]`,
|
|
82
|
+
`${selector}[aria-roledescription]`,
|
|
83
|
+
`${selector}[aria-labelledby]`,
|
|
84
|
+
`${selector}[aria-describedby]`,
|
|
85
|
+
`${selector}[tabindex]`,
|
|
86
|
+
`${selector}[role]`,
|
|
87
|
+
];
|
|
88
|
+
};
|
|
89
|
+
|
|
72
90
|
// https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings
|
|
73
91
|
// https://www.w3.org/TR/wai-aria/roles
|
|
74
|
-
|
|
92
|
+
export const roles = {
|
|
75
93
|
alert: {
|
|
76
94
|
childRoles: ['alertdialog'],
|
|
77
95
|
defaults: {
|
|
@@ -83,6 +101,7 @@ exports.roles = {
|
|
|
83
101
|
application: {},
|
|
84
102
|
article: {
|
|
85
103
|
selectors: ['article'],
|
|
104
|
+
childRoles: ['comment'],
|
|
86
105
|
},
|
|
87
106
|
banner: {
|
|
88
107
|
selectors: [`header:not(main *, ${scoped})`],
|
|
@@ -145,6 +164,9 @@ exports.roles = {
|
|
|
145
164
|
abstract: true,
|
|
146
165
|
childRoles: ['button', 'link', 'menuitem'],
|
|
147
166
|
},
|
|
167
|
+
comment: {
|
|
168
|
+
nameFromContents: true,
|
|
169
|
+
},
|
|
148
170
|
complementary: {
|
|
149
171
|
selectors: [
|
|
150
172
|
`aside:not(${scoped})`,
|
|
@@ -240,8 +262,8 @@ exports.roles = {
|
|
|
240
262
|
},
|
|
241
263
|
generic: {
|
|
242
264
|
selectors: [
|
|
243
|
-
'a:not([href])',
|
|
244
|
-
'area:not([href])',
|
|
265
|
+
'a:not([*|href])',
|
|
266
|
+
'area:not([*|href])',
|
|
245
267
|
`aside:not(${scoped}):not([aria-label]):not([aria-labelledby]):not([title])`,
|
|
246
268
|
'b',
|
|
247
269
|
'bdi',
|
|
@@ -265,8 +287,23 @@ exports.roles = {
|
|
|
265
287
|
'graphics-document': {
|
|
266
288
|
selectors: ['svg'],
|
|
267
289
|
},
|
|
268
|
-
'graphics-object': {
|
|
269
|
-
|
|
290
|
+
'graphics-object': {
|
|
291
|
+
selectors: [
|
|
292
|
+
...svgSelectors('symbol'),
|
|
293
|
+
...svgSelectors('use'),
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
'graphics-symbol': {
|
|
297
|
+
selectors: [
|
|
298
|
+
...svgSelectors('circle'),
|
|
299
|
+
...svgSelectors('ellipse'),
|
|
300
|
+
...svgSelectors('line'),
|
|
301
|
+
...svgSelectors('path'),
|
|
302
|
+
...svgSelectors('polygon'),
|
|
303
|
+
...svgSelectors('polyline'),
|
|
304
|
+
...svgSelectors('rect'),
|
|
305
|
+
],
|
|
306
|
+
},
|
|
270
307
|
grid: {
|
|
271
308
|
childRoles: ['treegrid'],
|
|
272
309
|
},
|
|
@@ -281,7 +318,11 @@ exports.roles = {
|
|
|
281
318
|
'fieldset',
|
|
282
319
|
'hgroup',
|
|
283
320
|
'optgroup',
|
|
321
|
+
...svgSelectors('foreignObject'),
|
|
322
|
+
...svgSelectors('g'),
|
|
284
323
|
'text',
|
|
324
|
+
...svgSelectors('textPath'),
|
|
325
|
+
...svgSelectors('tspan'),
|
|
285
326
|
],
|
|
286
327
|
childRoles: ['row', 'select', 'toolbar', 'graphics-object'],
|
|
287
328
|
},
|
|
@@ -292,8 +333,13 @@ exports.roles = {
|
|
|
292
333
|
'level': 2,
|
|
293
334
|
},
|
|
294
335
|
},
|
|
295
|
-
|
|
296
|
-
selectors: [
|
|
336
|
+
image: {
|
|
337
|
+
selectors: [
|
|
338
|
+
'img:not([alt=""])',
|
|
339
|
+
'graphics-symbol',
|
|
340
|
+
...svgSelectors('image'),
|
|
341
|
+
...svgSelectors('mesh'),
|
|
342
|
+
],
|
|
297
343
|
childRoles: ['doc-cover'],
|
|
298
344
|
},
|
|
299
345
|
input: {
|
|
@@ -341,7 +387,7 @@ exports.roles = {
|
|
|
341
387
|
],
|
|
342
388
|
},
|
|
343
389
|
link: {
|
|
344
|
-
selectors: ['a[href]', 'area[href]'],
|
|
390
|
+
selectors: ['a[*|href]', 'area[*|href]'],
|
|
345
391
|
childRoles: ['doc-backlink', 'doc-biblioref', 'doc-glossref', 'doc-noteref'],
|
|
346
392
|
nameFromContents: true,
|
|
347
393
|
},
|
|
@@ -371,6 +417,9 @@ exports.roles = {
|
|
|
371
417
|
main: {
|
|
372
418
|
selectors: ['main'],
|
|
373
419
|
},
|
|
420
|
+
mark: {
|
|
421
|
+
selectors: ['mark'],
|
|
422
|
+
},
|
|
374
423
|
marquee: {},
|
|
375
424
|
math: {
|
|
376
425
|
selectors: ['math'],
|
|
@@ -394,11 +443,10 @@ exports.roles = {
|
|
|
394
443
|
},
|
|
395
444
|
},
|
|
396
445
|
menuitem: {
|
|
397
|
-
childRoles: ['menuitemcheckbox'],
|
|
446
|
+
childRoles: ['menuitemcheckbox', 'menuitemradio'],
|
|
398
447
|
nameFromContents: true,
|
|
399
448
|
},
|
|
400
449
|
menuitemcheckbox: {
|
|
401
|
-
childRoles: ['menuitemradio'],
|
|
402
450
|
nameFromContents: true,
|
|
403
451
|
defaults: {
|
|
404
452
|
'checked': 'false',
|
|
@@ -505,12 +553,13 @@ exports.roles = {
|
|
|
505
553
|
'emphasis',
|
|
506
554
|
'figure',
|
|
507
555
|
'group',
|
|
508
|
-
'
|
|
556
|
+
'image',
|
|
509
557
|
'insertion',
|
|
510
558
|
'landmark',
|
|
511
559
|
'list',
|
|
512
560
|
'listitem',
|
|
513
561
|
'log',
|
|
562
|
+
'mark',
|
|
514
563
|
'marquee',
|
|
515
564
|
'math',
|
|
516
565
|
'note',
|
|
@@ -518,6 +567,7 @@ exports.roles = {
|
|
|
518
567
|
'status',
|
|
519
568
|
'strong',
|
|
520
569
|
'subscript',
|
|
570
|
+
'suggestion',
|
|
521
571
|
'superscript',
|
|
522
572
|
'table',
|
|
523
573
|
'tabpanel',
|
|
@@ -682,7 +732,7 @@ exports.roles = {
|
|
|
682
732
|
};
|
|
683
733
|
|
|
684
734
|
const getSubRoles = function(role) {
|
|
685
|
-
const children = (
|
|
735
|
+
const children = (roles[role]).childRoles || [];
|
|
686
736
|
const descendents = children.map(getSubRoles);
|
|
687
737
|
|
|
688
738
|
const result = [role];
|
|
@@ -698,29 +748,30 @@ const getSubRoles = function(role) {
|
|
|
698
748
|
return result;
|
|
699
749
|
};
|
|
700
750
|
|
|
701
|
-
|
|
751
|
+
export const attrsWithDefaults = [];
|
|
702
752
|
|
|
703
|
-
for (const role in
|
|
704
|
-
|
|
705
|
-
for (const key in
|
|
706
|
-
if (!
|
|
707
|
-
|
|
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);
|
|
708
758
|
}
|
|
709
759
|
}
|
|
710
760
|
}
|
|
711
761
|
|
|
712
|
-
|
|
762
|
+
export const aliases = {
|
|
713
763
|
'presentation': 'none',
|
|
714
764
|
'directory': 'list',
|
|
765
|
+
'img': 'image',
|
|
715
766
|
};
|
|
716
767
|
|
|
717
|
-
|
|
768
|
+
export const nameFromDescendant = {
|
|
718
769
|
'figure': 'figcaption',
|
|
719
770
|
'table': 'caption',
|
|
720
771
|
'fieldset': 'legend',
|
|
721
772
|
};
|
|
722
773
|
|
|
723
|
-
|
|
774
|
+
export const nameDefaults = {
|
|
724
775
|
'input[type="submit"]': 'Submit',
|
|
725
776
|
'input[type="reset"]': 'Reset',
|
|
726
777
|
'summary': 'Details',
|
package/lib/name.js
CHANGED
|
@@ -1,42 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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';
|
|
5
|
+
|
|
6
|
+
const addSpaces = function(text, el, pseudoSelector) {
|
|
7
|
+
// https://github.com/w3c/accname/issues/3
|
|
8
|
+
const styles = window.getComputedStyle(el, pseudoSelector);
|
|
9
|
+
const inline = styles.display === 'inline';
|
|
10
|
+
return inline ? text : ` ${text} `;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getPseudoContent = function(el, pseudoSelector) {
|
|
14
|
+
const styles = window.getComputedStyle(el, pseudoSelector);
|
|
15
|
+
let tail = styles.getPropertyValue('content').trim();
|
|
16
|
+
let ret = [];
|
|
17
|
+
|
|
18
|
+
let match;
|
|
19
|
+
while (tail.length) {
|
|
20
|
+
if ((match = tail.match(/^"([^"]*)"/))) {
|
|
21
|
+
ret.push(match[1]);
|
|
22
|
+
} else if ((match = tail.match(/^([a-z-]+)\(([^)]*)\)/))) {
|
|
23
|
+
if (match[1] === 'attr') {
|
|
24
|
+
ret.push(el.getAttribute(match[2]) || '');
|
|
25
|
+
}
|
|
26
|
+
} else if ((match = tail.match(/^([a-z-]+)/))) {
|
|
27
|
+
if (match[1] === 'open-quote' || match[1] === 'close-quote') {
|
|
28
|
+
ret.push('"');
|
|
29
|
+
}
|
|
30
|
+
} else if ((match = tail.match(/^\//))) {
|
|
31
|
+
ret = [];
|
|
17
32
|
} else {
|
|
18
|
-
|
|
33
|
+
// invalid content, ignore
|
|
34
|
+
return '';
|
|
19
35
|
}
|
|
36
|
+
tail = tail.slice(match[0].length).trim();
|
|
20
37
|
}
|
|
38
|
+
|
|
39
|
+
return addSpaces(ret.join(''), el, pseudoSelector);
|
|
21
40
|
};
|
|
22
41
|
|
|
23
|
-
const getContent = function(root, visited) {
|
|
42
|
+
const getContent = function(root, ongoingLabelledBy, visited) {
|
|
24
43
|
const children = atree.getChildNodes(root);
|
|
25
44
|
|
|
26
45
|
let ret = '';
|
|
27
46
|
for (let i = 0; i < children.length; i++) {
|
|
28
47
|
const node = children[i];
|
|
29
48
|
if (node.nodeType === node.TEXT_NODE) {
|
|
30
|
-
|
|
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
|
+
}
|
|
31
59
|
} else if (node.nodeType === node.ELEMENT_NODE) {
|
|
32
60
|
if (node.tagName.toLowerCase() === 'br') {
|
|
33
61
|
ret += '\n';
|
|
34
|
-
} else if (window.getComputedStyle(node).display.substr(0, 6) === 'inline' &&
|
|
35
|
-
node.tagName.toLowerCase() !== 'input' &&
|
|
36
|
-
node.tagName.toLowerCase() !== 'img') { // https://github.com/w3c/accname/issues/3
|
|
37
|
-
ret += getName(node, true, visited);
|
|
38
62
|
} else {
|
|
39
|
-
ret +=
|
|
63
|
+
ret += getNameRaw(node, true, ongoingLabelledBy, visited);
|
|
40
64
|
}
|
|
41
65
|
}
|
|
42
66
|
}
|
|
@@ -45,13 +69,13 @@ const getContent = function(root, visited) {
|
|
|
45
69
|
};
|
|
46
70
|
|
|
47
71
|
const allowNameFromContent = function(el) {
|
|
48
|
-
const role =
|
|
72
|
+
const role = attrs.getRole(el);
|
|
49
73
|
if (role) {
|
|
50
74
|
return constants.roles[role].nameFromContents;
|
|
51
75
|
}
|
|
52
76
|
};
|
|
53
77
|
|
|
54
|
-
const
|
|
78
|
+
const getNameRaw = function(el, recursive, ongoingLabelledBy, visited, directReference) {
|
|
55
79
|
let ret = '';
|
|
56
80
|
|
|
57
81
|
visited = visited || [];
|
|
@@ -67,28 +91,28 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
67
91
|
// handled in atree
|
|
68
92
|
|
|
69
93
|
// B
|
|
70
|
-
if (!
|
|
94
|
+
if (!ongoingLabelledBy && el.matches('[aria-labelledby]')) {
|
|
71
95
|
const ids = el.getAttribute('aria-labelledby').split(/\s+/);
|
|
72
96
|
const strings = ids.map(id => {
|
|
73
97
|
const label = document.getElementById(id);
|
|
74
|
-
return label ?
|
|
98
|
+
return label ? getNameRaw(label, true, true, visited, true) : '';
|
|
75
99
|
});
|
|
76
100
|
ret = strings.join(' ');
|
|
77
101
|
}
|
|
78
102
|
|
|
79
103
|
// E (the current draft has this at this high priority)
|
|
80
104
|
if (!ret.trim() && recursive) {
|
|
81
|
-
if (query.matches(el, 'textbox
|
|
105
|
+
if (query.matches(el, 'textbox')) {
|
|
82
106
|
ret = el.value || el.textContent;
|
|
83
107
|
} else if (query.matches(el, 'combobox,listbox')) {
|
|
84
108
|
const selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
|
|
85
109
|
if (selected) {
|
|
86
|
-
ret =
|
|
110
|
+
ret = getNameRaw(selected, recursive, ongoingLabelledBy, visited);
|
|
87
111
|
} else {
|
|
88
112
|
ret = el.value || '';
|
|
89
113
|
}
|
|
90
114
|
} else if (query.matches(el, 'range')) {
|
|
91
|
-
ret = '' + (
|
|
115
|
+
ret = '' + (attrs.getAttribute(el, 'valuetext') || attrs.getAttribute(el, 'valuenow') || el.value);
|
|
92
116
|
}
|
|
93
117
|
}
|
|
94
118
|
|
|
@@ -101,13 +125,10 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
101
125
|
// D
|
|
102
126
|
if (!ret.trim() && !recursive && el.labels) {
|
|
103
127
|
const strings = Array.prototype.map.call(el.labels, label => {
|
|
104
|
-
return
|
|
128
|
+
return getNameRaw(label, true, ongoingLabelledBy, visited);
|
|
105
129
|
});
|
|
106
130
|
ret = strings.join(' ');
|
|
107
131
|
}
|
|
108
|
-
if (!ret.trim()) {
|
|
109
|
-
ret = el.placeholder || '';
|
|
110
|
-
}
|
|
111
132
|
if (!ret.trim()) {
|
|
112
133
|
ret = el.alt || '';
|
|
113
134
|
}
|
|
@@ -119,7 +140,7 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
119
140
|
if (el.matches(selector)) {
|
|
120
141
|
const descendant = el.querySelector(constants.nameFromDescendant[selector]);
|
|
121
142
|
if (descendant) {
|
|
122
|
-
ret =
|
|
143
|
+
ret = getNameRaw(descendant, true, ongoingLabelledBy, visited);
|
|
123
144
|
}
|
|
124
145
|
}
|
|
125
146
|
}
|
|
@@ -130,11 +151,14 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
130
151
|
ret = svgTitle.textContent;
|
|
131
152
|
}
|
|
132
153
|
}
|
|
154
|
+
if (!ret.trim() && el.matches('a')) {
|
|
155
|
+
ret = el.getAttribute('xlink:title') || '';
|
|
156
|
+
}
|
|
133
157
|
|
|
134
158
|
// F
|
|
135
159
|
// FIXME: menu is not mentioned in the spec
|
|
136
160
|
if (!ret.trim() && (recursive || allowNameFromContent(el) || el.closest('label')) && !query.matches(el, 'menu')) {
|
|
137
|
-
ret = getContent(el, visited);
|
|
161
|
+
ret = getContent(el, ongoingLabelledBy, visited);
|
|
138
162
|
}
|
|
139
163
|
|
|
140
164
|
if (!ret.trim() && query.matches(el, 'button')) {
|
|
@@ -153,9 +177,8 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
153
177
|
// handled in getContent
|
|
154
178
|
|
|
155
179
|
// I
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
ret = el.title || '';
|
|
180
|
+
if (!ret.trim()) {
|
|
181
|
+
ret = el.title || el.placeholder || '';
|
|
159
182
|
}
|
|
160
183
|
|
|
161
184
|
// FIXME: not exactly sure about this, but it reduces the number of failing
|
|
@@ -166,21 +189,24 @@ const getName = function(el, recursive, visited, directReference) {
|
|
|
166
189
|
|
|
167
190
|
const before = getPseudoContent(el, ':before');
|
|
168
191
|
const after = getPseudoContent(el, ':after');
|
|
169
|
-
return before + ret + after;
|
|
192
|
+
return addSpaces(before + ret + after, el);
|
|
170
193
|
};
|
|
171
194
|
|
|
172
|
-
const
|
|
173
|
-
return
|
|
195
|
+
export const getName = function(el) {
|
|
196
|
+
return getNameRaw(el)
|
|
197
|
+
.replace(/[ \n\r\t\f]+/g, ' ')
|
|
198
|
+
.replace(/^ /, '')
|
|
199
|
+
.replace(/ $/, '');
|
|
174
200
|
};
|
|
175
201
|
|
|
176
|
-
const getDescription = function(el) {
|
|
202
|
+
export const getDescription = function(el) {
|
|
177
203
|
let ret = '';
|
|
178
204
|
|
|
179
205
|
if (el.matches('[aria-describedby]')) {
|
|
180
206
|
const ids = el.getAttribute('aria-describedby').split(/\s+/);
|
|
181
207
|
const strings = ids.map(id => {
|
|
182
208
|
const label = document.getElementById(id);
|
|
183
|
-
return label ?
|
|
209
|
+
return label ? getNameRaw(label, true, true) : '';
|
|
184
210
|
});
|
|
185
211
|
ret = strings.join(' ');
|
|
186
212
|
} else if (el.matches('[aria-description]')) {
|
|
@@ -193,17 +219,15 @@ const getDescription = function(el) {
|
|
|
193
219
|
} else if (el.title) {
|
|
194
220
|
ret = el.title;
|
|
195
221
|
}
|
|
222
|
+
if (!ret.trim() && el.matches('a')) {
|
|
223
|
+
ret = el.getAttribute('xlink:title') || '';
|
|
224
|
+
}
|
|
196
225
|
|
|
197
226
|
ret = (ret || '').trim().replace(/\s+/g, ' ');
|
|
198
227
|
|
|
199
|
-
if (ret ===
|
|
228
|
+
if (ret === getName(el)) {
|
|
200
229
|
ret = '';
|
|
201
230
|
}
|
|
202
231
|
|
|
203
232
|
return ret;
|
|
204
233
|
};
|
|
205
|
-
|
|
206
|
-
module.exports = {
|
|
207
|
-
getName: getNameTrimmed,
|
|
208
|
-
getDescription: getDescription,
|
|
209
|
-
};
|
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",
|