@afixt/test-utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc +78 -0
  3. package/.gitattributes +5 -0
  4. package/.nvmrc +1 -0
  5. package/CLAUDE.md +33 -0
  6. package/README.md +72 -0
  7. package/docs/arrayUtils.js.html +69 -0
  8. package/docs/data/search.json +1 -0
  9. package/docs/domUtils.js.html +182 -0
  10. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  11. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  12. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  13. package/docs/getAccessibleName.js.html +456 -0
  14. package/docs/getAccessibleText.js.html +65 -0
  15. package/docs/getAriaAttributesByElement.js.html +22 -0
  16. package/docs/getCSSGeneratedContent.js.html +62 -0
  17. package/docs/getComputedRole.js.html +172 -0
  18. package/docs/getFocusableElements.js.html +29 -0
  19. package/docs/getGeneratedContent.js.html +18 -0
  20. package/docs/getImageText.js.html +28 -0
  21. package/docs/getStyleObject.js.html +48 -0
  22. package/docs/global.html +3 -0
  23. package/docs/hasAccessibleName.js.html +30 -0
  24. package/docs/hasAttribute.js.html +18 -0
  25. package/docs/hasCSSGeneratedContent.js.html +23 -0
  26. package/docs/hasHiddenParent.js.html +32 -0
  27. package/docs/hasParent.js.html +57 -0
  28. package/docs/hasValidAriaAttributes.js.html +33 -0
  29. package/docs/hasValidAriaRole.js.html +32 -0
  30. package/docs/index.html +3 -0
  31. package/docs/index.js.html +66 -0
  32. package/docs/isAriaAttributesValid.js.html +76 -0
  33. package/docs/isComplexTable.js.html +112 -0
  34. package/docs/isDataTable.js.html +241 -0
  35. package/docs/isFocusable.js.html +37 -0
  36. package/docs/isHidden.js.html +20 -0
  37. package/docs/isOffScreen.js.html +19 -0
  38. package/docs/isValidUrl.js.html +16 -0
  39. package/docs/isVisible.js.html +65 -0
  40. package/docs/module-afixt-test-utils.html +3 -0
  41. package/docs/scripts/core.js +726 -0
  42. package/docs/scripts/core.min.js +23 -0
  43. package/docs/scripts/resize.js +90 -0
  44. package/docs/scripts/search.js +265 -0
  45. package/docs/scripts/search.min.js +6 -0
  46. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  47. package/docs/scripts/third-party/fuse.js +9 -0
  48. package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
  49. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  50. package/docs/scripts/third-party/hljs-original.js +5171 -0
  51. package/docs/scripts/third-party/hljs.js +1 -0
  52. package/docs/scripts/third-party/popper.js +5 -0
  53. package/docs/scripts/third-party/tippy.js +1 -0
  54. package/docs/scripts/third-party/tocbot.js +672 -0
  55. package/docs/scripts/third-party/tocbot.min.js +1 -0
  56. package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
  57. package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
  58. package/docs/styles/clean-jsdoc-theme-light.css +482 -0
  59. package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  60. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  61. package/docs/styles/clean-jsdoc-theme.min.css +1 -0
  62. package/docs/testContrast.js.html +236 -0
  63. package/docs/testLang.js.html +578 -0
  64. package/docs/testOrder.js.html +93 -0
  65. package/jsdoc.json +67 -0
  66. package/package.json +32 -0
  67. package/src/arrayUtils.js +67 -0
  68. package/src/domUtils.js +179 -0
  69. package/src/getAccessibleName.js +454 -0
  70. package/src/getAccessibleText.js +63 -0
  71. package/src/getAriaAttributesByElement.js +19 -0
  72. package/src/getCSSGeneratedContent.js +60 -0
  73. package/src/getComputedRole.js +169 -0
  74. package/src/getFocusableElements.js +26 -0
  75. package/src/getGeneratedContent.js +15 -0
  76. package/src/getImageText.js +25 -0
  77. package/src/getStyleObject.js +45 -0
  78. package/src/hasAccessibleName.js +28 -0
  79. package/src/hasAttribute.js +15 -0
  80. package/src/hasCSSGeneratedContent.js +20 -0
  81. package/src/hasHiddenParent.js +29 -0
  82. package/src/hasParent.js +54 -0
  83. package/src/hasValidAriaAttributes.js +30 -0
  84. package/src/hasValidAriaRole.js +29 -0
  85. package/src/index.js +64 -0
  86. package/src/interactiveRoles.js +20 -0
  87. package/src/isAriaAttributesValid.js +74 -0
  88. package/src/isComplexTable.js +109 -0
  89. package/src/isDataTable.js +239 -0
  90. package/src/isFocusable.js +34 -0
  91. package/src/isHidden.js +17 -0
  92. package/src/isOffScreen.js +16 -0
  93. package/src/isValidUrl.js +13 -0
  94. package/src/isVisible.js +62 -0
  95. package/src/stringUtils.js +150 -0
  96. package/src/testContrast.js +233 -0
  97. package/src/testLang.js +575 -0
  98. package/src/testOrder.js +90 -0
  99. package/test/_template.test.js +21 -0
  100. package/test/arrayUtils.test.js +84 -0
  101. package/test/domUtils.test.js +147 -0
  102. package/test/generate-test-stubs.js +37 -0
  103. package/test/getAccessibleName.test.js +113 -0
  104. package/test/getAccessibleText.test.js +94 -0
  105. package/test/getAriaAttributesByElement.test.js +112 -0
  106. package/test/getCSSGeneratedContent.test.js +102 -0
  107. package/test/getComputedRole.test.js +180 -0
  108. package/test/getFocusableElements.test.js +134 -0
  109. package/test/getGeneratedContent.test.js +321 -0
  110. package/test/getImageText.test.js +21 -0
  111. package/test/getStyleObject.test.js +134 -0
  112. package/test/hasAccessibleName.test.js +59 -0
  113. package/test/hasAttribute.test.js +132 -0
  114. package/test/hasCSSGeneratedContent.test.js +143 -0
  115. package/test/hasHiddenParent.test.js +176 -0
  116. package/test/hasParent.test.js +266 -0
  117. package/test/hasValidAriaAttributes.test.js +79 -0
  118. package/test/hasValidAriaRole.test.js +98 -0
  119. package/test/isAriaAttributesValid.test.js +83 -0
  120. package/test/isComplexTable.test.js +363 -0
  121. package/test/isDataTable.test.js +948 -0
  122. package/test/isFocusable.test.js +182 -0
  123. package/test/isHidden.test.js +157 -0
  124. package/test/isOffScreen.test.js +249 -0
  125. package/test/isValidUrl.test.js +63 -0
  126. package/test/isVisible.test.js +104 -0
  127. package/test/setup.js +11 -0
  128. package/test/stringUtils.test.js +106 -0
  129. package/test/testContrast.test.js +77 -0
  130. package/test/testLang.test.js +21 -0
  131. package/test/testOrder.test.js +157 -0
  132. package/vitest.config.js +25 -0
