- 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 },