get-accessible-refs.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import getRootNode from '../dom/get-root-node';
  2. import cache from '../../core/base/cache';
  3. import { tokenList } from '../../core/utils';
  4. import standards from '../../standards';
  5. import { sanitize } from '../text/';
  6. const idRefsRegex = /^idrefs?$/;
  7. /**
  8. * Cache all ID references of a node and its children
  9. */
  10. function cacheIdRefs(node, idRefs, refAttrs) {
  11. if (node.hasAttribute) {
  12. if (node.nodeName.toUpperCase() === 'LABEL' && node.hasAttribute('for')) {
  13. const id = node.getAttribute('for');
  14. idRefs[id] = idRefs[id] || [];
  15. idRefs[id].push(node);
  16. }
  17. for (let i = 0; i < refAttrs.length; ++i) {
  18. const attr = refAttrs[i];
  19. const attrValue = sanitize(node.getAttribute(attr) || '');
  20. if (!attrValue) {
  21. continue;
  22. }
  23. const tokens = tokenList(attrValue);
  24. for (let k = 0; k < tokens.length; ++k) {
  25. idRefs[tokens[k]] = idRefs[tokens[k]] || [];
  26. idRefs[tokens[k]].push(node);
  27. }
  28. }
  29. }
  30. for (let i = 0; i < node.children.length; i++) {
  31. cacheIdRefs(node.children[i], idRefs, refAttrs);
  32. }
  33. }
  34. /**
  35. * Return all DOM nodes that use the nodes ID in the accessibility tree.
  36. * @param {Element} node
  37. * @returns {Element[]}
  38. */
  39. function getAccessibleRefs(node) {
  40. node = node.actualNode || node;
  41. let root = getRootNode(node);
  42. root = root.documentElement || root; // account for shadow roots
  43. let idRefsByRoot = cache.get('idRefsByRoot');
  44. if (!idRefsByRoot) {
  45. idRefsByRoot = new WeakMap();
  46. cache.set('idRefsByRoot', idRefsByRoot);
  47. }
  48. let idRefs = idRefsByRoot.get(root);
  49. if (!idRefs) {
  50. idRefs = {};
  51. idRefsByRoot.set(root, idRefs);
  52. const refAttrs = Object.keys(standards.ariaAttrs).filter(attr => {
  53. const { type } = standards.ariaAttrs[attr];
  54. return idRefsRegex.test(type);
  55. });
  56. cacheIdRefs(root, idRefs, refAttrs);
  57. }
  58. return idRefs[node.id] || [];
  59. }
  60. export default getAccessibleRefs;