babelacc

compare different implementations of the text alternative computation  https://p.ce9e.org/babelacc/
git clone https://git.ce9e.org/babelacc.git

commit
329ecafc7b611dc29dca16ecaa016f72a182d621
parent
1200041f701e3c4d79001fff95ea9289d5e0e433
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2018-03-08 08:58
update aria-api (0.2.4) and acdcc

Diffstat

M babel.js 395 ++++++++++++++++++++++++++++++++++---------------------------
M package.json 2 +-

2 files changed, 222 insertions, 175 deletions


diff --git a/babel.js b/babel.js

@@ -4807,7 +4807,7 @@ exports.extraSelectors = {
 4807  4807 	option: ['option'],
 4808  4808 	progressbar: ['progress'],
 4809  4809 	radio: ['input[type="radio"]'],
 4810    -1 	region: ['section'],
   -1  4810 	region: ['section[aria-label]', 'section[aria-labelledby]'],
 4811  4811 	rowgroup: ['tbody', 'thead', 'tfoot'],
 4812  4812 	row: ['tr'],
 4813  4813 	searchbox: ['input[type="search"]:not([list])'],
@@ -5019,17 +5019,18 @@ var util = require('./util.js');
 5019  5019 var getPseudoContent = function(node, selector) {
 5020  5020 	var styles = window.getComputedStyle(node, selector);
 5021  5021 	var ret = styles.getPropertyValue('content');
 5022    -1 	if (ret === 'none' || ret.substr(0, 4) === '-moz') {
   -1  5022 	if (!ret) {
   -1  5023 		return ''
   -1  5024 	}
   -1  5025 	if (ret.substr(0, 1) !== '"') {
 5023  5026 		return '';
 5024  5027 	} else {
 5025    -1 		return ret
 5026    -1 			.replace(/^["']/, '')
 5027    -1 			.replace(/["']$/, '');
   -1  5028 		return ret.slice(1, -1);
 5028  5029 	}
 5029  5030 };
 5030  5031 
 5031  5032 var getContent = function(root, referenced) {
 5032    -1 	var ret = getPseudoContent(root, ':before');
   -1  5033 	var ret = '';
 5033  5034 	var node = root.firstChild;
 5034  5035 	while (node) {
 5035  5036 		if (node.nodeType === node.TEXT_NODE) {
@@ -5037,7 +5038,9 @@ var getContent = function(root, referenced) {
 5037  5038 		} else if (node.nodeType === node.ELEMENT_NODE) {
 5038  5039 			if (node.tagName.toLowerCase() === 'br') {
 5039  5040 				ret += '\n';
 5040    -1 			} else if (window.getComputedStyle(node).display.substr(0, 6) === 'inline') {
   -1  5041 			} else if (window.getComputedStyle(node).display.substr(0, 6) === 'inline' &&
   -1  5042 					node.tagName.toLowerCase() !== 'input' &&
   -1  5043 					node.tagName.toLowerCase() !== 'img') {  // https://github.com/w3c/accname/issues/3
 5041  5044 				ret += getName(node, true, referenced);
 5042  5045 			} else {
 5043  5046 				ret += ' ' + getName(node, true, referenced) + ' ';
@@ -5045,7 +5048,6 @@ var getContent = function(root, referenced) {
 5045  5048 		}
 5046  5049 		node = node.nextSibling;
 5047  5050 	}
 5048    -1 	ret += getPseudoContent(root, ':after');
 5049  5051 	return ret;
 5050  5052 };
 5051  5053 
@@ -5080,7 +5082,7 @@ var getLabelNodes = function(element) {
 5080  5082 // http://www.ssbbartgroup.com/blog/how-the-w3c-text-alternative-computation-works/
 5081  5083 // https://www.w3.org/TR/accname-aam-1.1/#h-mapping_additional_nd_te
 5082  5084 var getName = function(el, recursive, referenced) {
 5083    -1 	var ret;
   -1  5085 	var ret = '';
 5084  5086 
 5085  5087 	if (query.getAttribute(el, 'hidden', referenced)) {
 5086  5088 		return '';
@@ -5096,7 +5098,7 @@ var getName = function(el, recursive, referenced) {
 5096  5098 		});
 5097  5099 		ret = strings.join(' ');
 5098  5100 	}
 5099    -1 	if (!ret && el.matches('[aria-label]')) {
   -1  5101 	if (!ret.trim() && el.matches('[aria-label]')) {
 5100  5102 		ret = el.getAttribute('aria-label');
 5101  5103 	}
 5102  5104 	if (!query.matches(el, 'presentation')) {
@@ -5106,13 +5108,13 @@ var getName = function(el, recursive, referenced) {
 5106  5108 			});
 5107  5109 			ret = strings.join(' ');
 5108  5110 		}
 5109    -1 		if (!ret) {
 5110    -1 			ret = el.getAttribute('placeholder');
   -1  5111 		if (!ret.trim()) {
   -1  5112 			ret = el.getAttribute('placeholder') || '';
 5111  5113 		}
 5112    -1 		if (!ret) {
 5113    -1 			ret = el.getAttribute('alt');
   -1  5114 		if (!ret.trim()) {
   -1  5115 			ret = el.getAttribute('alt') || '';
 5114  5116 		}
 5115    -1 		if (!ret && el.matches('abbr,acronym') && el.title) {
   -1  5117 		if (!ret.trim() && el.matches('abbr,acronym') && el.title) {
 5116  5118 			ret = el.title;
 5117  5119 		}
 5118  5120 		// figcaption
@@ -5120,11 +5122,11 @@ var getName = function(el, recursive, referenced) {
 5120  5122 		// table
 5121  5123 	}
 5122  5124 	// FIXME only if this is embedded in a label
 5123    -1 	if (!ret && query.matches(el, 'textbox,button,combobox,range')) {
   -1  5125 	if (!ret.trim() && query.matches(el, 'textbox,button,combobox,range,menu')) {
 5124  5126 		if (query.matches(el, 'textbox,button')) {
 5125  5127 			ret = el.value || el.textContent;
 5126    -1 		} else if (query.matches(el, 'combobox')) {
 5127    -1 			var selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option');
   -1  5128 		} else if (query.matches(el, 'combobox,menu')) {
   -1  5129 			var selected = query.querySelector(el, ':selected') || query.querySelector(el, 'option,menuitem');
 5128  5130 			if (selected) {
 5129  5131 				ret = getName(selected, recursive, referenced);
 5130  5132 			}
@@ -5132,14 +5134,16 @@ var getName = function(el, recursive, referenced) {
 5132  5134 			ret = '' + (query.getAttribute(el, 'valuetext') || query.getAttribute(el, 'valuenow') || el.value);
 5133  5135 		}
 5134  5136 	}
 5135    -1 	if (!ret && (recursive || allowNameFromContent(el))) {
   -1  5137 	if (!ret.trim() && (recursive || allowNameFromContent(el))) {
 5136  5138 		ret = getContent(el, referenced);
 5137  5139 	}
 5138    -1 	if (!ret) {
 5139    -1 		ret = el.getAttribute('title');
   -1  5140 	if (!ret.trim()) {
   -1  5141 		ret = el.title || '';
 5140  5142 	}
 5141  5143 
 5142    -1 	return ret || '';
   -1  5144 	var before = getPseudoContent(el, ':before');
   -1  5145 	var after = getPseudoContent(el, ':after');
   -1  5146 	return before + ret + after;
 5143  5147 };
 5144  5148 
 5145  5149 var getDescription = function(el) {
@@ -14206,28 +14210,107 @@ module.exports = {
14206 14210   });
14207 14211 })(typeof window === 'object' ? window : this);
14208 14212 },{}],13:[function(require,module,exports){
   -1 14213 var currentVersion = '1.15';
   -1 14214 
14209 14215 /*!
14210    -1 CalcNames 1.8, compute the Name and Description property values for a DOM node
   -1 14216 CalcNames: The Naming Computation Prototype, compute the Name and Description property values for a DOM node
14211 14217 Returns an object with 'name' and 'desc' properties.
14212 14218 Functionality mirrors the steps within the W3C Accessible Name and Description computation algorithm.
14213 14219 http://www.w3.org/TR/accname-aam-1.1/
14214    -1 Authored by Bryan Garaventa plus refactoring contrabutions by Tobias Bengfort
   -1 14220 Authored by Bryan Garaventa, plus refactoring contrabutions by Tobias Bengfort
14215 14221 https://github.com/whatsock/w3c-alternative-text-computation
14216 14222 Distributed under the terms of the Open Source Initiative OSI - MIT License
14217 14223 */
14218 14224 
   -1 14225 // Naming Computation Prototype
14219 14226 var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14220 14227 	if (!node || node.nodeType !== 1) {
14221 14228 		return;
14222 14229 	}
   -1 14230 	var topNode = node;
14223 14231 
14224 14232 	// Track nodes to prevent duplicate node reference parsing.
14225 14233 	var nodes = [];
   -1 14234 	// Track aria-owns references to prevent duplicate parsing.
   -1 14235 	var owns = [];
14226 14236 
14227 14237 	// Recursively process a DOM node to compute an accessible name in accordance with the spec
14228    -1 	var walk = function(refNode, stop, skip, nodesToIgnoreValues, skipAbort) {
   -1 14238 	var walk = function(refNode, stop, skip, nodesToIgnoreValues, skipAbort, ownedBy) {
14229 14239 		var fullName = '';
14230 14240 
   -1 14241 		/*
   -1 14242 		ARIA Role Exception Rule Set 1.1
   -1 14243 		The following Role Exception Rule Set is based on the following ARIA Working Group discussion involving all relevant browser venders.
   -1 14244 		https://lists.w3.org/Archives/Public/public-aria/2017Jun/0057.html
   -1 14245 		*/
   -1 14246 		var isException = function(node, refNode) {
   -1 14247 			if (!refNode || !node || refNode.nodeType !== 1 || node.nodeType !== 1) {
   -1 14248 				return false;
   -1 14249 			}
   -1 14250 
   -1 14251 			// Always include name from content when the referenced node matches list1, as well as when child nodes match those within list3
   -1 14252 			// Note: gridcell was added to list1 to account for focusable gridcells that match the ARIA 1.0 paradigm for interactive grids.
   -1 14253 			var list1 = {
   -1 14254 				roles: ['button', 'checkbox', 'link', 'option', 'radio', 'switch', 'tab', 'treeitem', 'menuitem', 'menuitemcheckbox', 'menuitemradio', 'cell', 'gridcell', 'columnheader', 'rowheader', 'tooltip', 'heading'],
   -1 14255 				tags: ['a', 'button', 'summary', 'input', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'menuitem', 'option', 'td', 'th']
   -1 14256 			};
   -1 14257 
   -1 14258 			// Never include name from content when current node matches list2
   -1 14259 			// Note: combobox was added to account for the ARIA 1.1 design pattern change from 1.0, but this is still overridden in list3 when combobox is applied to focusable elements so that the 1.0 design pattern will remain supported.
   -1 14260 			var list2 = {
   -1 14261 				roles: ['combobox', 'application', 'alert', 'log', 'marquee', 'timer', 'alertdialog', 'dialog', 'banner', 'complementary', 'form', 'main', 'navigation', 'region', 'search', 'article', 'document', 'feed', 'figure', 'img', 'math', 'toolbar', 'menu', 'menubar', 'grid', 'listbox', 'radiogroup', 'textbox', 'searchbox', 'spinbutton', 'scrollbar', 'slider', 'tablist', 'tabpanel', 'tree', 'treegrid', 'separator'],
   -1 14262 				tags: ['article', 'aside', 'body', 'select', 'datalist', 'optgroup', 'dialog', 'figure', 'footer', 'form', 'header', 'hr', 'img', 'textarea', 'input', 'main', 'math', 'menu', 'nav', 'section']
   -1 14263 			};
   -1 14264 
   -1 14265 			// As an override of list2, conditionally include name from content if current node is focusable, or if the current node matches list3 while the referenced parent node matches list1.
   -1 14266 			var list3 = {
   -1 14267 				roles: ['combobox', 'term', 'definition', 'directory', 'list', 'group', 'note', 'status', 'table', 'rowgroup', 'row', 'contentinfo'],
   -1 14268 				tags: ['dl', 'ul', 'ol', 'dd', 'details', 'output', 'table', 'thead', 'tbody', 'tfoot', 'tr']
   -1 14269 			};
   -1 14270 
   -1 14271 			var inList = function(node, list) {
   -1 14272 				var role = node.getAttribute('role');
   -1 14273 				var tag = node.nodeName.toLowerCase();
   -1 14274 				return (role && list.roles.indexOf(role) >= 0) || (!role && list.tags.indexOf(tag) >= 0);
   -1 14275 			};
   -1 14276 
   -1 14277 			// The list3 overrides must be checked first.
   -1 14278 			if (inList(node, list3)) {
   -1 14279 				if (node === refNode && !(node.id && ownedBy[node.id] && ownedBy[node.id].node)) {
   -1 14280 					return !isFocusable(node);
   -1 14281 				} else {
   -1 14282 					// Note: the inParent checker needs to be present to allow for embedded roles matching list3 when the referenced parent is referenced using aria-labelledby, aria-describedby, or aria-owns.
   -1 14283 					return !(inParent(node, ownedBy.top) || inList(refNode, list1));
   -1 14284 				}
   -1 14285 			}
   -1 14286 			// Otherwise process list2 to identify roles to ignore processing name from content.
   -1 14287 			else if (inList(node, list2) || (node === topNode && !inList(node, list1))) {
   -1 14288 				return true;
   -1 14289 			}
   -1 14290 			else {
   -1 14291 				return false;
   -1 14292 			}
   -1 14293 		};
   -1 14294 
   -1 14295 		var inParent = function(node, parent) {
   -1 14296 			var trackNodes = [];
   -1 14297 			while (node) {
   -1 14298 				if (node.id && ownedBy[node.id] && ownedBy[node.id].node && trackNodes.indexOf(node) === -1) {
   -1 14299 					trackNodes.push(node);
   -1 14300 					node = ownedBy[node.id].node;
   -1 14301 				} else {
   -1 14302 					node = node.parentNode;
   -1 14303 				}
   -1 14304 				if (node && node === parent) {
   -1 14305 					return true;
   -1 14306 				}
   -1 14307 				else if ((!node || node === ownedBy.top) || node === document.body) {
   -1 14308 					return false;
   -1 14309 				}
   -1 14310 			}
   -1 14311 			return false;
   -1 14312 		};
   -1 14313 
14231 14314 		// Placeholder for storing CSS before and after pseudo element text values for the top level node
14232 14315 		var cssOP = {
14233 14316 			before: '',
@@ -14246,25 +14329,33 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14246 14329 			}
14247 14330 		}
14248 14331 
14249    -1 		var blockNodeStack = [];
14250    -1 
14251    -1 		var hasLeftBlockNodeStack = function(node) {
14252    -1 			var blocks = blockNodeStack.length;
14253    -1 			for (var i = blocks; i; i--) {
14254    -1 				if (!inParent(node, blockNodeStack[i - 1], refNode)) {
14255    -1 					blockNodeStack.splice(i - 1, 1);
   -1 14332 		// Recursively apply the same naming computation to all nodes within the referenced structure
   -1 14333 		var walkDOM = function(node, fn, refNode) {
   -1 14334 			if (!node) {
   -1 14335 				return '';
   -1 14336 			}
   -1 14337 			var nodeIsBlock = node && node.nodeType === 1 && isBlockLevelElement(node);
   -1 14338 			if (nodeIsBlock) {
   -1 14339 				fullName += ' ';
   -1 14340 			}
   -1 14341 			var ariaOwns = fn(node) || '';
   -1 14342 			if (!isException(node, ownedBy.top)) {
   -1 14343 				node = node.firstChild;
   -1 14344 				while (node) {
   -1 14345 					walkDOM(node, fn, refNode);
   -1 14346 					node = node.nextSibling;
14256 14347 				}
14257 14348 			}
14258    -1 			if (blockNodeStack.length < blocks) {
14259    -1 				return true;
   -1 14349 			if (nodeIsBlock) {
   -1 14350 				fullName += ' ';
14260 14351 			}
14261    -1 			return false;
   -1 14352 			fullName += ariaOwns;
14262 14353 		};
14263 14354 
14264    -1 		// Recursively apply the same naming computation to all nodes within the referenced structure
14265 14355 		walkDOM(refNode, function(node) {
   -1 14356 			var isEmbeddedNode = node && node.nodeType === 1 && nodesToIgnoreValues && nodesToIgnoreValues.length && nodesToIgnoreValues.indexOf(node) !== -1 && node === topNode && node !== refNode;
14266 14357 
14267    -1 			if ((skip || !node || nodes.indexOf(node) !== -1 || (isHidden(node, refNode))) && !skipAbort) {
   -1 14358 			if ((skip || !node || nodes.indexOf(node) !== -1 || (isHidden(node, ownedBy.top))) && !skipAbort && !isEmbeddedNode) {
14268 14359 				// Abort if algorithm step is already completed, or if node is a hidden child of refNode, or if this node has already been processed, or skip abort if aria-labelledby self references same node.
14269 14360 				return;
14270 14361 			}
@@ -14275,6 +14366,8 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14275 14366 
14276 14367 			// Store name for the current node.
14277 14368 			var name = '';
   -1 14369 			// Store name from aria-owns references if detected.
   -1 14370 			var ariaO = '';
14278 14371 			// Placeholder for storing CSS before and after pseudo element text values for the current node container element
14279 14372 			var cssO = {
14280 14373 				before: '',
@@ -14299,15 +14392,6 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14299 14392 			// Process standard DOM element node
14300 14393 			if (node.nodeType === 1) {
14301 14394 
14302    -1 				var nodeIsBlock = isBlockLevelElement(node);
14303    -1 				if (nodeIsBlock && blockNodeStack.indexOf(node) === -1) {
14304    -1 					blockNodeStack.push(node);
14305    -1 				}
14306    -1 				if (nodeIsBlock && node !== refNode) {
14307    -1 					// Add space at beginning of block level element if detected.
14308    -1 					name += ' ';
14309    -1 				}
14310    -1 
14311 14395 				var aLabelledby = node.getAttribute('aria-labelledby') || '';
14312 14396 				var aLabel = node.getAttribute('aria-label') || '';
14313 14397 				var nTitle = node.getAttribute('title') || '';
@@ -14326,20 +14410,20 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14326 14410 						for (var i = 0; i < ids.length; i++) {
14327 14411 							var element = document.getElementById(ids[i]);
14328 14412 							// Also prevent the current form field from having its value included in the naming computation if nested as a child of label
14329    -1 							parts.push(walk(element, true, skip, [node], element === refNode));
   -1 14413 							parts.push(walk(element, true, skip, [node], element === refNode, {ref: ownedBy, top: element}));
14330 14414 						}
14331 14415 						// Check for blank value, since whitespace chars alone are not valid as a name
14332 14416 						name = addSpacing(trim(parts.join(' ')));
14333 14417 					}
14334 14418 
14335    -1 					if (name || rolePresentation) {
   -1 14419 					if (trim(name) || rolePresentation) {
14336 14420 						// Abort further recursion if name is valid or if the referenced node is presentational.
14337 14421 						skip = true;
14338 14422 					}
14339 14423 				}
14340 14424 
14341 14425 				// Otherwise, if the current node is non-presentational and is a nested widget control within the parent ref obj, then add only its value and process no deeper
14342    -1 				if (!rolePresentation && node !== refNode && (isNativeFormField || isSimulatedFormField)) {
   -1 14426 				if ((!rolePresentation && node !== refNode && (isNativeFormField || isSimulatedFormField)) || (node.id && ownedBy[node.id] && ownedBy[node.id].target && ownedBy[node.id].target === node)) {
14343 14427 
14344 14428 					// Prevent the referencing node from having its value included in the case of form control labels that contain the element with focus.
14345 14429 					if (!(nodesToIgnoreValues && nodesToIgnoreValues.length && nodesToIgnoreValues.indexOf(node) !== -1)) {
@@ -14348,7 +14432,7 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14348 14432 							// For range widgets, append aria-valuetext if non-empty, or aria-valuenow if non-empty, or node.value if applicable.
14349 14433 							name = getObjectValue(nRole, node, true);
14350 14434 						}
14351    -1 						else if (isSimulatedFormField && ['searchbox', 'textbox', 'combobox'].indexOf(nRole) !== -1) {
   -1 14435 						else if (isSimulatedFormField && ['searchbox', 'textbox'].indexOf(nRole) !== -1) {
14352 14436 							// For simulated edit widgets, append text from content if applicable, or node.value if applicable.
14353 14437 							name = getObjectValue(nRole, node, false, true);
14354 14438 						}
@@ -14362,7 +14446,7 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14362 14446 							name = getObjectValue(nRole, node, false, false, false, true);
14363 14447 						}
14364 14448 						else if (isNativeFormField && nTag === 'select') {
14365    -1 							// For native select fields, append node.value for single select, or text from content for all options with selected attribute separated by a space when multiple.
   -1 14449 							// For native select fields, get text from content for all options with selected attribute separated by a space when multiple.
14366 14450 							name = getObjectValue(nRole, node, false, false, true, true);
14367 14451 						}
14368 14452 
@@ -14373,51 +14457,52 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14373 14457 				}
14374 14458 
14375 14459 				// Otherwise, if current node is non-presentational and has a non-empty aria-label then set as name and process no deeper.
14376    -1 				else if (!name && !rolePresentation && aLabel) {
   -1 14460 				else if (!trim(name) && !rolePresentation && aLabel) {
14377 14461 					// Check for blank value, since whitespace chars alone are not valid as a name
14378 14462 					name = addSpacing(trim(aLabel));
14379 14463 
14380    -1 					if (name && node === refNode) {
   -1 14464 					if (trim(name) && node === refNode) {
14381 14465 						// If name is non-empty and both the current and refObject nodes match, then don't process any deeper.
14382 14466 						skip = true;
14383 14467 					}
14384 14468 				}
14385 14469 
14386 14470 				// Otherwise, if name is still empty and the current node is non-presentational and matches the ref node and is a standard form field with a non-empty associated label element, process label with same naming computation algorithm.
14387    -1 				if (!name && !rolePresentation && node === refNode && isNativeFormField && node.id && document.querySelectorAll('label[for="' + node.id + '"]').length) {
   -1 14471 				if (!trim(name) && !rolePresentation && node === refNode && isNativeFormField && node.id && document.querySelectorAll('label[for="' + node.id + '"]').length) {
14388 14472 					var label = document.querySelector('label[for="' + node.id + '"]');
14389 14473 					// Check for blank value, since whitespace chars alone are not valid as a name
14390    -1 					name = addSpacing(trim(walk(label, true, skip, [node])));
   -1 14474 					name = addSpacing(trim(walk(label, true, skip, [node], false, {ref: ownedBy, top: label})));
14391 14475 				}
14392 14476 
14393 14477 				// Otherwise, if name is still empty and the current node is non-presentational and matches the ref node and is a standard form field with an implicit label element surrounding it, process label with same naming computation algorithm.
14394    -1 				if (!name && !rolePresentation && node === refNode && isNativeFormField && getParent(node, 'label').nodeType === 1) {
   -1 14478 				if (!trim(name) && !rolePresentation && node === refNode && isNativeFormField && getParent(node, 'label').nodeType === 1) {
14395 14479 					// Check for blank value, since whitespace chars alone are not valid as a name
14396    -1 					name = addSpacing(trim(walk(getParent(node, 'label'), true, skip, [node])));
14397    -1 				}
14398    -1 
14399    -1 				// Otherwise, if name is still empty and the current node is non-presentational and is a standard form field with a non-empty value property, set name as the property value.
14400    -1 				if (!name && !rolePresentation && node === refNode && isNativeFormField && node.value) {
14401    -1 					// Check for blank value, since whitespace chars alone are not valid as a name
14402    -1 					name = addSpacing(trim(node.value));
14403    -1 				}
14404    -1 				else if (!name && !rolePresentation && node === refNode && isSimulatedFormField && ['scrollbar', 'slider', 'spinbutton'].indexOf(nRole) !== -1) {
14405    -1 					// For range widgets, append aria-valuetext if non-empty, or aria-valuenow if non-empty, or node.value if applicable.
14406    -1 					name = getObjectValue(nRole, node, true);
   -1 14480 					var label = getParent(node, 'label');
   -1 14481 					name = addSpacing(trim(walk(label, true, skip, [node], false, {ref: ownedBy, top: label})));
14407 14482 				}
14408 14483 
14409 14484 				// Otherwise, if name is still empty and current node is non-presentational and is a standard img or image button with a non-empty alt attribute, set alt attribute value as the accessible name.
14410    -1 				else if (!name && !rolePresentation && (nTag == 'img' || (nTag == 'input' && node.getAttribute('type') == 'image')) && node.getAttribute('alt')) {
   -1 14485 				else if (!trim(name) && !rolePresentation && (nTag == 'img' || (nTag == 'input' && node.getAttribute('type') == 'image')) && node.getAttribute('alt')) {
14411 14486 					// Check for blank value, since whitespace chars alone are not valid as a name
14412 14487 					name = addSpacing(trim(node.getAttribute('alt')));
14413 14488 				}
14414 14489 
14415 14490 				// Otherwise, if name is still empty and current node is non-presentational and includes a non-empty title attribute, set title attribute value as the accessible name.
14416    -1 				if (!name && !rolePresentation && nTitle) {
   -1 14491 				if (!trim(name) && !rolePresentation && nTitle) {
14417 14492 					// Check for blank value, since whitespace chars alone are not valid as a name
14418 14493 					name = addSpacing(trim(nTitle));
14419 14494 				}
14420 14495 
   -1 14496 				// Otherwise, if name is still empty and the current node is non-presentational and is a standard form field with a non-empty value property, set name as the property value.
   -1 14497 				if (!trim(name) && !rolePresentation && node === refNode && isNativeFormField && node.value) {
   -1 14498 					// Check for blank value, since whitespace chars alone are not valid as a name
   -1 14499 					name = addSpacing(trim(node.value));
   -1 14500 				}
   -1 14501 				else if (!trim(name) && !rolePresentation && node === refNode && isSimulatedFormField && ['scrollbar', 'slider', 'spinbutton'].indexOf(nRole) !== -1) {
   -1 14502 					// For range widgets, append aria-valuetext if non-empty, or aria-valuenow if non-empty, or node.value if applicable.
   -1 14503 					name = getObjectValue(nRole, node, true);
   -1 14504 				}
   -1 14505 
14421 14506 				// Check for non-empty value of aria-owns, follow each ID ref, then process with same naming computation.
14422 14507 				// Also abort aria-owns processing if contained on an element that does not support child elements.
14423 14508 				if (aOwns && !isNativeFormField && nTag != 'img') {
@@ -14425,13 +14510,20 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14425 14510 					var parts = [];
14426 14511 					for (var i = 0; i < ids.length; i++) {
14427 14512 						var element = document.getElementById(ids[i]);
14428    -1 						// Abort processing if the referenced node is already a child DOM node
14429    -1 						if (!inParent(element, node)) {
14430    -1 							parts.push(trim(walk(element, true, skip)));
   -1 14513 						// Abort processing if the referenced node has already been traversed
   -1 14514 						if (element && owns.indexOf(ids[i]) === -1) {
   -1 14515 							owns.push(ids[i]);
   -1 14516 							var oBy = {ref: ownedBy, top: ownedBy.top};
   -1 14517 							oBy[ids[i]] = {
   -1 14518 								refNode: refNode,
   -1 14519 								node: node,
   -1 14520 target: element
   -1 14521 							};
   -1 14522 							parts.push(trim(walk(element, true, skip, [], false, oBy)));
14431 14523 						}
14432 14524 					}
14433 14525 					// Surround returned aria-owns naming computation with spaces since these will be separated visually if not already included as nested DOM nodes.
14434    -1 					name += addSpacing(parts.join(' '));
   -1 14526 					ariaO = addSpacing(parts.join(' '));
14435 14527 				}
14436 14528 
14437 14529 			}
@@ -14439,79 +14531,26 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14439 14531 			// Otherwise, process text node
14440 14532 			else if (node.nodeType === 3) {
14441 14533 
14442    -1 				// Add space at end of block level element if detected.
14443    -1 				name = (hasLeftBlockNodeStack(node) ? ' ' : '') + node.data;
   -1 14534 				name = node.data;
14444 14535 
14445 14536 			}
14446 14537 
14447 14538 			// Prepend and append the current CSS pseudo element text, plus normalize all whitespace such as newline characters and others into flat spaces.
14448 14539 			name = cssO.before + name.replace(/\s+/g, ' ') + cssO.after;
14449 14540 
14450    -1 			if (name && !hasParentLabel(node, false, refNode)) {
   -1 14541 			if (name.length && !hasParentLabel(node, false, ownedBy.top, ownedBy)) {
14451 14542 				fullName += name;
14452 14543 			}
14453 14544 
   -1 14545 			return ariaO;
14454 14546 		}, refNode);
14455 14547 
14456 14548 		// Prepend and append the refObj CSS pseudo element text, plus normalize whitespace chars into flat spaces.
14457 14549 		fullName = cssOP.before + fullName.replace(/\s+/g, ' ') + cssOP.after;
14458 14550 
14459    -1 		// Clear the tracked nodes array for garbage collection.
14460    -1 		nodes = [];
14461    -1 
14462 14551 		return fullName;
14463 14552 	};
14464 14553 
14465    -1 	/*
14466    -1 	ARIA Role Exception Rule Set 1.0
14467    -1 	The following Role Exception Rule Set is based on the following ARIA Working Group discussion involving all relevant browser venders.
14468    -1 	https://lists.w3.org/Archives/Public/public-aria/2017Jun/0057.html
14469    -1 	*/
14470    -1 	var isException = function(node, refNode) {
14471    -1 		if (!refNode || !node || refNode.nodeType !== 1 || node.nodeType !== 1) {
14472    -1 			return false;
14473    -1 		}
14474    -1 
14475    -1 		// Always include name from content when the referenced node matches list1, as well as when child nodes match those within list3
14476    -1 		var list1 = {
14477    -1 			roles: ['link', 'button', 'checkbox', 'option', 'radio', 'switch', 'tab', 'treeitem', 'menuitem', 'menuitemcheckbox', 'menuitemradio', 'cell', 'columnheader', 'rowheader', 'tooltip', 'heading'],
14478    -1 			tags: ['a', 'button', 'summary', 'input', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'menuitem', 'option', 'td', 'th']
14479    -1 		};
14480    -1 
14481    -1 		// Never include name from content when current node matches list2
14482    -1 		var list2 = {
14483    -1 			roles: ['application', 'alert', 'log', 'marquee', 'timer', 'alertdialog', 'dialog', 'banner', 'complementary', 'form', 'main', 'navigation', 'region', 'search', 'article', 'document', 'feed', 'figure', 'img', 'math', 'toolbar', 'menu', 'menubar', 'grid', 'listbox', 'radiogroup', 'textbox', 'searchbox', 'spinbutton', 'scrollbar', 'slider', 'tablist', 'tabpanel', 'tree', 'treegrid', 'separator'],
14484    -1 			tags: ['article', 'aside', 'body', 'select', 'datalist', 'optgroup', 'dialog', 'figure', 'footer', 'form', 'header', 'hr', 'img', 'textarea', 'input', 'main', 'math', 'menu', 'nav', 'section']
14485    -1 		};
14486    -1 
14487    -1 		// As an override of list2, conditionally include name from content if current node is focusable, or if the current node matches list3 while the referenced parent node matches list1.
14488    -1 		var list3 = {
14489    -1 			roles: ['combobox', 'term', 'definition', 'directory', 'list', 'group', 'note', 'status', 'table', 'rowgroup', 'row', 'contentinfo'],
14490    -1 			tags: ['dl', 'ul', 'ol', 'dd', 'details', 'output', 'table', 'thead', 'tbody', 'tfoot', 'tr']
14491    -1 		};
14492    -1 
14493    -1 		var inList = function(node, list) {
14494    -1 			var role = node.getAttribute('role');
14495    -1 			var tag = node.nodeName.toLowerCase();
14496    -1 			return (
14497    -1 				list.roles.indexOf(role) >= 0 ||
14498    -1 				(!role && list2.tags.indexOf(tag) >= 0)
14499    -1 			);
14500    -1 		};
14501    -1 
14502    -1 		if (inList(node, list2)) {
14503    -1 			return true;
14504    -1 		} else if (inList(node, list3)) {
14505    -1 			if (node === refNode) {
14506    -1 				return !isFocusable(node);
14507    -1 			} else {
14508    -1 				return !inList(refNode, list1);
14509    -1 			}
14510    -1 		} else {
14511    -1 			return false;
14512    -1 		}
14513    -1 	};
14514    -1 
14515 14554 	var isFocusable = function(node) {
14516 14555 		var nodeName = node.nodeName.toLowerCase();
14517 14556 		if (node.getAttribute('tabindex')) {
@@ -14535,6 +14574,10 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14535 14574 			return true;
14536 14575 		}
14537 14576 
   -1 14577 		if (node.getAttribute('hidden')) {
   -1 14578 			return true;
   -1 14579 		}
   -1 14580 
14538 14581 		var style = getStyleObject(node);
14539 14582 		if (style['display'] === 'none' || style['visibility'] === 'hidden') {
14540 14583 			return true;
@@ -14543,20 +14586,6 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14543 14586 		return false;
14544 14587 	};
14545 14588 
14546    -1 	var walkDOM = function(node, fn, refNode) {
14547    -1 		if (!node) {
14548    -1 			return;
14549    -1 		}
14550    -1 		fn(node);
14551    -1 		if (!isException(node, refNode)) {
14552    -1 			node = node.firstChild;
14553    -1 			while (node) {
14554    -1 				walkDOM(node, fn, refNode);
14555    -1 				node = node.nextSibling;
14556    -1 			}
14557    -1 		}
14558    -1 	};
14559    -1 
14560 14589 	var getStyleObject = function(node) {
14561 14590 		var style = {};
14562 14591 		if (document.defaultView && document.defaultView.getComputedStyle) {
@@ -14567,6 +14596,19 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14567 14596 		return style;
14568 14597 	};
14569 14598 
   -1 14599 	var cleanCSSText = function(node, text) {
   -1 14600 		var s = text;
   -1 14601 		if (s.indexOf('attr(') !== -1) {
   -1 14602 			var m = s.match(/attr\((.|\n|\r\n)*?\)/g);
   -1 14603 			for (var i = 0; i < m.length; i++) {
   -1 14604 				var b = m[i].slice(5, -1);
   -1 14605 				b = node.getAttribute(b) || '';
   -1 14606 				s = s.replace(m[i], b);
   -1 14607 			}
   -1 14608 		}
   -1 14609 		return s || text;
   -1 14610 	};
   -1 14611 
14570 14612 	var isBlockLevelElement = function(node, cssObj) {
14571 14613 		var styleObject = cssObj || getStyleObject(node);
14572 14614 		for (var prop in blockStyles) {
@@ -14604,8 +14646,9 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14604 14646 	https://github.com/webmodules/block-elements
14605 14647 	Note: 'br' was added to this array because it impacts visual display and should thus add a space .
14606 14648 	Reference issue: https://github.com/w3c/accname/issues/4
   -1 14649 Note: Added in 1.13, td, th, tr, and legend
14607 14650 	*/
14608    -1 	var blockElements = ['address', 'article', 'aside', 'blockquote', 'br', 'canvas', 'dd', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'li', 'main', 'nav', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'tfoot', 'ul', 'video'];
   -1 14651 	var blockElements = ['address', 'article', 'aside', 'blockquote', 'br', 'canvas', 'dd', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'legend', 'li', 'main', 'nav', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'td', 'tfoot', 'th', 'tr', 'ul', 'video'];
14609 14652 
14610 14653 	var getObjectValue = function(role, node, isRange, isEdit, isSelect, isNative) {
14611 14654 		var val = '';
@@ -14639,7 +14682,11 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14639 14682 			val = node.value;
14640 14683 		}
14641 14684 		if (!bypass && !val && isNative) {
14642    -1 			val = (isSelect && node.multiple) ? joinSelectedParts(node, node.querySelectorAll('option[selected]'), true) : node.value;
   -1 14685 			if (isSelect) {
   -1 14686 				val = joinSelectedParts(node, node.querySelectorAll('option[selected]'), true);
   -1 14687 			} else {
   -1 14688 				val = node.value;
   -1 14689 			}
14643 14690 		}
14644 14691 
14645 14692 		return val;
@@ -14658,7 +14705,7 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14658 14705 			var role = nOA[i].getAttribute('role');
14659 14706 			var isValidChildRole = !childRoles || childRoles.indexOf(role) !== -1;
14660 14707 			if (isValidChildRole) {
14661    -1 				parts.push(isNative ? getText(nOA[i]) : walk(nOA[i], true));
   -1 14708 				parts.push(isNative ? getText(nOA[i]) : walk(nOA[i], true, false, [], false, {top: nOA[i]}));
14662 14709 			}
14663 14710 		}
14664 14711 		return parts.join(' ');
@@ -14694,32 +14741,19 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14694 14741 	};
14695 14742 
14696 14743 	var getCSSText = function(node, refNode) {
14697    -1 		if (node.nodeType !== 1 || node == refNode || ['input', 'select', 'textarea', 'img', 'iframe'].indexOf(node.nodeName.toLowerCase()) !== -1) {
   -1 14744 		if (node && node.nodeType !== 1 || node == refNode || ['input', 'select', 'textarea', 'img', 'iframe'].indexOf(node.nodeName.toLowerCase()) !== -1) {
14698 14745 			return {before: '', after: ''};
14699 14746 		}
14700 14747 		if (document.defaultView && document.defaultView.getComputedStyle) {
14701 14748 			return {
14702    -1 				before: getText(node, ':before'),
14703    -1 				after: getText(node, ':after')
   -1 14749 				before: cleanCSSText(node, getText(node, ':before')),
   -1 14750 				after: cleanCSSText(node, getText(node, ':after'))
14704 14751 			};
14705 14752 		} else {
14706 14753 			return {before: '', after: ''};
14707 14754 		}
14708 14755 	};
14709 14756 
14710    -1 	var inParent = function(node, parent, refNode) {
14711    -1 		while (node) {
14712    -1 			node = node.parentNode;
14713    -1 			if (node == parent) {
14714    -1 				return true;
14715    -1 			}
14716    -1 			else if (node == refNode) {
14717    -1 				return false;
14718    -1 			}
14719    -1 		}
14720    -1 		return false;
14721    -1 	};
14722    -1 
14723 14757 	var getParent = function(node, nTag) {
14724 14758 		while (node) {
14725 14759 			node = node.parentNode;
@@ -14730,11 +14764,16 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14730 14764 		return {};
14731 14765 	};
14732 14766 
14733    -1 	var hasParentLabel = function(node, noLabel, refNode) {
   -1 14767 	var hasParentLabel = function(node, noLabel, refNode, ownedBy) {
   -1 14768 		var trackNodes = [];
14734 14769 		while (node && node !== refNode) {
14735    -1 			node = node.parentNode;
14736    -1 
14737    -1 			if (node.getAttribute) {
   -1 14770 				if (node.id && ownedBy && ownedBy[node.id] && ownedBy[node.id].node && trackNodes.indexOf(node) === -1) {
   -1 14771 				trackNodes.push(node);
   -1 14772 				node = ownedBy[node.id].node;
   -1 14773 			} else {
   -1 14774 				node = node.parentNode;
   -1 14775 			}
   -1 14776 			if (node && node.getAttribute) {
14738 14777 				if (['presentation', 'none'].indexOf(node.getAttribute('role')) === -1) {
14739 14778 					if (!noLabel && node.getAttribute('aria-label')) {
14740 14779 						return true;
@@ -14745,7 +14784,6 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14745 14784 				}
14746 14785 			}
14747 14786 		}
14748    -1 
14749 14787 		return false;
14750 14788 	};
14751 14789 
@@ -14761,18 +14799,19 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14761 14799 	}
14762 14800 
14763 14801 	// Compute accessible Name property value for node
14764    -1 	var accName = walk(node, false);
   -1 14802 	var accName = walk(node, false, false, [], false, {top: node});
14765 14803 
14766 14804 	var accDesc = '';
14767 14805 	if (['presentation', 'none'].indexOf(node.getAttribute('role')) === -1) {
14768 14806 		// Check for blank value, since whitespace chars alone are not valid as a name
14769 14807 		var title = trim(node.getAttribute('title'));
14770 14808 		if (title) {
14771    -1 			if (!accName) {
   -1 14809 			if (!trim(accName)) {
14772 14810 				// Set accessible Name to title value as a fallback if no other labelling mechanism is available.
14773 14811 				accName = title;
14774    -1 			} else {
14775    -1 				// Otherwise, set Description using title attribute if available and including more than whitespace characters.
   -1 14812 			}
   -1 14813 			else if (accName.indexOf(title) === -1) {
   -1 14814 				// Otherwise, set Description using title attribute if available and including more than whitespace characters, but only if title is not already present within accName.
14776 14815 				accDesc = title;
14777 14816 			}
14778 14817 		}
@@ -14784,7 +14823,11 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14784 14823 			var parts = [];
14785 14824 			for (var j = 0; j < ids.length; j++) {
14786 14825 				var element = document.getElementById(ids[j]);
14787    -1 				parts.push(walk(element, true));
   -1 14826 				var eD = walk(element, true, false, [], false, {top: element});
   -1 14827 				if (accName.indexOf(eD) === -1) {
   -1 14828 					// Add aria-describedby reference to Description, but only if the returned value is not already included within accName.
   -1 14829 					parts.push(eD);
   -1 14830 				}
14788 14831 			}
14789 14832 			// Check for blank value, since whitespace chars alone are not valid as a name
14790 14833 			var desc = trim(parts.join(' '));
@@ -14809,6 +14852,9 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14809 14852 		desc: accDesc
14810 14853 	};
14811 14854 
   -1 14855 	nodes = [];
   -1 14856 	owns = [];
   -1 14857 
14812 14858 	if (fnc && typeof fnc == 'function') {
14813 14859 		return fnc.apply(node, [
14814 14860 			node,
@@ -14819,11 +14865,12 @@ var calcNames = function(node, fnc, preventVisualARIASelfCSSRef) {
14819 14865 	}
14820 14866 };
14821 14867 
14822    -1 // Customize returned string
   -1 14868 
   -1 14869 // Customize returned string for testable statements
14823 14870 
14824 14871 var getNames = function(node) {
14825 14872 	var props = calcNames(node);
14826    -1 	return 'accName: "' + props.name + '"\n\naccDesc: "' + props.desc + '"';
   -1 14873 	return 'accName: "' + props.name + '"\n\naccDesc: "' + props.desc + '"\n\n(Running Name Computation Prototype version: ' + currentVersion + ')';
14827 14874 };
14828 14875 
14829 14876 if (typeof module === 'object' && module.exports) {

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

@@ -4,7 +4,7 @@
    4     4   "description": "compare different implementations of accname",
    5     5   "devDependencies": {
    6     6     "accessibility-developer-tools": "^2.12.0",
    7    -1     "aria-api": "^0.2.2",
   -1     7     "aria-api": "^0.2.4",
    8     8     "axe-core": "^2.6.1",
    9     9     "w3c-alternative-text-computation": "github:accdc/w3c-alternative-text-computation"
   10    10   },