govuk_publishing_components 21.57.1 → 21.60.2

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -6
  3. data/app/assets/javascripts/component_guide/accessibility-test.js +21 -21
  4. data/app/assets/javascripts/component_guide/filter-components.js +19 -19
  5. data/app/assets/javascripts/component_guide/visual-regression.js +38 -37
  6. data/app/assets/javascripts/govuk_publishing_components/components/checkboxes.js +2 -2
  7. data/app/assets/javascripts/govuk_publishing_components/components/details.js +6 -4
  8. data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +4 -4
  9. data/app/assets/javascripts/govuk_publishing_components/lib/auto-track-event.js +31 -0
  10. data/app/assets/javascripts/govuk_publishing_components/lib/cookie-functions.js +24 -24
  11. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/youtube-link-enhancement.js +17 -17
  12. data/app/assets/stylesheets/component_guide/application.scss +15 -15
  13. data/app/assets/stylesheets/govuk_publishing_components/components/_action-link.scss +0 -8
  14. data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +1 -1
  15. data/app/assets/stylesheets/govuk_publishing_components/components/_checkboxes.scss +4 -0
  16. data/app/assets/stylesheets/govuk_publishing_components/components/_cookie-banner.scss +1 -8
  17. data/app/assets/stylesheets/govuk_publishing_components/components/_feedback.scss +0 -1
  18. data/app/assets/stylesheets/govuk_publishing_components/components/_govspeak-html-publication.scss +4 -5
  19. data/app/assets/stylesheets/govuk_publishing_components/components/_heading.scss +3 -8
  20. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -1
  21. data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +1 -1
  22. data/app/assets/stylesheets/govuk_publishing_components/components/_inverse-header.scss +5 -8
  23. data/app/assets/stylesheets/govuk_publishing_components/components/_list.scss +1 -0
  24. data/app/assets/stylesheets/govuk_publishing_components/components/_radio.scss +4 -0
  25. data/app/assets/stylesheets/govuk_publishing_components/components/_related-navigation.scss +2 -2
  26. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +7 -3
  27. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-header.scss +0 -5
  28. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-related.scss +1 -4
  29. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav.scss +8 -12
  30. data/app/assets/stylesheets/govuk_publishing_components/components/_table.scss +21 -24
  31. data/app/assets/stylesheets/govuk_publishing_components/components/_tabs.scss +4 -8
  32. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_attachment.scss +2 -0
  33. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_button.scss +1 -4
  34. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_charts.scss +6 -6
  35. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_contact.scss +2 -0
  36. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_footnotes.scss +2 -0
  37. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_highlight-answer.scss +2 -0
  38. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_place.scss +1 -1
  39. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_typography.scss +2 -0
  40. data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -1
  41. data/app/assets/stylesheets/govuk_publishing_components/components/print/_govspeak.scss +2 -0
  42. data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav-header.scss +0 -4
  43. data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav.scss +2 -10
  44. data/app/controllers/govuk_publishing_components/audit_controller.rb +52 -0
  45. data/app/controllers/govuk_publishing_components/component_guide_controller.rb +2 -1
  46. data/app/models/govuk_publishing_components/audit_applications.rb +117 -0
  47. data/app/models/govuk_publishing_components/audit_comparer.rb +198 -0
  48. data/app/models/govuk_publishing_components/audit_components.rb +158 -0
  49. data/app/views/govuk_publishing_components/audit/show.html.erb +258 -0
  50. data/app/views/govuk_publishing_components/component_guide/index.html.erb +9 -4
  51. data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +1 -1
  52. data/app/views/govuk_publishing_components/components/_image_card.html.erb +1 -1
  53. data/app/views/govuk_publishing_components/components/_list.html.erb +26 -0
  54. data/app/views/govuk_publishing_components/components/_machine_readable_metadata.html.erb +1 -1
  55. data/app/views/govuk_publishing_components/components/_radio.html.erb +13 -5
  56. data/app/views/govuk_publishing_components/components/_step_by_step_nav_header.html.erb +2 -2
  57. data/app/views/govuk_publishing_components/components/docs/checkboxes.yml +4 -0
  58. data/app/views/govuk_publishing_components/components/docs/govspeak.yml +45 -0
  59. data/app/views/govuk_publishing_components/components/docs/heading.yml +6 -3
  60. data/app/views/govuk_publishing_components/components/docs/image_card.yml +13 -1
  61. data/app/views/govuk_publishing_components/components/docs/list.yml +64 -0
  62. data/app/views/govuk_publishing_components/components/docs/radio.yml +4 -0
  63. data/config/routes.rb +1 -0
  64. data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +15 -7
  65. data/lib/govuk_publishing_components/presenters/heading_helper.rb +21 -1
  66. data/lib/govuk_publishing_components/presenters/image_card_helper.rb +2 -1
  67. data/lib/govuk_publishing_components/version.rb +1 -1
  68. data/node_modules/axe-core/package.json +145 -220
  69. data/node_modules/govuk-frontend/govuk/all.js +160 -57
  70. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +16 -8
  71. data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +6 -0
  72. data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +1 -0
  73. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +6 -5
  74. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +68 -21
  75. data/node_modules/govuk-frontend/govuk/components/date-input/macro-options.json +1 -1
  76. data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +0 -27
  77. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +0 -3
  78. data/node_modules/govuk-frontend/govuk/components/footer/template.njk +1 -1
  79. data/node_modules/govuk-frontend/govuk/components/header/template.njk +1 -1
  80. data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +2 -2
  81. data/node_modules/govuk-frontend/govuk/components/hint/template.njk +2 -2
  82. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +0 -3
  83. data/node_modules/govuk-frontend/govuk/components/input/macro-options.json +6 -0
  84. data/node_modules/govuk-frontend/govuk/components/input/template.njk +1 -0
  85. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +76 -28
  86. data/node_modules/govuk-frontend/govuk/components/select/_index.scss +0 -3
  87. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -0
  88. data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +0 -3
  89. data/node_modules/govuk-frontend/govuk/components/textarea/macro-options.json +6 -0
  90. data/node_modules/govuk-frontend/govuk/components/textarea/template.njk +1 -0
  91. data/node_modules/govuk-frontend/govuk/components/warning-text/_index.scss +4 -2
  92. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +1 -1
  93. data/node_modules/govuk-frontend/govuk/settings/_colours-applied.scss +2 -2
  94. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +1 -1
  95. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +4 -1
  96. data/node_modules/govuk-frontend/package.json +14 -81
  97. data/node_modules/jquery/package.json +44 -116
  98. metadata +46 -66
  99. data/Rakefile +0 -32
