govuk_tech_docs 2.2.2 → 2.4.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.nvmrc +1 -1
  4. data/.travis.yml +2 -0
  5. data/CHANGELOG.md +24 -0
  6. data/example/config/tech-docs.yml +1 -0
  7. data/example/source/single-page-nav.html.md +13 -0
  8. data/govuk_tech_docs.gemspec +2 -1
  9. data/lib/assets/javascripts/_modules/collapsible-navigation.js +7 -7
  10. data/lib/assets/javascripts/_modules/in-page-navigation.js +2 -4
  11. data/lib/assets/stylesheets/_govuk_tech_docs.scss +9 -10
  12. data/lib/assets/stylesheets/modules/_search.scss +4 -25
  13. data/lib/assets/stylesheets/modules/_technical-documentation.scss +1 -1
  14. data/lib/assets/stylesheets/modules/_toc.scss +11 -11
  15. data/lib/govuk_tech_docs/table_of_contents/heading.rb +5 -1
  16. data/lib/govuk_tech_docs/table_of_contents/heading_tree_renderer.rb +2 -2
  17. data/lib/govuk_tech_docs/table_of_contents/helpers.rb +22 -11
  18. data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +1 -1
  19. data/lib/govuk_tech_docs/version.rb +1 -1
  20. data/lib/source/layouts/_header.erb +1 -2
  21. data/lib/source/layouts/layout.erb +3 -1
  22. data/node_modules/govuk-frontend/govuk/_base.scss +3 -0
  23. data/node_modules/govuk-frontend/govuk/all.js +306 -94
  24. data/node_modules/govuk-frontend/govuk/all.scss +1 -3
  25. data/node_modules/govuk-frontend/govuk/components/_all.scss +33 -29
  26. data/node_modules/govuk-frontend/govuk/components/accordion/_accordion.scss +2 -208
  27. data/node_modules/govuk-frontend/govuk/components/accordion/_index.scss +197 -0
  28. data/node_modules/govuk-frontend/govuk/components/accordion/accordion.js +1 -1
  29. data/node_modules/govuk-frontend/govuk/components/back-link/_back-link.scss +2 -65
  30. data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +99 -0
  31. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_breadcrumbs.scss +2 -118
  32. data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +138 -0
  33. data/node_modules/govuk-frontend/govuk/components/button/_button.scss +2 -284
  34. data/node_modules/govuk-frontend/govuk/components/button/_index.scss +288 -0
  35. data/node_modules/govuk-frontend/govuk/components/character-count/_character-count.scss +2 -31
  36. data/node_modules/govuk-frontend/govuk/components/character-count/_index.scss +25 -0
  37. data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +17 -9
  38. data/node_modules/govuk-frontend/govuk/components/checkboxes/_checkboxes.scss +2 -308
  39. data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +320 -0
  40. data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +129 -24
  41. data/node_modules/govuk-frontend/govuk/components/cookie-banner/_cookie-banner.scss +2 -0
  42. data/node_modules/govuk-frontend/govuk/components/cookie-banner/_index.scss +51 -0
  43. data/node_modules/govuk-frontend/govuk/components/date-input/_date-input.scss +2 -30
  44. data/node_modules/govuk-frontend/govuk/components/date-input/_index.scss +26 -0
  45. data/node_modules/govuk-frontend/govuk/components/details/_details.scss +2 -88
  46. data/node_modules/govuk-frontend/govuk/components/details/_index.scss +87 -0
  47. data/node_modules/govuk-frontend/govuk/components/error-message/_error-message.scss +2 -15
  48. data/node_modules/govuk-frontend/govuk/components/error-message/_index.scss +11 -0
  49. data/node_modules/govuk-frontend/govuk/components/error-summary/_error-summary.scss +2 -59
  50. data/node_modules/govuk-frontend/govuk/components/error-summary/_index.scss +43 -0
  51. data/node_modules/govuk-frontend/govuk/components/fieldset/_fieldset.scss +2 -68
  52. data/node_modules/govuk-frontend/govuk/components/fieldset/_index.scss +64 -0
  53. data/node_modules/govuk-frontend/govuk/components/file-upload/_file-upload.scss +2 -81
  54. data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +49 -0
  55. data/node_modules/govuk-frontend/govuk/components/footer/_footer.scss +2 -244
  56. data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +241 -0
  57. data/node_modules/govuk-frontend/govuk/components/header/_header.scss +2 -318
  58. data/node_modules/govuk-frontend/govuk/components/header/_index.scss +331 -0
  59. data/node_modules/govuk-frontend/govuk/components/header/header.js +665 -316
  60. data/node_modules/govuk-frontend/govuk/components/hint/_hint.scss +2 -50
  61. data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +44 -0
  62. data/node_modules/govuk-frontend/govuk/components/input/_index.scss +191 -0
  63. data/node_modules/govuk-frontend/govuk/components/input/_input.scss +2 -103
  64. data/node_modules/govuk-frontend/govuk/components/inset-text/_index.scss +24 -0
  65. data/node_modules/govuk-frontend/govuk/components/inset-text/_inset-text.scss +2 -28
  66. data/node_modules/govuk-frontend/govuk/components/label/_index.scss +41 -0
  67. data/node_modules/govuk-frontend/govuk/components/label/_label.scss +2 -45
  68. data/node_modules/govuk-frontend/govuk/components/notification-banner/_index.scss +89 -0
  69. data/node_modules/govuk-frontend/govuk/components/notification-banner/_notification-banner.scss +2 -0
  70. data/node_modules/govuk-frontend/govuk/components/notification-banner/notification-banner.js +61 -0
  71. data/node_modules/govuk-frontend/govuk/components/panel/_index.scss +44 -0
  72. data/node_modules/govuk-frontend/govuk/components/panel/_panel.scss +2 -44
  73. data/node_modules/govuk-frontend/govuk/components/phase-banner/_index.scss +27 -0
  74. data/node_modules/govuk-frontend/govuk/components/phase-banner/_phase-banner.scss +2 -31
  75. data/node_modules/govuk-frontend/govuk/components/radios/_index.scss +342 -0
  76. data/node_modules/govuk-frontend/govuk/components/radios/_radios.scss +2 -346
  77. data/node_modules/govuk-frontend/govuk/components/radios/radios.js +76 -28
  78. data/node_modules/govuk-frontend/govuk/components/select/_index.scss +49 -0
  79. data/node_modules/govuk-frontend/govuk/components/select/_select.scss +2 -57
  80. data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +36 -0
  81. data/node_modules/govuk-frontend/govuk/components/skip-link/_skip-link.scss +2 -37
  82. data/node_modules/govuk-frontend/govuk/components/summary-list/_index.scss +145 -0
  83. data/node_modules/govuk-frontend/govuk/components/summary-list/_summary-list.scss +2 -157
  84. data/node_modules/govuk-frontend/govuk/components/table/_index.scss +71 -0
  85. data/node_modules/govuk-frontend/govuk/components/table/_table.scss +2 -54
  86. data/node_modules/govuk-frontend/govuk/components/tabs/_index.scss +130 -0
  87. data/node_modules/govuk-frontend/govuk/components/tabs/_tabs.scss +2 -142
  88. data/node_modules/govuk-frontend/govuk/components/tag/_index.scss +86 -0
  89. data/node_modules/govuk-frontend/govuk/components/tag/_tag.scss +2 -91
  90. data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +47 -0
  91. data/node_modules/govuk-frontend/govuk/components/textarea/_textarea.scss +2 -55
  92. data/node_modules/govuk-frontend/govuk/components/warning-text/_index.scss +66 -0
  93. data/node_modules/govuk-frontend/govuk/components/warning-text/_warning-text.scss +2 -60
  94. data/node_modules/govuk-frontend/govuk/core/_global-styles.scss +5 -3
  95. data/node_modules/govuk-frontend/govuk/core/_links.scss +13 -3
  96. data/node_modules/govuk-frontend/govuk/core/_lists.scss +17 -3
  97. data/node_modules/govuk-frontend/govuk/core/_section-break.scss +5 -3
  98. data/node_modules/govuk-frontend/govuk/core/_template.scss +5 -4
  99. data/node_modules/govuk-frontend/govuk/core/_typography.scss +5 -3
  100. data/node_modules/govuk-frontend/govuk/helpers/_clearfix.scss +1 -1
  101. data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +1 -1
  102. data/node_modules/govuk-frontend/govuk/helpers/_device-pixels.scss +3 -3
  103. data/node_modules/govuk-frontend/govuk/helpers/_focused.scss +1 -1
  104. data/node_modules/govuk-frontend/govuk/helpers/_font-faces.scss +9 -11
  105. data/node_modules/govuk-frontend/govuk/helpers/_grid.scss +2 -1
  106. data/node_modules/govuk-frontend/govuk/helpers/_links.scss +246 -33
  107. data/node_modules/govuk-frontend/govuk/helpers/_media-queries.scss +2 -6
  108. data/node_modules/govuk-frontend/govuk/helpers/_shape-arrow.scss +1 -1
  109. data/node_modules/govuk-frontend/govuk/helpers/_spacing.scss +3 -2
  110. data/node_modules/govuk-frontend/govuk/helpers/_typography.scss +8 -7
  111. data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +1 -1
  112. data/node_modules/govuk-frontend/govuk/objects/_all.scss +1 -0
  113. data/node_modules/govuk-frontend/govuk/objects/_button-group.scss +101 -0
  114. data/node_modules/govuk-frontend/govuk/objects/_form-group.scss +1 -4
  115. data/node_modules/govuk-frontend/govuk/objects/_grid.scss +3 -6
  116. data/node_modules/govuk-frontend/govuk/objects/_main-wrapper.scss +5 -4
  117. data/node_modules/govuk-frontend/govuk/objects/_width-container.scss +6 -4
  118. data/node_modules/govuk-frontend/govuk/overrides/_display.scss +6 -4
  119. data/node_modules/govuk-frontend/govuk/overrides/_spacing.scss +5 -3
  120. data/node_modules/govuk-frontend/govuk/overrides/_typography.scss +5 -3
  121. data/node_modules/govuk-frontend/govuk/overrides/_width.scss +6 -3
  122. data/node_modules/govuk-frontend/govuk/settings/_all.scss +2 -0
  123. data/node_modules/govuk-frontend/govuk/settings/_colours-applied.scss +11 -5
  124. data/node_modules/govuk-frontend/govuk/settings/_colours-organisations.scss +3 -0
  125. data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +42 -35
  126. data/node_modules/govuk-frontend/govuk/settings/_compatibility.scss +0 -1
  127. data/node_modules/govuk-frontend/govuk/settings/_ie8.scss +1 -1
  128. data/node_modules/govuk-frontend/govuk/settings/_links.scss +62 -0
  129. data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +4 -5
  130. data/node_modules/govuk-frontend/govuk/settings/_typography-font-families.scss +2 -2
  131. data/node_modules/govuk-frontend/govuk/settings/_typography-font.scss +14 -5
  132. data/node_modules/govuk-frontend/govuk/settings/_typography-responsive.scss +6 -2
  133. data/node_modules/govuk-frontend/govuk/tools/_compatibility.scss +1 -1
  134. data/node_modules/govuk-frontend/govuk/tools/_font-url.scss +1 -4
  135. data/node_modules/govuk-frontend/govuk/tools/_ie8.scss +1 -1
  136. data/node_modules/govuk-frontend/govuk/tools/_image-url.scss +1 -4
  137. data/node_modules/govuk-frontend/govuk/tools/_px-to-em.scss +1 -1
  138. data/node_modules/govuk-frontend/govuk/tools/_px-to-rem.scss +1 -1
  139. data/node_modules/govuk-frontend/govuk/utilities/_visually-hidden.scss +0 -1
  140. data/node_modules/govuk-frontend/govuk/vendor/_sass-mq.scss +0 -4
  141. data/package-lock.json +358 -288
  142. data/package.json +2 -2
  143. metadata +56 -4
