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,4 +1,6 @@
1
- var nn = node.nodeName.toLowerCase();
2
- return (
3
- node.hasAttribute('alt') && (nn === 'img' || nn === 'input' || nn === 'area')
4
- );
1
+ const { nodeName } = virtualNode.props;
2
+ if (!['img', 'input', 'area'].includes(nodeName)) {
3
+ return false;
4
+ }
5
+
6
+ return virtualNode.hasAttr('alt');
@@ -1,2 +1,2 @@
1
- var label = node.getAttribute('alt');
1
+ const label = virtualNode.attr('alt');
2
2
  return !!(label ? axe.commons.text.sanitize(label).trim() : '');
@@ -5,7 +5,7 @@
5
5
  "impact": "serious",
6
6
  "messages": {
7
7
  "pass": "The first row of a table is not used as a caption",
8
- "fail": "The first row of the table should be a caption instead of a table cell"
8
+ "fail": "The first child of the table should be a caption instead of a table cell"
9
9
  }
10
10
  }
11
11
  }
@@ -1,6 +1,7 @@
1
- var tableUtils = axe.commons.table;
2
- var badCells = [];
3
- var cells = tableUtils.getAllCells(node);
1
+ const tableUtils = axe.commons.table;
2
+ const badCells = [];
3
+ const cells = tableUtils.getAllCells(node);
4
+ const tableGrid = tableUtils.toGrid(node);
4
5
 
