aria-api

access ARIA information from JavaScript
git clone https://git.ce9e.org/aria-api.git

commit
b13f37b1176869471a322557d36eee9e78d9793e
parent
8af9bdb6042d92f405942772006196e264f4c989
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-01-12 19:07
bump version to 0.4.7

Diffstat

M CHANGES.md 6 ++++++
M dist/aria.js 128 ++++++++++++++++++++++++++++++++-----------------------------
M package.json 2 +-

3 files changed, 74 insertions, 62 deletions


diff --git a/CHANGES.md b/CHANGES.md

@@ -1,3 +1,9 @@
   -1     1 0.4.7 (2023-01-12)
   -1     2 ------------------
   -1     3 
   -1     4 -	internal refactoring and performance improvements
   -1     5 
   -1     6 
    1     7 0.4.6 (2023-01-08)
    2     8 ------------------
    3     9 

diff --git a/dist/aria.js b/dist/aria.js

@@ -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    -1 var _getOwner = function(node) {
   -1    24 var _getOwner = function(node, owners) {
   25    25 	if (node.nodeType === node.ELEMENT_NODE && node.id) {
   26    -1 		var owner = document.querySelector('[aria-owns~="' + CSS.escape(node.id) + '"]');
   27    -1 		if (owner) {
   28    -1 			return owner;
   -1    26 		var selector = '[aria-owns~="' + CSS.escape(node.id) + '"]';
   -1    27 		if (owners) {
   -1    28 			for (var owner of owners) {
   -1    29 				if (owner.matches(selector)) {
   -1    30 					return owner;
   -1    31 				}
   -1    32 			}
   -1    33 		} else {
   -1    34 			return document.querySelector(selector);
   29    35 		}
   30    36 	}
   31    37 };
   32    38 
   33    -1 var _getParentNode = function(node) {
   34    -1 	return _getOwner(node) || node.parentNode;
   -1    39 var _getParentNode = function(node, owners) {
   -1    40 	return _getOwner(node, owners) || node.parentNode;
   35    41 };
   36    42 
   37    -1 var detectLoop = function(node) {
   38    -1 	var seen = [node]
   39    -1 	while ((node = _getParentNode(node))) {
   -1    43 var detectLoop = function(node, owners) {
   -1    44 	var seen = [node];
   -1    45 	while ((node = _getParentNode(node, owners))) {
   40    46 		if (seen.includes(node)) {
   41    47 			return true;
   42    48 		}
   43    -1 		seen.push(node)
   -1    49 		seen.push(node);
   44    50 	}
   45    51 };
   46    52 
   47    -1 var getOwner = function(node) {
   48    -1 	if (node.nodeType === node.ELEMENT_NODE && node.id) {
   49    -1 		var owner = document.querySelector('[aria-owns~="' + CSS.escape(node.id) + '"]');
   50    -1 		if (owner && !detectLoop(node)) {
   51    -1 			return owner;
   52    -1 		}
   -1    53 var getOwner = function(node, owners) {
   -1    54 	var owner = _getOwner(node, owners);
   -1    55 	if (owner && !detectLoop(node, owners)) {
   -1    56 		return owner;
   53    57 	}
   54    58 };
   55    59 
   56    -1 var getParentNode = function(node) {
   57    -1 	return getOwner(node) || node.parentNode;
   -1    60 var getParentNode = function(node, owners) {
   -1    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    -1 var getChildNodes = function(node) {
   -1    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    -1 		if (!getOwner(child) && !isHidden(child)) {
   -1    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    -1 			if (child && getOwner(child) === node && !isHidden(child)) {
   -1    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    -1 	fn(root);
   90    -1 	getChildNodes(root).forEach(function(child) {
   91    -1 		walk(child, fn);
   92    -1 	});
   -1    93 	var owners = document.querySelectorAll('[aria-owns]');
   -1    94 	var queue = [root];
   -1    95 	while (queue.length) {
   -1    96 		var item = queue.shift();
   -1    97 		fn(item);
   -1    98 		queue = getChildNodes(item, owners).concat(queue);
   -1    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    -1 		return el.getAttribute('role');
  120    -1 	}
  121    -1 	for (var role in constants.roles) {
  122    -1 		var selector = (constants.roles[role].selectors || []).join(',');
  123    -1 		if (selector && (!candidates || candidates.includes(role)) && el.matches(selector)) {
   -1   126 		var role = el.getAttribute('role');
   -1   127 		if (!candidates || candidates.includes(role)) {
  124   128 			return role;
   -1   129 		} else {
   -1   130 			return;
  125   131 		}
  126   132 	}
  127    -1 
  128    -1 	if (!candidates ||
  129    -1 			candidates.includes('banner') ||
  130    -1 			candidates.includes('contentinfo')) {
  131    -1 		if (!el.matches(constants.scoped)) {
  132    -1 			if (el.matches('header')) {
  133    -1 				return 'banner';
  134    -1 			}
  135    -1 			if (el.matches('footer')) {
  136    -1 				return 'contentinfo';
   -1   133 	var roles = candidates ? candidates : Object.keys(constants.roles);
   -1   134 	for (var role of roles) {
   -1   135 		var r = constants.roles[role];
   -1   136 		if (r) {
   -1   137 			var selector = (r.selectors || []).join(',');
   -1   138 			if (selector && el.matches(selector)) {
   -1   139 				return role;
  137   140 			}
  138   141 		}
  139   142 	}
  140   143 };
  141   144 
  142   145 var hasRole = function(el, roles) {
  143    -1 	var candidates = [].concat.apply([], roles.map(function(role) {
   -1   146 	var candidates = [].concat.apply([], roles.map(role => {
  144   147 		return (constants.roles[role] || {}).subRoles || [role];
  145   148 	}));
  146    -1 	var actual = getRole(el, candidates);
  147    -1 	return candidates.includes(actual);
   -1   149 	return !!getRole(el, candidates);
  148   150 };
  149   151 
  150   152 var getAttribute = function(el, key) {
@@ -299,6 +301,14 @@ exports.attributeWeakMapping = {
  299   301 	'selected': 'selected',
  300   302 };
  301   303 
   -1   304 var scoped = [
   -1   305 	'main *',
   -1   306 	// https://www.w3.org/TR/html/dom.html#sectioning-content-2
   -1   307 	'article *', 'aside *', 'nav *', 'section *',
   -1   308 	// https://www.w3.org/TR/html/sections.html#sectioning-roots
   -1   309 	'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
   -1   310 ].join(',');
   -1   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 	},
   -1   325 	banner: {
   -1   326 		selectors: ['header:not(' + scoped + ')'],
   -1   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 	},
   -1   382 	contentinfo: {
   -1   383 		selectors: ['footer:not(' + scoped + ')'],
   -1   384 	},
  369   385 	definition: {
  370   386 		selectors: ['dd'],
  371   387 	},
@@ -731,22 +747,14 @@ exports.roles = {
  731   747 	},
  732   748 };
  733   749 
  734    -1 exports.scoped = [
  735    -1 	'main *',
  736    -1 	// https://www.w3.org/TR/html/dom.html#sectioning-content-2
  737    -1 	'article *', 'aside *', 'nav *', 'section *',
  738    -1 	// https://www.w3.org/TR/html/sections.html#sectioning-roots
  739    -1 	'blockquote *', 'details *', 'dialog *', 'fieldset *', 'figure *', 'td *',
  740    -1 ].join(',');
  741    -1 
  742   750 var getSubRoles = function(role) {
  743   751 	var children = (exports.roles[role] || {}).childRoles || [];
  744   752 	var descendents = children.map(getSubRoles);
  745   753 
  746   754 	var result = [role];
  747   755 
  748    -1 	descendents.forEach(function(list) {
  749    -1 		list.forEach(function(r) {
   -1   756 	descendents.forEach(list => {
   -1   757 		list.forEach(r => {
  750   758 			if (!result.includes(r)) {
  751   759 				result.push(r);
  752   760 			}
@@ -858,7 +866,7 @@ var getName = function(el, recursive, visited, directReference) {
  858   866 	// B
  859   867 	if (!recursive && el.matches('[aria-labelledby]')) {
  860   868 		var ids = el.getAttribute('aria-labelledby').split(/\s+/);
  861    -1 		var strings = ids.map(function(id) {
   -1   869 		var strings = ids.map(id => {
  862   870 			var label = document.getElementById(id);
  863   871 			return label ? getName(label, true, visited, true) : '';
  864   872 		});
@@ -873,7 +881,7 @@ var getName = function(el, recursive, visited, directReference) {
  873   881 
  874   882 	// D
  875   883 	if (!ret.trim() && !recursive && el.labels) {
  876    -1 		var strings = Array.prototype.map.call(el.labels, function(label) {
   -1   884 		var strings = Array.prototype.map.call(el.labels, label => {
  877   885 			return getName(label, true, visited);
  878   886 		});
  879   887 		ret = strings.join(' ');
@@ -959,7 +967,7 @@ var getDescription = function(el) {
  959   967 
  960   968 	if (el.matches('[aria-describedby]')) {
  961   969 		var ids = el.getAttribute('aria-describedby').split(/\s+/);
  962    -1 		var strings = ids.map(function(id) {
   -1   970 		var strings = ids.map(id => {
  963   971 			var label = document.getElementById(id);
  964   972 			return label ? getName(label, true) : '';
  965   973 		});
@@ -1009,7 +1017,7 @@ var _querySelector = function(all) {
 1009  1017 	return function(root, role) {
 1010  1018 		var results = [];
 1011  1019 		try {
 1012    -1 			atree.walk(root, function(node) {
   -1  1020 			atree.walk(root, node => {
 1013  1021 				if (node.nodeType === node.ELEMENT_NODE) {
 1014  1022 					// FIXME: skip hidden elements
 1015  1023 					if (matches(node, role)) {
@@ -1030,7 +1038,7 @@ var _querySelector = function(all) {
 1030  1038 };
 1031  1039 
 1032  1040 var closest = function(el, selector) {
 1033    -1 	return atree.searchUp(el, function(candidate) {
   -1  1041 	return atree.searchUp(el, candidate => {
 1034  1042 		if (candidate.nodeType === candidate.ELEMENT_NODE) {
 1035  1043 			return matches(candidate, selector);
 1036  1044 		}
@@ -1038,9 +1046,7 @@ var closest = function(el, selector) {
 1038  1046 };
 1039  1047 
 1040  1048 module.exports = {
 1041    -1 	getRole: function(el) {
 1042    -1 		return attrs.getRole(el);
 1043    -1 	},
   -1  1049 	getRole: el => attrs.getRole(el),
 1044  1050 	getAttribute: attrs.getAttribute,
 1045  1051 	matches: matches,
 1046  1052 	querySelector: _querySelector(),

diff --git a/package.json b/package.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "aria-api",
    3    -1   "version": "0.4.6",
   -1     3   "version": "0.4.7",
    4     4   "description": "Access ARIA information from JavaScript",
    5     5   "main": "index.js",
    6     6   "keywords": [