@@ -0,0 +1,456 @@
1
+ <!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: getAccessibleName.js</title><!--[if lt IE 9]>
2
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
3
+ <![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-afixt-test-utils.html">afixt-test-utils</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#arrayCount">arrayCount</a></div><div class="sidebar-section-children"><a href="global.html#arrayRemoveByValue">arrayRemoveByValue</a></div><div class="sidebar-section-children"><a href="global.html#arrayUnique">arrayUnique</a></div><div class="sidebar-section-children"><a href="global.html#cellColorDiffs">cellColorDiffs</a></div><div class="sidebar-section-children"><a href="global.html#cellCount">cellCount</a></div><div class="sidebar-section-children"><a href="global.html#checkInconsistent">checkInconsistent</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsInHeader">checkMultiRowsInHeader</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsWithColspan">checkMultiRowsWithColspan</a></div><div class="sidebar-section-children"><a href="global.html#cleanBlank">cleanBlank</a></div><div class="sidebar-section-children"><a href="global.html#colCount">colCount</a></div><div class="sidebar-section-children"><a href="global.html#countBordersPct">countBordersPct</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleName">getAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleText">getAccessibleText</a></div><div class="sidebar-section-children"><a href="global.html#getAriaAttributes">getAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#getCSSGeneratedContent">getCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getColorContrast">getColorContrast</a></div><div class="sidebar-section-children"><a href="global.html#getComputedBackgroundColor">getComputedBackgroundColor</a></div><div class="sidebar-section-children"><a href="global.html#getComputedRole">getComputedRole</a></div><div class="sidebar-section-children"><a href="global.html#getFocusableElements">getFocusableElements</a></div><div class="sidebar-section-children"><a href="global.html#getGeneratedContent">getGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getImageText">getImageText</a></div><div class="sidebar-section-children"><a href="global.html#getStyleObject">getStyleObject</a></div><div class="sidebar-section-children"><a href="global.html#getTwoLetterCode">getTwoLetterCode</a></div><div class="sidebar-section-children"><a href="global.html#hasAccessibleName">hasAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#hasAttribute">hasAttribute</a></div><div class="sidebar-section-children"><a href="global.html#hasCSSGeneratedContent">hasCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#hasHiddenParent">hasHiddenParent</a></div><div class="sidebar-section-children"><a href="global.html#hasParent">hasParent</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaAttributes">hasValidAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaRole">hasValidAriaRole</a></div><div class="sidebar-section-children"><a href="global.html#isAriaAttributeValid">isAriaAttributeValid</a></div><div class="sidebar-section-children"><a href="global.html#isComplexTable">isComplexTable</a></div><div class="sidebar-section-children"><a href="global.html#isDataTable">isDataTable</a></div><div class="sidebar-section-children"><a href="global.html#isFocusable">isFocusable</a></div><div class="sidebar-section-children"><a href="global.html#isHidden">isHidden</a></div><div class="sidebar-section-children"><a href="global.html#isNotVisible">isNotVisible</a></div><div class="sidebar-section-children"><a href="global.html#isOffScreen">isOffScreen</a></div><div class="sidebar-section-children"><a href="global.html#isValidUrl">isValidUrl</a></div><div class="sidebar-section-children"><a href="global.html#isVisible">isVisible</a></div><div class="sidebar-section-children"><a href="global.html#langCodes">langCodes</a></div><div class="sidebar-section-children"><a href="global.html#luminance">luminance</a></div><div class="sidebar-section-children"><a href="global.html#matchesSelector">matchesSelector</a></div><div class="sidebar-section-children"><a href="global.html#parseRGB">parseRGB</a></div><div class="sidebar-section-children"><a href="global.html#rowCount">rowCount</a></div><div class="sidebar-section-children"><a href="global.html#rtls">rtls</a></div><div class="sidebar-section-children"><a href="global.html#sortByVisualOrder">sortByVisualOrder</a></div><div class="sidebar-section-children"><a href="global.html#strlen">strlen</a></div><div class="sidebar-section-children"><a href="global.html#testContrast">testContrast</a></div><div class="sidebar-section-children"><a href="global.html#testLang">testLang</a></div><div class="sidebar-section-children"><a href="global.html#testOrder">testOrder</a></div><div class="sidebar-section-children"><a href="global.html#validAriaAttributes">validAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#validLangCodes">validLangCodes</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">getAccessibleName.js</h1></header><article><pre class="prettyprint source lang-js"><code>import { isEmpty } from "./stringUtils.js";
4
+ import { getAccessibleText } from "./getAccessibleText.js";
5
+
6
+ /**
7
+ * Gets the accessible name of an element according to the accessible name calculation algorithm
8
+ * @param {Element} element - The DOM element to get the accessible name for
9
+ * @returns {string|boolean} The accessible name or false if none exists
10
+ */
11
+ function getAccessibleName(element) {
12
+ if (!element) return false;
13
+
14
+ // These are elements which are totally not able to be labeled at all.
15
+ // Even if the title attribute is valid per HTML for these elements,
16
+ // the title won't be used in any meaningful way by Accessibility APIs
17
+ const unlabellable =
18
+ "head *, hr, param, caption, colgroup, col, tbody, tfoot, thead, tr";
19
+
20
+ // STEP 0 - verify item is visible and can be labelled
21
+ // if it isn't visible or can't be labelled then just bail
22
+ if (isNotVisible(element) || matchesSelector(element, unlabellable)) {
23
+ return false;
24
+ }
25
+
26
+ let id, ids, label;
27
+
28
+ // STEP 1 - always check for aria-labelledby first
29
+ // STEP 1.1 - if aria-labelledby exists, check that the referenced element exists
30
+ // STEP 1.1.1 - return the text from the referenced item
31
+ if (element.hasAttribute("aria-labelledby")) {
32
+ ids = element.getAttribute("aria-labelledby").trim().split(" ");
33
+
34
+ const text = [];
35
+ for (const id of ids) {
36
+ const labelElement = document.getElementById(id);
37
+ if (!labelElement || !getAccessibleText(labelElement)) {
38
+ return false;
39
+ }
40
+ text.push(getAccessibleText(labelElement));
41
+ }
42
+
43
+ return text.join(" ");
44
+ }
45
+
46
+ // STEP 2 - (next) always check for aria-label second
47
+ // STEP 2.1 - if aria-label exists, return the text in it
48
+ if (element.hasAttribute("aria-label")) {
49
+ const ariaLabel = element.getAttribute("aria-label");
50
+ if (ariaLabel) {
51
+ return ariaLabel;
52
+ }
53
+ // there is no 'else' here because an empty aria-label is/ should be ignored and calculation continued
54
+ }
55
+
56
+ // STEP 3 - When it comes to AT, an object's ARIA role overrides native semantics for the object.
57
+ // Most ARIA controls/ widgets rely on labelling per steps 1 &amp; 2 above.
58
+ // If a label isn't found in Step 1 &amp; 2, we can (for some roles) use DOM subtree content to find the label.
59
+ // We check all of those here.
60
+ if (element.hasAttribute("role")) {
61
+ const roleValue = element.getAttribute("role");
62
+ const textRoles = [
63
+ "button", "checkbox", "columnheader", "gridcell", "heading", "link",
64
+ "listitem", "menuitem", "menuitemcheckbox", "menuitemradio", "option",
65
+ "radio", "row", "rowgroup", "rowheader", "tab", "tooltip", "treeitem"
66
+ ];
67
+
68
+ if (textRoles.includes(roleValue)) {
69
+ // quick sanity check to make sure the object can hold text in the first place and that it actually has text in it
70
+ if (!isEmpty(element.textContent)) {
71
+ return getAccessibleText(element);
72
+ }
73
+ }
74
+ }
75
+
76
+ // STEP 4: is the tag one of:
77
+ // input without any type, input type="text", input type="email", input type="password", input type="search", input type="tel", input type="url" and textarea element
78
+ // STEP 4.1 use the associated label
79
+ // STEP 4.3 Otherwise use the title attribute
80
+ // STEP 4.4 - return false. If none of the above yield a usable text string there is no accessible name
81
+ if (
82
+ matchesSelector(element,
83
+ 'input:not([type]), input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="tel"], input[type="url"], textarea'
84
+ )
85
+ ) {
86
+ // first we choose the explicit relationship over all others.
87
+ if (element.id &amp;&amp; document.querySelector('label[for="' + element.id + '"]')) {
88
+ id = element.id;
89
+ // Use only the *first* label that matches this ID.
90
+ // Sometimes JS libraries screw this up by hiding one of the labels or misnaming one
91
+ label = document.querySelector('label[for="' + id + '"]');
92
+ if (label) {
93
+ return getAccessibleText(label);
94
+ }
95
+ }
96
+
97
+ // if the element's parent is a label, use the text in that
98
+ else if (element.closest("label")) {
99
+ return getAccessibleText(element.closest("label"));
100
+ }
101
+
102
+ // title attribute is last resort
103
+ else if (element.hasAttribute("title")) {
104
+ if (strlen(element.getAttribute("title")) > 0) {
105
+ return element.getAttribute("title");
106
+ } else {
107
+ return false;
108
+ }
109
+ }
110
+
111
+ //if we got this far, there is no accessible name for this type of element
112
+ else {
113
+ return false;
114
+ }
115
+ }
116
+
117
+ // STEP 5: is the tag one of:
118
+ // input type="button", input type="submit" and input type="reset"
119
+ // STEP 5.1 use the value attribute
120
+ // STEP 5.2 For input type=submit: return localized string of the word "submit"
121
+ // STEP 5.3 For input type=reset: return localized string of the word "reset"
122
+ // STEP 5.4 For input type=button: return title attribute
123
+ // STEP 5.5 - return false. If none of the above yield a usable text string there is no accessible name
124
+ if (
125
+ matchesSelector(element,
126
+ 'input[type="button"], input[type="submit"], input[type="reset"]'
127
+ )
128
+ ) {
129
+ if (element.hasAttribute("value")) {
130
+ if (element.getAttribute("value")) {
131
+ return element.getAttribute("value");
132
+ }
133
+ } else if (matchesSelector(element, 'input[type="button"]')) {
134
+ if (element.hasAttribute("title")) {
135
+ return element.getAttribute("title");
136
+ }
137
+ return false;
138
+ }
139
+
140
+ // We really have no guarantee that these *specific* default values will be used by the browser
141
+ // And these return values are especially not accurate for non-english users,
142
+ // but we make a safe guess here anyway because getting the real name involves inspecting the Shadow DOM
143
+ // which we cannot do
144
+ else if (matchesSelector(element, 'input[type="submit"]')) {
145
+ if (element.hasAttribute("title")) {
146
+ return element.getAttribute("title");
147
+ } else {
148
+ return "Submit";
149
+ }
150
+ } else if (matchesSelector(element, 'input[type="reset"]')) {
151
+ if (element.hasAttribute("title")) {
152
+ return element.getAttribute("title");
153
+ } else {
154
+ return "Reset";
155
+ }
156
+ }
157
+ }
158
+
159
+ // STEP 6: input type="image"
160
+ // STEP 6.1: use alt attribute
161
+ // STEP 6.2: value attribute
162
+ // STEP 6.3: Otherwise the user agent may provide an accessible name via a localized string of the phrase "Submit Query"
163
+ // STEP 6.4: Otherwise use title attribute
164
+ // STEP 6.5: return false. If none of the above yield a usable text string there is no accessible name
165
+ if (matchesSelector(element, 'input[type="image"]')) {
166
+ if (element.hasAttribute("alt")) {
167
+ return element.getAttribute("alt");
168
+ } else if (element.hasAttribute("value")) {
169
+ return element.getAttribute("value");
170
+ } else if (element.hasAttribute("title")) {
171
+ return element.getAttribute("title");
172
+ } else {
173
+ return false;
174
+ }
175
+ }
176
+
177
+ // STEP 7: button element
178
+ // STEP 7.1: use the button element subtree
179
+ // STEP 7.2: use title attribute
180
+ // STEP 7.3: return false. If none of the above yield a usable text string there is no accessible name
181
+ if (element.tagName.toLowerCase() === "button") {
182
+ if (strlen(getAccessibleText(element)) > 0) {
183
+ return getAccessibleText(element);
184
+ } else if (element.hasAttribute("title")) {
185
+ return element.getAttribute("title");
186
+ } else {
187
+ return false;
188
+ }
189
+ }
190
+
191
+ // STEP 8: Other form elements
192
+ // STEP 8.1: use label element
193
+ // STEP 8.2: use title attribute
194
+ // STEP 8.3: return false. If none of the above yield a usable text string there is no accessible name
195
+ if (
196
+ matchesSelector(element,
197
+ 'select, input[type="checkbox"], input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="file"], input[type="month"], input[type="number"], input[type="radio"], input[type="range"], input[type="time"], input[type="week"]'
198
+ )
199
+ ) {
200
+ // first we choose the explicit relationship over all others.
201
+ if (element.id &amp;&amp; document.querySelector('label[for="' + element.id + '"]')) {
202
+ id = element.id;
203
+
204
+ //Use only the *first* label that matches this ID. Sometimes ppl screw this up
205
+ label = document.querySelector('label[for="' + id + '"]');
206
+ if (label) {
207
+ return getAccessibleText(label);
208
+ }
209
+ }
210
+
211
+ // if the element's parent is a label, use the text in that
212
+ else if (element.closest("label")) {
213
+ return getAccessibleText(element.closest("label"));
214
+ }
215
+
216
+ // title attribute is last resort
217
+ else if (element.hasAttribute("title")) {
218
+ return element.getAttribute("title");
219
+ }
220
+
221
+ //if we got this far, there is no accessible name
222
+ else {
223
+ return false;
224
+ }
225
+ }
226
+
227
+ // STEP 9: summary element
228
+ // STEP 9.1: use summary element subtree
229
+ // STEP 9.2: Otherwise use title attribute
230
+ // STEP 9.3: default: If none of the above yield a usable text string
231
+ // the user agent should provide its own text string (e.g. "Details")
232
+ // We really have no guarantee that these *specific* default values
233
+ // will be used by the browser
234
+ // And these return values are especially not accurate for
235
+ // non-english users, but we make a safe guess here anyway because
236
+ // like Submit buttons, getting the real value involves inspecting Shadow DOM
237
+ if (element.tagName.toLowerCase() === "details") {
238
+ const summary = element.querySelector("summary");
239
+ if (summary) {
240
+ if (strlen(getAccessibleText(summary)) > 0) {
241
+ return getAccessibleText(summary);
242
+ }
243
+ } else if (element.hasAttribute("title")) {
244
+ if (strlen(element.getAttribute("title")) > 0) {
245
+ return element.getAttribute("title");
246
+ } else {
247
+ return "Details";
248
+ }
249
+ } else {
250
+ return "Details";
251
+ }
252
+ }
253
+
254
+ // STEP 10: figure (and figcaption) elements
255
+ // STEP 10.1: figcaption subtree
256
+ // STEP 10.2: title attribute
257
+ // STEP 10.3: return false. If none of the above yield a usable text
258
+ // string there is no accessible name
259
+ if (element.tagName.toLowerCase() === "figure") {
260
+ const figcaption = element.querySelector("figcaption");
261
+ if (figcaption) {
262
+ if (strlen(getAccessibleText(figcaption)) > 0) {
263
+ return getAccessibleText(figcaption);
264
+ }
265
+ } else if (element.hasAttribute("title")) {
266
+ return element.getAttribute("title");
267
+ } else {
268
+ return false;
269
+ }
270
+ }
271
+
272
+ // STEP 11: img element
273
+ // STEP 11.1: use alt attribute
274
+ // STEP 11.2: use title attribute
275
+ // STEP 11.3: return false. If none of the above yield a usable
276
+ // text string there is no accessible name
277
+ if (element.tagName.toLowerCase() === "img") {
278
+ if (element.hasAttribute("alt")) {
279
+ return element.getAttribute("alt");
280
+ } else if (element.hasAttribute("title")) {
281
+ return element.getAttribute("title");
282
+ } else {
283
+ return false;
284
+ }
285
+ }
286
+
287
+ // STEP 11-1: area element that is linked
288
+ // STEP 11-1.1: use alt attribute
289
+ // STEP 11-1.2: use title attribute
290
+ // STEP 11-1.3: return false. If none of the above yield a usable
291
+ // text string there is no accessible name
292
+ if (matchesSelector(element, "area[href]")) {
293
+ if (element.hasAttribute("alt")) {
294
+ return element.getAttribute("alt");
295
+ } else if (element.hasAttribute("title")) {
296
+ return element.getAttribute("title");
297
+ } else {
298
+ return false;
299
+ }
300
+ }
301
+
302
+ // STEP 11-2: applet element
303
+ // STEP 11-2.1: use alt attribute
304
+ // STEP 11-2.3: return false. If none of the above yield a usable
305
+ // text string there is no accessible name
306
+ if (element.tagName.toLowerCase() === "applet") {
307
+ if (element.hasAttribute("alt")) {
308
+ return element.getAttribute("alt");
309
+ } else {
310
+ return false;
311
+ }
312
+ }
313
+
314
+ // STEP 12: table element
315
+ // STEP 12.1: caption element
316
+ // STEP 12.2: use the title attribute
317
+ // STEP 12.3: use the summary attribute
318
+ // STEP 12.4: return false. If none of the above yield a usable
319
+ // text string there is no accessible name
320
+ if (element.tagName.toLowerCase() === "table") {
321
+ const caption = element.querySelector("caption");
322
+ if (caption) {
323
+ if (strlen(getAccessibleText(caption)) > 0) {
324
+ return getAccessibleText(caption);
325
+ }
326
+ } else if (element.hasAttribute("title")) {
327
+ return element.getAttribute("title");
328
+ } else if (element.hasAttribute("summary")) {
329
+ return element.getAttribute("summary");
330
+ }
331
+ return false;
332
+ }
333
+
334
+ // STEP 13: a element that is linked
335
+ // STEP 13.1: use a element subtree
336
+ // STEP 13.2: the title attribute
337
+ // STEP 13.3: return false. If none of the above yield a usable
338
+ // text string there is no accessible name
339
+ if (matchesSelector(element, "a[href]")) {
340
+ if (strlen(getAccessibleText(element)) > 0) {
341
+ return getAccessibleText(element);
342
+ } else if (element.hasAttribute("title")) {
343
+ return element.getAttribute("title");
344
+ } else {
345
+ return false;
346
+ }
347
+ }
348
+
349
+ // STEP 14: Text level elements not listed elsewhere
350
+ // STEP 14.0: must be one of: em, strong, small, s, cite, q, dfn,
351
+ // abbr, time, code, var, samp, kbd, sub and sup, i, b, u, mark,
352
+ // ruby, rt, rp, bdi, bdo, br, wbr
353
+ // STEP 14.1: use the title attribute
354
+ // STEP 14.2: return false. If none of the above yield a usable
355
+ // text string there is no accessible name
356
+ if (
357
+ matchesSelector(element,
358
+ "em, strong, small, s, cite, q, dfn, abbr, time, code, var, samp, kbd, sub, sup, i, b, u, mark, ruby, rt, rp, bdi, bdo, br, wbr"
359
+ )
360
+ ) {
361
+ if (strlen(element.textContent) > 0) {
362
+ return element.textContent;
363
+ } else if (element.hasAttribute("title")) {
364
+ return element.getAttribute("title");
365
+ } else {
366
+ return false;
367
+ }
368
+ }
369
+
370
+ // Absolute last ditch for the whole plugin:
371
+ // use the accessible text from the element itself.
372
+ if (strlen(getAccessibleText(element)) > 0) {
373
+ return getAccessibleText(element);
374
+ }
375
+
376
+ // If we get here, there is no accessible name
377
+ else {
378
+ return false;
379
+ }
380
+ }
381
+
382
+ /**
383
+ * Helper function to check if element is NOT visible
384
+ * @param {Element} element - The element to check
385
+ * @returns {boolean} True if element is not visible, false otherwise
386
+ */
387
+ function isNotVisible(element) {
388
+ // Importing isVisible would be better, but for this standalone function we'll check it this way
389
+ if (!element) return true;
390
+
391
+ // These elements are inherently not visible
392
+ const nonVisibleSelectors = [
393
+ 'base', 'head', 'meta', 'title', 'link', 'style', 'script', 'br', 'nobr', 'col', 'embed',
394
+ 'input[type="hidden"]', 'keygen', 'source', 'track', 'wbr', 'datalist', 'area', 'param', 'noframes', 'ruby > rp'
395
+ ];
396
+
397
+ if (nonVisibleSelectors.some(selector => matchesSelector(element, selector))) {
398
+ return true; // Not visible in accessibility tree
399
+ }
400
+
401
+ // Check if display is none
402
+ const isElemDisplayed = el => window.getComputedStyle(el).display === 'none';
403
+
404
+ if (isElemDisplayed(element)) return true;
405
+
406
+ // Check parent elements
407
+ let parent = element.parentElement;
408
+ while (parent) {
409
+ if (isElemDisplayed(parent)) return true;
410
+ parent = parent.parentElement;
411
+ }
412
+
413
+ return element.getAttribute('aria-hidden') === 'true';
414
+ }
415
+
416
+ /**
417
+ * Helper function to check if an element matches a selector
418
+ * @param {Element} element - Element to check
419
+ * @param {string} selector - CSS selector to match against
420
+ * @returns {boolean} True if element matches the selector
421
+ */
422
+ function matchesSelector(element, selector) {
423
+ if (!element) return false;
424
+
425
+ // Use the right matches function depending on browser support
426
+ const matchesMethod = element.matches ||
427
+ element.mozMatchesSelector ||
428
+ element.msMatchesSelector;
429
+
430
+ // Handle multiple selectors (comma-separated)
431
+ if (selector.includes(',')) {
432
+ return selector.split(',').some(s => matchesMethod.call(element, s.trim()));
433
+ }
434
+
435
+ return matchesMethod.call(element, selector);
436
+ }
437
+
438
+ /**
439
+ * Get the length of a trimmed string, or return 0 if not a valid string
440
+ * @param {string} str - The string to measure
441
+ * @returns {number} The string length or 0
442
+ */
443
+ function strlen(str) {
444
+ return typeof str === "string" &amp;&amp; !isEmpty(str.trim()) ? str.trim().length : 0;
445
+ }
446
+
447
+ // Export as default for ES modules
448
+ export default getAccessibleName;
449
+
450
+ // Export the function for CommonJS module usage
451
+ if (typeof module !== 'undefined' &amp;&amp; module.exports) {
452
+ module.exports = getAccessibleName;
453
+ } else if (typeof window !== 'undefined') {
454
+ // Add to window object for browser usage
455
+ window.getAccessibleName = getAccessibleName;
456
+ }</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-afixt-test-utils.html">afixt-test-utils</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#arrayCount">arrayCount</a></div><div class="sidebar-section-children"><a href="global.html#arrayRemoveByValue">arrayRemoveByValue</a></div><div class="sidebar-section-children"><a href="global.html#arrayUnique">arrayUnique</a></div><div class="sidebar-section-children"><a href="global.html#cellColorDiffs">cellColorDiffs</a></div><div class="sidebar-section-children"><a href="global.html#cellCount">cellCount</a></div><div class="sidebar-section-children"><a href="global.html#checkInconsistent">checkInconsistent</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsInHeader">checkMultiRowsInHeader</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsWithColspan">checkMultiRowsWithColspan</a></div><div class="sidebar-section-children"><a href="global.html#cleanBlank">cleanBlank</a></div><div class="sidebar-section-children"><a href="global.html#colCount">colCount</a></div><div class="sidebar-section-children"><a href="global.html#countBordersPct">countBordersPct</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleName">getAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleText">getAccessibleText</a></div><div class="sidebar-section-children"><a href="global.html#getAriaAttributes">getAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#getCSSGeneratedContent">getCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getColorContrast">getColorContrast</a></div><div class="sidebar-section-children"><a href="global.html#getComputedBackgroundColor">getComputedBackgroundColor</a></div><div class="sidebar-section-children"><a href="global.html#getComputedRole">getComputedRole</a></div><div class="sidebar-section-children"><a href="global.html#getFocusableElements">getFocusableElements</a></div><div class="sidebar-section-children"><a href="global.html#getGeneratedContent">getGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getImageText">getImageText</a></div><div class="sidebar-section-children"><a href="global.html#getStyleObject">getStyleObject</a></div><div class="sidebar-section-children"><a href="global.html#getTwoLetterCode">getTwoLetterCode</a></div><div class="sidebar-section-children"><a href="global.html#hasAccessibleName">hasAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#hasAttribute">hasAttribute</a></div><div class="sidebar-section-children"><a href="global.html#hasCSSGeneratedContent">hasCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#hasHiddenParent">hasHiddenParent</a></div><div class="sidebar-section-children"><a href="global.html#hasParent">hasParent</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaAttributes">hasValidAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaRole">hasValidAriaRole</a></div><div class="sidebar-section-children"><a href="global.html#isAriaAttributeValid">isAriaAttributeValid</a></div><div class="sidebar-section-children"><a href="global.html#isComplexTable">isComplexTable</a></div><div class="sidebar-section-children"><a href="global.html#isDataTable">isDataTable</a></div><div class="sidebar-section-children"><a href="global.html#isFocusable">isFocusable</a></div><div class="sidebar-section-children"><a href="global.html#isHidden">isHidden</a></div><div class="sidebar-section-children"><a href="global.html#isNotVisible">isNotVisible</a></div><div class="sidebar-section-children"><a href="global.html#isOffScreen">isOffScreen</a></div><div class="sidebar-section-children"><a href="global.html#isValidUrl">isValidUrl</a></div><div class="sidebar-section-children"><a href="global.html#isVisible">isVisible</a></div><div class="sidebar-section-children"><a href="global.html#langCodes">langCodes</a></div><div class="sidebar-section-children"><a href="global.html#luminance">luminance</a></div><div class="sidebar-section-children"><a href="global.html#matchesSelector">matchesSelector</a></div><div class="sidebar-section-children"><a href="global.html#parseRGB">parseRGB</a></div><div class="sidebar-section-children"><a href="global.html#rowCount">rowCount</a></div><div class="sidebar-section-children"><a href="global.html#rtls">rtls</a></div><div class="sidebar-section-children"><a href="global.html#sortByVisualOrder">sortByVisualOrder</a></div><div class="sidebar-section-children"><a href="global.html#strlen">strlen</a></div><div class="sidebar-section-children"><a href="global.html#testContrast">testContrast</a></div><div class="sidebar-section-children"><a href="global.html#testLang">testLang</a></div><div class="sidebar-section-children"><a href="global.html#testOrder">testOrder</a></div><div class="sidebar-section-children"><a href="global.html#validAriaAttributes">validAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#validLangCodes">validLangCodes</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: getAccessibleText.js</title><!--[if lt IE 9]>
2
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
3
+ <![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-afixt-test-utils.html">afixt-test-utils</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#arrayCount">arrayCount</a></div><div class="sidebar-section-children"><a href="global.html#arrayRemoveByValue">arrayRemoveByValue</a></div><div class="sidebar-section-children"><a href="global.html#arrayUnique">arrayUnique</a></div><div class="sidebar-section-children"><a href="global.html#cellColorDiffs">cellColorDiffs</a></div><div class="sidebar-section-children"><a href="global.html#cellCount">cellCount</a></div><div class="sidebar-section-children"><a href="global.html#checkInconsistent">checkInconsistent</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsInHeader">checkMultiRowsInHeader</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsWithColspan">checkMultiRowsWithColspan</a></div><div class="sidebar-section-children"><a href="global.html#cleanBlank">cleanBlank</a></div><div class="sidebar-section-children"><a href="global.html#colCount">colCount</a></div><div class="sidebar-section-children"><a href="global.html#countBordersPct">countBordersPct</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleName">getAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleText">getAccessibleText</a></div><div class="sidebar-section-children"><a href="global.html#getAriaAttributes">getAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#getCSSGeneratedContent">getCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getColorContrast">getColorContrast</a></div><div class="sidebar-section-children"><a href="global.html#getComputedBackgroundColor">getComputedBackgroundColor</a></div><div class="sidebar-section-children"><a href="global.html#getComputedRole">getComputedRole</a></div><div class="sidebar-section-children"><a href="global.html#getFocusableElements">getFocusableElements</a></div><div class="sidebar-section-children"><a href="global.html#getGeneratedContent">getGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getImageText">getImageText</a></div><div class="sidebar-section-children"><a href="global.html#getStyleObject">getStyleObject</a></div><div class="sidebar-section-children"><a href="global.html#getTwoLetterCode">getTwoLetterCode</a></div><div class="sidebar-section-children"><a href="global.html#hasAccessibleName">hasAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#hasAttribute">hasAttribute</a></div><div class="sidebar-section-children"><a href="global.html#hasCSSGeneratedContent">hasCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#hasHiddenParent">hasHiddenParent</a></div><div class="sidebar-section-children"><a href="global.html#hasParent">hasParent</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaAttributes">hasValidAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaRole">hasValidAriaRole</a></div><div class="sidebar-section-children"><a href="global.html#isAriaAttributeValid">isAriaAttributeValid</a></div><div class="sidebar-section-children"><a href="global.html#isComplexTable">isComplexTable</a></div><div class="sidebar-section-children"><a href="global.html#isDataTable">isDataTable</a></div><div class="sidebar-section-children"><a href="global.html#isFocusable">isFocusable</a></div><div class="sidebar-section-children"><a href="global.html#isHidden">isHidden</a></div><div class="sidebar-section-children"><a href="global.html#isNotVisible">isNotVisible</a></div><div class="sidebar-section-children"><a href="global.html#isOffScreen">isOffScreen</a></div><div class="sidebar-section-children"><a href="global.html#isValidUrl">isValidUrl</a></div><div class="sidebar-section-children"><a href="global.html#isVisible">isVisible</a></div><div class="sidebar-section-children"><a href="global.html#langCodes">langCodes</a></div><div class="sidebar-section-children"><a href="global.html#luminance">luminance</a></div><div class="sidebar-section-children"><a href="global.html#matchesSelector">matchesSelector</a></div><div class="sidebar-section-children"><a href="global.html#parseRGB">parseRGB</a></div><div class="sidebar-section-children"><a href="global.html#rowCount">rowCount</a></div><div class="sidebar-section-children"><a href="global.html#rtls">rtls</a></div><div class="sidebar-section-children"><a href="global.html#sortByVisualOrder">sortByVisualOrder</a></div><div class="sidebar-section-children"><a href="global.html#strlen">strlen</a></div><div class="sidebar-section-children"><a href="global.html#testContrast">testContrast</a></div><div class="sidebar-section-children"><a href="global.html#testLang">testLang</a></div><div class="sidebar-section-children"><a href="global.html#testOrder">testOrder</a></div><div class="sidebar-section-children"><a href="global.html#validAriaAttributes">validAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#validLangCodes">validLangCodes</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">getAccessibleText.js</h1></header><article><pre class="prettyprint source lang-js"><code>import { isEmpty } from "./stringUtils.js";
4
+
5
+ /**
6
+ * Get all accessible text for an element, including aria-labels and content from children.
7
+ * @param {Element} el - The DOM element.
8
+ * @returns {string} The accessible text.
9
+ */
10
+ export function getAccessibleText(el) {
11
+ if (!el) return "";
12
+
13
+ let textContent = "";
14
+
15
+ // Check for element's own text content
16
+ if (el.textContent) {
17
+ textContent = el.textContent.trim();
18
+ }
19
+
20
+ // Check for aria-label
21
+ if (el.hasAttribute("aria-label")) {
22
+ const ariaLabel = el.getAttribute("aria-label").trim();
23
+ if (ariaLabel) {
24
+ // Prioritize aria-label if present
25
+ return ariaLabel;
26
+ }
27
+ }
28
+
29
+ // Check for img alt text
30
+ if (el.tagName.toLowerCase() === "img" &amp;&amp; el.hasAttribute("alt")) {
31
+ return el.getAttribute("alt").trim();
32
+ }
33
+
34
+ // Handle other elements by getting visible text
35
+ if (!textContent) {
36
+ const walker = document.createTreeWalker(
37
+ el,
38
+ NodeFilter.SHOW_TEXT,
39
+ {
40
+ acceptNode: function (node) {
41
+ // Only accept non-empty text nodes
42
+ return node.nodeType === Node.TEXT_NODE &amp;&amp; !isEmpty(node.nodeValue)
43
+ ? NodeFilter.FILTER_ACCEPT
44
+ : NodeFilter.FILTER_REJECT;
45
+ },
46
+ }
47
+ );
48
+
49
+ let textNodes = [];
50
+ let node;
51
+
52
+ while ((node = walker.nextNode())) {
53
+ textNodes.push(node.nodeValue.trim());
54
+ }
55
+
56
+ textContent = textNodes.join(" ").trim();
57
+ }
58
+
59
+ return textContent;
60
+ }
61
+
62
+ // Export for CommonJS module usage
63
+ if (typeof module !== 'undefined' &amp;&amp; module.exports) {
64
+ module.exports = { getAccessibleText };
65
+ }</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-afixt-test-utils.html">afixt-test-utils</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#arrayCount">arrayCount</a></div><div class="sidebar-section-children"><a href="global.html#arrayRemoveByValue">arrayRemoveByValue</a></div><div class="sidebar-section-children"><a href="global.html#arrayUnique">arrayUnique</a></div><div class="sidebar-section-children"><a href="global.html#cellColorDiffs">cellColorDiffs</a></div><div class="sidebar-section-children"><a href="global.html#cellCount">cellCount</a></div><div class="sidebar-section-children"><a href="global.html#checkInconsistent">checkInconsistent</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsInHeader">checkMultiRowsInHeader</a></div><div class="sidebar-section-children"><a href="global.html#checkMultiRowsWithColspan">checkMultiRowsWithColspan</a></div><div class="sidebar-section-children"><a href="global.html#cleanBlank">cleanBlank</a></div><div class="sidebar-section-children"><a href="global.html#colCount">colCount</a></div><div class="sidebar-section-children"><a href="global.html#countBordersPct">countBordersPct</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleName">getAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#getAccessibleText">getAccessibleText</a></div><div class="sidebar-section-children"><a href="global.html#getAriaAttributes">getAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#getCSSGeneratedContent">getCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getColorContrast">getColorContrast</a></div><div class="sidebar-section-children"><a href="global.html#getComputedBackgroundColor">getComputedBackgroundColor</a></div><div class="sidebar-section-children"><a href="global.html#getComputedRole">getComputedRole</a></div><div class="sidebar-section-children"><a href="global.html#getFocusableElements">getFocusableElements</a></div><div class="sidebar-section-children"><a href="global.html#getGeneratedContent">getGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#getImageText">getImageText</a></div><div class="sidebar-section-children"><a href="global.html#getStyleObject">getStyleObject</a></div><div class="sidebar-section-children"><a href="global.html#getTwoLetterCode">getTwoLetterCode</a></div><div class="sidebar-section-children"><a href="global.html#hasAccessibleName">hasAccessibleName</a></div><div class="sidebar-section-children"><a href="global.html#hasAttribute">hasAttribute</a></div><div class="sidebar-section-children"><a href="global.html#hasCSSGeneratedContent">hasCSSGeneratedContent</a></div><div class="sidebar-section-children"><a href="global.html#hasHiddenParent">hasHiddenParent</a></div><div class="sidebar-section-children"><a href="global.html#hasParent">hasParent</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaAttributes">hasValidAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#hasValidAriaRole">hasValidAriaRole</a></div><div class="sidebar-section-children"><a href="global.html#isAriaAttributeValid">isAriaAttributeValid</a></div><div class="sidebar-section-children"><a href="global.html#isComplexTable">isComplexTable</a></div><div class="sidebar-section-children"><a href="global.html#isDataTable">isDataTable</a></div><div class="sidebar-section-children"><a href="global.html#isFocusable">isFocusable</a></div><div class="sidebar-section-children"><a href="global.html#isHidden">isHidden</a></div><div class="sidebar-section-children"><a href="global.html#isNotVisible">isNotVisible</a></div><div class="sidebar-section-children"><a href="global.html#isOffScreen">isOffScreen</a></div><div class="sidebar-section-children"><a href="global.html#isValidUrl">isValidUrl</a></div><div class="sidebar-section-children"><a href="global.html#isVisible">isVisible</a></div><div class="sidebar-section-children"><a href="global.html#langCodes">langCodes</a></div><div class="sidebar-section-children"><a href="global.html#luminance">luminance</a></div><div class="sidebar-section-children"><a href="global.html#matchesSelector">matchesSelector</a></div><div class="sidebar-section-children"><a href="global.html#parseRGB">parseRGB</a></div><div class="sidebar-section-children"><a href="global.html#rowCount">rowCount</a></div><div class="sidebar-section-children"><a href="global.html#rtls">rtls</a></div><div class="sidebar-section-children"><a href="global.html#sortByVisualOrder">sortByVisualOrder</a></div><div class="sidebar-section-children"><a href="global.html#strlen">strlen</a></div><div class="sidebar-section-children"><a href="global.html#testContrast">testContrast</a></div><div class="sidebar-section-children"><a href="global.html#testLang">testLang</a></div><div class="sidebar-section-children"><a href="global.html#testOrder">testOrder</a></div><div class="sidebar-section-children"><a href="global.html#validAriaAttributes">validAriaAttributes</a></div><div class="sidebar-section-children"><a href="global.html#validLangCodes">validLangCodes</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>