@@ -1,346 +1,2 @@
1
- @import "../../settings/all";
2
- @import "../../tools/all";
3
- @import "../../helpers/all";
4
-
5
- @import "../error-message/error-message";
6
- @import "../fieldset/fieldset";
7
- @import "../hint/hint";
8
- @import "../label/label";
9
-
10
- @include govuk-exports("govuk/component/radios") {
11
-
12
- $govuk-touch-target-size: 44px;
13
- $govuk-radios-size: 40px;
14
- $govuk-small-radios-size: 24px;
15
- $govuk-radios-label-padding-left-right: govuk-spacing(3);
16
- // When the default focus width is used on a curved edge it looks visually smaller.
17
- // So for the circular radios we bump the default to make it look visually consistent.
18
- $govuk-radios-focus-width: $govuk-focus-width + 1px;
19
-
20
- .govuk-radios__item {
21
- @include govuk-font($size: 19);
22
-
23
- display: block;
24
- position: relative;
25
-
26
- min-height: $govuk-radios-size;
27
-
28
- margin-bottom: govuk-spacing(2);
29
- padding-left: $govuk-radios-size;
30
-
31
- clear: left;
32
- }
33
-
34
- .govuk-radios__item:last-child,
35
- .govuk-radios__item:last-of-type {
36
- margin-bottom: 0;
37
- }
38
-
39
- .govuk-radios__input {
40
- $input-offset: ($govuk-touch-target-size - $govuk-radios-size) / 2;
41
-
42
- cursor: pointer;
43
-
44
- // IE8 doesn’t support pseudo-elements, so we don’t want to hide native
45
- // elements there.
46
- @include govuk-not-ie8 {
47
- position: absolute;
48
-
49
- z-index: 1;
50
- top: $input-offset * -1;
51
- left: $input-offset * -1;
52
-
53
- width: $govuk-touch-target-size;
54
- height: $govuk-touch-target-size;
55
- margin: 0;
56
-
57
- opacity: 0;
58
- }
59
-
60
- @include govuk-if-ie8 {
61
- margin-top: 10px;
62
- margin-right: $govuk-radios-size / -2;
63
- margin-left: $govuk-radios-size / -2;
64
- float: left;
65
-
66
- // add focus outline to input
67
- &:focus {
68
- outline: $govuk-focus-width solid $govuk-focus-colour;
69
- }
70
- }
71
- }
72
-
73
- .govuk-radios__label {
74
- display: inline-block;
75
- margin-bottom: 0;
76
- padding: 8px $govuk-radios-label-padding-left-right govuk-spacing(1);
77
- cursor: pointer;
78
- // remove 300ms pause on mobile
79
- -ms-touch-action: manipulation;
80
- touch-action: manipulation;
81
- }
82
-
83
- // ( ) Radio ring
84
- .govuk-radios__label::before {
85
- content: "";
86
- box-sizing: border-box;
87
- position: absolute;
88
- top: 0;
89
- left: 0;
90
-
91
- width: $govuk-radios-size;
92
- height: $govuk-radios-size;
93
-
94
- border: $govuk-border-width-form-element solid currentColor;
95
- border-radius: 50%;
96
- background: transparent;
97
- }
98
-
99
- // • Radio button
100
- //
101
- // We create the 'button' entirely out of 'border' so that they remain
102
- // 'filled' even when colours are overridden in the browser.
103
- .govuk-radios__label::after {
104
- content: "";
105
-
106
- position: absolute;
107
- top: govuk-spacing(2);
108
- left: govuk-spacing(2);
109
-
110
- width: 0;
111
- height: 0;
112
-
113
- border: govuk-spacing(2) solid currentColor;
114
- border-radius: 50%;
115
- opacity: 0;
116
- background: currentColor;
117
- }
118
-
119
- .govuk-radios__hint {
120
- display: block;
121
- padding-right: $govuk-radios-label-padding-left-right;
122
- padding-left: $govuk-radios-label-padding-left-right;
123
- }
124
-
125
- // Focused state
126
- .govuk-radios__input:focus + .govuk-radios__label::before {
127
- border-width: 4px;
128
- box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour;
129
- }
130
-
131
- // Selected state
132
- .govuk-radios__input:checked + .govuk-radios__label::after {
133
- opacity: 1;
134
- }
135
-
136
- // Disabled state
137
- .govuk-radios__input:disabled,
138
- .govuk-radios__input:disabled + .govuk-radios__label {
139
- cursor: default;
140
- }
141
-
142
- .govuk-radios__input:disabled + .govuk-radios__label {
143
- opacity: .5;
144
- }
145
-
146
- // =========================================================
147
- // Inline radios
148
- // =========================================================
149
-
150
- .govuk-radios--inline {
151
- @include govuk-media-query ($from: tablet) {
152
- @include govuk-clearfix;
153
-
154
- .govuk-radios__item {
155
- margin-right: govuk-spacing(4);
156
- float: left;
157
- clear: none;
158
- }
159
- }
160
-
161
- // Prevent inline modifier being used with conditional reveals
162
- &.govuk-radios--conditional {
163
- .govuk-radios__item {
164
- margin-right: 0;
165
- float: none;
166
- }
167
- }
168
- }
169
-
170
- // =========================================================
171
- // Dividers ('or')
172
- // =========================================================
173
-
174
- .govuk-radios__divider {
175
- $govuk-divider-size: $govuk-radios-size !default;
176
- @include govuk-font($size: 19);
177
- @include govuk-text-colour;
178
- width: $govuk-divider-size;
179
- margin-bottom: govuk-spacing(2);
180
- text-align: center;
181
- }
182
-
183
- // =========================================================
184
- // Conditional reveals
185
- // =========================================================
186
-
187
- // The narrow border is used in the conditional reveals because the border has
188
- // to be an even number in order to be centred under the 40px checkbox or radio.
189
- $conditional-border-width: $govuk-border-width-narrow;
190
- // Calculate the amount of padding needed to keep the border centered against the radios.
191
- $conditional-border-padding: ($govuk-radios-size / 2) - ($conditional-border-width / 2);
192
- // Move the border centered with the radios
193
- $conditional-margin-left: $conditional-border-padding;
194
- // Move the contents of the conditional inline with the label
195
- $conditional-padding-left: $conditional-border-padding + $govuk-radios-label-padding-left-right;
196
-
197
- .govuk-radios__conditional {
198
- @include govuk-responsive-margin(4, "bottom");
199
- margin-left: $conditional-margin-left;
200
- padding-left: $conditional-padding-left;
201
- border-left: $conditional-border-width solid $govuk-border-colour;
202
-
203
- .js-enabled &--hidden {
204
- display: none;
205
- }
206
-
207
- & > :last-child {
208
- margin-bottom: 0;
209
- }
210
- }
211
-
212
- // =========================================================
213
- // Small checkboxes
214
- // =========================================================
215
-
216
- .govuk-radios--small {
217
-
218
- $input-offset: ($govuk-touch-target-size - $govuk-small-radios-size) / 2;
219
- $label-offset: $govuk-touch-target-size - $input-offset;
220
-
221
- .govuk-radios__item {
222
- @include govuk-clearfix;
223
- min-height: 0;
224
- margin-bottom: 0;
225
- padding-left: $label-offset;
226
- float: left;
227
- }
228
-
229
- // Shift the touch target into the left margin so that the visible edge of
230
- // the control is aligned
231
- //
232
- // ┆Which colour is your favourite?
233
- // ┌┆───┐
234
- // │┆() │ Purple
235
- // └┆▲──┘
236
- // ▲┆└─ Radio pseudo element, aligned with margin
237
- // └─── Touch target (invisible input), shifted into the margin
238
- .govuk-radios__input {
239
- @include govuk-not-ie8 {
240
- left: $input-offset * -1;
241
- }
242
-
243
- @include govuk-if-ie8 {
244
- margin-left: $govuk-small-radios-size * -1;
245
- }
246
- }
247
-
248
- // Adjust the size and position of the label.
249
- //
250
- // Unlike larger radios, we also have to float the label in order to
251
- // 'shrink' it, preventing the hover state from kicking in across the full
252
- // width of the parent element.
253
- .govuk-radios__label {
254
- margin-top: -2px;
255
- padding: 13px govuk-spacing(3) 13px 1px;
256
- float: left;
257
-
258
- @include govuk-media-query($from: tablet) {
259
- padding: 11px govuk-spacing(3) 10px 1px;
260
- }
261
- }
262
-
263
- // ( ) Radio ring
264
- //
265
- // Reduce the size of the control [1], vertically centering it within the
266
- // touch target [2]
267
- .govuk-radios__label::before {
268
- top: $input-offset - $govuk-border-width-form-element; // 2
269
- width: $govuk-small-radios-size; // 1
270
- height: $govuk-small-radios-size; // 1
271
- }
272
-
273
- // • Radio button
274
- //
275
- // Reduce the size of the 'button' and center it within the ring
276
- .govuk-radios__label::after {
277
- top: 15px;
278
- left: 7px;
279
- border-width: 5px;
280
- }
281
-
282
- // Fix position of hint with small radios
283
- //
284
- // Do not use hints with small radios – because they're within the input
285
- // wrapper they trigger the hover state, but clicking them doesn't actually
286
- // activate the control.
287
- //
288
- // (If you do use them, they won't look completely broken... but seriously,
289
- // don't use them)
290
- .govuk-radios__hint {
291
- padding: 0;
292
- clear: both;
293
- pointer-events: none;
294
- }
295
-
296
- // Align conditional reveals with small radios
297
- .govuk-radios__conditional {
298
- $margin-left: ($govuk-small-radios-size / 2) - ($conditional-border-width / 2);
299
- margin-left: $margin-left;
300
- padding-left: $label-offset - ($margin-left + $conditional-border-width);
301
- clear: both;
302
- }
303
-
304
- .govuk-radios__divider {
305
- width: $govuk-small-radios-size;
306
- margin-bottom: govuk-spacing(1);
307
- }
308
-
309
- // Hover state for small radios.
310
- //
311
- // We use a hover state for small radios because the touch target size
312
- // is so much larger than their visible size, and so we need to provide
313
- // feedback to the user as to which radio they will select when their
314
- // cursor is outside of the visible area.
315
- .govuk-radios__item:hover .govuk-radios__input:not(:disabled) + .govuk-radios__label::before {
316
- box-shadow: 0 0 0 $govuk-hover-width $govuk-hover-colour;
317
- }
318
-
319
- // Because we've overridden the border-shadow provided by the focus state,
320
- // we need to redefine that too.
321
- //
322
- // We use two box shadows, one that restores the original focus state [1]
323
- // and another that then applies the hover state [2].
324
- .govuk-radios__item:hover .govuk-radios__input:focus + .govuk-radios__label::before {
325
- // sass-lint:disable indentation
326
- box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour, // 1
327
- 0 0 0 $govuk-hover-width $govuk-hover-colour; // 2
328
- }
329
-
330
- // For devices that explicitly don't support hover, don't provide a hover
331
- // state (e.g. on touch devices like iOS).
332
- //
333
- // We can't use `@media (hover: hover)` because we wouldn't get the hover
334
- // state in browsers that don't support `@media (hover)` (like Internet
335
- // Explorer) – so we have to 'undo' the hover state instead.
336
- @media (hover: none), (pointer: coarse) {
337
- .govuk-radios__item:hover .govuk-radios__input:not(:disabled) + .govuk-radios__label::before {
338
- box-shadow: initial;
339
- }
340
-
341
- .govuk-radios__item:hover .govuk-radios__input:focus + .govuk-radios__label::before {
342
- box-shadow: 0 0 0 $govuk-radios-focus-width $govuk-focus-colour;
343
- }
344
- }
345
- }
346
- }
1
+ @import "../../base";
2
+ @import "./index";
@@ -1030,67 +1030,115 @@ function nodeListForEach (nodes, callback) {
1030
1030
 
1031
1031
  function Radios ($module) {
1032
1032
  this.$module = $module;
1033
+ this.$inputs = $module.querySelectorAll('input[type="radio"]');
1033
1034
  }
1034
1035
 
1036
+ /**
1037
+ * Initialise Radios
1038
+ *
1039
+ * Radios can be associated with a 'conditionally revealed' content block – for
1040
+ * example, a radio for 'Phone' could reveal an additional form field for the
1041
+ * user to enter their phone number.
1042
+ *
1043
+ * These associations are made using a `data-aria-controls` attribute, which is
1044
+ * promoted to an aria-controls attribute during initialisation.
1045
+ *
1046
+ * We also need to restore the state of any conditional reveals on the page (for
1047
+ * example if the user has navigated back), and set up event handlers to keep
1048
+ * the reveal in sync with the radio state.
1049
+ */
1035
1050
  Radios.prototype.init = function () {
1036
1051
  var $module = this.$module;
1037
- var $inputs = $module.querySelectorAll('input[type="radio"]');
1052
+ var $inputs = this.$inputs;
1038
1053
 
1039
- /**
1040
- * Loop over all items with [data-controls]
1041
- * Check if they have a matching conditional reveal
1042
- * If they do, assign attributes.
1043
- **/
1044
1054
  nodeListForEach($inputs, function ($input) {
1045
- var controls = $input.getAttribute('data-aria-controls');
1055
+ var target = $input.getAttribute('data-aria-controls');
1046
1056
 
1047
- // Check if input controls anything
1048
- // Check if content exists, before setting attributes.
1049
- if (!controls || !$module.querySelector('#' + controls)) {
1057
+ // Skip radios without data-aria-controls attributes, or where the
1058
+ // target element does not exist.
1059
+ if (!target || !$module.querySelector('#' + target)) {
1050
1060
  return
1051
1061
  }
1052
1062
 
1053
- // If we have content that is controlled, set attributes.
1054
- $input.setAttribute('aria-controls', controls);
1063
+ // Promote the data-aria-controls attribute to a aria-controls attribute
1064
+ // so that the relationship is exposed in the AOM
1065
+ $input.setAttribute('aria-controls', target);
1055
1066
  $input.removeAttribute('data-aria-controls');
1056
- this.setAttributes($input);
1057
- }.bind(this));
1067
+ });
1068
+
1069
+ // When the page is restored after navigating 'back' in some browsers the
1070
+ // state of form controls is not restored until *after* the DOMContentLoaded
1071
+ // event is fired, so we need to sync after the pageshow event in browsers
1072
+ // that support it.
1073
+ if ('onpageshow' in window) {
1074
+ window.addEventListener('pageshow', this.syncAllConditionalReveals.bind(this));
1075
+ } else {
1076
+ window.addEventListener('DOMContentLoaded', this.syncAllConditionalReveals.bind(this));
1077
+ }
1078
+
1079
+ // Although we've set up handlers to sync state on the pageshow or
1080
+ // DOMContentLoaded event, init could be called after those events have fired,
1081
+ // for example if they are added to the page dynamically, so sync now too.
1082
+ this.syncAllConditionalReveals();
1058
1083
 
1059
1084
  // Handle events
1060
1085
  $module.addEventListener('click', this.handleClick.bind(this));
1061
1086
  };
