govuk_publishing_components 21.16.3 → 21.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/component_guide/accessibility-test.js +0 -6
  3. data/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml +7 -0
  4. data/lib/govuk_publishing_components/presenters/machine_readable/dataset_schema.rb +34 -0
  5. data/lib/govuk_publishing_components/presenters/schema_org.rb +3 -0
  6. data/lib/govuk_publishing_components/version.rb +1 -1
  7. data/node_modules/axe-core/CHANGELOG.md +166 -2
  8. data/node_modules/axe-core/CONTRIBUTING.md +5 -5
  9. data/node_modules/axe-core/README.md +4 -4
  10. data/node_modules/axe-core/axe.d.ts +27 -11
  11. data/node_modules/axe-core/axe.js +9597 -2431
  12. data/node_modules/axe-core/axe.min.js +2 -2
  13. data/node_modules/axe-core/bower.json +1 -1
  14. data/node_modules/axe-core/doc/API.md +211 -128
  15. data/node_modules/axe-core/doc/accessibility-supported.md +1 -1
  16. data/node_modules/axe-core/doc/aria-supported.md +4 -13
  17. data/node_modules/axe-core/doc/backwards-compatibility-doc.md +93 -0
  18. data/node_modules/axe-core/doc/code-submission-guidelines.md +4 -4
  19. data/node_modules/axe-core/doc/developer-guide.md +27 -13
  20. data/node_modules/axe-core/doc/examples/chrome-debugging-protocol/package.json +5 -2
  21. data/node_modules/axe-core/doc/examples/jasmine/README.md +3 -5
  22. data/node_modules/axe-core/doc/examples/jasmine/karma.conf.js +29 -0
  23. data/node_modules/axe-core/doc/examples/jasmine/package.json +6 -5
  24. data/node_modules/axe-core/doc/examples/jest_react/README.md +1 -1
  25. data/node_modules/axe-core/doc/examples/jest_react/link.test.js +3 -3
  26. data/node_modules/axe-core/doc/examples/jest_react/package.json +9 -9
  27. data/node_modules/axe-core/doc/examples/jsdom/package.json +15 -0
  28. data/node_modules/axe-core/doc/examples/mocha/README.md +5 -7
  29. data/node_modules/axe-core/doc/examples/mocha/karma.conf.js +29 -0
  30. data/node_modules/axe-core/doc/examples/mocha/package.json +7 -6
  31. data/node_modules/axe-core/doc/examples/phantomjs/README.md +3 -3
  32. data/node_modules/axe-core/doc/examples/phantomjs/axe-phantom.js +4 -2
  33. data/node_modules/axe-core/doc/examples/phantomjs/package.json +3 -3
  34. data/node_modules/axe-core/doc/examples/puppeteer/package.json +5 -2
  35. data/node_modules/axe-core/doc/examples/qunit/README.md +2 -2
  36. data/node_modules/axe-core/doc/examples/qunit/package.json +2 -2
  37. data/node_modules/axe-core/doc/examples/test-examples.js +32 -0
  38. data/node_modules/axe-core/doc/plugins.md +10 -10
  39. data/node_modules/axe-core/doc/projects.md +12 -8
  40. data/node_modules/axe-core/doc/rule-descriptions.md +87 -79
  41. data/node_modules/axe-core/doc/rule-development.md +30 -2
  42. data/node_modules/axe-core/lib/checks/aria/allowed-attr.js +1 -1
  43. data/node_modules/axe-core/lib/checks/aria/aria-roledescription.js +14 -0
  44. data/node_modules/axe-core/lib/checks/aria/aria-roledescription.json +23 -0
  45. data/node_modules/axe-core/lib/checks/aria/no-implicit-explicit-label.js +21 -0
  46. data/node_modules/axe-core/lib/checks/aria/no-implicit-explicit-label.json +11 -0
  47. data/node_modules/axe-core/lib/checks/aria/required-attr.js +32 -7
  48. data/node_modules/axe-core/lib/checks/aria/required-children.js +40 -14
  49. data/node_modules/axe-core/lib/checks/aria/required-children.json +12 -1
  50. data/node_modules/axe-core/lib/checks/aria/required-parent.js +1 -1
  51. data/node_modules/axe-core/lib/checks/aria/unsupportedattr.js +1 -1
  52. data/node_modules/axe-core/lib/checks/aria/valid-attr-value.js +50 -17
  53. data/node_modules/axe-core/lib/checks/aria/valid-attr-value.json +2 -1
  54. data/node_modules/axe-core/lib/checks/aria/valid-attr.js +1 -1
  55. data/node_modules/axe-core/lib/checks/color/color-contrast.js +2 -2
  56. data/node_modules/axe-core/lib/checks/forms/autocomplete-appropriate.js +4 -4
  57. data/node_modules/axe-core/lib/checks/forms/autocomplete-valid.js +1 -1
  58. data/node_modules/axe-core/lib/checks/forms/fieldset.json +1 -0
  59. data/node_modules/axe-core/lib/checks/forms/group-labelledby.json +1 -0
  60. data/node_modules/axe-core/lib/checks/keyboard/focusable-content.js +16 -0
  61. data/node_modules/axe-core/lib/checks/keyboard/focusable-content.json +11 -0
  62. data/node_modules/axe-core/lib/checks/keyboard/focusable-element.js +12 -0
  63. data/node_modules/axe-core/lib/checks/keyboard/focusable-element.json +11 -0
  64. data/node_modules/axe-core/lib/checks/keyboard/tabindex.js +6 -1
  65. data/node_modules/axe-core/lib/checks/label/alt-space-value.js +3 -2
  66. data/node_modules/axe-core/lib/checks/label/duplicate-img-label.js +18 -15
  67. data/node_modules/axe-core/lib/checks/label/label-content-name-mismatch.js +13 -3
  68. data/node_modules/axe-core/lib/checks/label/label-content-name-mismatch.json +4 -0
  69. data/node_modules/axe-core/lib/checks/label/multiple-label.js +22 -12
  70. data/node_modules/axe-core/lib/checks/label/multiple-label.json +1 -1
  71. data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique-after.js +23 -0
  72. data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique.js +7 -0
  73. data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique.json +12 -0
  74. data/node_modules/axe-core/lib/checks/lists/listitem.js +1 -0
  75. data/node_modules/axe-core/lib/checks/lists/listitem.json +1 -1
  76. data/node_modules/axe-core/lib/checks/lists/only-listitems.js +0 -4
  77. data/node_modules/axe-core/lib/checks/mobile/css-orientation-lock.js +8 -6
  78. data/node_modules/axe-core/lib/checks/navigation/region.js +2 -19
  79. data/node_modules/axe-core/lib/checks/shared/avoid-inline-spacing.js +18 -0
  80. data/node_modules/axe-core/lib/checks/shared/avoid-inline-spacing.json +11 -0
  81. data/node_modules/axe-core/lib/checks/shared/exists.js +1 -1
  82. data/node_modules/axe-core/lib/checks/shared/exists.json +1 -1
  83. data/node_modules/axe-core/lib/checks/shared/has-alt.js +6 -4
  84. data/node_modules/axe-core/lib/checks/shared/non-empty-alt.js +1 -1
  85. data/node_modules/axe-core/lib/checks/tables/caption-faked.json +1 -1
  86. data/node_modules/axe-core/lib/checks/tables/td-has-header.js +5 -4
  87. data/node_modules/axe-core/lib/checks/tables/th-has-data-cells.js +19 -29
  88. data/node_modules/axe-core/lib/commons/aria/get-owned-virtual.js +1 -1
  89. data/node_modules/axe-core/lib/commons/aria/index.js +50 -46
  90. data/node_modules/axe-core/lib/commons/aria/is-accessible-ref.js +41 -37
  91. data/node_modules/axe-core/lib/commons/aria/label-virtual.js +2 -2
  92. data/node_modules/axe-core/lib/commons/aria/roles.js +1 -1
  93. data/node_modules/axe-core/lib/commons/aria/validate-attr-value.js +0 -1
  94. data/node_modules/axe-core/lib/commons/color/center-point-of-rect.js +30 -0
  95. data/node_modules/axe-core/lib/commons/color/contrast.js +7 -1
  96. data/node_modules/axe-core/lib/commons/color/element-has-image.js +36 -0
  97. data/node_modules/axe-core/lib/commons/color/get-background-color.js +332 -306
  98. data/node_modules/axe-core/lib/commons/color/get-foreground-color.js +35 -6
  99. data/node_modules/axe-core/lib/commons/color/get-own-background-color.js +22 -0
  100. data/node_modules/axe-core/lib/commons/dom/find-up.js +5 -5
  101. data/node_modules/axe-core/lib/commons/dom/get-scroll-offset.js +0 -1
  102. data/node_modules/axe-core/lib/commons/dom/get-tabbable-elements.js +1 -1
  103. data/node_modules/axe-core/lib/commons/dom/has-content-virtual.js +7 -5
  104. data/node_modules/axe-core/lib/commons/dom/is-focusable.js +8 -5
  105. data/node_modules/axe-core/lib/commons/dom/is-hidden-with-css.js +15 -2
  106. data/node_modules/axe-core/lib/commons/dom/is-in-text-block.js +1 -2
  107. data/node_modules/axe-core/lib/commons/dom/is-skip-link.js +45 -0
  108. data/node_modules/axe-core/lib/commons/dom/is-visible.js +43 -17
  109. data/node_modules/axe-core/lib/commons/dom/is-visual-content.js +0 -1
  110. data/node_modules/axe-core/lib/commons/dom/visually-contains.js +0 -1
  111. data/node_modules/axe-core/lib/commons/dom/visually-overlaps.js +0 -1
  112. data/node_modules/axe-core/lib/commons/forms/index.js +8 -0
  113. data/node_modules/axe-core/lib/commons/forms/is-aria-combobox.js +13 -0
  114. data/node_modules/axe-core/lib/commons/forms/is-aria-listbox.js +13 -0
  115. data/node_modules/axe-core/lib/commons/forms/is-aria-range.js +14 -0
  116. data/node_modules/axe-core/lib/commons/forms/is-aria-textbox.js +13 -0
  117. data/node_modules/axe-core/lib/commons/forms/is-native-select.js +13 -0
  118. data/node_modules/axe-core/lib/commons/forms/is-native-textbox.js +28 -0
  119. data/node_modules/axe-core/lib/commons/table/get-cell-position.js +2 -2
  120. data/node_modules/axe-core/lib/commons/table/get-headers.js +55 -11
  121. data/node_modules/axe-core/lib/commons/table/get-scope.js +1 -1
  122. data/node_modules/axe-core/lib/commons/table/is-data-table.js +0 -1
  123. data/node_modules/axe-core/lib/commons/table/to-grid.js +2 -2
  124. data/node_modules/axe-core/lib/commons/text/accessible-text-virtual.js +5 -5
  125. data/node_modules/axe-core/lib/commons/text/form-control-value.js +18 -30
  126. data/node_modules/axe-core/lib/commons/text/is-icon-ligature.js +210 -0
  127. data/node_modules/axe-core/lib/commons/text/is-valid-autocomplete.js +0 -1
  128. data/node_modules/axe-core/lib/commons/text/label-text.js +1 -1
  129. data/node_modules/axe-core/lib/commons/text/label-virtual.js +1 -1
  130. data/node_modules/axe-core/lib/commons/text/native-text-methods.js +1 -1
  131. data/node_modules/axe-core/lib/commons/text/subtree-text.js +3 -3
  132. data/node_modules/axe-core/lib/commons/text/unicode.js +15 -0
  133. data/node_modules/axe-core/lib/commons/text/visible-text-nodes.js +25 -0
  134. data/node_modules/axe-core/lib/commons/text/visible-virtual.js +1 -1
  135. data/node_modules/axe-core/lib/core/base/audit.js +90 -15
  136. data/node_modules/axe-core/lib/core/base/cache.js +33 -0
  137. data/node_modules/axe-core/lib/core/base/check.js +48 -1
  138. data/node_modules/axe-core/lib/core/base/context.js +15 -14
  139. data/node_modules/axe-core/lib/core/base/rule.js +223 -46
  140. data/node_modules/axe-core/lib/core/base/virtual-node/abstract-virtual-node.js +40 -0
  141. data/node_modules/axe-core/lib/core/base/virtual-node/serial-virtual-node.js +86 -0
  142. data/node_modules/axe-core/lib/core/base/virtual-node/virtual-node.js +85 -0
  143. data/node_modules/axe-core/lib/core/constants.js +10 -2
  144. data/node_modules/axe-core/lib/core/imports/index.js +28 -3
  145. data/node_modules/axe-core/lib/core/index.js +2 -4
  146. data/node_modules/axe-core/lib/core/public/configure.js +28 -1
  147. data/node_modules/axe-core/lib/core/public/run-rules.js +2 -0
  148. data/node_modules/axe-core/lib/core/public/run-virtual-rule.js +50 -0
  149. data/node_modules/axe-core/lib/core/public/run.js +13 -2
  150. data/node_modules/axe-core/lib/core/reporters/helpers/process-aggregate.js +1 -1
  151. data/node_modules/axe-core/lib/core/reporters/na.js +4 -0
  152. data/node_modules/axe-core/lib/core/reporters/raw-env.js +12 -0
  153. data/node_modules/axe-core/lib/core/reporters/raw.js +25 -1
  154. data/node_modules/axe-core/lib/core/utils/are-styles-set.js +4 -7
  155. data/node_modules/axe-core/lib/core/utils/assert.js +12 -0
  156. data/node_modules/axe-core/lib/core/utils/collect-results-from-frames.js +2 -2
  157. data/node_modules/axe-core/lib/core/utils/contains.js +27 -13
  158. data/node_modules/axe-core/lib/core/utils/css-parser.js +2 -0
  159. data/node_modules/axe-core/lib/core/utils/element-matches.js +5 -1
  160. data/node_modules/axe-core/lib/core/utils/escape-selector.js +1 -2
  161. data/node_modules/axe-core/lib/core/utils/flattened-tree.js +47 -61
  162. data/node_modules/axe-core/lib/core/utils/get-check-option.js +0 -1
  163. data/node_modules/axe-core/lib/core/utils/get-friendly-uri-end.js +1 -1
  164. data/node_modules/axe-core/lib/core/utils/get-node-attributes.js +21 -0
  165. data/node_modules/axe-core/lib/core/utils/get-scroll.js +39 -0
  166. data/node_modules/axe-core/lib/core/utils/get-selector.js +9 -6
  167. data/node_modules/axe-core/lib/core/utils/get-stylesheet-factory.js +51 -0
  168. data/node_modules/axe-core/lib/core/utils/get-xpath.js +0 -1
  169. data/node_modules/axe-core/lib/core/utils/is-hidden.js +16 -4
  170. data/node_modules/axe-core/lib/core/utils/is-html-element.js +5 -5
  171. data/node_modules/axe-core/lib/core/utils/is-shadow-root.js +3 -3
  172. data/node_modules/axe-core/lib/core/utils/memoize.js +17 -0
  173. data/node_modules/axe-core/lib/core/utils/parse-crossorigin-stylesheet.js +53 -0
  174. data/node_modules/axe-core/lib/core/utils/parse-sameorigin-stylesheet.js +96 -0
  175. data/node_modules/axe-core/lib/core/utils/parse-stylesheet.js +70 -0
  176. data/node_modules/axe-core/lib/core/utils/performance-timer.js +7 -2
  177. data/node_modules/axe-core/lib/core/utils/preload-cssom.js +77 -281
  178. data/node_modules/axe-core/lib/core/utils/preload.js +49 -23
  179. data/node_modules/axe-core/lib/core/utils/qsa.js +39 -50
  180. data/node_modules/axe-core/lib/core/utils/respondable.js +20 -3
  181. data/node_modules/axe-core/lib/core/utils/rule-should-run.js +0 -1
  182. data/node_modules/axe-core/lib/core/utils/scroll-state.js +12 -25
  183. data/node_modules/axe-core/lib/core/utils/select.js +12 -23
  184. data/node_modules/axe-core/lib/core/utils/uuid.js +1 -2
  185. data/node_modules/axe-core/lib/intro.stub +1 -1
  186. data/node_modules/axe-core/lib/misc/incomplete-fallback.json +1 -1
  187. data/node_modules/axe-core/lib/rules/aria-allowed-attr-matches.js +1 -1
  188. data/node_modules/axe-core/lib/rules/aria-form-field-name-matches.js +50 -0
  189. data/node_modules/axe-core/lib/rules/aria-has-attr-matches.js +1 -1
  190. data/node_modules/axe-core/lib/rules/aria-hidden-focus.json +1 -1
  191. data/node_modules/axe-core/lib/rules/aria-input-field-name.json +13 -0
  192. data/node_modules/axe-core/lib/rules/aria-roledescription.json +12 -0
  193. data/node_modules/axe-core/lib/rules/aria-toggle-field-name.json +18 -0
  194. data/node_modules/axe-core/lib/rules/autocomplete-matches.js +14 -10
  195. data/node_modules/axe-core/lib/rules/avoid-inline-spacing.json +12 -0
  196. data/node_modules/axe-core/lib/rules/button-name.json +3 -5
  197. data/node_modules/axe-core/lib/rules/checkboxgroup.json +2 -1
  198. data/node_modules/axe-core/lib/rules/color-contrast-matches.js +37 -22
  199. data/node_modules/axe-core/lib/rules/duplicate-id-active-matches.js +1 -1
  200. data/node_modules/axe-core/lib/rules/duplicate-id-misc-matches.js +2 -2
  201. data/node_modules/axe-core/lib/rules/form-field-multiple-labels.json +1 -1
  202. data/node_modules/axe-core/lib/rules/html-has-lang.json +1 -0
  203. data/node_modules/axe-core/lib/rules/image-alt.json +1 -1
  204. data/node_modules/axe-core/lib/rules/img-redundant-alt.json +3 -3
  205. data/node_modules/axe-core/lib/rules/input-button-name.json +26 -0
  206. data/node_modules/axe-core/lib/rules/landmark-unique-matches.js +41 -0
  207. data/node_modules/axe-core/lib/rules/landmark-unique.json +13 -0
  208. data/node_modules/axe-core/lib/rules/link-name.json +5 -4
  209. data/node_modules/axe-core/lib/rules/meta-refresh.json +8 -1
  210. data/node_modules/axe-core/lib/rules/radiogroup.json +2 -1
  211. data/node_modules/axe-core/lib/rules/role-img-alt.json +18 -0
  212. data/node_modules/axe-core/lib/rules/scrollable-region-focusable-matches.js +30 -0
  213. data/node_modules/axe-core/lib/rules/scrollable-region-focusable.json +12 -0
  214. data/node_modules/axe-core/lib/rules/skip-link-matches.js +1 -1
  215. data/node_modules/axe-core/lib/rules/skip-link.json +1 -1
  216. data/node_modules/axe-core/lib/rules/video-description.json +3 -1
  217. data/node_modules/axe-core/locales/de.json +1 -5
  218. data/node_modules/axe-core/locales/es.json +773 -0
  219. data/node_modules/axe-core/locales/fr.json +15 -19
  220. data/node_modules/axe-core/locales/ja.json +65 -11
  221. data/node_modules/axe-core/locales/ko.json +777 -0
  222. data/node_modules/axe-core/locales/nl.json +35 -35
  223. data/node_modules/axe-core/locales/pt_BR.json +773 -0
  224. data/node_modules/axe-core/package.json +56 -52
  225. data/node_modules/axe-core/sri-history.json +20 -0
  226. data/node_modules/axe-core/typings/axe-core/axe-core-tests.ts +5 -15
  227. data/node_modules/govuk-frontend/package.json +10 -10
  228. metadata +62 -4
  229. data/node_modules/axe-core/doc/axelogo2018.png +0 -0
  230. data/node_modules/axe-core/lib/rules/role-not-button-matches.js +0 -1
