Skip to content

Commit

Permalink
Es modules commons aria (#2143)
Browse files Browse the repository at this point in the history
* chore: convert commons.aria to ES Modules

* import outside aria
  • Loading branch information
straker authored Apr 2, 2020
1 parent 5021c80 commit 86e3324
Show file tree
Hide file tree
Showing 35 changed files with 2,906 additions and 2,752 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"overrides": [
{
"files": [
"lib/commons/aria/*.js",
"lib/commons/forms/*.js",
"lib/commons/matches/*.js",
"lib/commons/utils/*.js"
Expand Down
5 changes: 5 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ module.exports = function(grunt) {
'lib/commons/**/*.js',

// directories we've converted to ES Modules
'!lib/commons/aria/*.js',
'!lib/commons/forms/*.js',
'!lib/commons/matches/*.js',
'!lib/commons/utils/*.js',
Expand All @@ -171,6 +172,10 @@ module.exports = function(grunt) {
'lib/commons/utils/index.js',
'tmp/commons/utils'
),
commonsAria: createWebpackConfig(
'lib/commons/aria/index.js',
'tmp/commons/aria'
),
commonsForms: createWebpackConfig(
'lib/commons/forms/index.js',
'tmp/commons/forms'
Expand Down
20 changes: 20 additions & 0 deletions lib/commons/aria/allowed-attr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import lookupTable from './lookup-table';

/**
* Get allowed attributes for a given role
* @method allowedAttr
* @memberof axe.commons.aria
* @instance
* @param {String} role The role to check
* @return {Array}
*/
function allowedAttr(role) {
const roles = lookupTable.role[role];
const attr = (roles && roles.attributes && roles.attributes.allowed) || [];
const requiredAttr =
(roles && roles.attributes && roles.attributes.required) || [];

return attr.concat(lookupTable.globalAttributes).concat(requiredAttr);
}

export default allowedAttr;
10 changes: 6 additions & 4 deletions lib/commons/aria/arialabel-text.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
/* global aria */

/**
* Get the text value of aria-label, if any
*
* @deprecated Do not use Element directly. Pass VirtualNode instead
* @param {VirtualNode|Element} element
* @return {string} ARIA label
*/
aria.arialabelText = function arialabelText(node) {
function arialabelText(node) {
// TODO: es-module-AbstractVirtualNode
if (node instanceof axe.AbstractVirtualNode === false) {
if (node.nodeType !== 1) {
return '';
}
// TODO: es-module-utils.getNodeFromTree
node = axe.utils.getNodeFromTree(node);
}
return node.attr('aria-label') || '';
};
}

export default arialabelText;
10 changes: 7 additions & 3 deletions lib/commons/aria/arialabelledby-text.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global aria, dom, text */
/* global dom, text */

/**
* Get the accessible name based on aria-labelledby
Expand All @@ -11,7 +11,7 @@
* @property {Bool} debug Enable logging for formControlValue
* @return {string} Cancatinated text value for referenced elements
*/
aria.arialabelledbyText = function arialabelledbyText(node, context = {}) {
function arialabelledbyText(node, context = {}) {
node = node.actualNode || node;
/**
* Note: The there are significant difference in how many "leads" browsers follow.
Expand All @@ -34,8 +34,10 @@ aria.arialabelledbyText = function arialabelledbyText(node, context = {}) {
return '';
}

// TODO: es-module-dom.idrefs
const refs = dom.idrefs(node, 'aria-labelledby').filter(elm => elm);
return refs.reduce((accessibleName, elm) => {
// TODO: es-module-text.accessibleText
const accessibleNameAdd = text.accessibleText(elm, {
// Prevent the infinite reference loop:
inLabelledByContext: true,
Expand All @@ -49,4 +51,6 @@ aria.arialabelledbyText = function arialabelledbyText(node, context = {}) {
return `${accessibleName} ${accessibleNameAdd}`;
}
}, '');
};
}

export default arialabelledbyText;
45 changes: 0 additions & 45 deletions lib/commons/aria/attributes.js

This file was deleted.

26 changes: 16 additions & 10 deletions lib/commons/aria/get-element-unallowed-roles.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* global aria */
import isValidRole from './is-valid-role';
import getImplicitRole from './implicit-role';
import getRoleType from './get-role-type';
import isAriaRoleAllowedOnElement from './is-aria-role-allowed-on-element';

// dpub roles which are subclassing roles that are implicit on some native
// HTML elements (img, link, etc.)
Expand Down Expand Up @@ -29,13 +32,15 @@ function getRoleSegments(node) {
}

if (node.hasAttribute('role')) {
// TODO: es-module-utils.tokenList
const nodeRoles = axe.utils.tokenList(
node.getAttribute('role').toLowerCase()
);
roles = roles.concat(nodeRoles);
}

if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) {
// TODO: es-module-utils.tokenList
const epubRoles = axe.utils
.tokenList(
node
Expand All @@ -48,7 +53,7 @@ function getRoleSegments(node) {
}

// filter invalid roles
roles = roles.filter(role => axe.commons.aria.isValidRole(role));
roles = roles.filter(role => isValidRole(role));

return roles;
}
Expand All @@ -61,19 +66,17 @@ function getRoleSegments(node) {
* @param {String} allowImplicit option to allow implicit roles, defaults to true
* @return {Array<String>} retruns an array of roles that are not allowed on the given node
*/
aria.getElementUnallowedRoles = function getElementUnallowedRoles(
node,
allowImplicit = true
) {
function getElementUnallowedRoles(node, allowImplicit = true) {
const tagName = node.nodeName.toUpperCase();

// by pass custom elements
// TODO: es-module-utils.isHtmlElement
if (!axe.utils.isHtmlElement(node)) {
return [];
}

const roleSegments = getRoleSegments(node);
const implicitRole = axe.commons.aria.implicitRole(node);
const implicitRole = getImplicitRole(node);

// stores all roles that are not allowed for a specific element most often an element only has one explicit role
const unallowedRoles = roleSegments.filter(role => {
Expand All @@ -86,7 +89,7 @@ aria.getElementUnallowedRoles = function getElementUnallowedRoles(
// if role is a dpub role make sure it's used on an element with a valid
// implicit role fallback
if (allowImplicit && dpubRoles.includes(role)) {
const roleType = axe.commons.aria.getRoleType(role);
const roleType = getRoleType(role);
if (implicitRole !== roleType) {
return true;
}
Expand All @@ -99,15 +102,18 @@ aria.getElementUnallowedRoles = function getElementUnallowedRoles(
!(
role === 'row' &&
tagName === 'TR' &&
// TODO: es-module-utils.matchesSelector
axe.utils.matchesSelector(node, 'table[role="grid"] > tr')
)
) {
return true;
}

// check if role is allowed on element
return !aria.isAriaRoleAllowedOnElement(node, role);
return !isAriaRoleAllowedOnElement(node, role);
});

return unallowedRoles;
};
}

export default getElementUnallowedRoles;
10 changes: 7 additions & 3 deletions lib/commons/aria/get-owned-virtual.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
/* global aria, dom */
/* global dom */

/**
* Get an element's owned elements
*
* @param {VirtualNode} element
* @return {VirtualNode[]} Owned elements
*/
aria.getOwnedVirtual = function getOwned({ actualNode, children }) {
function getOwnedVirtual({ actualNode, children }) {
if (!actualNode || !children) {
throw new Error('getOwnedVirtual requires a virtual node');
}
// TODO: Check that the element has a role
// TODO: Descend into children with role=presentation|none
// TODO: Exclude descendents owned by other elements

// TODO: es-module-dom.idrefs
return dom.idrefs(actualNode, 'aria-owns').reduce((ownedElms, element) => {
if (element) {
// TODO: es-module-utils.getNodeFromTree
const virtualNode = axe.utils.getNodeFromTree(element);
ownedElms.push(virtualNode);
}
return ownedElms;
}, children);
};
}

export default getOwnedVirtual;
16 changes: 16 additions & 0 deletions lib/commons/aria/get-role-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import lookupTable from './lookup-table';

/**
* Get the "type" of role; either widget, composite, abstract, landmark or `null`
* @method getRoleType
* @memberof axe.commons.aria
* @instance
* @param {String} role The role to check
* @return {Mixed} String if a matching role and its type are found, otherwise `null`
*/
function getRoleType(role) {
var r = lookupTable.role[role];
return (r && r.type) || null;
}

export default getRoleType;
17 changes: 9 additions & 8 deletions lib/commons/aria/get-role.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* global aria, axe */
import isValidRole from './is-valid-role';
import getImplicitRole from './implicit-role';

/**
* Return the accessible role of an element
Expand All @@ -14,31 +15,31 @@
* @param {boolean} options.dpub Allow role to be any (valid) doc-* roles
* @returns {string|null} Role or null
*/
aria.getRole = function getRole(
node,
{ noImplicit, fallback, abstracts, dpub } = {}
) {
function getRole(node, { noImplicit, fallback, abstracts, dpub } = {}) {
node = node.actualNode || node;
if (node.nodeType !== 1) {
return null;
}
const roleAttr = (node.getAttribute('role') || '').trim().toLowerCase();
// TODO: es-module-utils.tokenList
const roleList = fallback ? axe.utils.tokenList(roleAttr) : [roleAttr];

// Get the first valid role:
const validRoles = roleList.filter(role => {
if (!dpub && role.substr(0, 4) === 'doc-') {
return false;
}
return aria.isValidRole(role, { allowAbstract: abstracts });
return isValidRole(role, { allowAbstract: abstracts });
});

const explicitRole = validRoles[0];

// Get the implicit role, if permitted
if (!explicitRole && !noImplicit) {
return aria.implicitRole(node);
return getImplicitRole(node);
}

return explicitRole || null;
};
}

export default getRole;
17 changes: 17 additions & 0 deletions lib/commons/aria/get-roles-by-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import lookupTable from './lookup-table';

/**
* Get the roles that have a certain "type"
* @method getRolesByType
* @memberof axe.commons.aria
* @instance
* @param {String} roleType The roletype to check
* @return {Array} Array of roles that match the type
*/
function getRolesByType(roleType) {
return Object.keys(lookupTable.role).filter(function(r) {
return lookupTable.role[r].type === roleType;
});
}

export default getRolesByType;
19 changes: 19 additions & 0 deletions lib/commons/aria/get-roles-with-name-from-contents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import lookupTable from './lookup-table';

/**
* Get the roles that get name from the element's contents
* @method getRolesWithNameFromContents
* @memberof axe.commons.aria
* @instance
* @return {Array} Array of roles that match the type
*/
function getRolesWithNameFromContents() {
return Object.keys(lookupTable.role).filter(function(r) {
return (
lookupTable.role[r].nameFrom &&
lookupTable.role[r].nameFrom.indexOf('contents') !== -1
);
});
}

export default getRolesWithNameFromContents;
24 changes: 24 additions & 0 deletions lib/commons/aria/implicit-nodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import lookupTable from './lookup-table';

/**
* Get a list of CSS selectors of nodes that have an implicit role
* @method implicitNodes
* @memberof axe.commons.aria
* @instance
* @param {String} role The role to check
* @return {Mixed} Either an Array of CSS selectors or `null` if there are none
*/
function implicitNodes(role) {
'use strict';

let implicit = null;
const roles = lookupTable.role[role];

if (roles && roles.implicit) {
// TODO: es-module-utils.clone
implicit = axe.utils.clone(roles.implicit);
}
return implicit;
}

export default implicitNodes;
Loading

0 comments on commit 86e3324

Please sign in to comment.