label-text.js 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import accessibleTextVirtual from './accessible-text-virtual';
  2. import accessibleText from './accessible-text';
  3. import findElmsInContext from '../dom/find-elms-in-context';
  4. import { closest, nodeSorter } from '../../core/utils';
  5. /**
  6. * Return accessible text for an implicit and/or explicit HTML label element
  7. * @param {VirtualNode} element
  8. * @param {Object} context
  9. * @property {Bool} inControlContext
  10. * @property {Bool} inLabelledByContext
  11. * @return {String} Label text
  12. */
  13. function labelText(virtualNode, context = {}) {
  14. const { alreadyProcessed } = accessibleTextVirtual;
  15. if (
  16. context.inControlContext ||
  17. context.inLabelledByContext ||
  18. alreadyProcessed(virtualNode, context)
  19. ) {
  20. return '';
  21. }
  22. if (!context.startNode) {
  23. context.startNode = virtualNode;
  24. }
  25. const labelContext = { inControlContext: true, ...context };
  26. const explicitLabels = getExplicitLabels(virtualNode);
  27. const implicitLabel = closest(virtualNode, 'label');
  28. let labels;
  29. if (implicitLabel) {
  30. labels = [...explicitLabels, implicitLabel.actualNode];
  31. labels.sort(nodeSorter);
  32. } else {
  33. labels = explicitLabels;
  34. }
  35. return labels
  36. .map(label => accessibleText(label, labelContext))
  37. .filter(text => text !== '')
  38. .join(' ');
  39. }
  40. /**
  41. * Find a non-ARIA label for an element
  42. * @private
  43. * @param {VirtualNode} element The VirtualNode instance whose label we are seeking
  44. * @return {HTMLElement} The label element, or null if none is found
  45. */
  46. function getExplicitLabels(virtualNode) {
  47. if (!virtualNode.attr('id')) {
  48. return [];
  49. }
  50. if (!virtualNode.actualNode) {
  51. throw new TypeError(
  52. 'Cannot resolve explicit label reference for non-DOM nodes'
  53. );
  54. }
  55. return findElmsInContext({
  56. elm: 'label',
  57. attr: 'for',
  58. value: virtualNode.attr('id'),
  59. context: virtualNode.actualNode
  60. });
  61. }
  62. export default labelText;