@@ -1,5 +1,30 @@
1
1
  /* global axe, color */
2
2
 
3
+ function getOpacity(node) {
4
+ if (!node) {
5
+ return 1;
6
+ }
7
+
8
+ const vNode = axe.utils.getNodeFromTree(node);
9
+
10
+ if (vNode && vNode._opacity !== undefined && vNode._opacity !== null) {
11
+ return vNode._opacity;
12
+ }
13
+
14
+ const nodeStyle = window.getComputedStyle(node);
15
+ const opacity = nodeStyle.getPropertyValue('opacity');
16
+ const finalOpacity = opacity * getOpacity(node.parentElement);
17
+
18
+ // cache the results of the getOpacity check on the parent tree
19
+ // so we don't have to look at the parent tree again for all its
20
+ // descendants
21
+ if (vNode) {
22
+ vNode._opacity = finalOpacity;
23
+ }
24
+
25
+ return finalOpacity;
26
+ }
27
+
3
28
  /**
4
29
  * Returns the flattened foreground color of an element, or null if it can't be determined because
5
30
  * of transparency
@@ -8,22 +33,26 @@
8
33
  * @instance
9
34
  * @param {Element} node
10
35
  * @param {Boolean} noScroll (default false)
36
+ * @param {Color} bgColor
11
37
  * @return {Color|null}
12
38
  */
