govuk_publishing_components 21.16.3 → 21.17.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 (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,5 @@
1
1
  // Select and textarea is always allowed
2
- if (node.nodeName.toUpperCase() !== 'INPUT') {
2
+ if (virtualNode.props.nodeName !== 'input') {
3
3
  return true;
4
4
  }
5
5
 
@@ -34,7 +34,7 @@ if (typeof options === 'object') {
34
34
  });
35
35
  }
36
36
 
37
- const autocomplete = node.getAttribute('autocomplete');
37
+ const autocomplete = virtualNode.attr('autocomplete');
38
38
  const autocompleteTerms = autocomplete
39
39
  .split(/\s+/g)
40
40
  .map(term => term.toLowerCase());
@@ -55,8 +55,8 @@ const allowedTypes = allowedTypesMap[purposeTerm];
55
55
  * Reference HTML Spec - https://html.spec.whatwg.org/multipage/input.html#the-input-element to filter allowed values for `type`
56
56
  * and sanitize (https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm)
57
57
  */
58
- let type = node.hasAttribute('type')
59
- ? axe.commons.text.sanitize(node.getAttribute('type')).toLowerCase()
58
+ let type = virtualNode.hasAttr('type')
59
+ ? axe.commons.text.sanitize(virtualNode.attr('type')).toLowerCase()
60
60
  : 'text';
61
61
  type = axe.utils.validInputTypes().includes(type) ? type : 'text';
62
62
 
@@ -1,2 +1,2 @@
1
- const autocomplete = node.getAttribute('autocomplete') || '';
1
+ const autocomplete = virtualNode.attr('autocomplete') || '';
2
2
  return axe.commons.text.isValidAutocomplete(autocomplete, options);
@@ -2,6 +2,7 @@
2
2
  "id": "fieldset",
3
3
  "evaluate": "fieldset.js",
4
4
  "after": "fieldset-after.js",
