123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import arialabelledbyText from '../aria/arialabelledby-text';
- import arialabelText from '../aria/arialabel-text';
- import nativeTextAlternative from './native-text-alternative';
- import formControlValue from './form-control-value';
- import subtreeText from './subtree-text';
- import titleText from './title-text';
- import sanitize from './sanitize';
- import isVisible from '../dom/is-visible';
- /**
- * Finds virtual node and calls accessibleTextVirtual()
- * IMPORTANT: This method requires the composed tree at axe._tree
- *
- * @param {HTMLElement} element The HTMLElement
- * @param {Object} context
- * @property {Bool} inControlContext
- * @property {Bool} inLabelledByContext
- * @return {string}
- */
- function accessibleTextVirtual(virtualNode, context = {}) {
- const { actualNode } = virtualNode;
- context = prepareContext(virtualNode, context);
- // Step 2A, check visibility
- if (shouldIgnoreHidden(virtualNode, context)) {
- return '';
- }
- const computationSteps = [
- arialabelledbyText, // Step 2B.1
- arialabelText, // Step 2C
- nativeTextAlternative, // Step 2D
- formControlValue, // Step 2E
- subtreeText, // Step 2F + Step 2H
- textNodeValue, // Step 2G (order with 2H does not matter)
- titleText // Step 2I
- ];
- // Find the first step that returns a non-empty string
- const accName = computationSteps.reduce((accName, step) => {
- if (context.startNode === virtualNode) {
- accName = sanitize(accName);
- }
- if (accName !== '') {
- // yes, whitespace only a11y names halt the algorithm
- return accName;
- }
- return step(virtualNode, context);
- }, '');
- if (context.debug) {
- axe.log(accName || '{empty-value}', actualNode, context);
- }
- return accName;
- }
- /**
- * Return the nodeValue of a node
- * @param {VirtualNode} element
- * @return {String} nodeValue value
- */
- function textNodeValue(virtualNode) {
- if (virtualNode.props.nodeType !== 3) {
- return '';
- }
- return virtualNode.props.nodeValue;
- }
- /**
- * Check if the
- * @param {VirtualNode} element
- * @param {Object} context
- * @property {VirtualNode[]} processed
- * @return {Boolean}
- */
- function shouldIgnoreHidden({ actualNode }, context) {
- if (!actualNode) {
- return false;
- }
- if (
- // If the parent isn't ignored, the text node should not be either
- actualNode.nodeType !== 1 ||
- // If the target of aria-labelledby is hidden, ignore all descendents
- context.includeHidden
- ) {
- return false;
- }
- return !isVisible(actualNode, true);
- }
- /**
- * Apply defaults to the context
- * @param {VirtualNode} element
- * @param {Object} context
- * @return {Object} context object with defaults applied
- */
- function prepareContext(virtualNode, context) {
- const { actualNode } = virtualNode;
- if (!context.startNode) {
- context = { startNode: virtualNode, ...context };
- }
- if (!actualNode) {
- return context;
- }
- /**
- * When `aria-labelledby` directly references a `hidden` element
- * the element needs to be included in the accessible name.
- *
- * When a descendent of the `aria-labelledby` reference is `hidden`
- * the element should not be included in the accessible name.
- *
- * This is done by setting `includeHidden` for the `aria-labelledby` reference.
- */
- if (
- actualNode.nodeType === 1 &&
- context.inLabelledByContext &&
- context.includeHidden === undefined
- ) {
- context = {
- includeHidden: !isVisible(actualNode, true),
- ...context
- };
- }
- return context;
- }
- /**
- * Check if the node is processed with this context before
- * @param {VirtualNode} element
- * @param {Object} context
- * @property {VirtualNode[]} processed
- * @return {Boolean}
- */
- accessibleTextVirtual.alreadyProcessed = function alreadyProcessed(
- virtualnode,
- context
- ) {
- context.processed = context.processed || [];
- if (context.processed.includes(virtualnode)) {
- return true;
- }
- context.processed.push(virtualnode);
- return false;
- };
- export default accessibleTextVirtual;
|