@@ -1,222 +1,147 @@
1
1
  {
2
- "_args": [
3
- [
4
- {
5
- "raw": "axe-core@^3.5.4",
6
- "scope": null,
7
- "escapedName": "axe-core",
8
- "name": "axe-core",
9
- "rawSpec": "^3.5.4",
10
- "spec": ">=3.5.4 <4.0.0",
11
- "type": "range"
12
- },
13
- "/var/lib/jenkins/workspace/ublishing_components_master-N4FWJIUY4CIFHKGZOAAEVVXODRY3YBORQOPIBBXWX72VUPSGJRRQ"
14
- ]
15
- ],
16
- "_from": "axe-core@>=3.5.4 <4.0.0",
17
- "_hasShrinkwrap": false,
18
- "_id": "axe-core@3.5.5",
19
- "_inCache": true,
20
- "_location": "/axe-core",
21
- "_nodeVersion": "10.21.0",
22
- "_npmOperationalInternal": {
23
- "host": "s3://npm-registry-packages",
24
- "tmp": "tmp/axe-core_3.5.5_1592406217427_0.7348143825163969"
25
- },
26
- "_npmUser": {
27
- "name": "npmdeque",
28
- "email": "axe@deque.com"
29
- },
30
- "_npmVersion": "6.14.4",
31
- "_phantomChildren": {},
32
- "_requested": {
33
- "raw": "axe-core@^3.5.4",
34
- "scope": null,
35
- "escapedName": "axe-core",
36
- "name": "axe-core",
37
- "rawSpec": "^3.5.4",
38
- "spec": ">=3.5.4 <4.0.0",
39
- "type": "range"
40
- },
41
- "_requiredBy": [
42
- "/"
43
- ],
44
- "_resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.5.5.tgz",
45
- "_shasum": "84315073b53fa3c0c51676c588d59da09a192227",
46
- "_shrinkwrap": null,
47
- "_spec": "axe-core@^3.5.4",
48
- "_where": "/var/lib/jenkins/workspace/ublishing_components_master-N4FWJIUY4CIFHKGZOAAEVVXODRY3YBORQOPIBBXWX72VUPSGJRRQ",
49
- "bugs": {
50
- "url": "https://github.com/dequelabs/axe-core/issues"
51
- },
52
- "contributors": [
53
- {
54
- "name": "David Sturley",
55
- "url": "http://deque.com/"
56
- },
57
- {
58
- "name": "Dylan Barrell",
59
- "email": "dylan@barrell.com",
60
- "url": "http://deque.com/"
61
- },
62
- {
63
- "name": "Wilco Fiers",
64
- "url": "http://deque.com/"
65
- },
66
- {
67
- "name": "Dian Fay",
68
- "url": "http://deque.com/"
69
- },
70
- {
71
- "name": "Marcy Sutton",
72
- "url": "http://deque.com/"
73
- }
74
- ],
75
- "dependencies": {},
76
- "description": "Accessibility engine for automated Web UI testing",
77
- "devDependencies": {
78
- "@babel/core": "^7.5.4",
79
- "@babel/plugin-proposal-object-rest-spread": "^7.5.4",
80
- "@babel/polyfill": "^7.4.4",
81
- "@babel/preset-env": "^7.5.4",
82
- "@deque/dot": "^1.1.5",
83
- "aria-query": "^3.0.0",
84
- "axios": "^0.19.0",
85
- "babelify": "^10.0.0",
86
- "blanket": "~1.2.3",
87
- "browserify": "^16.2.3",
88
- "chai": "~4.2.0",
89
- "clone": "~2.1.1",
90
- "core-js": "^3.2.1",
91
- "css-selector-parser": "^1.3.0",
92
- "derequire": "^2.0.6",
93
- "emoji-regex": "8.0.0",
94
- "es6-promise": "^4.2.6",
95
- "eslint": "^6.1.0",
96
- "eslint-config-prettier": "^6.2.0",
97
- "execa": "^2.0.2",
98
- "fs-extra": "^8.0.1",
99
- "globby": "^10.0.0",
100
- "grunt": "^1.0.3",
101
- "grunt-babel": "^8.0.0",
102
- "grunt-contrib-clean": "^2.0.0",
103
- "grunt-contrib-concat": "^1.0.1",
104
- "grunt-contrib-connect": "^2.0.0",
105
- "grunt-contrib-copy": "^1.0.0",
106
- "grunt-contrib-uglify": "^4.0.0",
107
- "grunt-contrib-watch": "^1.1.0",
108
- "grunt-parallel": "^0.5.1",
109
- "grunt-run": "^0.8.1",
110
- "html-entities": "^1.2.0",
111
- "husky": "^3.0.0",
112
- "jquery": "^3.0.0",
113
- "jsdoc": "^3.5.5",
114
- "lint-staged": "^9.2.1",
115
- "make-dir": "^3.0.0",
116
- "markdown-table": "^1.1.2",
117
- "memoizee": "^0.4.14",
118
- "minami": "^1.2.3",
119
- "mkdirp": "^0.5.1",
120
- "mocha": "^6.1.2",
121
- "mocha-headless-chrome": "^2.0.3",
122
- "prettier": "^1.17.1",
123
- "puppeteer": "^2.0.0",
124
- "revalidator": "~0.3.1",
125
- "selenium-webdriver": "~3.6.0",
126
- "sinon": "^7.5.0",
127
- "sri-toolbox": "^0.2.0",
128
- "standard-version": "^7.0.0",
129
- "typescript": "^3.5.3",
130
- "uglify-js": "^3.4.4",
131
- "weakmap-polyfill": "^2.0.0"
132
- },
133
- "directories": {},
134
- "dist": {
135
- "integrity": "sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==",
136
- "shasum": "84315073b53fa3c0c51676c588d59da09a192227",
137
- "tarball": "https://registry.npmjs.org/axe-core/-/axe-core-3.5.5.tgz",
138
- "fileCount": 596,
139
- "unpackedSize": 2642777,
140
- "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe6jDJCRA9TVsSAnZWagAAGCMQAJ1oBZRRo34GrgSa/2t6\nYeU2J8z5qkLNFILI65HVEzcu2e/TL8rHFgi9Q1Ga4szh41PTXJd0YfnPvYWt\nx+EiZ+TSoeSSksj5VoS3wjQFn2cQ55LyUOW0lQ3s1sPwEgALZPG3pLCn7GW+\nZiOW+Ai1FHESY/dbxZ1Rl1IrOt+jbOZqsczb0yk8PkZ9QwPJjZL70iLI8DRL\n5JMGoAmO4dJ3Vk+t2Dhy7vnwz+bFbs9lRKZaBJp4dYqY0F8HHC91hROv9pTP\n4hCNXevA6SKSf/Ddl7ub51EN1qQalYHQTQ0al4i0isv6NPlUnPVYaGzTHpZE\n2OTvoZ+dVqSDnCJqYH/WrIRfO0xA3bKTlRn6HyMkHFJOcXmi6NR/47uQfY/6\nr5a/N7nBsWh92aaoEw9ZVoNyMAgeEJlOt5uzXQgOWgJM8WIpqbTUJOeqXfEe\nI9FC2NhNU8Gqw9Ee24KCrCg8PWeODV/r47IHkQRdHqoqh1+/hzkUUhVP1smC\n6eI8qFTnhwws+EwNbxvBg73BCwsEiRwXaE7U0PToPLQvxyr0CRjqzJsl6Hhi\nOowldaReyMQALfJTipnc/Eb1VqCVQ1ABaYltnyVRnCL22mZUJGgq65OINJjT\nYGr9pWAh8r+C4MkIJf8C05eYJB6QL8+kry8YDDDtd2NdUHW8IKOax1p3MuqD\nG8u9\r\n=lmaS\r\n-----END PGP SIGNATURE-----\r\n"
141
- },
142
- "engines": {
143
- "node": ">=4"
144
- },
145
- "gitHead": "c19c8b616f9ed836fb72f14aaaff53072ea13fdc",
146
- "homepage": "https://www.deque.com/axe/",
147
- "keywords": [
148
- "Accessibility",
149
- "a11y",
150
- "testing",
151
- "unit",
152
- "tdd",
153
- "bdd",
154
- "axe"
155
- ],
156
- "license": "MPL-2.0",
157
- "lint-staged": {
158
- "*.{md,json,ts,html}": [
159
- "prettier --write",
160
- "git add"
161
- ],
162
- "*.js": [
163
- "eslint --fix",
164
- "prettier --write",
165
- "git add"
166
- ]
167
- },
168
- "main": "axe.js",
169
- "maintainers": [
170
- {
171
- "name": "dequelabs",
172
- "email": "labs@deque.com"
173
- },
174
- {
175
- "name": "dylanb",
176
- "email": "dylan@barrell.com"
177
- },
178
- {
179
- "name": "marcysutton",
180
- "email": "marcy.sutton@deque.com"
181
- },
182
- {
183
- "name": "wilcofiers",
184
- "email": "wilcofiers@gmail.com"
185
- }
186
- ],
187
- "name": "axe-core",
188
- "optionalDependencies": {},
189
- "readme": "ERROR: No README data found!",
190
- "repository": {
191
- "type": "git",
192
- "url": "git+https://github.com/dequelabs/axe-core.git"
193
- },
194
- "scripts": {
195
- "api-docs": "jsdoc --configure .jsdoc.json",
196
- "build": "grunt",
197
- "develop": "grunt dev --force",
198
- "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'",
199
- "fmt": "prettier --write *.{json,md,js} **/*.ts './{.github,build,doc,lib,test}/**/*.{json,md,js,ts,html}'",
200
- "imports-gen": "node ./build/imports-generator",
201
- "next-release": "standard-version --scripts.prebump=./build/next-version.js --skip.commit=true --skip.tag=true",
202
- "prepublishOnly": "grunt build && grunt file-exists",
203
- "release": "standard-version -a",
204
- "rule-gen": "node build/rule-generator",
205
- "sri-update": "grunt build && node build/sri-update && git add sri-history.json",
206
- "sri-validate": "node build/sri-update --validate",
207
- "start": "npm run develop",
208
- "test": "tsc && grunt test",
209
- "test:examples": "node ./doc/examples/test-examples",
210
- "test:headless": "node ./build/test/headless",
211
- "test:locales": "mocha test/test-locales.js",
212
- "test:rule-help-version": "mocha test/test-rule-help-version.js",
213
- "version": "echo \"use 'npm run release' to bump axe-core version\" && exit 1"
214
- },
215
- "standard-version": {
216
- "scripts": {
217
- "postbump": "npm ci && npm run sri-update"
218
- }
219
- },
220
- "typings": "axe.d.ts",
221
- "version": "3.5.5"
2
+ "name": "axe-core",
3
+ "description": "Accessibility engine for automated Web UI testing",
4
+ "version": "3.5.5",
5
+ "license": "MPL-2.0",
6
+ "engines": {
7
+ "node": ">=4"
8
+ },
9
+ "contributors": [
10
+ {
11
+ "name": "David Sturley",
12
+ "organization": "Deque Systems, Inc.",
13
+ "url": "http://deque.com/"
14
+ },
15
+ {
16
+ "name": "Dylan Barrell",
17
+ "email": "dylan@barrell.com",
18
+ "organization": "Deque Systems, Inc.",
19
+ "url": "http://deque.com/"
20
+ },
21
+ {
22
+ "name": "Wilco Fiers",
23
+ "organization": "Deque Systems, Inc.",
24
+ "url": "http://deque.com/"
25
+ },
26
+ {
27
+ "name": "Dian Fay",
28
+ "organization": "Deque Systems, Inc.",
29
+ "url": "http://deque.com/"
30
+ },
31
+ {
32
+ "name": "Marcy Sutton",
33
+ "organization": "Deque Systems, Inc.",
34
+ "url": "http://deque.com/"
35
+ }
36
+ ],
37
+ "homepage": "https://www.deque.com/axe/",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/dequelabs/axe-core.git"
41
+ },
42
+ "keywords": [
43
+ "Accessibility",
44
+ "a11y",
45
+ "testing",
46
+ "unit",
47
+ "tdd",
48
+ "bdd",
49
+ "axe"
50
+ ],
51
+ "main": "axe.js",
52
+ "typings": "axe.d.ts",
53
+ "standard-version": {
54
+ "scripts": {
55
+ "postbump": "npm ci && npm run sri-update"
56
+ }
57
+ },
58
+ "scripts": {
59
+ "start": "npm run develop",
60
+ "develop": "grunt dev --force",
61
+ "api-docs": "jsdoc --configure .jsdoc.json",
62
+ "imports-gen": "node ./build/imports-generator",
63
+ "build": "grunt",
64
+ "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'",
65
+ "test:headless": "node ./build/test/headless",
66
+ "test": "tsc && grunt test",
67
+ "test:examples": "node ./doc/examples/test-examples",
68
+ "test:locales": "mocha test/test-locales.js",
69
+ "test:rule-help-version": "mocha test/test-rule-help-version.js",
70
+ "version": "echo \"use 'npm run release' to bump axe-core version\" && exit 1",
71
+ "prepublishOnly": "grunt build && grunt file-exists",
72
+ "release": "standard-version -a",
73
+ "rule-gen": "node build/rule-generator",
74
+ "next-release": "standard-version --scripts.prebump=./build/next-version.js --skip.commit=true --skip.tag=true",
75
+ "sri-update": "grunt build && node build/sri-update && git add sri-history.json",
76
+ "sri-validate": "node build/sri-update --validate",
77
+ "fmt": "prettier --write *.{json,md,js} **/*.ts './{.github,build,doc,lib,test}/**/*.{json,md,js,ts,html}'"
78
+ },
79
+ "devDependencies": {
80
+ "@babel/core": "^7.5.4",
81
+ "@babel/plugin-proposal-object-rest-spread": "^7.5.4",
82
+ "@babel/polyfill": "^7.4.4",
83
+ "@babel/preset-env": "^7.5.4",
84
+ "@deque/dot": "^1.1.5",
85
+ "aria-query": "^3.0.0",
86
+ "axios": "^0.19.0",
87
+ "babelify": "^10.0.0",
88
+ "blanket": "~1.2.3",
89
+ "browserify": "^16.2.3",
90
+ "chai": "~4.2.0",
91
+ "clone": "~2.1.1",
92
+ "core-js": "^3.2.1",
93
+ "css-selector-parser": "^1.3.0",
94
+ "derequire": "^2.0.6",
95
+ "emoji-regex": "8.0.0",
96
+ "es6-promise": "^4.2.6",
97
+ "eslint": "^6.1.0",
98
+ "eslint-config-prettier": "^6.2.0",
99
+ "execa": "^2.0.2",
100
+ "fs-extra": "^8.0.1",
101
+ "globby": "^10.0.0",
102
+ "grunt": "^1.0.3",
103
+ "grunt-babel": "^8.0.0",
104
+ "grunt-contrib-clean": "^2.0.0",
105
+ "grunt-contrib-concat": "^1.0.1",
106
+ "grunt-contrib-connect": "^2.0.0",
107
+ "grunt-contrib-copy": "^1.0.0",
108
+ "grunt-contrib-uglify": "^4.0.0",
109
+ "grunt-contrib-watch": "^1.1.0",
110
+ "grunt-parallel": "^0.5.1",
111
+ "grunt-run": "^0.8.1",
112
+ "html-entities": "^1.2.0",
113
+ "husky": "^3.0.0",
114
+ "jquery": "^3.0.0",
115
+ "jsdoc": "^3.5.5",
116
+ "lint-staged": "^9.2.1",
117
+ "make-dir": "^3.0.0",
118
+ "markdown-table": "^1.1.2",
119
+ "memoizee": "^0.4.14",
120
+ "minami": "^1.2.3",
121
+ "mkdirp": "^0.5.1",
122
+ "mocha": "^6.1.2",
123
+ "mocha-headless-chrome": "^2.0.3",
124
+ "prettier": "^1.17.1",
125
+ "puppeteer": "^2.0.0",
126
+ "revalidator": "~0.3.1",
127
+ "selenium-webdriver": "~3.6.0",
128
+ "sinon": "^7.5.0",
129
+ "sri-toolbox": "^0.2.0",
130
+ "standard-version": "^7.0.0",
131
+ "typescript": "^3.5.3",
132
+ "uglify-js": "^3.4.4",
133
+ "weakmap-polyfill": "^2.0.0"
134
+ },
135
+ "dependencies": {},
136
+ "lint-staged": {
137
+ "*.{md,json,ts,html}": [
138
+ "prettier --write",
139
+ "git add"
140
+ ],
141
+ "*.js": [
142
+ "eslint --fix",
143
+ "prettier --write",
144
+ "git add"
145
+ ]
146
+ }
222
147
  }