5
6
  cells.forEach(cell => {
6
7
  // For each non-empty data cell that doesn't have an aria label
@@ -10,7 +11,7 @@ cells.forEach(cell => {
10
11
  !axe.commons.aria.label(cell)
11
12
  ) {
12
13
  // Check if it has any headers
13
- const hasHeaders = tableUtils.getHeaders(cell).some(header => {
14
+ const hasHeaders = tableUtils.getHeaders(cell, tableGrid).some(header => {
14
15
  return header !== null && !!axe.commons.dom.hasContent(header);
15
16
  });
16
17
 
@@ -1,23 +1,23 @@
1
- var tableUtils = axe.commons.table;
2
- var cells = tableUtils.getAllCells(node);
3
- var checkResult = this;
1
+ const tableUtils = axe.commons.table;
2
+ const cells = tableUtils.getAllCells(node);
3
+ const checkResult = this;
4
4
 
5
5
  // Get a list of all headers reffed to in this rule
6
- var reffedHeaders = [];
6
+ let reffedHeaders = [];
7
7
  cells.forEach(function(cell) {
8
- var headers = cell.getAttribute('headers');
8
+ const headers = cell.getAttribute('headers');
9
9
  if (headers) {
10
10
  reffedHeaders = reffedHeaders.concat(headers.split(/\s+/));
11
11
  }
12
12
 
13
- var ariaLabel = cell.getAttribute('aria-labelledby');
13
+ const ariaLabel = cell.getAttribute('aria-labelledby');
14
14
  if (ariaLabel) {
15
15
  reffedHeaders = reffedHeaders.concat(ariaLabel.split(/\s+/));
16
16
  }
17
17
  });
18
18
 
19
19
  // Get all the headers
20
- var headers = cells.filter(function(cell) {
20
+ const headers = cells.filter(function(cell) {
21
21
  if (axe.commons.text.sanitize(cell.textContent) === '') {
22
22
  return false;
23
23
  }
@@ -27,42 +27,32 @@ var headers = cells.filter(function(cell) {
27
27
  );
28
28
  });
29
29
 
30
- var tableGrid = tableUtils.toGrid(node);
30
+ const tableGrid = tableUtils.toGrid(node);
31
31
 
32
- // Look for all the bad headers
33
- var out = headers.reduce(function(res, header) {
32
+ let out = true;
33
+ headers.forEach(header => {
34
34
  if (
35
35
  header.getAttribute('id') &&
36
36
  reffedHeaders.includes(header.getAttribute('id'))
37
37
  ) {
38
- return !res ? res : true;
38
+ return;
39
39
  }
40
40
 
41
- var hasCell = false;
42
- var pos = tableUtils.getCellPosition(header, tableGrid);
41
+ const pos = tableUtils.getCellPosition(header, tableGrid);
43
42
 
44
- // Look for any data cells or row headers that this might refer to
43
+ // ensure column header has at least 1 non-header cell
44
+ let hasCell = false;
45
45
  if (tableUtils.isColumnHeader(header)) {
46
46
  hasCell = tableUtils
47
47
  .traverse('down', pos, tableGrid)
48
- .reduce((out, cell) => {
49
- return (
50
- out ||
51
- (axe.commons.dom.hasContent(cell) && !tableUtils.isColumnHeader(cell))
52
- );
53
- }, false);
48
+ .find(cell => !tableUtils.isColumnHeader(cell));
54
49
  }
55
50
 
56
- // Look for any data cells or column headers that this might refer to
51
+ // ensure row header has at least 1 non-header cell
57
52
  if (!hasCell && tableUtils.isRowHeader(header)) {
58
53
  hasCell = tableUtils
59
54
  .traverse('right', pos, tableGrid)
60
- .reduce((out, cell) => {
61
- return (
62
- out ||
63
- (axe.commons.dom.hasContent(cell) && !tableUtils.isRowHeader(cell))
64
- );
65
- }, false);
55
+ .find(cell => !tableUtils.isRowHeader(cell));
66
56
  }
67
57
 
68
58
  // report the node as having failed
@@ -70,7 +60,7 @@ var out = headers.reduce(function(res, header) {
70
60
  checkResult.relatedNodes(header);
71
61
  }
72
62
 
73
- return res && hasCell;
74
- }, true);
63
+ out = out && hasCell;
64
+ });
75
65
 
76
66
  return out ? true : undefined;
@@ -16,7 +16,7 @@ aria.getOwnedVirtual = function getOwned({ actualNode, children }) {
16
16
 
17
17
  return dom.idrefs(actualNode, 'aria-owns').reduce((ownedElms, element) => {
18
18
  if (element) {
19
- const virtualNode = axe.utils.getNodeFromTree(axe._tree[0], element);
19
+ const virtualNode = axe.utils.getNodeFromTree(element);
20
20
  ownedElms.push(virtualNode);
21
21
  }
22
22
  return ownedElms;
@@ -198,20 +198,7 @@ lookupTable.attributes = {
198
198
  'aria-roledescription': {
199
199
  type: 'string',
200
200
  allowEmpty: true,
201
- unsupported: {
202
- exceptions: [
203
- 'button',
204
- {
205
- nodeName: 'input',
206
- properties: {
207
- type: ['button', 'checkbox', 'image', 'radio', 'reset', 'submit']
208
- }
209
- },
210
- 'img',
211
- 'select',
212
- 'summary'
213
- ]
214
- }
201
+ unsupported: false
215
202
  },
216
203
  'aria-rowcount': {
217
204
  type: 'int',
@@ -455,7 +442,7 @@ lookupTable.role = {
455
442
  {
456
443
  nodeName: 'input',
457
444
  properties: {
458
- type: 'text'
445
+ type: ['text', 'search', 'tel', 'url', 'email']
459
446
  }
460
447
  }
461
448
  ]
@@ -624,7 +611,9 @@ lookupTable.role = {
624
611
  attributes: {
625
612
  allowed: ['aria-expanded', 'aria-errormessage']
626
613
  },
627
- owned: null,
614
+ owned: {
615
+ one: ['doc-biblioentry']
616
+ },
628
617
  nameFrom: ['author'],
629
618
  context: null,
630
619
  unsupported: false,
@@ -746,7 +735,9 @@ lookupTable.role = {
746
735
  attributes: {
747
736
  allowed: ['aria-expanded', 'aria-errormessage']
748
737
  },
749
- owned: ['doc-endnote'],
738
+ owned: {
739
+ one: ['doc-endnote']
740
+ },
750
741
  namefrom: ['author'],
751
742
  context: null,
752
743
  unsupported: false,
@@ -1024,7 +1015,7 @@ lookupTable.role = {
1024
1015
  },
1025
1016
  figure: {
1026
1017
  type: 'structure',
1027
- unsupported: true
1018
+ unsupported: false
1028
1019
  },
1029
1020
  form: {
1030
1021
  type: 'landmark',
@@ -1174,6 +1165,7 @@ lookupTable.role = {
1174
1165
  allowed: [
1175
1166
  'aria-activedescendant',
1176
1167
  'aria-multiselectable',
1168
+ 'aria-readonly',
1177
1169
  'aria-required',
1178
1170
  'aria-expanded',
1179
1171
  'aria-orientation',
@@ -1280,7 +1272,9 @@ lookupTable.role = {
1280
1272
  'aria-errormessage'
1281
1273
  ]
1282
1274
  },
1283
- owned: null,
1275
+ owned: {
1276
+ one: ['menuitem', 'menuitemradio', 'menuitemcheckbox']
1277
+ },
1284
1278
  nameFrom: ['author'],
1285
1279
  context: null,
1286
1280
  unsupported: false,
@@ -1550,9 +1544,9 @@ lookupTable.role = {
1550
1544
  'aria-posinset',
1551
1545
  'aria-setsize',
1552
1546
  'aria-required',
1553
- 'aria-errormessage'
1554
- ],
1555
- required: ['aria-checked']
1547
+ 'aria-errormessage',
1548
+ 'aria-checked'
1549
+ ]
1556
1550
  },
1557
1551
  owned: null,
1558
1552
  nameFrom: ['author', 'contents'],
@@ -1653,7 +1647,7 @@ lookupTable.role = {
1653
1647
  all: ['row']
1654
1648
  },
1655
1649
  nameFrom: ['author', 'contents'],
1656
- context: ['grid', 'table'],
1650
+ context: ['grid', 'table', 'treegrid'],
1657
1651
  implicit: ['tbody', 'thead', 'tfoot'],
1658
1652
  unsupported: false
1659
1653
  },
@@ -1682,13 +1676,14 @@ lookupTable.role = {
1682
1676
  scrollbar: {
1683
1677
  type: 'widget',
1684
1678
  attributes: {
1685
- required: [
1686
- 'aria-controls',
1687
- 'aria-valuenow',
1679
+ required: ['aria-controls', 'aria-valuenow'],
1680
+ allowed: [
1681
+ 'aria-valuetext',
1682
+ 'aria-orientation',
1683
+ 'aria-errormessage',
1688
1684
  'aria-valuemax',
1689
1685
  'aria-valuemin'
1690
- ],
1691
- allowed: ['aria-valuetext', 'aria-orientation', 'aria-errormessage']
1686
+ ]
1692
1687
  },
1693
1688
  owned: null,
1694
1689
  nameFrom: ['author'],
@@ -1775,9 +1770,11 @@ lookupTable.role = {
1775
1770
  'aria-valuetext',
1776
1771
  'aria-orientation',
1777
1772
  'aria-readonly',
1778
- 'aria-errormessage'
1773
+ 'aria-errormessage',
1774
+ 'aria-valuemax',
1775
+ 'aria-valuemin'
1779
1776
  ],
1780
- required: ['aria-valuenow', 'aria-valuemax', 'aria-valuemin']
1777
+ required: ['aria-valuenow']
1781
1778
  },
1782
1779
  owned: null,
1783
1780
  nameFrom: ['author'],
@@ -1792,9 +1789,11 @@ lookupTable.role = {
1792
1789
  'aria-valuetext',
1793
1790
  'aria-required',
1794
1791
  'aria-readonly',
1795
- 'aria-errormessage'
1792
+ 'aria-errormessage',
1793
+ 'aria-valuemax',
1794
+ 'aria-valuemin'
1796
1795
  ],
1797
- required: ['aria-valuenow', 'aria-valuemax', 'aria-valuemin']
1796
+ required: ['aria-valuenow']
1798
1797
  },
1799
1798
  owned: null,
1800
1799
  nameFrom: ['author'],
@@ -2147,15 +2146,6 @@ lookupTable.elementsAllowedNoRole = [
2147
2146
  ]
2148
2147
  }
2149
2148
  },
2150
- {
2151
- nodeName: 'input',
2152
- attributes: {
2153
- list: isNull
2154
- },
2155
- properties: {
2156
- type: ['email', 'search', 'tel', 'url']
2157
- }
2158
- },
2159
2149
  {
2160
2150
  nodeName: 'link',
2161
2151
  attributes: {
@@ -2244,6 +2234,12 @@ lookupTable.elementsAllowedAnyRole = [
2244
2234
  href: isNull
2245
2235
  }
2246
2236
  },
2237
+ {
2238
+ nodeName: 'img',
2239
+ attributes: {
2240
+ alt: isNull
2241
+ }
2242
+ },
2247
2243
  {
2248
2244
  nodeName: [
2249
2245
  'abbr',
@@ -2311,11 +2307,15 @@ lookupTable.evaluateRoleForElement = {
2311
2307
  }
2312
2308
  return out;
2313
2309
  },
2314
- IMG: ({ node, out }) => {
2315
- if (node.alt) {
2316
- return !out;
2310
+ IMG: ({ node, role, out }) => {
2311
+ switch (node.alt) {
2312
+ case null:
2313
+ return out;
2314
+ case '':
2315
+ return role === 'presentation' || role === 'none';
2316
+ default:
2317
+ return role !== 'presentation' && role !== 'none';
2317
2318
  }
2318
- return out;
2319
2319
  },
2320
2320
  INPUT: ({ node, role, out }) => {
2321
2321
  switch (node.type) {
@@ -2333,6 +2333,11 @@ lookupTable.evaluateRoleForElement = {
2333
2333
  return (
2334
2334
  role === 'combobox' || role === 'searchbox' || role === 'spinbutton'
2335
2335
  );
2336
+ case 'tel':
2337
+ case 'url':
2338
+ case 'search':
2339
+ case 'email':
2340
+ return role === 'combobox';
2336
2341
  default:
2337
2342
  return false;
2338
2343
  }
@@ -2391,7 +2396,6 @@ lookupTable.rolesOfType = {
2391
2396
  'checkbox',
2392
2397
  'dialog',
2393
2398
  'gridcell',
2394
- 'heading',
2395
2399
  'link',
2396
2400
  'log',
2397
2401
  'marquee',
@@ -1,13 +1,33 @@
1
1
  /* global aria, axe, dom */
2
- function findDomNode(node, functor) {
3
- if (functor(node)) {
4
- return node;
2
+ const idRefsRegex = /^idrefs?$/;
3
+
4
+ function cacheIdRefs(node, refAttrs) {
5
+ if (node.hasAttribute) {
6
+ const idRefs = axe._cache.get('idRefs');
7
+
8
+ if (node.nodeName.toUpperCase() === 'LABEL' && node.hasAttribute('for')) {
9
+ idRefs[node.getAttribute('for')] = true;
10
+ }
11
+
12
+ for (let i = 0; i < refAttrs.length; ++i) {
13
+ const attr = refAttrs[i];
14
+
15
+ if (!node.hasAttribute(attr)) {
16
+ continue;
17
+ }
18
+
19
+ const attrValue = node.getAttribute(attr);
20
+
21
+ const tokens = axe.utils.tokenList(attrValue);
22
+
23
+ for (let k = 0; k < tokens.length; ++k) {
24
+ idRefs[tokens[k]] = true;
25
+ }
26
+ }
5
27
  }
28
+
6
29
  for (let i = 0; i < node.children.length; i++) {
7
- const out = findDomNode(node.children[i], functor);
8
- if (out) {
9
- return out;
10
- }
30
+ cacheIdRefs(node.children[i], refAttrs);
11
31
  }
12
32
  }
13
33
 
@@ -22,34 +42,18 @@ aria.isAccessibleRef = function isAccessibleRef(node) {
22
42
  root = root.documentElement || root; // account for shadow roots
23
43
  const id = node.id;
24
44
 
25
- // Get all idref(s) attributes on the lookup table
26
- const refAttrs = Object.keys(aria.lookupTable.attributes).filter(attr => {
27
- const { type } = aria.lookupTable.attributes[attr];
28
- return /^idrefs?$/.test(type);
29
- });
30
-
31
- // Find the first element that IDREF(S) the node
32
- let refElm = findDomNode(root, elm => {
33
- if (elm.nodeType !== 1) {
34
- // Elements only
35
- return;
36
- }
37
- if (
38
- elm.nodeName.toUpperCase() === 'LABEL' &&
39
- elm.getAttribute('for') === id
40
- ) {
41
- return true;
42
- }
43
- // See if there are any aria attributes that reference the node
44
- return refAttrs
45
- .filter(attr => elm.hasAttribute(attr))
46
- .some(attr => {
47
- const attrValue = elm.getAttribute(attr);
48
- if (aria.lookupTable.attributes[attr].type === 'idref') {
49
- return attrValue === id;
50
- }
51
- return axe.utils.tokenList(attrValue).includes(id);
52
- });
53
- });
54
- return typeof refElm !== 'undefined';
45
+ // because axe.commons is not available in axe.utils, we can't do
46
+ // this caching when we build up the virtual tree
47
+ if (!axe._cache.get('idRefs')) {
48
+ axe._cache.set('idRefs', {});
49
+ // Get all idref(s) attributes on the lookup table
50
+ const refAttrs = Object.keys(aria.lookupTable.attributes).filter(attr => {
51
+ const { type } = aria.lookupTable.attributes[attr];
52
+ return idRefsRegex.test(type);
53
+ });
54
+
55
+ cacheIdRefs(root, refAttrs);
56
+ }
57
+
58
+ return axe._cache.get('idRefs')[id] === true;
55
59
  };