5
+ "deprecated": true,
5
6
  "metadata": {
6
7
  "impact": "critical",
7
8
  "messages": {
@@ -2,6 +2,7 @@
2
2
  "id": "group-labelledby",
3
3
  "evaluate": "group-labelledby.js",
4
4
  "after": "group-labelledby-after.js",
5
+ "deprecated": true,
5
6
  "metadata": {
6
7
  "impact": "critical",
7
8
  "messages": {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Note:
3
+ * Check if given node contains focusable elements (excluding thyself)
4
+ */
5
+ const tabbableElements = virtualNode.tabbableElements;
6
+
7
+ if (!tabbableElements) {
8
+ return false;
9
+ }
10
+
11
+ // remove thyself from tabbable elements (if exists)
12
+ const tabbableContentElements = tabbableElements.filter(
13
+ el => el !== virtualNode
14
+ );
15
+
16
+ return tabbableContentElements.length > 0;
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "focusable-content",
3
+ "evaluate": "focusable-content.js",
4
+ "metadata": {
5
+ "impact": "moderate",
6
+ "messages": {
7
+ "pass": "Element contains focusable elements",
8
+ "fail": "Element should have focusable content"
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Note:
3
+ * Check
4
+ * - if element is focusable
5
+ * - if element is in focus order via `tabindex`
6
+ */
7
+ const isFocusable = virtualNode.isFocusable;
8
+
9
+ let tabIndex = parseInt(virtualNode.actualNode.getAttribute('tabindex'), 10);
10
+ tabIndex = !isNaN(tabIndex) ? tabIndex : null;
11
+
12
+ return tabIndex ? isFocusable && tabIndex >= 0 : isFocusable;
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "focusable-element",
3
+ "evaluate": "focusable-element.js",
4
+ "metadata": {
5
+ "impact": "moderate",
6
+ "messages": {
7
+ "pass": "Element is focusable",
8
+ "fail": "Element should be focusable"
9
+ }
10
+ }
11
+ }
@@ -1 +1,6 @@
1
- return node.tabIndex <= 0;
1
+ const tabIndex = parseInt(node.getAttribute('tabindex'), 10);
2
+
3
+ // an invalid tabindex will either return 0 or -1 (based on the element) so
4
+ // will never be above 0
5
+ // @see https://www.w3.org/TR/html51/editing.html#the-tabindex-attribute
6
+ return isNaN(tabIndex) ? true : tabIndex <= 0;
@@ -1,2 +1,3 @@
1
- const validAttrValue = /^\s+$/.test(node.getAttribute('alt'));
2
- return node.hasAttribute('alt') && validAttrValue;
1
+ const alt = virtualNode.attr('alt');
2
+ const isOnlySpace = /^\s+$/;
3
+ return typeof alt === 'string' && isOnlySpace.test(alt);
@@ -1,19 +1,22 @@
1
- const text = axe.commons.text.visibleVirtual(virtualNode, true).toLowerCase();
2
- if (text === '') {
1
+ const { aria, text, dom } = axe.commons;
2
+
3
+ if (['none', 'presentation'].includes(aria.getRole(node))) {
3
4
  return false;
4
5
  }
5
6
 
6
- // Get all visible images in the composed tree of the current node
7
- const images = axe.utils
8
- .querySelectorAll(virtualNode, 'img')
9
- // Ignore hidden or role=none/presentation images
10
- .filter(
11
- ({ actualNode }) =>
12
- axe.commons.dom.isVisible(actualNode) &&
13
- !['none', 'presentation'].includes(actualNode.getAttribute('role'))
14
- );
15
-
16
- // See if any of the images duplicate the node's text
17
- return images.some(
18
- img => text === axe.commons.text.accessibleTextVirtual(img).toLowerCase()
7
+ const parent = dom.findUpVirtual(
8
+ virtualNode,
9
+ 'button, [role="button"], a[href], p, li, td, th'
19
10
  );
11
+
12
+ if (!parent) {
13
+ return false;
14
+ }
15
+
16
+ const parentVNode = axe.utils.getNodeFromTree(parent);
17
+ const visibleText = text.visibleVirtual(parentVNode, true).toLowerCase();
18
+ if (visibleText === '') {
19
+ return false;
20
+ }
21
+
22
+ return visibleText === text.accessibleTextVirtual(virtualNode).toLowerCase();
@@ -1,13 +1,23 @@
1
1
  const { text } = axe.commons;
2
+ const { pixelThreshold, occuranceThreshold } = options || {};
2
3
 
3
4
  const accText = text.accessibleText(node).toLowerCase();
4
5
  if (text.isHumanInterpretable(accText) < 1) {
5
6
  return undefined;
6
7
  }
7
8
 
8
- const visibleText = text
9
- .sanitize(text.visibleVirtual(virtualNode))
10
- .toLowerCase();
9
+ const textVNodes = text.visibleTextNodes(virtualNode);
10
+ const nonLigatureText = textVNodes
11
+ .filter(
12
+ textVNode =>
13
+ !text.isIconLigature(textVNode, pixelThreshold, occuranceThreshold)
14
+ )
15
+ .map(textVNode => textVNode.actualNode.nodeValue)
16
+ .join('');
17
+ const visibleText = text.sanitize(nonLigatureText).toLowerCase();
18
+ if (!visibleText) {
19
+ return true;
20
+ }
11
21
  if (text.isHumanInterpretable(visibleText) < 1) {
12
22
  if (isStringContained(visibleText, accText)) {
13
23
  return true;
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "id": "label-content-name-mismatch",
3
3
  "evaluate": "label-content-name-mismatch.js",
4
+ "options": {
5
+ "pixelThreshold": 0.1,
6
+ "occuranceThreshold": 3
7
+ },
4
8
  "metadata": {
5
9
  "impact": "serious",
6
10
  "messages": {
@@ -1,18 +1,12 @@
1
1
  const id = axe.utils.escapeSelector(node.getAttribute('id'));
2
- let labels = Array.from(document.querySelectorAll(`label[for="${id}"]`));
3
2
  let parent = node.parentNode;
3
+ let root = axe.commons.dom.getRootNode(node);
4
+ root = root.documentElement || root;
5
+ let labels = Array.from(root.querySelectorAll(`label[for="${id}"]`));
4
6
 
5
7
  if (labels.length) {
6
- // filter out hidden labels because they're fine
7
- // except: fail first label if hidden because of VO
8
- labels = labels.filter(function(label, index) {
9
- if (
10
- (index === 0 && !axe.commons.dom.isVisible(label, true)) ||
11
- axe.commons.dom.isVisible(label, true)
12
- ) {
13
- return label;
14
- }
15
- });
8
+ // filter out CSS hidden labels because they're fine
9
+ labels = labels.filter(label => axe.commons.dom.isVisible(label));
16
10
  }
17
11
 
18
12
  while (parent) {
@@ -26,4 +20,20 @@ while (parent) {
26
20
  }
27
21
 
28
22
  this.relatedNodes(labels);
29
- return labels.length > 1;
23
+
24
+ // more than 1 CSS visible label
25
+ if (labels.length > 1) {
26
+ const ATVisibleLabels = labels.filter(label =>
27
+ axe.commons.dom.isVisible(label, true)
28
+ );
29
+ // more than 1 AT visible label will fail IOS/Safari/VO even with aria-labelledby
30
+ if (ATVisibleLabels.length > 1) {
31
+ return undefined;
32
+ }
33
+ // make sure the ONE AT visible label is in the list of idRefs of aria-labelledby
34
+ const labelledby = axe.commons.dom.idrefs(node, 'aria-labelledby');
35
+ return !labelledby.includes(ATVisibleLabels[0]) ? undefined : false;
36
+ }
37
+
38
+ // only 1 CSS visible label
39
+ return false;
@@ -5,7 +5,7 @@
5
5
  "impact": "moderate",
6
6
  "messages": {
7
7
  "pass": "Form field does not have multiple label elements",
8
- "fail": "Multiple label elements is not widely supported in assistive technologies"
8
+ "incomplete": "Multiple label elements is not widely supported in assistive technologies. Ensure the first label contains all necessary information."
9
9
  }
10
10
  }
11
11
  }
@@ -0,0 +1,23 @@
1
+ var uniqueLandmarks = [];
2
+
3
+ // filter out landmark elements that share the same role and accessible text
4
+ // so every non-unique landmark isn't reported as a failure (just the first)
5
+ return results.filter(currentResult => {
6
+ var findMatch = someResult => {
7
+ return (
8
+ currentResult.data.role === someResult.data.role &&
9
+ currentResult.data.accessibleText === someResult.data.accessibleText
10
+ );
11
+ };
12
+
13
+ var matchedResult = uniqueLandmarks.find(findMatch);
14
+ if (matchedResult) {
15
+ matchedResult.result = false;
16
+ matchedResult.relatedNodes.push(currentResult.relatedNodes[0]);
17
+ return false;
18
+ }
19
+
20
+ uniqueLandmarks.push(currentResult);
21
+ currentResult.relatedNodes = [];
22
+ return true;
23
+ });
@@ -0,0 +1,7 @@
1
+ var role = axe.commons.aria.getRole(node);
2
+ var accessibleText = axe.commons.text.accessibleTextVirtual(virtualNode);
3
+ accessibleText = accessibleText ? accessibleText.toLowerCase() : null;
4
+ this.data({ role: role, accessibleText: accessibleText });
5
+ this.relatedNodes([node]);
6
+
7
+ return true;
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "landmark-is-unique",
3
+ "evaluate": "landmark-is-unique.js",
4
+ "after": "landmark-is-unique-after.js",
5
+ "metadata": {
6
+ "impact": "moderate",
7
+ "messages": {
8
+ "pass": "Landmarks must have a unique role or role/label/title (i.e. accessible name) combination",
9
+ "fail": "The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable"
10
+ }
11
+ }
12
+ }
@@ -12,6 +12,7 @@ if (parentRole === 'list') {
12
12
  }
13
13
 
14
14
  if (parentRole && axe.commons.aria.isValidRole(parentRole)) {
15
+ this.data('roleNotValid');
15
16
  return false;
16
17
  }
17
18
 
@@ -5,7 +5,7 @@
5
5
  "impact": "serious",
6
6
  "messages": {
7
7
  "pass": "List item has a <ul>, <ol> or role=\"list\" parent element",
8
- "fail": "List item does not have a <ul>, <ol> or role=\"list\" parent element"
8
+ "fail": "List item does not have a <ul>, <ol>{{? it.data === 'roleNotValid'}} without a role, or a role=\"list\"{{?}} parent element"
9
9
  }
10
10
  }
11
11
  }
@@ -16,10 +16,6 @@ let base = {
16
16
  };
17
17
 
18
18
  let out = virtualNode.children.reduce((out, { actualNode }) => {
19
- /*eslint
20
- max-statements: ["error", 20]
21
- complexity: ["error", 12]
22
- */
23
19
  const tagName = actualNode.nodeName.toUpperCase();
24
20
 
25
21
  if (actualNode.nodeType === 1 && dom.isVisible(actualNode, true, false)) {
@@ -61,8 +61,8 @@ Object.keys(rulesGroupByDocumentFragment).forEach(key => {
61
61
  // eg: screen and (max-width: 767px) and (min-width: 320px) and (orientation: landscape)
62
62
  const cssText = r.cssText;
63
63
  return (
64
- /orientation:\s+landscape/i.test(cssText) ||
65
- /orientation:\s+portrait/i.test(cssText)
64
+ /orientation:\s*landscape/i.test(cssText) ||
65
+ /orientation:\s*portrait/i.test(cssText)
66
66
  );
67
67
  });
68
68
  if (!orientationRules || !orientationRules.length) {
@@ -78,8 +78,6 @@ Object.keys(rulesGroupByDocumentFragment).forEach(key => {
78
78
  // a media query has framents of css styles applied to various selectors
79
79
  // iteration through cssRules and see if orientation lock has been applied
80
80
  Array.from(r.cssRules).forEach(cssRule => {
81
- /* eslint max-statements: ["error", 20], complexity: ["error", 15] */
82
-
83
81
  // ensure selectorText exists
84
82
  if (!cssRule.selectorText) {
85
83
  return;
@@ -89,8 +87,12 @@ Object.keys(rulesGroupByDocumentFragment).forEach(key => {
89
87
  return;
90
88
  }
91
89
 
92
- // check if transform style exists
93
- const transformStyleValue = cssRule.style.transform || false;
90
+ // check if transform style exists (don't forget vendor prefixes)
91
+ const transformStyleValue =
92
+ cssRule.style.transform ||
93
+ cssRule.style.webkitTransform ||
94
+ cssRule.style.msTransform ||
95
+ false;
94
96
  // transformStyleValue -> is the value applied to property
95
97
  // eg: "rotate(-90deg)"
96
98
  if (!transformStyleValue) {
@@ -1,17 +1,4 @@
1
1
  const { dom, aria } = axe.commons;
2
-
3
- // Return the skplink, if any
4
- function getSkiplink(virtualNode) {
5
- const firstLink = axe.utils.querySelectorAll(virtualNode, 'a[href]')[0];
6
- if (
7
- firstLink &&
8
- axe.commons.dom.getElementByReference(firstLink.actualNode, 'href')
9
- ) {
10
- return firstLink.actualNode;
11
- }
12
- }
13
-
14
- const skipLink = getSkiplink(virtualNode);
15
2
  const landmarkRoles = aria.getRolesByType('landmark');
16
3
 
17
4
  // Create a list of nodeNames that have a landmark as an implicit role
@@ -19,11 +6,6 @@ const implicitLandmarks = landmarkRoles
19
6
  .reduce((arr, role) => arr.concat(aria.implicitNodes(role)), [])
20
7
  .filter(r => r !== null);
21
8
 
22
- // Check if the current element is the skiplink
23
- function isSkipLink(vNode) {
24
- return skipLink && skipLink === vNode.actualNode;
25
- }
26
-
27
9
  // Check if the current element is a landmark
28
10
  function isRegion(virtualNode) {
29
11
  const node = virtualNode.actualNode;
@@ -61,7 +43,8 @@ function findRegionlessElms(virtualNode) {
61
43
  // End recursion if the element is a landmark, skiplink, or hidden content
62
44
  if (
63
45
  isRegion(virtualNode) ||
64
- isSkipLink(virtualNode) ||
46
+ (dom.isSkipLink(virtualNode.actualNode) &&
47
+ dom.getElementByReference(virtualNode.actualNode, 'href')) ||
65
48
  !dom.isVisible(node, true)
66
49
  ) {
67
50
  return [];
@@ -0,0 +1,18 @@
1
+ const inlineSpacingCssProperties = [
2
+ 'line-height',
3
+ 'letter-spacing',
4
+ 'word-spacing'
5
+ ];
6
+
7
+ const overriddenProperties = inlineSpacingCssProperties.filter(property => {
8
+ if (node.style.getPropertyPriority(property) === `important`) {
9
+ return property;
10
+ }
11
+ });
12
+
13
+ if (overriddenProperties.length > 0) {
14
+ this.data(overriddenProperties);
15
+ return false;
16
+ }
17
+
18
+ return true;
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "avoid-inline-spacing",
3
+ "evaluate": "avoid-inline-spacing.js",
4
+ "metadata": {
5
+ "impact": "serious",
6
+ "messages": {
7
+ "pass": "No inline styles with '!important' that affect text spacing has been specified",
8
+ "fail": "Remove '!important' from inline style{{=it.data && it.data.length > 1 ? 's' : ''}} {{=it.data.join(', ')}}, as overriding this is not supported by most browsers"
9
+ }
10
+ }
11
+ }
@@ -1 +1 @@
1
- return true;
1
+ return undefined;
@@ -5,7 +5,7 @@
5
5
  "impact": "minor",
6
6
  "messages": {
7
7
  "pass": "Element does not exist",
8
- "fail": "Element exists"
8
+ "incomplete": "Element exists"
9
9
  }
10
10
  }
11
11
  }