@@ -1542,13 +1542,22 @@ CharacterCount.prototype.init = function () {
1542
1542
  // Remove hard limit if set
1543
1543
  $module.removeAttribute('maxlength');
1544
1544
 
1545
- // Bind event changes to the textarea
1546
- var boundChangeEvents = this.bindChangeEvents.bind(this);
1547
- boundChangeEvents();
1545
+ // When the page is restored after navigating 'back' in some browsers the
1546
+ // state of the character count is not restored until *after* the DOMContentLoaded
1547
+ // event is fired, so we need to sync after the pageshow event in browsers
1548
+ // that support it.
1549
+ if ('onpageshow' in window) {
1550
+ window.addEventListener('pageshow', this.sync.bind(this));
1551
+ } else {
1552
+ window.addEventListener('DOMContentLoaded', this.sync.bind(this));
1553
+ }
1554
+
1555
+ this.sync();
1556
+ };
1548
1557
 
1549
- // Update count message
1550
- var boundUpdateCountMessage = this.updateCountMessage.bind(this);
1551
- boundUpdateCountMessage();
1558
+ CharacterCount.prototype.sync = function () {
1559
+ this.bindChangeEvents();
1560
+ this.updateCountMessage();
1552
1561
  };
1553
1562
 
1554
1563
  // Read data attributes
