multiple-label-evaluate.js 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. import { getRootNode, isVisible, idrefs } from '../../commons/dom';
  2. import { escapeSelector } from '../../core/utils';
  3. function multipleLabelEvaluate(node) {
  4. const id = escapeSelector(node.getAttribute('id'));
  5. let parent = node.parentNode;
  6. let root = getRootNode(node);
  7. root = root.documentElement || root;
  8. let labels = Array.from(root.querySelectorAll(`label[for="${id}"]`));
  9. if (labels.length) {
  10. // filter out CSS hidden labels because they're fine
  11. labels = labels.filter(label => isVisible(label));
  12. }
  13. while (parent) {
  14. if (
  15. parent.nodeName.toUpperCase() === 'LABEL' &&
  16. labels.indexOf(parent) === -1
  17. ) {
  18. labels.push(parent);
  19. }
  20. parent = parent.parentNode;
  21. }
  22. this.relatedNodes(labels);
  23. // more than 1 CSS visible label
  24. if (labels.length > 1) {
  25. const ATVisibleLabels = labels.filter(label => isVisible(label, true));
  26. // more than 1 AT visible label will fail IOS/Safari/VO even with aria-labelledby
  27. if (ATVisibleLabels.length > 1) {
  28. return undefined;
  29. }
  30. // make sure the ONE AT visible label is in the list of idRefs of aria-labelledby
  31. const labelledby = idrefs(node, 'aria-labelledby');
  32. return !labelledby.includes(ATVisibleLabels[0]) ? undefined : false;
  33. }
  34. // only 1 CSS visible label
  35. return false;
  36. }
  37. export default multipleLabelEvaluate;