13
- color.getForegroundColor = function(node, noScroll) {
14
- var nodeStyle = window.getComputedStyle(node);
39
+ color.getForegroundColor = function(node, noScroll, bgColor) {
40
+ const nodeStyle = window.getComputedStyle(node);
15
41
 
16
- var fgColor = new color.Color();
42
+ const fgColor = new color.Color();
17
43
  fgColor.parseRgbString(nodeStyle.getPropertyValue('color'));
18
- var opacity = nodeStyle.getPropertyValue('opacity');
44
+ const opacity = getOpacity(node);
19
45
  fgColor.alpha = fgColor.alpha * opacity;
20
46
  if (fgColor.alpha === 1) {
21
47
  return fgColor;
22
48
  }
23
49
 
24
- var bgColor = color.getBackgroundColor(node, [], noScroll);
50
+ if (!bgColor) {
51
+ bgColor = color.getBackgroundColor(node, [], noScroll);
52
+ }
53
+
25
54
  if (bgColor === null) {
26
- var reason = axe.commons.color.incompleteData.get('bgColor');
55
+ const reason = axe.commons.color.incompleteData.get('bgColor');
27
56
  axe.commons.color.incompleteData.set('fgColor', reason);
28
57
  return null;
29
58
  }
@@ -0,0 +1,22 @@
1
+ /* global color */
2
+
3
+ /**
4
+ * Returns the non-alpha-blended background color of an element
5
+ *
6
+ * @method getOwnBackgroundColor
7
+ * @memberof axe.commons.color
8
+ *
9
+ * @param {Object} elmStyle style of the element
10
+ * @return {Color}
11
+ */
12
+ color.getOwnBackgroundColor = function getOwnBackgroundColor(elmStyle) {
13
+ const bgColor = new color.Color();
14
+ bgColor.parseRgbString(elmStyle.getPropertyValue('background-color'));
15
+
16
+ if (bgColor.alpha !== 0) {
17
+ const opacity = elmStyle.getPropertyValue('opacity');
18
+ bgColor.alpha = bgColor.alpha * opacity;
19
+ }
20
+
21
+ return bgColor;
22
+ };
@@ -11,10 +11,7 @@
11
11
  * @return {HTMLElement|null} Either the matching HTMLElement or `null` if there was no match
12
12
  */
13
13
  dom.findUp = function(element, target) {
14
- return dom.findUpVirtual(
15
- axe.utils.getNodeFromTree(axe._tree[0], element),
16
- target
17
- );
14
+ return dom.findUpVirtual(axe.utils.getNodeFromTree(element), target);
18
15
  };
19
16
 
20
17
  /**
@@ -29,7 +26,6 @@ dom.findUp = function(element, target) {
29
26
  * @return {HTMLElement|null} Either the matching HTMLElement or `null` if there was no match
30
27
  */
31
28
  dom.findUpVirtual = function(element, target) {
32
- /*eslint complexity: ["error", 12]*/
33
29
  let parent;
34
30
 
35
31
  parent = element.actualNode;
@@ -56,6 +52,10 @@ dom.findUpVirtual = function(element, target) {
56
52
  parent !== document.documentElement
57
53
  );
58
54
 
55
+ if (!parent) {
56
+ return null;
57
+ }
58
+
59
59
  if (!axe.utils.matchesSelector(parent, target)) {
60
60
  return null;
61
61
  }
@@ -1,5 +1,4 @@
1
1
  /* global dom */
2
- /*eslint complexity: ["error", 14]*/
3
2
  /**
4
3
  * Get the scroll offset of the document passed in
5
4
  * @method getScrollOffset
@@ -1,7 +1,7 @@
1
1
  /* global dom */
2
2
 
3
3
  /**
4
- * Get all elements (including given node) that are part if the tab order
4
+ * Get all elements (including given node) that are part of the tab order
5
5
  * @method getTabbableElements
6
6
  * @memberof axe.commons.dom
7
7
  * @instance
@@ -29,16 +29,17 @@ function hasChildTextNodes(elm) {
29
29
  * @instance
30
30
  * @param {VirtualNode} elm Virtual Node to search
31
31
  * @param {Boolean} noRecursion If true, only the element is checked, otherwise it will search all child nodes
32
+ * @param {Boolean} ignoreAria if true, ignores `aria label` computation for content deduction
32
33
  * @return {Boolean}
33
34
  */
34
- dom.hasContentVirtual = function(elm, noRecursion) {
35
+ dom.hasContentVirtual = function(elm, noRecursion, ignoreAria) {
35
36
  return (
36
37
  // It has text
37
38
  hasChildTextNodes(elm) ||
38
39
  // It is a graphical element
39
40
  dom.isVisualContent(elm.actualNode) ||
40
41
  // It has an ARIA label
41
- !!aria.labelVirtual(elm) ||
42
+ (!ignoreAria && !!aria.labelVirtual(elm)) ||
42
43
  // or one of it's descendants does
43
44
  (!noRecursion &&
44
45
  elm.children.some(
@@ -56,11 +57,12 @@ dom.hasContentVirtual = function(elm, noRecursion) {
56
57
  * @instance
57
58
  * @param {DOMNode} elm DOMNode element to check
58
59
  * @param {Boolean} noRecursion If true, only the element is checked, otherwise it will search all child nodes
60
+ * @param {Boolean} ignoreAria if true, ignores `aria label` computation for content deduction
59
61
  * @return {Boolean}
60
62
  */
61
- dom.hasContent = function hasContent(elm, noRecursion) {
62
- elm = axe.utils.getNodeFromTree(axe._tree[0], elm);
63
- return dom.hasContentVirtual(elm, noRecursion);
63
+ dom.hasContent = function hasContent(elm, noRecursion, ignoreAria) {
64
+ elm = axe.utils.getNodeFromTree(elm);
65
+ return dom.hasContentVirtual(elm, noRecursion, ignoreAria);
64
66
  };
65
67
 
66
68
  /**
@@ -1,5 +1,4 @@
1
1
  /* global dom */
2
- /* eslint complexity: ["error",20] */
3
2
 
4
3
  /**
5
4
  * Determines if focusing has been disabled on an element.
@@ -9,7 +8,7 @@
9
8
  function focusDisabled(el) {
10
9
  return (
11
10
  el.disabled ||
12
- (dom.isHiddenWithCSS(el) && el.nodeName.toUpperCase() !== 'AREA')
11
+ (el.nodeName.toUpperCase() !== 'AREA' && dom.isHiddenWithCSS(el))
13
12
  );
14
13
  }
15
14
 
@@ -84,7 +83,11 @@ dom.isNativelyFocusable = function(el) {
84
83
  * if its tabindex were removed. Else, false.
85
84
  */
86
85
  dom.insertedIntoFocusOrder = function(el) {
87
- return (
88
- el.tabIndex > -1 && dom.isFocusable(el) && !dom.isNativelyFocusable(el)
89
- );
86
+ let tabIndex = parseInt(el.getAttribute('tabindex'), 10);
87
+
88
+ // an element that has an invalid tabindex will return 0 or -1 based on
89
+ // if it is natively focusable or not, which will always be false for this
90
+ // check as NaN is not > 1
91
+ // @see https://www.w3.org/TR/html51/editing.html#the-tabindex-attribute
92
+ return tabIndex > -1 && dom.isFocusable(el) && !dom.isNativelyFocusable(el);
90
93
  };
@@ -1,4 +1,3 @@
1
- /* eslint complexity: ["error", 13], max-statements: ["error", 25] */
2
1
  /* global dom */
3
2
 
4
3
  /**
@@ -11,6 +10,20 @@
11
10
  * @return {Boolean} the element's hidden status
12
11
  */
13
12
  dom.isHiddenWithCSS = function isHiddenWithCSS(el, descendentVisibilityValue) {
13
+ const vNode = axe.utils.getNodeFromTree(el);
14
+
15
+ if (!vNode) {
16
+ return _isHiddenWithCSS(el, descendentVisibilityValue);
17
+ }
18
+
19
+ if (vNode._isHiddenWithCSS === void 0) {
20
+ vNode._isHiddenWithCSS = _isHiddenWithCSS(el, descendentVisibilityValue);
21
+ }
22
+
23
+ return vNode._isHiddenWithCSS;
24
+ };
25
+
26
+ function _isHiddenWithCSS(el, descendentVisibilityValue) {
14
27
  if (el.nodeType === 9) {
15
28
  // 9 === Node.DOCUMENT
16
29
  return false;
@@ -57,4 +70,4 @@ dom.isHiddenWithCSS = function isHiddenWithCSS(el, descendentVisibilityValue) {
57
70
  return dom.isHiddenWithCSS(parent, visibilityValue);
58
71
  }
59
72
  return false;
60
- };
73
+ }
@@ -17,7 +17,7 @@ function getBlockParent(node) {
17
17
  while (parentBlock && !isBlock(parentBlock)) {
18
18
  parentBlock = dom.getComposedParent(parentBlock);
19
19
  }
20
- return axe.utils.getNodeFromTree(axe._tree[0], parentBlock);
20
+ return axe.utils.getNodeFromTree(parentBlock);
21
21
  }
22
22
 
23
23
  /**
@@ -26,7 +26,6 @@ function getBlockParent(node) {
26
26
  * @return {Boolean} [description]
27
27
  */
28
28
  dom.isInTextBlock = function isInTextBlock(node) {
29
- /* eslint complexity: ["error",17]*/
30
29
  if (isBlock(node)) {
31
30
  // Ignore if the link is a block
32
31
  return false;
@@ -0,0 +1,45 @@
1
+ /* global dom */
2
+
3
+ // test for hrefs that start with # or /# (for angular)
4
+ const isInternalLinkRegex = /^\/?#[^/!]/;
5
+
6
+ /**
7
+ * Determines if element is a skip link
8
+ * @method isSkipLink
9
+ * @memberof axe.commons.dom
10
+ * @instance
11
+ * @param {Element} element
12
+ * @return {Boolean}
13
+ */
14
+ dom.isSkipLink = function(element) {
15
+ if (!isInternalLinkRegex.test(element.getAttribute('href'))) {
16
+ return false;
17
+ }
18
+
19
+ let firstPageLink;
20
+ if (typeof axe._cache.get('firstPageLink') !== 'undefined') {
21
+ firstPageLink = axe._cache.get('firstPageLink');
22
+ } else {
23
+ // define a skip link as any anchor element whose href starts with `#...`
24
+ // and which precedes the first anchor element whose href doesn't start
25
+ // with `#...` (that is, a link to a page)
26
+ firstPageLink = axe.utils.querySelectorAll(
27
+ axe._tree,
28
+ 'a:not([href^="#"]):not([href^="/#"]):not([href^="javascript"])'
29
+ )[0];
30
+
31
+ // null will signify no first page link
32
+ axe._cache.set('firstPageLink', firstPageLink || null);
33
+ }
34
+
35
+ // if there are no page links then all all links will need to be
36
+ // considered as skip links
37
+ if (!firstPageLink) {
38
+ return true;
39
+ }
40
+
41
+ return (
42
+ element.compareDocumentPosition(firstPageLink.actualNode) ===
43
+ element.DOCUMENT_POSITION_FOLLOWING
44
+ );
45
+ };
@@ -1,22 +1,39 @@
1
1
  /* global dom */
2
- /* eslint complexity: ["error", 20] */
2
+ const clipRegex = /rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/;
3
+ const clipPathRegex = /(\w+)\((\d+)/;
3
4
 
4
5
  /**
5
- * Determines if an element is hidden with the clip rect technique
6
+ * Determines if an element is hidden with a clip or clip-path technique
6
7
  * @method isClipped
7
8
  * @memberof axe.commons.dom
8
9
  * @private
9
- * @param {String} clip Computed property value of clip
10
+ * @param {CSSStyleDeclaration} style Computed style
10
11
  * @return {Boolean}
11
12
  */
12
- function isClipped(clip) {
13
+ function isClipped(style) {
13
14
  'use strict';
14
15
 
15
- var matches = clip.match(
16
- /rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/
17
- );
18
- if (matches && matches.length === 5) {
19
- return matches[3] - matches[1] <= 0 && matches[2] - matches[4] <= 0;
16
+ const matchesClip = style.getPropertyValue('clip').match(clipRegex);
17
+ const matchesClipPath = style
18
+ .getPropertyValue('clip-path')
19
+ .match(clipPathRegex);
20
+ if (matchesClip && matchesClip.length === 5) {
21
+ return (
22
+ matchesClip[3] - matchesClip[1] <= 0 &&
23
+ matchesClip[2] - matchesClip[4] <= 0
24
+ );
25
+ }
26
+ if (matchesClipPath) {
27
+ const type = matchesClipPath[1];
28
+ const value = parseInt(matchesClipPath[2], 10);
29
+
30
+ switch (type) {
31
+ case 'inset':
32
+ return value >= 50;
33
+ case 'circle':
34
+ return value === 0;
35
+ default:
36
+ }
20
37
  }
21
38
 
22
39
  return false;
@@ -33,9 +50,9 @@ function isClipped(clip) {
33
50
  * @return {Boolean} The element's visibilty status
34
51
  */
35
52
  dom.isVisible = function(el, screenReader, recursed) {
36
- //eslint complexity: 13
37
53
  'use strict';
38
- var style, nodeName, parent;
54
+ const node = axe.utils.getNodeFromTree(el);
55
+ const cacheName = '_isVisible' + (screenReader ? 'ScreenReader' : '');
39
56
 
40
57
  // 9 === Node.DOCUMENT
41
58
  if (el.nodeType === 9) {
@@ -47,17 +64,21 @@ dom.isVisible = function(el, screenReader, recursed) {
47
64
  el = el.host; // grab the host Node
48
65
  }
49
66
 
50
- style = window.getComputedStyle(el, null);
67
+ if (node && typeof node[cacheName] !== 'undefined') {
68
+ return node[cacheName];
69
+ }
70
+
71
+ const style = window.getComputedStyle(el, null);
51
72
  if (style === null) {
52
73
  return false;
53
74
  }
54
75
 
55
- nodeName = el.nodeName.toUpperCase();
76
+ const nodeName = el.nodeName.toUpperCase();
56
77
 
57
78
  if (
58
79
  style.getPropertyValue('display') === 'none' ||
59
80
  ['STYLE', 'SCRIPT', 'NOSCRIPT', 'TEMPLATE'].includes(nodeName) ||
60
- (!screenReader && isClipped(style.getPropertyValue('clip'))) ||
81
+ (!screenReader && isClipped(style)) ||
61
82
  (!recursed &&
62
83
  // visibility is only accurate on the first element
63
84
  (style.getPropertyValue('visibility') === 'hidden' ||
@@ -68,10 +89,15 @@ dom.isVisible = function(el, screenReader, recursed) {
68
89
  return false;
69
90
  }
70
91
 
71
- parent = el.assignedSlot ? el.assignedSlot : el.parentNode;
92
+ const parent = el.assignedSlot ? el.assignedSlot : el.parentNode;
93
+ let isVisible = false;
72
94
  if (parent) {
73
- return dom.isVisible(parent, screenReader, true);
95
+ isVisible = dom.isVisible(parent, screenReader, true);
74
96
  }
75
97
 
76
- return false;
98
+ if (node) {
99
+ node[cacheName] = isVisible;
100
+ }
101
+
102
+ return isVisible;
77
103
  };
@@ -1,5 +1,4 @@
1
1
  /*global dom */
2
- /*eslint complexity: ["error",20] */
3
2
 
4
3
  const visualRoles = [
5
4
  'checkbox',
@@ -1,5 +1,4 @@
1
1
  /* global dom */
2
- /* eslint complexity: ["error",17] */
3
2
 
4
3
  /**
5
4
  * Checks whether a parent element visually contains its child, either directly or via scrolling.
@@ -1,5 +1,4 @@
1
1
  /* global dom */
2
- /* eslint complexity: ["error",15] */
3
2
 
4
3
  /**
5
4
  * Checks whether a parent element visually overlaps a rectangle, either directly or via scrolling.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Namespace for forms-related utilities.
3
+ * @namespace commons.forms
4
+ * @memberof axe
5
+ */
6
+
7
+ var forms = {};
8
+ commons.forms = forms;
@@ -0,0 +1,13 @@
1
+ /* global forms */
2
+
3
+ /**
4
+ * Determines if an element is an aria combobox element
5
+ * @method isAriaCombobox
6
+ * @memberof axe.commons.forms
7
+ * @param {Element} node Node to determine if aria combobox
8
+ * @returns {Bool}
9
+ */
10
+ forms.isAriaCombobox = function(node) {
11
+ const role = axe.commons.aria.getRole(node, { noImplicit: true });
12
+ return role === 'combobox';
13
+ };
@@ -0,0 +1,13 @@
1
+ /* global forms */
2
+
3
+ /**
4
+ * Determines if an element is an aria listbox element
5
+ * @method isAriaListbox
6
+ * @memberof axe.commons.forms
7
+ * @param {Element} node Node to determine if aria listbox
8
+ * @returns {Bool}
9
+ */
10
+ forms.isAriaListbox = function(node) {
11
+ const role = axe.commons.aria.getRole(node, { noImplicit: true });
12
+ return role === 'listbox';
13
+ };