123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- 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';
- import { tokenList, isHtmlElement, matchesSelector } from '../../core/utils';
- // dpub roles which are subclassing roles that are implicit on some native
- // HTML elements (img, link, etc.)
- const dpubRoles = [
- 'doc-backlink',
- 'doc-biblioentry',
- 'doc-biblioref',
- 'doc-cover',
- 'doc-endnote',
- 'doc-glossref',
- 'doc-noteref'
- ];
- /**
- * Returns all roles applicable to element in a list
- *
- * @method getRoleSegments
- * @private
- * @param {Element} node
- * @returns {Array} Roles list or empty list
- */
- function getRoleSegments(node) {
- let roles = [];
- if (!node) {
- return roles;
- }
- if (node.hasAttribute('role')) {
- const nodeRoles = tokenList(node.getAttribute('role').toLowerCase());
- roles = roles.concat(nodeRoles);
- }
- if (node.hasAttributeNS('http://www.idpf.org/2007/ops', 'type')) {
- const epubRoles = tokenList(
- node.getAttributeNS('http://www.idpf.org/2007/ops', 'type').toLowerCase()
- ).map(role => `doc-${role}`);
- roles = roles.concat(epubRoles);
- }
- // filter invalid roles
- roles = roles.filter(role => isValidRole(role));
- return roles;
- }
- /**
- * gets all unallowed roles for a given node
- * @method getElementUnallowedRoles
- * @param {Object} node HTMLElement to validate
- * @param {String} tagName tag name of a 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
- */
- function getElementUnallowedRoles(node, allowImplicit = true) {
- const tagName = node.nodeName.toUpperCase();
- // by pass custom elements
- if (!isHtmlElement(node)) {
- return [];
- }
- const roleSegments = getRoleSegments(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 => {
- // if role and implicit role are same, when allowImplicit: true
- // ignore as it is a redundant role
- if (allowImplicit && role === implicitRole) {
- return false;
- }
- // 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 = getRoleType(role);
- if (implicitRole !== roleType) {
- return true;
- }
- }
- // Edge case:
- // setting implicit role row on tr element is allowed when child of table[role='grid']
- if (
- !allowImplicit &&
- !(
- role === 'row' &&
- tagName === 'TR' &&
- matchesSelector(node, 'table[role="grid"] > tr')
- )
- ) {
- return true;
- }
- // check if role is allowed on element
- return !isAriaRoleAllowedOnElement(node, role);
- });
- return unallowedRoles;
- }
- export default getElementUnallowedRoles;
|