luhn-generator
Version:
A generator of numbers that passes the validation of Luhn algorithm or Luhn formula, also known as the 'modulus 10' or 'mod 10' algorithm
123 lines (105 loc) • 3.31 kB
JavaScript
import {
requiredOwned,
getRole,
getExplicitRole,
getOwnedVirtual
} from '../../commons/aria';
import { hasContentVirtual, idrefs } from '../../commons/dom';
/**
* Get all owned roles of an element
*/
function getOwnedRoles(virtualNode) {
const ownedRoles = [];
const ownedElements = getOwnedVirtual(virtualNode);
for (let i = 0; i < ownedElements.length; i++) {
let ownedElement = ownedElements[i];
let role = getRole(ownedElement);
// if owned node has no role or is presentational we keep
// parsing the descendant tree. this means intermediate roles
// between a required parent and child will fail the check
if (['presentation', 'none', null].includes(role)) {
ownedElements.push(...ownedElement.children);
} else if (role) {
ownedRoles.push(role);
}
}
return ownedRoles;
}
/**
* Get missing children roles
*/
function missingRequiredChildren(virtualNode, role, required, ownedRoles) {
const isCombobox = role === 'combobox';
// combobox exceptions
if (isCombobox) {
// remove 'textbox' from missing roles if combobox is a native
// text-type input or owns a 'searchbox'
const textTypeInputs = ['text', 'search', 'email', 'url', 'tel'];
if (
(virtualNode.props.nodeName === 'input' &&
textTypeInputs.includes(virtualNode.props.type)) ||
ownedRoles.includes('searchbox')
) {
required = required.filter(requiredRole => requiredRole !== 'textbox');
}
// combobox only needs one of [listbox, tree, grid, dialog] and
// only the type that matches the aria-popup value. remove
// all the other popup roles from the list of required
const expandedChildRoles = ['listbox', 'tree', 'grid', 'dialog'];
const expandedValue = virtualNode.attr('aria-expanded');
const expanded = expandedValue && expandedValue.toLowerCase() !== 'false';
const popupRole = (
virtualNode.attr('aria-haspopup') || 'listbox'
).toLowerCase();
required = required.filter(
requiredRole =>
!expandedChildRoles.includes(requiredRole) ||
(expanded && requiredRole === popupRole)
);
}
for (let i = 0; i < ownedRoles.length; i++) {
var ownedRole = ownedRoles[i];
if (required.includes(ownedRole)) {
required = required.filter(requiredRole => requiredRole !== ownedRole);
// combobox requires all the roles not just any one of them
if (!isCombobox) {
return null;
}
}
}
if (required.length) {
return required;
}
return null;
}
function ariaRequiredChildrenEvaluate(node, options, virtualNode) {
const reviewEmpty =
options && Array.isArray(options.reviewEmpty) ? options.reviewEmpty : [];
const role = getExplicitRole(virtualNode, { dpub: true });
const required = requiredOwned(role);
if (!required) {
return true;
}
const ownedRoles = getOwnedRoles(virtualNode);
const missing = missingRequiredChildren(
virtualNode,
role,
required,
ownedRoles
);
if (!missing) {
return true;
}
this.data(missing);
// Only review empty nodes when a node is both empty and does not have an aria-owns relationship
if (
reviewEmpty.includes(role) &&
!hasContentVirtual(virtualNode, false, true) &&
!ownedRoles.length &&
(!virtualNode.hasAttr('aria-owns') || !idrefs(node, 'aria-owns').length)
) {
return undefined;
}
return false;
}
export default ariaRequiredChildrenEvaluate;