@@ -1596,8 +1605,7 @@ CharacterCount.prototype.checkIfValueChanged = function () {
1596
1605
  if (!this.$textarea.oldValue) this.$textarea.oldValue = '';
1597
1606
  if (this.$textarea.value !== this.$textarea.oldValue) {
1598
1607
  this.$textarea.oldValue = this.$textarea.value;
1599
- var boundUpdateCountMessage = this.updateCountMessage.bind(this);
1600
- boundUpdateCountMessage();
1608
+ this.updateCountMessage();
1601
1609
  }
1602
1610
  };
1603
1611
 
@@ -1666,44 +1674,91 @@ function Checkboxes ($module) {
1666
1674
  this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
1667
1675
  }
1668
1676
 
1677
+ /**
1678
+ * Initialise Checkboxes
1679
+ *
1680
+ * Checkboxes can be associated with a 'conditionally revealed' content block –
1681
+ * for example, a checkbox for 'Phone' could reveal an additional form field for
1682
+ * the user to enter their phone number.
1683
+ *
1684
+ * These associations are made using a `data-aria-controls` attribute, which is
1685
+ * promoted to an aria-controls attribute during initialisation.
1686
+ *
1687
+ * We also need to restore the state of any conditional reveals on the page (for
1688
+ * example if the user has navigated back), and set up event handlers to keep
1689
+ * the reveal in sync with the checkbox state.
1690
+ */
1669
1691
  Checkboxes.prototype.init = function () {
1670
1692
  var $module = this.$module;
1671
1693
  var $inputs = this.$inputs;
1672
1694
 
1673
- /**
1674
- * Loop over all items with [data-controls]
1675
- * Check if they have a matching conditional reveal
1676
- * If they do, assign attributes.
1677
- **/
1678
1695
  nodeListForEach($inputs, function ($input) {
1679
- var controls = $input.getAttribute('data-aria-controls');
1696
+ var target = $input.getAttribute('data-aria-controls');
1680
1697
 
1681
- // Check if input controls anything
1682
- // Check if content exists, before setting attributes.
1683
- if (!controls || !$module.querySelector('#' + controls)) {
1698
+ // Skip checkboxes without data-aria-controls attributes, or where the
1699
+ // target element does not exist.
1700
+ if (!target || !$module.querySelector('#' + target)) {
1684
1701
  return
1685
1702
  }
1686
1703
 
1687
- // If we have content that is controlled, set attributes.
1688
- $input.setAttribute('aria-controls', controls);
1704
+ // Promote the data-aria-controls attribute to a aria-controls attribute
1705
+ // so that the relationship is exposed in the AOM
1706
+ $input.setAttribute('aria-controls', target);
1689
1707
  $input.removeAttribute('data-aria-controls');
1690
- this.setAttributes($input);
1691
- }.bind(this));
1708
+ });
1709
+
1710
+ // When the page is restored after navigating 'back' in some browsers the
1711
+ // state of form controls is not restored until *after* the DOMContentLoaded
1712
+ // event is fired, so we need to sync after the pageshow event in browsers
1713
+ // that support it.
1714
+ if ('onpageshow' in window) {
1715
+ window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
1716
+ } else {
1717
+ window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
1718
+ }
1719
+
1720
+ // Although we've set up handlers to sync state on the pageshow or
1721
+ // DOMContentLoaded event, init could be called after those events have fired,
1722
+ // for example if they are added to the page dynamically, so sync now too.
1723
+ this.syncAllConditionalReveals();
1692
1724
 
