arialabelledby-text.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import idrefs from '../dom/idrefs';
  2. import accessibleText from '../text/accessible-text';
  3. import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node';
  4. import { getNodeFromTree } from '../../core/utils';
  5. /**
  6. * Get the accessible name based on aria-labelledby
  7. *
  8. * @deprecated Do not use Element directly. Pass VirtualNode instead
  9. * @param {VirtualNode} element
  10. * @param {Object} context
  11. * @property {Bool} inLabelledByContext Whether or not the lookup is part of aria-labelledby reference
  12. * @property {Bool} inControlContext Whether or not the lookup is part of a native label reference
  13. * @property {Element} startNode First node in accessible name computation
  14. * @property {Bool} debug Enable logging for formControlValue
  15. * @return {string} Cancatinated text value for referenced elements
  16. */
  17. function arialabelledbyText(vNode, context = {}) {
  18. if (!(vNode instanceof AbstractVirtualNode)) {
  19. if (vNode.nodeType !== 1) {
  20. return '';
  21. }
  22. vNode = getNodeFromTree(vNode);
  23. }
  24. /**
  25. * Note: The there are significant difference in how many "leads" browsers follow.
  26. * - Firefox stops after the first IDREF, so it
  27. * doesn't follow aria-labelledby after a for:>ID ref.
  28. * - Chrome seems to just keep iterating no matter how many levels deep.
  29. * - AccName-AAM 1.1 suggests going one level deep, but to treat
  30. * each ref type separately.
  31. *
  32. * Axe-core's implementation behaves most closely like Firefox as it seems
  33. * to be the common denominator. Main difference is that Firefox
  34. * includes the value of form controls in addition to aria-label(s),
  35. * something no other browser seems to do. Axe doesn't do that.
  36. */
  37. if (
  38. vNode.props.nodeType !== 1 ||
  39. context.inLabelledByContext ||
  40. context.inControlContext ||
  41. !vNode.attr('aria-labelledby')
  42. ) {
  43. return '';
  44. }
  45. const refs = idrefs(vNode, 'aria-labelledby').filter(elm => elm);
  46. return refs.reduce((accessibleName, elm) => {
  47. const accessibleNameAdd = accessibleText(elm, {
  48. // Prevent the infinite reference loop:
  49. inLabelledByContext: true,
  50. startNode: context.startNode || vNode,
  51. ...context
  52. });
  53. if (!accessibleName) {
  54. return accessibleNameAdd;
  55. } else {
  56. return `${accessibleName} ${accessibleNameAdd}`;
  57. }
  58. }, '');
  59. }
  60. export default arialabelledbyText;