aria-api 0.7.0 → 0.9.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/index.js CHANGED
@@ -1,18 +1,4 @@
1
- var query = require('./lib/query.js');
2
- var name = require('./lib/name.js');
3
- var atree = require('./lib/atree.js');
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,27 +1,19 @@
1
- const attrs = require('./attrs');
1
+ import * as attrs from './attrs';
2
2
 
3
- const _getOwner = function(node, owners) {
3
+ const _getOwner = function(node) {
4
4
  if (node.nodeType === node.ELEMENT_NODE && node.id) {
5
- const selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
6
- if (owners) {
7
- for (const owner of owners) {
8
- if (owner.matches(selector)) {
9
- return owner;
10
- }
11
- }
12
- } else {
13
- return document.querySelector(selector);
14
- }
5
+ const selector = `[aria-owns~="${CSS.escape(node.id)}"]`;
6
+ return node.getRootNode().querySelector(selector);
15
7
  }
16
8
  };
17
9
 
18
- const _getParentNode = function(node, owners) {
19
- return _getOwner(node, owners) || node.parentNode;
10
+ const _getParentNode = function(node) {
11
+ return _getOwner(node) || node.parentNode || node.host;
20
12
  };
21
13
 
22
- const detectLoop = function(node, owners) {
14
+ const detectLoop = function(node) {
23
15
  const seen = [node];
24
- while ((node = _getParentNode(node, owners))) {
16
+ while ((node = _getParentNode(node))) {
25
17
  if (seen.includes(node)) {
26
18
  return true;
27
19
  }
@@ -29,27 +21,36 @@ const detectLoop = function(node, owners) {
29
21
  }
30
22
  };
31
23
 
32
- const getOwner = function(node, owners) {
33
- const owner = _getOwner(node, owners);
34
- if (owner && !detectLoop(node, owners)) {
24
+ const getOwner = function(node) {
25
+ const owner = _getOwner(node);
26
+ if (owner && !detectLoop(node)) {
35
27
  return owner;
36
28
  }
37
29
  };
38
30
 
39
- const getParentNode = function(node, owners) {
40
- return getOwner(node, owners) || node.parentNode;
31
+ export const getParentNode = function(node) {
32
+ return getOwner(node) || node.parentNode || node.host;
41
33
  };
42
34
 
43
35
  const isHidden = function(node) {
44
36
  return node.nodeType === node.ELEMENT_NODE && attrs.getAttribute(node, 'hidden');
45
37
  };
46
38
 
47
- const getChildNodes = function(node, owners) {
39
+ export const getChildNodes = function(node) {
48
40
  const childNodes = [];
41
+ let rawChildNodes = [];
49
42
 
50
- for (let i = 0; i < node.childNodes.length; i++) {
51
- const child = node.childNodes[i];
52
- if (!getOwner(child, owners) && !isHidden(child)) {
43
+ if (node.shadowRoot) {
44
+ rawChildNodes = node.shadowRoot.childNodes;
45
+ } else if (node.assignedNodes) {
46
+ rawChildNodes = node.assignedNodes();
47
+ } else {
48
+ rawChildNodes = node.childNodes;
49
+ }
50
+
51
+ for (let i = 0; i < rawChildNodes.length; i++) {
52
+ const child = rawChildNodes[i];
53
+ if (!getOwner(child) && !isHidden(child)) {
53
54
  childNodes.push(child);
54
55
  }
55
56
  }
@@ -57,9 +58,9 @@ const getChildNodes = function(node, owners) {
57
58
  if (node.nodeType === node.ELEMENT_NODE) {
58
59
  const owns = attrs.getAttribute(node, 'owns') || [];
59
60
  for (let i = 0; i < owns.length; i++) {
60
- const child = document.getElementById(owns[i]);
61
+ const child = node.getRootNode().getElementById(owns[i]);
61
62
  // double check with getOwner for consistency
62
- if (child && getOwner(child, owners) === node && !isHidden(child)) {
63
+ if (child && getOwner(child) === node && !isHidden(child)) {
63
64
  childNodes.push(child);
64
65
  }
65
66
  }
@@ -68,17 +69,16 @@ const getChildNodes = function(node, owners) {
68
69
  return childNodes;
69
70
  };
70
71
 
71
- const walk = function(root, fn) {
72
- const owners = document.querySelectorAll('[aria-owns]');
72
+ export const walk = function(root, fn) {
73
73
  let queue = [root];
74
74
  while (queue.length) {
75
75
  const item = queue.shift();
76
76
  fn(item);
77
- queue = getChildNodes(item, owners).concat(queue);
77
+ queue = getChildNodes(item).concat(queue);
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
- const constants = require('./constants.js');
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 getRole = function(el, candidates) {
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 hasRole = function(el, roles) {
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 !!getRole(el, unique(flatten(subRoles)));
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
- exports.attributes = {
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
- exports.attributeStrongMapping = {
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
- exports.attributeWeakMapping = {
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
- exports.roles = {
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 = (exports.roles[role]).childRoles || [];
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
- exports.attrsWithDefaults = [];
751
+ export const attrsWithDefaults = [];
752
752
 
753
- for (const role in exports.roles) {
754
- exports.roles[role].subRoles = getSubRoles(role);
755
- for (const key in exports.roles[role].defaults) {
756
- if (!exports.attrsWithDefaults.includes(key)) {
757
- exports.attrsWithDefaults.push(key);
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
- exports.aliases = {
762
+ export const aliases = {
763
763
  'presentation': 'none',
764
764
  'directory': 'list',
765
765
  'img': 'image',
766
766
  };
767
767
 
768
- exports.nameFromDescendant = {
768
+ export const nameFromDescendant = {
769
769
  'figure': 'figcaption',
770
770
  'table': 'caption',
771
771
  'fieldset': 'legend',
772
772
  };
773
773
 
774
- exports.nameDefaults = {
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
- const constants = require('./constants.js');
2
- const atree = require('./atree.js');
3
- const query = require('./query.js');
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
- ret += node.textContent;
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 += getName(node, true, ongoingLabelledBy, visited);
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 = query.getRole(el);
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 getName = function(el, recursive, ongoingLabelledBy, visited, directReference) {
78
+ const getNameRaw = function(el, recursive, ongoingLabelledBy, visited, directReference) {
69
79
  let ret = '';
70
80
 
71
81
  visited = visited || [];
@@ -84,8 +94,8 @@ const getName = function(el, recursive, ongoingLabelledBy, visited, directRefere
84
94
  if (!ongoingLabelledBy && el.matches('[aria-labelledby]')) {
85
95
  const ids = el.getAttribute('aria-labelledby').split(/\s+/);
86
96
  const strings = ids.map(id => {
87
- const label = document.getElementById(id);
88
- return label ? getName(label, true, true, visited, true) : '';
97
+ const label = el.getRootNode().getElementById(id);
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 = getName(selected, recursive, ongoingLabelledBy, visited);
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 = '' + (query.getAttribute(el, 'valuetext') || query.getAttribute(el, 'valuenow') || el.value);
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 getName(label, true, ongoingLabelledBy, visited);
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 = getName(descendant, true, ongoingLabelledBy, visited);
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 getNameTrimmed = function(el) {
186
- return getName(el)
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
- const label = document.getElementById(id);
199
- return label ? getName(label, true, true) : '';
208
+ const label = el.getRootNode().getElementById(id);
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 === getNameTrimmed(el)) {
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
- const attrs = require('./attrs.js');
2
- const atree = require('./atree.js');
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
- module.exports = {
52
- getRole: el => attrs.getRole(el),
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,9 @@
1
1
  {
2
2
  "name": "aria-api",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Access ARIA information from JavaScript",
5
- "main": "index.js",
5
+ "main": "dist/aria.js",
6
+ "module": "index.js",
6
7
  "keywords": [
7
8
  "aria",
8
9
  "accessibility",
@@ -11,11 +12,10 @@
11
12
  "author": "Tobias Bengfort <tobias.bengfort@posteo.de>",
12
13
  "license": "MIT",
13
14
  "devDependencies": {
14
- "brfs": "^2.0.0",
15
- "browserify": "^17.0.0",
16
15
  "expect": "^1.20.2",
17
16
  "mocha": "^10.2.0",
18
- "mocha-headless-chrome": "^4.0.0"
17
+ "mocha-headless-chrome": "^4.0.0",
18
+ "rollup": "^4.24.3"
19
19
  },
20
20
  "files": [
21
21
  "index.js",