1693
- // Handle events
1694
1725
  $module.addEventListener('click', this.handleClick.bind(this));
1695
1726
  };
1696
1727
 
1697
- Checkboxes.prototype.setAttributes = function ($input) {
1698
- var inputIsChecked = $input.checked;
1699
- $input.setAttribute('aria-expanded', inputIsChecked);
1728
+ /**
1729
+ * Sync the conditional reveal states for all inputs in this $module.
1730
+ */
1731
+ Checkboxes.prototype.syncAllConditionalReveals = function () {
1732
+ nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
1733
+ };
1734
+
1735
+ /**
1736
+ * Sync conditional reveal with the input state
1737
+ *
1738
+ * Synchronise the visibility of the conditional reveal, and its accessible
1739
+ * state, with the input's checked state.
1740
+ *
1741
+ * @param {HTMLInputElement} $input Checkbox input
1742
+ */
1743
+ Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
1744
+ var $target = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
1700
1745
 
1701
- var $content = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
1702
- if ($content) {
1703
- $content.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
1746
+ if ($target && $target.classList.contains('govuk-checkboxes__conditional')) {
1747
+ var inputIsChecked = $input.checked;
1748
+
1749
+ $input.setAttribute('aria-expanded', inputIsChecked);
1750
+ $target.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
1704
1751
  }
1705
1752
  };
1706
1753
 
1754
+ /**
1755
+ * Click event handler
1756
+ *
1757
+ * Handle a click within the $module – if the click occurred on a checkbox, sync
1758
+ * the state of any associated conditional reveal with the checkbox state.
1759
+ *
1760
+ * @param {MouseEvent} event Click event
1761
+ */
1707
1762
  Checkboxes.prototype.handleClick = function (event) {
1708
1763
  var $target = event.target;
1709
1764
 
@@ -1711,7 +1766,7 @@ Checkboxes.prototype.handleClick = function (event) {
1711
1766
  var isCheckbox = $target.getAttribute('type') === 'checkbox';
1712
1767
  var hasAriaControls = $target.getAttribute('aria-controls');
1713
1768
  if (isCheckbox && hasAriaControls) {
1714
- this.setAttributes($target);
1769
+ this.syncConditionalRevealWithInputState($target);
1715
1770
  }
1716
1771
  };
1717
1772
 
@@ -1959,67 +2014,115 @@ Header.prototype.handleClick = function (event) {
1959
2014
 
1960
2015
  function Radios ($module) {
1961
2016
  this.$module = $module;
2017
+ this.$inputs = $module.querySelectorAll('input[type="radio"]');
1962
2018
  }
1963
2019
 
2020
+ /**
2021
+ * Initialise Radios
2022
+ *
2023
+ * Radios can be associated with a 'conditionally revealed' content block – for
2024
+ * example, a radio for 'Phone' could reveal an additional form field for the
2025
+ * user to enter their phone number.
2026
+ *
2027
+ * These associations are made using a `data-aria-controls` attribute, which is
2028
+ * promoted to an aria-controls attribute during initialisation.
2029
+ *
2030
+ * We also need to restore the state of any conditional reveals on the page (for
2031
+ * example if the user has navigated back), and set up event handlers to keep
2032
+ * the reveal in sync with the radio state.
2033
+ */
1964
2034
  Radios.prototype.init = function () {
1965
2035
  var $module = this.$module;
1966
- var $inputs = $module.querySelectorAll('input[type="radio"]');
2036
+ var $inputs = this.$inputs;
1967
2037
 
1968
- /**
1969
- * Loop over all items with [data-controls]
1970
- * Check if they have a matching conditional reveal
1971
- * If they do, assign attributes.
1972
- **/
1973
2038
  nodeListForEach($inputs, function ($input) {
1974
- var controls = $input.getAttribute('data-aria-controls');
2039
+ var target = $input.getAttribute('data-aria-controls');
1975
2040
 
1976
- // Check if input controls anything
1977
- // Check if content exists, before setting attributes.
1978
- if (!controls || !$module.querySelector('#' + controls)) {
2041
+ // Skip radios without data-aria-controls attributes, or where the
2042
+ // target element does not exist.
2043
+ if (!target || !$module.querySelector('#' + target)) {
1979
2044
  return
1980
2045
  }
1981
2046
 
1982
- // If we have content that is controlled, set attributes.
1983
- $input.setAttribute('aria-controls', controls);
2047
+ // Promote the data-aria-controls attribute to a aria-controls attribute
2048
+ // so that the relationship is exposed in the AOM
2049
+ $input.setAttribute('aria-controls', target);
1984
2050
  $input.removeAttribute('data-aria-controls');
1985
- this.setAttributes($input);
1986
- }.bind(this));
2051
+ });
2052
+
2053
+ // When the page is restored after navigating 'back' in some browsers the
2054
+ // state of form controls is not restored until *after* the DOMContentLoaded
2055
+ // event is fired, so we need to sync after the pageshow event in browsers
2056
+ // that support it.
2057
+ if ('onpageshow' in window) {
2058
+ window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
2059
+ } else {
2060
+ window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
2061
+ }
2062
+
2063
+ // Although we've set up handlers to sync state on the pageshow or
2064
+ // DOMContentLoaded event, init could be called after those events have fired,
2065
+ // for example if they are added to the page dynamically, so sync now too.
2066
+ this.syncAllConditionalReveals();
1987
2067
 
1988
2068
  // Handle events
1989
2069
  $module.addEventListener('click', this.handleClick.bind(this));
1990
2070
  };
1991
2071
 
1992
- Radios.prototype.setAttributes = function ($input) {
1993
- var $content = document.querySelector('#' + $input.getAttribute('aria-controls'));
2072
+ /**
2073
+ * Sync the conditional reveal states for all inputs in this $module.
2074
+ */
2075
+ Radios.prototype.syncAllConditionalReveals = function () {
2076
+ nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
2077
+ };
1994
2078
 
1995
- if ($content && $content.classList.contains('govuk-radios__conditional')) {
2079
+ /**
2080
+ * Sync conditional reveal with the input state
2081
+ *
2082
+ * Synchronise the visibility of the conditional reveal, and its accessible
2083
+ * state, with the input's checked state.
2084
+ *
2085
+ * @param {HTMLInputElement} $input Radio input
2086
+ */
2087
+ Radios.prototype.syncConditionalRevealWithInputState = function ($input) {
2088
+ var $target = document.querySelector('#' + $input.getAttribute('aria-controls'));
2089
+
2090
+ if ($target && $target.classList.contains('govuk-radios__conditional')) {
1996
2091
  var inputIsChecked = $input.checked;
1997
2092
 
1998
2093
  $input.setAttribute('aria-expanded', inputIsChecked);
1999
-
2000
- $content.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
2094
+ $target.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
2001
2095
  }
2002
2096
  };
2003
2097
 
2098
+ /**
2099
+ * Click event handler
2100
+ *
2101
+ * Handle a click within the $module – if the click occurred on a radio, sync
2102
+ * the state of the conditional reveal for all radio buttons in the same form
2103
+ * with the same name (because checking one radio could have un-checked a radio
2104
+ * in another $module)
2105
+ *
2106
+ * @param {MouseEvent} event Click event
2107
+ */
2004
2108
  Radios.prototype.handleClick = function (event) {
2005
2109
  var $clickedInput = event.target;
2006
- // We only want to handle clicks for radio inputs
2110
+
2111
+ // Ignore clicks on things that aren't radio buttons
2007
2112
  if ($clickedInput.type !== 'radio') {
2008
2113
  return
2009
2114
  }
2010
- // Because checking one radio can uncheck a radio in another $module,
2011
- // we need to call set attributes on all radios in the same form, or document if they're not in a form.
2012
- //
2013
- // We also only want radios which have aria-controls, as they support conditional reveals.
2115
+
2116
+ // We only need to consider radios with conditional reveals, which will have
2117
+ // aria-controls attributes.
2014
2118
  var $allInputs = document.querySelectorAll('input[type="radio"][aria-controls]');
2119
+
2015
2120
  nodeListForEach($allInputs, function ($input) {
2016
- // Only inputs with the same form owner should change.
2017
2121
  var hasSameFormOwner = ($input.form === $clickedInput.form);
2018
-
2019
- // In radios, only radios with the same name will affect each other.
2020
2122
  var hasSameName = ($input.name === $clickedInput.name);
2123
+
2021
2124
  if (hasSameName && hasSameFormOwner) {
2022
- this.setAttributes($input);
2125
+ this.syncConditionalRevealWithInputState($input);
2023
2126
  }
2024
2127
  }.bind(this));
2025
2128
  };