1062
1087
 
1063
- Radios.prototype.setAttributes = function ($input) {
1064
- var $content = document.querySelector('#' + $input.getAttribute('aria-controls'));
1088
+ /**
1089
+ * Sync the conditional reveal states for all inputs in this $module.
1090
+ */
1091
+ Radios.prototype.syncAllConditionalReveals = function () {
1092
+ nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
1093
+ };
1065
1094
 
1066
- if ($content && $content.classList.contains('govuk-radios__conditional')) {
1095
+ /**
1096
+ * Sync conditional reveal with the input state
1097
+ *
1098
+ * Synchronise the visibility of the conditional reveal, and its accessible
1099
+ * state, with the input's checked state.
1100
+ *
1101
+ * @param {HTMLInputElement} $input Radio input
1102
+ */
1103
+ Radios.prototype.syncConditionalRevealWithInputState = function ($input) {
1104
+ var $target = document.querySelector('#' + $input.getAttribute('aria-controls'));
1105
+
1106
+ if ($target && $target.classList.contains('govuk-radios__conditional')) {
1067
1107
  var inputIsChecked = $input.checked;
1068
1108
 
1069
1109
  $input.setAttribute('aria-expanded', inputIsChecked);
1070
-
1071
- $content.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
1110
+ $target.classList.toggle('govuk-radios__conditional--hidden', !inputIsChecked);
1072
1111
  }
1073
1112
  };
1074
1113
 
1114
+ /**
1115
+ * Click event handler
1116
+ *
1117
+ * Handle a click within the $module – if the click occurred on a radio, sync
1118
+ * the state of the conditional reveal for all radio buttons in the same form
1119
+ * with the same name (because checking one radio could have un-checked a radio
1120
+ * in another $module)
1121
+ *
1122
+ * @param {MouseEvent} event Click event
1123
+ */
1075
1124
  Radios.prototype.handleClick = function (event) {
1076
1125
  var $clickedInput = event.target;
1077
- // We only want to handle clicks for radio inputs
1126
+
1127
+ // Ignore clicks on things that aren't radio buttons
1078
1128
  if ($clickedInput.type !== 'radio') {
1079
1129
  return
1080
1130
  }
1081
- // Because checking one radio can uncheck a radio in another $module,
1082
- // we need to call set attributes on all radios in the same form, or document if they're not in a form.
1083
- //
1084
- // We also only want radios which have aria-controls, as they support conditional reveals.
1131
+
1132
+ // We only need to consider radios with conditional reveals, which will have
1133
+ // aria-controls attributes.
1085
1134
  var $allInputs = document.querySelectorAll('input[type="radio"][aria-controls]');
1135
+
1086
1136
  nodeListForEach($allInputs, function ($input) {
1087
- // Only inputs with the same form owner should change.
1088
1137
  var hasSameFormOwner = ($input.form === $clickedInput.form);
1089
-
1090
- // In radios, only radios with the same name will affect each other.
1091
1138
  var hasSameName = ($input.name === $clickedInput.name);
1139
+
1092
1140
  if (hasSameName && hasSameFormOwner) {
1093
- this.setAttributes($input);
1141
+ this.syncConditionalRevealWithInputState($input);
1094
1142
  }
1095
1143
  }.bind(this));
1096
1144
  };