import accessibleTextVirtual from './accessible-text-virtual'; import accessibleText from './accessible-text'; import findElmsInContext from '../dom/find-elms-in-context'; import { closest, nodeSorter } from '../../core/utils'; /** * Return accessible text for an implicit and/or explicit HTML label element * @param {VirtualNode} element * @param {Object} context * @property {Bool} inControlContext * @property {Bool} inLabelledByContext * @return {String} Label text */ function labelText(virtualNode, context = {}) { const { alreadyProcessed } = accessibleTextVirtual; if ( context.inControlContext || context.inLabelledByContext || alreadyProcessed(virtualNode, context) ) { return ''; } if (!context.startNode) { context.startNode = virtualNode; } const labelContext = { inControlContext: true, ...context }; const explicitLabels = getExplicitLabels(virtualNode); const implicitLabel = closest(virtualNode, 'label'); let labels; if (implicitLabel) { labels = [...explicitLabels, implicitLabel.actualNode]; labels.sort(nodeSorter); } else { labels = explicitLabels; } return labels .map(label => accessibleText(label, labelContext)) .filter(text => text !== '') .join(' '); } /** * Find a non-ARIA label for an element * @private * @param {VirtualNode} element The VirtualNode instance whose label we are seeking * @return {HTMLElement} The label element, or null if none is found */ function getExplicitLabels(virtualNode) { if (!virtualNode.attr('id')) { return []; } if (!virtualNode.actualNode) { throw new TypeError( 'Cannot resolve explicit label reference for non-DOM nodes' ); } return findElmsInContext({ elm: 'label', attr: 'for', value: virtualNode.attr('id'), context: virtualNode.actualNode }); } export default labelText;