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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/component_guide/accessibility-test.js +0 -6
- data/app/views/govuk_publishing_components/components/docs/machine_readable_metadata.yml +7 -0
- data/lib/govuk_publishing_components/presenters/machine_readable/dataset_schema.rb +34 -0
- data/lib/govuk_publishing_components/presenters/schema_org.rb +3 -0
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/axe-core/CHANGELOG.md +166 -2
- data/node_modules/axe-core/CONTRIBUTING.md +5 -5
- data/node_modules/axe-core/README.md +4 -4
- data/node_modules/axe-core/axe.d.ts +27 -11
- data/node_modules/axe-core/axe.js +9597 -2431
- data/node_modules/axe-core/axe.min.js +2 -2
- data/node_modules/axe-core/bower.json +1 -1
- data/node_modules/axe-core/doc/API.md +211 -128
- data/node_modules/axe-core/doc/accessibility-supported.md +1 -1
- data/node_modules/axe-core/doc/aria-supported.md +4 -13
- data/node_modules/axe-core/doc/backwards-compatibility-doc.md +93 -0
- data/node_modules/axe-core/doc/code-submission-guidelines.md +4 -4
- data/node_modules/axe-core/doc/developer-guide.md +27 -13
- data/node_modules/axe-core/doc/examples/chrome-debugging-protocol/package.json +5 -2
- data/node_modules/axe-core/doc/examples/jasmine/README.md +3 -5
- data/node_modules/axe-core/doc/examples/jasmine/karma.conf.js +29 -0
- data/node_modules/axe-core/doc/examples/jasmine/package.json +6 -5
- data/node_modules/axe-core/doc/examples/jest_react/README.md +1 -1
- data/node_modules/axe-core/doc/examples/jest_react/link.test.js +3 -3
- data/node_modules/axe-core/doc/examples/jest_react/package.json +9 -9
- data/node_modules/axe-core/doc/examples/jsdom/package.json +15 -0
- data/node_modules/axe-core/doc/examples/mocha/README.md +5 -7
- data/node_modules/axe-core/doc/examples/mocha/karma.conf.js +29 -0
- data/node_modules/axe-core/doc/examples/mocha/package.json +7 -6
- data/node_modules/axe-core/doc/examples/phantomjs/README.md +3 -3
- data/node_modules/axe-core/doc/examples/phantomjs/axe-phantom.js +4 -2
- data/node_modules/axe-core/doc/examples/phantomjs/package.json +3 -3
- data/node_modules/axe-core/doc/examples/puppeteer/package.json +5 -2
- data/node_modules/axe-core/doc/examples/qunit/README.md +2 -2
- data/node_modules/axe-core/doc/examples/qunit/package.json +2 -2
- data/node_modules/axe-core/doc/examples/test-examples.js +32 -0
- data/node_modules/axe-core/doc/plugins.md +10 -10
- data/node_modules/axe-core/doc/projects.md +12 -8
- data/node_modules/axe-core/doc/rule-descriptions.md +87 -79
- data/node_modules/axe-core/doc/rule-development.md +30 -2
- data/node_modules/axe-core/lib/checks/aria/allowed-attr.js +1 -1
- data/node_modules/axe-core/lib/checks/aria/aria-roledescription.js +14 -0
- data/node_modules/axe-core/lib/checks/aria/aria-roledescription.json +23 -0
- data/node_modules/axe-core/lib/checks/aria/no-implicit-explicit-label.js +21 -0
- data/node_modules/axe-core/lib/checks/aria/no-implicit-explicit-label.json +11 -0
- data/node_modules/axe-core/lib/checks/aria/required-attr.js +32 -7
- data/node_modules/axe-core/lib/checks/aria/required-children.js +40 -14
- data/node_modules/axe-core/lib/checks/aria/required-children.json +12 -1
- data/node_modules/axe-core/lib/checks/aria/required-parent.js +1 -1
- data/node_modules/axe-core/lib/checks/aria/unsupportedattr.js +1 -1
- data/node_modules/axe-core/lib/checks/aria/valid-attr-value.js +50 -17
- data/node_modules/axe-core/lib/checks/aria/valid-attr-value.json +2 -1
- data/node_modules/axe-core/lib/checks/aria/valid-attr.js +1 -1
- data/node_modules/axe-core/lib/checks/color/color-contrast.js +2 -2
- data/node_modules/axe-core/lib/checks/forms/autocomplete-appropriate.js +4 -4
- data/node_modules/axe-core/lib/checks/forms/autocomplete-valid.js +1 -1
- data/node_modules/axe-core/lib/checks/forms/fieldset.json +1 -0
- data/node_modules/axe-core/lib/checks/forms/group-labelledby.json +1 -0
- data/node_modules/axe-core/lib/checks/keyboard/focusable-content.js +16 -0
- data/node_modules/axe-core/lib/checks/keyboard/focusable-content.json +11 -0
- data/node_modules/axe-core/lib/checks/keyboard/focusable-element.js +12 -0
- data/node_modules/axe-core/lib/checks/keyboard/focusable-element.json +11 -0
- data/node_modules/axe-core/lib/checks/keyboard/tabindex.js +6 -1
- data/node_modules/axe-core/lib/checks/label/alt-space-value.js +3 -2
- data/node_modules/axe-core/lib/checks/label/duplicate-img-label.js +18 -15
- data/node_modules/axe-core/lib/checks/label/label-content-name-mismatch.js +13 -3
- data/node_modules/axe-core/lib/checks/label/label-content-name-mismatch.json +4 -0
- data/node_modules/axe-core/lib/checks/label/multiple-label.js +22 -12
- data/node_modules/axe-core/lib/checks/label/multiple-label.json +1 -1
- data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique-after.js +23 -0
- data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique.js +7 -0
- data/node_modules/axe-core/lib/checks/landmarks/landmark-is-unique.json +12 -0
- data/node_modules/axe-core/lib/checks/lists/listitem.js +1 -0
- data/node_modules/axe-core/lib/checks/lists/listitem.json +1 -1
- data/node_modules/axe-core/lib/checks/lists/only-listitems.js +0 -4
- data/node_modules/axe-core/lib/checks/mobile/css-orientation-lock.js +8 -6
- data/node_modules/axe-core/lib/checks/navigation/region.js +2 -19
- data/node_modules/axe-core/lib/checks/shared/avoid-inline-spacing.js +18 -0
- data/node_modules/axe-core/lib/checks/shared/avoid-inline-spacing.json +11 -0
- data/node_modules/axe-core/lib/checks/shared/exists.js +1 -1
- data/node_modules/axe-core/lib/checks/shared/exists.json +1 -1
- data/node_modules/axe-core/lib/checks/shared/has-alt.js +6 -4
- data/node_modules/axe-core/lib/checks/shared/non-empty-alt.js +1 -1
- data/node_modules/axe-core/lib/checks/tables/caption-faked.json +1 -1
- data/node_modules/axe-core/lib/checks/tables/td-has-header.js +5 -4
- data/node_modules/axe-core/lib/checks/tables/th-has-data-cells.js +19 -29
- data/node_modules/axe-core/lib/commons/aria/get-owned-virtual.js +1 -1
- data/node_modules/axe-core/lib/commons/aria/index.js +50 -46
- data/node_modules/axe-core/lib/commons/aria/is-accessible-ref.js +41 -37
- data/node_modules/axe-core/lib/commons/aria/label-virtual.js +2 -2
- data/node_modules/axe-core/lib/commons/aria/roles.js +1 -1
- data/node_modules/axe-core/lib/commons/aria/validate-attr-value.js +0 -1
- data/node_modules/axe-core/lib/commons/color/center-point-of-rect.js +30 -0
- data/node_modules/axe-core/lib/commons/color/contrast.js +7 -1
- data/node_modules/axe-core/lib/commons/color/element-has-image.js +36 -0
- data/node_modules/axe-core/lib/commons/color/get-background-color.js +332 -306
- data/node_modules/axe-core/lib/commons/color/get-foreground-color.js +35 -6
- data/node_modules/axe-core/lib/commons/color/get-own-background-color.js +22 -0
- data/node_modules/axe-core/lib/commons/dom/find-up.js +5 -5
- data/node_modules/axe-core/lib/commons/dom/get-scroll-offset.js +0 -1
- data/node_modules/axe-core/lib/commons/dom/get-tabbable-elements.js +1 -1
- data/node_modules/axe-core/lib/commons/dom/has-content-virtual.js +7 -5
- data/node_modules/axe-core/lib/commons/dom/is-focusable.js +8 -5
- data/node_modules/axe-core/lib/commons/dom/is-hidden-with-css.js +15 -2
- data/node_modules/axe-core/lib/commons/dom/is-in-text-block.js +1 -2
- data/node_modules/axe-core/lib/commons/dom/is-skip-link.js +45 -0
- data/node_modules/axe-core/lib/commons/dom/is-visible.js +43 -17
- data/node_modules/axe-core/lib/commons/dom/is-visual-content.js +0 -1
- data/node_modules/axe-core/lib/commons/dom/visually-contains.js +0 -1
- data/node_modules/axe-core/lib/commons/dom/visually-overlaps.js +0 -1
- data/node_modules/axe-core/lib/commons/forms/index.js +8 -0
- data/node_modules/axe-core/lib/commons/forms/is-aria-combobox.js +13 -0
- data/node_modules/axe-core/lib/commons/forms/is-aria-listbox.js +13 -0
- data/node_modules/axe-core/lib/commons/forms/is-aria-range.js +14 -0
- data/node_modules/axe-core/lib/commons/forms/is-aria-textbox.js +13 -0
- data/node_modules/axe-core/lib/commons/forms/is-native-select.js +13 -0
- data/node_modules/axe-core/lib/commons/forms/is-native-textbox.js +28 -0
- data/node_modules/axe-core/lib/commons/table/get-cell-position.js +2 -2
- data/node_modules/axe-core/lib/commons/table/get-headers.js +55 -11
- data/node_modules/axe-core/lib/commons/table/get-scope.js +1 -1
- data/node_modules/axe-core/lib/commons/table/is-data-table.js +0 -1
- data/node_modules/axe-core/lib/commons/table/to-grid.js +2 -2
- data/node_modules/axe-core/lib/commons/text/accessible-text-virtual.js +5 -5
- data/node_modules/axe-core/lib/commons/text/form-control-value.js +18 -30
- data/node_modules/axe-core/lib/commons/text/is-icon-ligature.js +210 -0
- data/node_modules/axe-core/lib/commons/text/is-valid-autocomplete.js +0 -1
- data/node_modules/axe-core/lib/commons/text/label-text.js +1 -1
- data/node_modules/axe-core/lib/commons/text/label-virtual.js +1 -1
- data/node_modules/axe-core/lib/commons/text/native-text-methods.js +1 -1
- data/node_modules/axe-core/lib/commons/text/subtree-text.js +3 -3
- data/node_modules/axe-core/lib/commons/text/unicode.js +15 -0
- data/node_modules/axe-core/lib/commons/text/visible-text-nodes.js +25 -0
- data/node_modules/axe-core/lib/commons/text/visible-virtual.js +1 -1
- data/node_modules/axe-core/lib/core/base/audit.js +90 -15
- data/node_modules/axe-core/lib/core/base/cache.js +33 -0
- data/node_modules/axe-core/lib/core/base/check.js +48 -1
- data/node_modules/axe-core/lib/core/base/context.js +15 -14
- data/node_modules/axe-core/lib/core/base/rule.js +223 -46
- data/node_modules/axe-core/lib/core/base/virtual-node/abstract-virtual-node.js +40 -0
- data/node_modules/axe-core/lib/core/base/virtual-node/serial-virtual-node.js +86 -0
- data/node_modules/axe-core/lib/core/base/virtual-node/virtual-node.js +85 -0
- data/node_modules/axe-core/lib/core/constants.js +10 -2
- data/node_modules/axe-core/lib/core/imports/index.js +28 -3
- data/node_modules/axe-core/lib/core/index.js +2 -4
- data/node_modules/axe-core/lib/core/public/configure.js +28 -1
- data/node_modules/axe-core/lib/core/public/run-rules.js +2 -0
- data/node_modules/axe-core/lib/core/public/run-virtual-rule.js +50 -0
- data/node_modules/axe-core/lib/core/public/run.js +13 -2
- data/node_modules/axe-core/lib/core/reporters/helpers/process-aggregate.js +1 -1
- data/node_modules/axe-core/lib/core/reporters/na.js +4 -0
- data/node_modules/axe-core/lib/core/reporters/raw-env.js +12 -0
- data/node_modules/axe-core/lib/core/reporters/raw.js +25 -1
- data/node_modules/axe-core/lib/core/utils/are-styles-set.js +4 -7
- data/node_modules/axe-core/lib/core/utils/assert.js +12 -0
- data/node_modules/axe-core/lib/core/utils/collect-results-from-frames.js +2 -2
- data/node_modules/axe-core/lib/core/utils/contains.js +27 -13
- data/node_modules/axe-core/lib/core/utils/css-parser.js +2 -0
- data/node_modules/axe-core/lib/core/utils/element-matches.js +5 -1
- data/node_modules/axe-core/lib/core/utils/escape-selector.js +1 -2
- data/node_modules/axe-core/lib/core/utils/flattened-tree.js +47 -61
- data/node_modules/axe-core/lib/core/utils/get-check-option.js +0 -1
- data/node_modules/axe-core/lib/core/utils/get-friendly-uri-end.js +1 -1
- data/node_modules/axe-core/lib/core/utils/get-node-attributes.js +21 -0
- data/node_modules/axe-core/lib/core/utils/get-scroll.js +39 -0
- data/node_modules/axe-core/lib/core/utils/get-selector.js +9 -6
- data/node_modules/axe-core/lib/core/utils/get-stylesheet-factory.js +51 -0
- data/node_modules/axe-core/lib/core/utils/get-xpath.js +0 -1
- data/node_modules/axe-core/lib/core/utils/is-hidden.js +16 -4
- data/node_modules/axe-core/lib/core/utils/is-html-element.js +5 -5
- data/node_modules/axe-core/lib/core/utils/is-shadow-root.js +3 -3
- data/node_modules/axe-core/lib/core/utils/memoize.js +17 -0
- data/node_modules/axe-core/lib/core/utils/parse-crossorigin-stylesheet.js +53 -0
- data/node_modules/axe-core/lib/core/utils/parse-sameorigin-stylesheet.js +96 -0
- data/node_modules/axe-core/lib/core/utils/parse-stylesheet.js +70 -0
- data/node_modules/axe-core/lib/core/utils/performance-timer.js +7 -2
- data/node_modules/axe-core/lib/core/utils/preload-cssom.js +77 -281
- data/node_modules/axe-core/lib/core/utils/preload.js +49 -23
- data/node_modules/axe-core/lib/core/utils/qsa.js +39 -50
- data/node_modules/axe-core/lib/core/utils/respondable.js +20 -3
- data/node_modules/axe-core/lib/core/utils/rule-should-run.js +0 -1
- data/node_modules/axe-core/lib/core/utils/scroll-state.js +12 -25
- data/node_modules/axe-core/lib/core/utils/select.js +12 -23
- data/node_modules/axe-core/lib/core/utils/uuid.js +1 -2
- data/node_modules/axe-core/lib/intro.stub +1 -1
- data/node_modules/axe-core/lib/misc/incomplete-fallback.json +1 -1
- data/node_modules/axe-core/lib/rules/aria-allowed-attr-matches.js +1 -1
- data/node_modules/axe-core/lib/rules/aria-form-field-name-matches.js +50 -0
- data/node_modules/axe-core/lib/rules/aria-has-attr-matches.js +1 -1
- data/node_modules/axe-core/lib/rules/aria-hidden-focus.json +1 -1
- data/node_modules/axe-core/lib/rules/aria-input-field-name.json +13 -0
- data/node_modules/axe-core/lib/rules/aria-roledescription.json +12 -0
- data/node_modules/axe-core/lib/rules/aria-toggle-field-name.json +18 -0
- data/node_modules/axe-core/lib/rules/autocomplete-matches.js +14 -10
- data/node_modules/axe-core/lib/rules/avoid-inline-spacing.json +12 -0
- data/node_modules/axe-core/lib/rules/button-name.json +3 -5
- data/node_modules/axe-core/lib/rules/checkboxgroup.json +2 -1
- data/node_modules/axe-core/lib/rules/color-contrast-matches.js +37 -22
- data/node_modules/axe-core/lib/rules/duplicate-id-active-matches.js +1 -1
- data/node_modules/axe-core/lib/rules/duplicate-id-misc-matches.js +2 -2
- data/node_modules/axe-core/lib/rules/form-field-multiple-labels.json +1 -1
- data/node_modules/axe-core/lib/rules/html-has-lang.json +1 -0
- data/node_modules/axe-core/lib/rules/image-alt.json +1 -1
- data/node_modules/axe-core/lib/rules/img-redundant-alt.json +3 -3
- data/node_modules/axe-core/lib/rules/input-button-name.json +26 -0
- data/node_modules/axe-core/lib/rules/landmark-unique-matches.js +41 -0
- data/node_modules/axe-core/lib/rules/landmark-unique.json +13 -0
- data/node_modules/axe-core/lib/rules/link-name.json +5 -4
- data/node_modules/axe-core/lib/rules/meta-refresh.json +8 -1
- data/node_modules/axe-core/lib/rules/radiogroup.json +2 -1
- data/node_modules/axe-core/lib/rules/role-img-alt.json +18 -0
- data/node_modules/axe-core/lib/rules/scrollable-region-focusable-matches.js +30 -0
- data/node_modules/axe-core/lib/rules/scrollable-region-focusable.json +12 -0
- data/node_modules/axe-core/lib/rules/skip-link-matches.js +1 -1
- data/node_modules/axe-core/lib/rules/skip-link.json +1 -1
- data/node_modules/axe-core/lib/rules/video-description.json +3 -1
- data/node_modules/axe-core/locales/de.json +1 -5
- data/node_modules/axe-core/locales/es.json +773 -0
- data/node_modules/axe-core/locales/fr.json +15 -19
- data/node_modules/axe-core/locales/ja.json +65 -11
- data/node_modules/axe-core/locales/ko.json +777 -0
- data/node_modules/axe-core/locales/nl.json +35 -35
- data/node_modules/axe-core/locales/pt_BR.json +773 -0
- data/node_modules/axe-core/package.json +56 -52
- data/node_modules/axe-core/sri-history.json +20 -0
- data/node_modules/axe-core/typings/axe-core/axe-core-tests.ts +5 -15
- data/node_modules/govuk-frontend/package.json +10 -10
- metadata +62 -4
- data/node_modules/axe-core/doc/axelogo2018.png +0 -0
- data/node_modules/axe-core/lib/rules/role-not-button-matches.js +0 -1
@@ -0,0 +1,17 @@
|
|
1
|
+
/**
|
2
|
+
* Memoize a function.
|
3
|
+
* @method memoize
|
4
|
+
* @memberof axe.utils
|
5
|
+
* @param {Function} fn Function to memoize
|
6
|
+
* @return {Function}
|
7
|
+
*/
|
8
|
+
axe._memoizedFns = [];
|
9
|
+
axe.utils.memoize = function(fn) {
|
10
|
+
// keep track of each function that is memoized so it can be cleared at
|
11
|
+
// the end of a run. each memoized function has its own cache, so there is
|
12
|
+
// no method to clear all memoized caches. instead, we have to clear each
|
13
|
+
// individual memoized function ourselves.
|
14
|
+
const memoized = axe.imports.memoize(fn);
|
15
|
+
axe._memoizedFns.push(memoized);
|
16
|
+
return memoized;
|
17
|
+
};
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/**
|
2
|
+
* Parse cross-origin stylesheets
|
3
|
+
*
|
4
|
+
* @method parseCrossOriginStylesheet
|
5
|
+
* @memberof axe.utils
|
6
|
+
* @param {String} url url from which to fetch stylesheet
|
7
|
+
* @param {Object} options options object from `axe.utils.parseStylesheet`
|
8
|
+
* @param {Array<Number>} priority sheet priority
|
9
|
+
* @param {Array<String>} importedUrls urls of already imported stylesheets
|
10
|
+
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin`
|
11
|
+
* @returns {Promise}
|
12
|
+
*/
|
13
|
+
axe.utils.parseCrossOriginStylesheet = function parseCrossOriginStylesheet(
|
14
|
+
url,
|
15
|
+
options,
|
16
|
+
priority,
|
17
|
+
importedUrls,
|
18
|
+
isCrossOrigin
|
19
|
+
) {
|
20
|
+
const axiosOptions = {
|
21
|
+
method: 'get',
|
22
|
+
url
|
23
|
+
};
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Add `url` to `importedUrls`
|
27
|
+
*/
|
28
|
+
importedUrls.push(url);
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Fetch `cross-origin stylesheet` via axios
|
32
|
+
*/
|
33
|
+
return axe.imports.axios(axiosOptions).then(({ data }) => {
|
34
|
+
const result = options.convertDataToStylesheet({
|
35
|
+
data,
|
36
|
+
isCrossOrigin,
|
37
|
+
priority,
|
38
|
+
root: options.rootNode,
|
39
|
+
shadowId: options.shadowId
|
40
|
+
});
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Parse resolved stylesheet further for any `@import` styles
|
44
|
+
*/
|
45
|
+
return axe.utils.parseStylesheet(
|
46
|
+
result.sheet,
|
47
|
+
options,
|
48
|
+
priority,
|
49
|
+
importedUrls,
|
50
|
+
result.isCrossOrigin
|
51
|
+
);
|
52
|
+
});
|
53
|
+
};
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/**
|
2
|
+
* Parse non cross-origin stylesheets
|
3
|
+
*
|
4
|
+
* @method parseSameOriginStylesheet
|
5
|
+
* @memberof axe.utils
|
6
|
+
* @param {Object} sheet CSSStylesheet object
|
7
|
+
* @param {Object} options options object from `axe.utils.parseStylesheet`
|
8
|
+
* @param {Array<Number>} priority sheet priority
|
9
|
+
* @param {Array<String>} importedUrls urls of already imported stylesheets
|
10
|
+
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin`
|
11
|
+
* @returns {Promise}
|
12
|
+
*/
|
13
|
+
axe.utils.parseSameOriginStylesheet = function parseSameOriginStylesheet(
|
14
|
+
sheet,
|
15
|
+
options,
|
16
|
+
priority,
|
17
|
+
importedUrls,
|
18
|
+
isCrossOrigin = false
|
19
|
+
) {
|
20
|
+
const rules = Array.from(sheet.cssRules);
|
21
|
+
|
22
|
+
if (!rules) {
|
23
|
+
return Promise.resolve();
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* reference -> https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants
|
28
|
+
*/
|
29
|
+
const cssImportRules = rules.filter(r => r.type === 3); // type === 3 -> CSSRule.IMPORT_RULE
|
30
|
+
|
31
|
+
/**
|
32
|
+
* when no `@import` rules in given sheet -> resolve the current `sheet` & exit
|
33
|
+
*/
|
34
|
+
if (!cssImportRules.length) {
|
35
|
+
// exit
|
36
|
+
return Promise.resolve({
|
37
|
+
isCrossOrigin,
|
38
|
+
priority,
|
39
|
+
root: options.rootNode,
|
40
|
+
shadowId: options.shadowId,
|
41
|
+
sheet
|
42
|
+
});
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* filter rules that are not already fetched
|
47
|
+
*/
|
48
|
+
const cssImportUrlsNotAlreadyImported = cssImportRules
|
49
|
+
// ensure rule has a href
|
50
|
+
.filter(rule => rule.href)
|
51
|
+
// extract href from object
|
52
|
+
.map(rule => rule.href)
|
53
|
+
// only href that are not already imported
|
54
|
+
.filter(url => !importedUrls.includes(url));
|
55
|
+
|
56
|
+
/**
|
57
|
+
* iterate `@import` rules and fetch styles
|
58
|
+
*/
|
59
|
+
const promises = cssImportUrlsNotAlreadyImported.map(
|
60
|
+
(importUrl, cssRuleIndex) => {
|
61
|
+
const newPriority = [...priority, cssRuleIndex];
|
62
|
+
const isCrossOriginRequest = /^https?:\/\/|^\/\//i.test(importUrl);
|
63
|
+
|
64
|
+
return axe.utils.parseCrossOriginStylesheet(
|
65
|
+
importUrl,
|
66
|
+
options,
|
67
|
+
newPriority,
|
68
|
+
importedUrls,
|
69
|
+
isCrossOriginRequest
|
70
|
+
);
|
71
|
+
}
|
72
|
+
);
|
73
|
+
|
74
|
+
const nonImportCSSRules = rules.filter(r => r.type !== 3);
|
75
|
+
|
76
|
+
// no further rules to process in this sheet
|
77
|
+
if (!nonImportCSSRules.length) {
|
78
|
+
return Promise.all(promises);
|
79
|
+
}
|
80
|
+
|
81
|
+
// convert all `nonImportCSSRules` style rules into `text` and chain
|
82
|
+
|
83
|
+
promises.push(
|
84
|
+
Promise.resolve(
|
85
|
+
options.convertDataToStylesheet({
|
86
|
+
data: nonImportCSSRules.map(rule => rule.cssText).join(),
|
87
|
+
isCrossOrigin,
|
88
|
+
priority,
|
89
|
+
root: options.rootNode,
|
90
|
+
shadowId: options.shadowId
|
91
|
+
})
|
92
|
+
)
|
93
|
+
);
|
94
|
+
|
95
|
+
return Promise.all(promises);
|
96
|
+
};
|
@@ -0,0 +1,70 @@
|
|
1
|
+
/**
|
2
|
+
* Parse a given stylesheet
|
3
|
+
*
|
4
|
+
* @method parseStylesheet
|
5
|
+
* @memberof axe.utils
|
6
|
+
* @param {Object} sheet stylesheet to parse
|
7
|
+
* @param {Object} options configuration options object from `axe.utils.parseStylesheets`
|
8
|
+
* @param {Array<Number>} priority priority of stylesheet
|
9
|
+
* @param {Array<String>} importedUrls list of resolved `@import` urls
|
10
|
+
* @param {Boolean} isCrossOrigin boolean denoting if a stylesheet is `cross-origin`, passed for re-parsing `cross-origin` sheets
|
11
|
+
* @returns {Promise}
|
12
|
+
*/
|
13
|
+
axe.utils.parseStylesheet = function parseStylesheet(
|
14
|
+
sheet,
|
15
|
+
options,
|
16
|
+
priority,
|
17
|
+
importedUrls,
|
18
|
+
isCrossOrigin = false
|
19
|
+
) {
|
20
|
+
const isSameOrigin = isSameOriginStylesheet(sheet);
|
21
|
+
if (isSameOrigin) {
|
22
|
+
/**
|
23
|
+
* resolve `same-origin` stylesheet
|
24
|
+
*/
|
25
|
+
return axe.utils.parseSameOriginStylesheet(
|
26
|
+
sheet,
|
27
|
+
options,
|
28
|
+
priority,
|
29
|
+
importedUrls,
|
30
|
+
isCrossOrigin
|
31
|
+
);
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* resolve `cross-origin` stylesheet
|
36
|
+
*/
|
37
|
+
return axe.utils.parseCrossOriginStylesheet(
|
38
|
+
sheet.href,
|
39
|
+
options,
|
40
|
+
priority,
|
41
|
+
importedUrls,
|
42
|
+
true // -> isCrossOrigin
|
43
|
+
);
|
44
|
+
};
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Check if a given stylesheet is from the `same-origin`
|
48
|
+
* Note:
|
49
|
+
* `sheet.cssRules` throws an error on `cross-origin` stylesheets
|
50
|
+
*
|
51
|
+
* @param {Object} sheet CSS stylesheet
|
52
|
+
* @returns {Boolean}
|
53
|
+
*/
|
54
|
+
function isSameOriginStylesheet(sheet) {
|
55
|
+
try {
|
56
|
+
/*eslint no-unused-vars: 0*/
|
57
|
+
const rules = sheet.cssRules;
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Safari, does not throw an error when accessing cssRules property,
|
61
|
+
*/
|
62
|
+
if (!rules && sheet.href) {
|
63
|
+
return false;
|
64
|
+
}
|
65
|
+
|
66
|
+
return true;
|
67
|
+
} catch (e) {
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
}
|
@@ -27,7 +27,7 @@ utils.performanceTimer = (function() {
|
|
27
27
|
*/
|
28
28
|
return {
|
29
29
|
/**
|
30
|
-
* @member {Function} start Kicks off performance timing for overall
|
30
|
+
* @member {Function} start Kicks off performance timing for overall axe audit
|
31
31
|
*/
|
32
32
|
start: function() {
|
33
33
|
this.mark('mark_axe_start');
|
@@ -90,7 +90,12 @@ utils.performanceTimer = (function() {
|
|
90
90
|
window.performance &&
|
91
91
|
window.performance.getEntriesByType !== undefined
|
92
92
|
) {
|
93
|
-
|
93
|
+
// only output measures that were started after axe started, otherwise
|
94
|
+
// we get measures made by the page before axe ran (which is confusing)
|
95
|
+
var axeStart = window.performance.getEntriesByName('mark_axe_start')[0];
|
96
|
+
var measures = window.performance
|
97
|
+
.getEntriesByType('measure')
|
98
|
+
.filter(measure => measure.startTime >= axeStart.startTime);
|
94
99
|
for (var i = 0; i < measures.length; ++i) {
|
95
100
|
var req = measures[i];
|
96
101
|
if (req.name === measureName) {
|
@@ -1,51 +1,41 @@
|
|
1
1
|
/**
|
2
|
-
* NOTE:
|
2
|
+
* NOTE:
|
3
3
|
* this `eslint` rule is disabled because of calling `getStyleSheetFactory` before it is defined (further below).
|
4
4
|
*/
|
5
5
|
/* eslint no-use-before-define: 0 */
|
6
6
|
|
7
|
-
|
8
7
|
/**
|
9
8
|
* Given a rootNode - construct CSSOM
|
10
9
|
* -> get all source nodes (document & document fragments) within given root node
|
11
|
-
* -> recursively call `
|
10
|
+
* -> recursively call `axe.utils.parseStylesheets` to resolve styles for each node
|
12
11
|
*
|
13
12
|
* @method preloadCssom
|
14
13
|
* @memberof `axe.utils`
|
15
|
-
*
|
16
|
-
* @
|
17
|
-
* @property {Number} timeout timeout
|
18
|
-
* @property {Object} treeRoot the DOM tree to be inspected
|
19
|
-
* @returns {
|
14
|
+
* @param {Object} options composite options object
|
15
|
+
* @property {Array<String>} options.assets array of preloaded assets requested, eg: [`cssom`]
|
16
|
+
* @property {Number} options.timeout timeout
|
17
|
+
* @property {Object} options.treeRoot (optional) the DOM tree to be inspected
|
18
|
+
* @returns {Promise}
|
20
19
|
*/
|
21
|
-
axe.utils.preloadCssom = function preloadCssom({
|
22
|
-
timeout,
|
23
|
-
treeRoot = axe._tree[0]
|
24
|
-
}) {
|
20
|
+
axe.utils.preloadCssom = function preloadCssom({ treeRoot = axe._tree[0] }) {
|
25
21
|
/**
|
26
22
|
* get all `document` and `documentFragment` with in given `tree`
|
27
23
|
*/
|
28
24
|
const rootNodes = getAllRootNodesInTree(treeRoot);
|
29
25
|
|
30
|
-
const q = axe.utils.queue();
|
31
|
-
|
32
26
|
if (!rootNodes.length) {
|
33
|
-
return
|
27
|
+
return Promise.resolve();
|
34
28
|
}
|
35
29
|
|
36
|
-
const dynamicDoc = document.implementation.createHTMLDocument(
|
37
|
-
|
30
|
+
const dynamicDoc = document.implementation.createHTMLDocument(
|
31
|
+
'Dynamic document for loading cssom'
|
32
|
+
);
|
38
33
|
|
39
|
-
|
40
|
-
getCssomForAllRootNodes(rootNodes, convertDataToStylesheet, timeout)
|
41
|
-
.then(assets => {
|
42
|
-
const cssom = processCssomAssets(assets);
|
43
|
-
resolve(cssom);
|
44
|
-
})
|
45
|
-
.catch(reject);
|
46
|
-
});
|
34
|
+
const convertDataToStylesheet = axe.utils.getStyleSheetFactory(dynamicDoc);
|
47
35
|
|
48
|
-
return
|
36
|
+
return getCssomForAllRootNodes(rootNodes, convertDataToStylesheet).then(
|
37
|
+
assets => flattenAssets(assets)
|
38
|
+
);
|
49
39
|
};
|
50
40
|
|
51
41
|
/**
|
@@ -76,283 +66,89 @@ function getAllRootNodesInTree(tree) {
|
|
76
66
|
}
|
77
67
|
|
78
68
|
/**
|
79
|
-
*
|
80
|
-
* Is a factory (closure) function, initialized with `document.implementation.createHTMLDocument()` which surfaces DOM API for creating `style` elements.
|
81
|
-
*
|
82
|
-
* @param {Object} param `document.implementation.createHTMLDocument()
|
83
|
-
* @param {Object} arg an object with properties to construct stylesheet
|
84
|
-
* @property {String} arg.data text content of the stylesheet
|
85
|
-
* @property {Boolean} arg.isExternal flag to notify if the resource was fetched from the network
|
86
|
-
* @property {String} arg.shadowId (Optional) shadowId if shadowDOM
|
87
|
-
* @property {Object} arg.root implementation document to create style elements
|
88
|
-
* @property {String} arg.priority a number indicating the loaded priority of CSS, to denote specificity of styles contained in the sheet.
|
89
|
-
*/
|
90
|
-
const getStyleSheetFactory = dynamicDoc => ({
|
91
|
-
data,
|
92
|
-
isExternal,
|
93
|
-
shadowId,
|
94
|
-
root,
|
95
|
-
priority,
|
96
|
-
isLink = false
|
97
|
-
}) => {
|
98
|
-
const style = dynamicDoc.createElement('style');
|
99
|
-
if (isLink) {
|
100
|
-
// as creating a stylesheet as link will need to be awaited
|
101
|
-
// till `onload`, it is wise to convert link href to @import statement
|
102
|
-
const text = dynamicDoc.createTextNode(`@import "${data.href}"`);
|
103
|
-
style.appendChild(text);
|
104
|
-
} else {
|
105
|
-
style.appendChild(dynamicDoc.createTextNode(data));
|
106
|
-
}
|
107
|
-
dynamicDoc.head.appendChild(style);
|
108
|
-
return {
|
109
|
-
sheet: style.sheet,
|
110
|
-
isExternal,
|
111
|
-
shadowId,
|
112
|
-
root,
|
113
|
-
priority
|
114
|
-
};
|
115
|
-
};
|
116
|
-
|
117
|
-
/**
|
118
|
-
* Deferred function for CSSOM queue processing on all root nodes
|
69
|
+
* Process CSSOM on all root nodes
|
119
70
|
*
|
120
71
|
* @param {Array<Object>} rootNodes array of root nodes, where node is an enhanced `document` or `documentFragment` object returned from `getAllRootNodesInTree`
|
121
72
|
* @param {Function} convertDataToStylesheet fn to convert given data to Stylesheet object
|
122
|
-
* @returns {
|
73
|
+
* @returns {Promise}
|
123
74
|
*/
|
124
|
-
function getCssomForAllRootNodes(rootNodes, convertDataToStylesheet
|
125
|
-
const
|
126
|
-
|
127
|
-
rootNodes.forEach(({ rootNode, shadowId }, index) =>
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
})
|
136
|
-
.then(resolve)
|
137
|
-
.catch(reject)
|
138
|
-
)
|
139
|
-
);
|
140
|
-
|
141
|
-
return q;
|
142
|
-
}
|
143
|
-
|
144
|
-
/**
|
145
|
-
* Process results from `loadCssom` queues of all root nodes
|
146
|
-
* NOTE:
|
147
|
-
* using `axe.utils.queue` from various `loadCssom` paths, returns a nested array of arrays at various depths,
|
148
|
-
* hence the need to flatten arrays
|
149
|
-
*
|
150
|
-
* @param {Array<Object>} assets CSSOM assets for each root
|
151
|
-
* @returns {Object} CSSOM object
|
152
|
-
*/
|
153
|
-
function processCssomAssets(nestedAssets) {
|
154
|
-
const result = [];
|
155
|
-
|
156
|
-
nestedAssets.forEach(item => {
|
157
|
-
if (Array.isArray(item)) {
|
158
|
-
result.push(...processCssomAssets(item));
|
159
|
-
} else {
|
160
|
-
result.push(item);
|
161
|
-
}
|
162
|
-
});
|
163
|
-
|
164
|
-
return result;
|
165
|
-
}
|
166
|
-
|
167
|
-
/**
|
168
|
-
* Returns `axe.utils.queue` of CSSStyleSheet(s) for a given root node
|
169
|
-
*
|
170
|
-
* @param {Object} options configuration options
|
171
|
-
* @property {Object} options.rootNode document or document fragment
|
172
|
-
* @property {Number} options.rootIndex a number representing the index of the document or document fragment, used for priority computation
|
173
|
-
* @property {String} options.shadowId an id if undefined denotes that given root is a document fragment/ shadowDOM
|
174
|
-
* @property {Number} options.timeout abort duration for network request
|
175
|
-
* @property {Function} options.convertDataToStylesheet a utility function to generate a style sheet from given data (text)
|
176
|
-
* @return {Object} queue
|
177
|
-
*/
|
178
|
-
function loadCssom(options) {
|
179
|
-
const { rootIndex } = options;
|
180
|
-
|
181
|
-
const q = axe.utils.queue();
|
182
|
-
|
183
|
-
const sheets = getStylesheetsOfRootNode(options);
|
184
|
-
if (!sheets) {
|
185
|
-
return q;
|
186
|
-
}
|
187
|
-
|
188
|
-
sheets.forEach((sheet, sheetIndex) => {
|
189
|
-
const priority = [rootIndex, sheetIndex];
|
190
|
-
try {
|
191
|
-
const deferredQ = parseNonCrossOriginStylesheet(sheet, options, priority);
|
192
|
-
q.defer(deferredQ);
|
193
|
-
} catch (e) {
|
194
|
-
// cross-origin stylesheet -> make an XHR and q the response
|
195
|
-
const deferredQ = parseCrossOriginStylesheet(
|
196
|
-
sheet.href,
|
197
|
-
options,
|
198
|
-
priority
|
199
|
-
);
|
200
|
-
q.defer(deferredQ);
|
75
|
+
function getCssomForAllRootNodes(rootNodes, convertDataToStylesheet) {
|
76
|
+
const promises = [];
|
77
|
+
|
78
|
+
rootNodes.forEach(({ rootNode, shadowId }, index) => {
|
79
|
+
const sheets = getStylesheetsOfRootNode(
|
80
|
+
rootNode,
|
81
|
+
shadowId,
|
82
|
+
convertDataToStylesheet
|
83
|
+
);
|
84
|
+
if (!sheets) {
|
85
|
+
return Promise.all(promises);
|
201
86
|
}
|
202
|
-
});
|
203
|
-
|
204
|
-
return q;
|
205
|
-
}
|
206
|
-
|
207
|
-
/**
|
208
|
-
* Parse non cross-origin stylesheets
|
209
|
-
*
|
210
|
-
* @param {Object} sheet CSSStylesheet object
|
211
|
-
* @param {Object} options `loadCssom` options
|
212
|
-
* @param {Array<Number>} priority sheet priority
|
213
|
-
*/
|
214
|
-
function parseNonCrossOriginStylesheet(sheet, options, priority) {
|
215
|
-
const q = axe.utils.queue();
|
216
|
-
|
217
|
-
/**
|
218
|
-
* `sheet.cssRules` throws an error on `cross-origin` stylesheets
|
219
|
-
*/
|
220
|
-
const cssRules = sheet.cssRules;
|
221
87
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
88
|
+
const rootIndex = index + 1;
|
89
|
+
const parseOptions = {
|
90
|
+
rootNode,
|
91
|
+
shadowId,
|
92
|
+
convertDataToStylesheet,
|
93
|
+
rootIndex
|
94
|
+
};
|
95
|
+
/**
|
96
|
+
* Note:
|
97
|
+
* `importedUrls` - keeps urls of already imported stylesheets, to prevent re-fetching
|
98
|
+
* eg: nested, cyclic or cross referenced `@import` urls
|
99
|
+
*/
|
100
|
+
const importedUrls = [];
|
101
|
+
|
102
|
+
const p = Promise.all(
|
103
|
+
sheets.map((sheet, sheetIndex) => {
|
104
|
+
const priority = [rootIndex, sheetIndex];
|
105
|
+
|
106
|
+
return axe.utils.parseStylesheet(
|
107
|
+
sheet,
|
108
|
+
parseOptions,
|
109
|
+
priority,
|
110
|
+
importedUrls
|
111
|
+
);
|
244
112
|
})
|
245
113
|
);
|
246
114
|
|
247
|
-
|
248
|
-
|
249
|
-
}
|
250
|
-
|
251
|
-
/**
|
252
|
-
* iterate `@import` rules and fetch styles
|
253
|
-
*/
|
254
|
-
cssImportRules.forEach((importRule, cssRuleIndex) =>
|
255
|
-
q.defer((resolve, reject) => {
|
256
|
-
const importUrl = importRule.href;
|
257
|
-
const newPriority = [...priority, cssRuleIndex];
|
258
|
-
const axiosOptions = {
|
259
|
-
method: 'get',
|
260
|
-
url: importUrl,
|
261
|
-
timeout: options.timeout
|
262
|
-
};
|
263
|
-
axe.imports
|
264
|
-
.axios(axiosOptions)
|
265
|
-
.then(({ data }) =>
|
266
|
-
resolve(
|
267
|
-
options.convertDataToStylesheet({
|
268
|
-
data,
|
269
|
-
isExternal: true,
|
270
|
-
priority: newPriority,
|
271
|
-
root: options.rootNode,
|
272
|
-
shadowId: options.shadowId
|
273
|
-
})
|
274
|
-
)
|
275
|
-
)
|
276
|
-
.catch(reject);
|
277
|
-
})
|
278
|
-
);
|
279
|
-
|
280
|
-
const nonImportCSSRules = rules.filter(r => r.type !== 3);
|
281
|
-
|
282
|
-
// no further rules to process in this sheet
|
283
|
-
if (!nonImportCSSRules.length) {
|
284
|
-
return q;
|
285
|
-
}
|
286
|
-
|
287
|
-
// convert all `nonImportCSSRules` style rules into `text` and defer into queue
|
288
|
-
q.defer(resolve =>
|
289
|
-
resolve(
|
290
|
-
options.convertDataToStylesheet({
|
291
|
-
data: nonImportCSSRules.map(rule => rule.cssText).join(),
|
292
|
-
isExternal: false,
|
293
|
-
priority,
|
294
|
-
root: options.rootNode,
|
295
|
-
shadowId: options.shadowId
|
296
|
-
})
|
297
|
-
)
|
298
|
-
);
|
115
|
+
promises.push(p);
|
116
|
+
});
|
299
117
|
|
300
|
-
return
|
118
|
+
return Promise.all(promises);
|
301
119
|
}
|
302
120
|
|
303
121
|
/**
|
304
|
-
*
|
122
|
+
* Flatten CSSOM assets
|
305
123
|
*
|
306
|
-
* @param {
|
307
|
-
* @
|
308
|
-
* @param {Array<Number>} priority sheet priority
|
124
|
+
* @param {Array.<Object[]>} assets nested assets (varying depth)
|
125
|
+
* @returns {Array<Object>} Array of CSSOM object
|
309
126
|
*/
|
310
|
-
function
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
const axiosOptions = {
|
318
|
-
method: 'get',
|
319
|
-
url,
|
320
|
-
timeout: options.timeout
|
321
|
-
};
|
322
|
-
|
323
|
-
q.defer((resolve, reject) => {
|
324
|
-
axe.imports
|
325
|
-
.axios(axiosOptions)
|
326
|
-
.then(({ data }) =>
|
327
|
-
resolve(
|
328
|
-
options.convertDataToStylesheet({
|
329
|
-
data,
|
330
|
-
isExternal: true,
|
331
|
-
priority,
|
332
|
-
root: options.rootNode,
|
333
|
-
shadowId: options.shadowId
|
334
|
-
})
|
335
|
-
)
|
336
|
-
)
|
337
|
-
.catch(reject);
|
338
|
-
});
|
339
|
-
|
340
|
-
return q;
|
127
|
+
function flattenAssets(assets) {
|
128
|
+
return assets.reduce(
|
129
|
+
(acc, val) =>
|
130
|
+
Array.isArray(val) ? acc.concat(flattenAssets(val)) : acc.concat(val),
|
131
|
+
[]
|
132
|
+
);
|
341
133
|
}
|
342
134
|
|
343
135
|
/**
|
344
136
|
* Get stylesheet(s) for root
|
345
137
|
*
|
346
|
-
* @param {Object} options
|
347
|
-
* @
|
138
|
+
* @param {Object} options.rootNode `document` or `documentFragment`
|
139
|
+
* @param {String} options.shadowId an id if undefined denotes that given root is a document fragment/ shadowDOM
|
140
|
+
* @param {Function} options.convertDataToStylesheet a utility function to generate a style sheet from given data (text)
|
141
|
+
* @returns {Array<Object>} an array of stylesheets
|
348
142
|
*/
|
349
|
-
function getStylesheetsOfRootNode(
|
350
|
-
const { rootNode, shadowId } = options;
|
143
|
+
function getStylesheetsOfRootNode(rootNode, shadowId, convertDataToStylesheet) {
|
351
144
|
let sheets;
|
352
145
|
|
353
146
|
// nodeType === 11 -> DOCUMENT_FRAGMENT
|
354
147
|
if (rootNode.nodeType === 11 && shadowId) {
|
355
|
-
sheets = getStylesheetsFromDocumentFragment(
|
148
|
+
sheets = getStylesheetsFromDocumentFragment(
|
149
|
+
rootNode,
|
150
|
+
convertDataToStylesheet
|
151
|
+
);
|
356
152
|
} else {
|
357
153
|
sheets = getStylesheetsFromDocument(rootNode);
|
358
154
|
}
|
@@ -363,11 +159,11 @@ function getStylesheetsOfRootNode(options) {
|
|
363
159
|
/**
|
364
160
|
* Get stylesheets from `documentFragment`
|
365
161
|
*
|
366
|
-
* @
|
162
|
+
* @property {Object} options.rootNode `documentFragment`
|
163
|
+
* @property {Function} options.convertDataToStylesheet a utility function to generate a stylesheet from given data
|
367
164
|
* @returns {Array<Object>}
|
368
165
|
*/
|
369
|
-
function getStylesheetsFromDocumentFragment(
|
370
|
-
const { rootNode, convertDataToStylesheet } = options;
|
166
|
+
function getStylesheetsFromDocumentFragment(rootNode, convertDataToStylesheet) {
|
371
167
|
return (
|
372
168
|
Array.from(rootNode.children)
|
373
169
|
.filter(filerStyleAndLinkAttributesInDocumentFragment)
|