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.
- checksums.yaml +4 -4
- data/README.md +31 -6
- data/app/assets/javascripts/component_guide/accessibility-test.js +21 -21
- data/app/assets/javascripts/component_guide/filter-components.js +19 -19
- data/app/assets/javascripts/component_guide/visual-regression.js +38 -37
- data/app/assets/javascripts/govuk_publishing_components/components/checkboxes.js +2 -2
- data/app/assets/javascripts/govuk_publishing_components/components/details.js +6 -4
- data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +4 -4
- data/app/assets/javascripts/govuk_publishing_components/lib/auto-track-event.js +31 -0
- data/app/assets/javascripts/govuk_publishing_components/lib/cookie-functions.js +24 -24
- data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/youtube-link-enhancement.js +17 -17
- data/app/assets/stylesheets/component_guide/application.scss +15 -15
- data/app/assets/stylesheets/govuk_publishing_components/components/_action-link.scss +0 -8
- data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/_checkboxes.scss +4 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_cookie-banner.scss +1 -8
- data/app/assets/stylesheets/govuk_publishing_components/components/_feedback.scss +0 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/_govspeak-html-publication.scss +4 -5
- data/app/assets/stylesheets/govuk_publishing_components/components/_heading.scss +3 -8
- data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/_inverse-header.scss +5 -8
- data/app/assets/stylesheets/govuk_publishing_components/components/_list.scss +1 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_radio.scss +4 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_related-navigation.scss +2 -2
- data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +7 -3
- data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-header.scss +0 -5
- data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-related.scss +1 -4
- data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav.scss +8 -12
- data/app/assets/stylesheets/govuk_publishing_components/components/_table.scss +21 -24
- data/app/assets/stylesheets/govuk_publishing_components/components/_tabs.scss +4 -8
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_attachment.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_button.scss +1 -4
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_charts.scss +6 -6
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_contact.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_footnotes.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_highlight-answer.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_place.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_typography.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -1
- data/app/assets/stylesheets/govuk_publishing_components/components/print/_govspeak.scss +2 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav-header.scss +0 -4
- data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav.scss +2 -10
- data/app/controllers/govuk_publishing_components/audit_controller.rb +52 -0
- data/app/controllers/govuk_publishing_components/component_guide_controller.rb +2 -1
- data/app/models/govuk_publishing_components/audit_applications.rb +117 -0
- data/app/models/govuk_publishing_components/audit_comparer.rb +198 -0
- data/app/models/govuk_publishing_components/audit_components.rb +158 -0
- data/app/views/govuk_publishing_components/audit/show.html.erb +258 -0
- data/app/views/govuk_publishing_components/component_guide/index.html.erb +9 -4
- data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +1 -1
- data/app/views/govuk_publishing_components/components/_image_card.html.erb +1 -1
- data/app/views/govuk_publishing_components/components/_list.html.erb +26 -0
- data/app/views/govuk_publishing_components/components/_machine_readable_metadata.html.erb +1 -1
- data/app/views/govuk_publishing_components/components/_radio.html.erb +13 -5
- data/app/views/govuk_publishing_components/components/_step_by_step_nav_header.html.erb +2 -2
- data/app/views/govuk_publishing_components/components/docs/checkboxes.yml +4 -0
- data/app/views/govuk_publishing_components/components/docs/govspeak.yml +45 -0
- data/app/views/govuk_publishing_components/components/docs/heading.yml +6 -3
- data/app/views/govuk_publishing_components/components/docs/image_card.yml +13 -1
- data/app/views/govuk_publishing_components/components/docs/list.yml +64 -0
- data/app/views/govuk_publishing_components/components/docs/radio.yml +4 -0
- data/config/routes.rb +1 -0
- data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +15 -7
- data/lib/govuk_publishing_components/presenters/heading_helper.rb +21 -1
- data/lib/govuk_publishing_components/presenters/image_card_helper.rb +2 -1
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/axe-core/package.json +145 -220
- data/node_modules/govuk-frontend/govuk/all.js +160 -57
- data/node_modules/govuk-frontend/govuk/components/character-count/character-count.js +16 -8
- data/node_modules/govuk-frontend/govuk/components/character-count/macro-options.json +6 -0
- data/node_modules/govuk-frontend/govuk/components/character-count/template.njk +1 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/_index.scss +6 -5
- data/node_modules/govuk-frontend/govuk/components/checkboxes/checkboxes.js +68 -21
- data/node_modules/govuk-frontend/govuk/components/date-input/macro-options.json +1 -1
- data/node_modules/govuk-frontend/govuk/components/file-upload/_index.scss +0 -27
- data/node_modules/govuk-frontend/govuk/components/footer/_index.scss +0 -3
- data/node_modules/govuk-frontend/govuk/components/footer/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/header/template.njk +1 -1
- data/node_modules/govuk-frontend/govuk/components/hint/_index.scss +2 -2
- data/node_modules/govuk-frontend/govuk/components/hint/template.njk +2 -2
- data/node_modules/govuk-frontend/govuk/components/input/_index.scss +0 -3
- data/node_modules/govuk-frontend/govuk/components/input/macro-options.json +6 -0
- data/node_modules/govuk-frontend/govuk/components/input/template.njk +1 -0
- data/node_modules/govuk-frontend/govuk/components/radios/radios.js +76 -28
- data/node_modules/govuk-frontend/govuk/components/select/_index.scss +0 -3
- data/node_modules/govuk-frontend/govuk/components/skip-link/_index.scss +1 -0
- data/node_modules/govuk-frontend/govuk/components/textarea/_index.scss +0 -3
- data/node_modules/govuk-frontend/govuk/components/textarea/macro-options.json +6 -0
- data/node_modules/govuk-frontend/govuk/components/textarea/template.njk +1 -0
- data/node_modules/govuk-frontend/govuk/components/warning-text/_index.scss +4 -2
- data/node_modules/govuk-frontend/govuk/helpers/_colour.scss +1 -1
- data/node_modules/govuk-frontend/govuk/settings/_colours-applied.scss +2 -2
- data/node_modules/govuk-frontend/govuk/settings/_colours-palette.scss +1 -1
- data/node_modules/govuk-frontend/govuk/settings/_measurements.scss +4 -1
- data/node_modules/govuk-frontend/package.json +14 -81
- data/node_modules/jquery/package.json +44 -116
- metadata +46 -66
- data/Rakefile +0 -32
@@ -1062,13 +1062,22 @@ CharacterCount.prototype.init = function () {
|
|
1062
1062
|
// Remove hard limit if set
|
1063
1063
|
$module.removeAttribute('maxlength');
|
1064
1064
|
|
1065
|
-
//
|
1066
|
-
|
1067
|
-
|
1065
|
+
// When the page is restored after navigating 'back' in some browsers the
|
1066
|
+
// state of the character count is not restored until *after* the DOMContentLoaded
|
1067
|
+
// event is fired, so we need to sync after the pageshow event in browsers
|
1068
|
+
// that support it.
|
1069
|
+
if ('onpageshow' in window) {
|
1070
|
+
window.addEventListener('pageshow', this.sync.bind(this));
|
1071
|
+
} else {
|
1072
|
+
window.addEventListener('DOMContentLoaded', this.sync.bind(this));
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
this.sync();
|
1076
|
+
};
|
1068
1077
|
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1078
|
+
CharacterCount.prototype.sync = function () {
|
1079
|
+
this.bindChangeEvents();
|
1080
|
+
this.updateCountMessage();
|
1072
1081
|
};
|
1073
1082
|
|
1074
1083
|
// Read data attributes
|
@@ -1116,8 +1125,7 @@ CharacterCount.prototype.checkIfValueChanged = function () {
|
|
1116
1125
|
if (!this.$textarea.oldValue) this.$textarea.oldValue = '';
|
1117
1126
|
if (this.$textarea.value !== this.$textarea.oldValue) {
|
1118
1127
|
this.$textarea.oldValue = this.$textarea.value;
|
1119
|
-
|
1120
|
-
boundUpdateCountMessage();
|
1128
|
+
this.updateCountMessage();
|
1121
1129
|
}
|
1122
1130
|
};
|
1123
1131
|
|
@@ -88,6 +88,12 @@
|
|
88
88
|
"required": false,
|
89
89
|
"description": "HTML attributes (for example data attributes) to add to the textarea."
|
90
90
|
},
|
91
|
+
{
|
92
|
+
"name": "spellcheck",
|
93
|
+
"type": "boolean",
|
94
|
+
"required": false,
|
95
|
+
"description": "Optional field to enable or disable the spellcheck attribute on the character count."
|
96
|
+
},
|
91
97
|
{
|
92
98
|
"name": "countMessage",
|
93
99
|
"type": "object",
|
@@ -10,6 +10,7 @@
|
|
10
10
|
name: params.name,
|
11
11
|
describedBy: params.id + '-info',
|
12
12
|
rows: params.rows,
|
13
|
+
spellcheck: params.spellcheck,
|
13
14
|
value: params.value,
|
14
15
|
formGroup: params.formGroup,
|
15
16
|
classes: 'govuk-js-character-count' + (' govuk-textarea--error' if params.errorMessage) + (' ' + params.classes if params.classes),
|
@@ -92,12 +92,13 @@
|
|
92
92
|
// rotated 45 degrees
|
93
93
|
.govuk-checkboxes__label::after {
|
94
94
|
content: "";
|
95
|
+
box-sizing: border-box;
|
95
96
|
|
96
97
|
position: absolute;
|
97
98
|
top: 11px;
|
98
99
|
left: 9px;
|
99
|
-
width:
|
100
|
-
height:
|
100
|
+
width: 23px;
|
101
|
+
height: 12px;
|
101
102
|
|
102
103
|
-webkit-transform: rotate(-45deg);
|
103
104
|
|
@@ -105,7 +106,7 @@
|
|
105
106
|
|
106
107
|
transform: rotate(-45deg);
|
107
108
|
border: solid;
|
108
|
-
border-width: 0 0
|
109
|
+
border-width: 0 0 5px 5px;
|
109
110
|
// Fix bug in IE11 caused by transform rotate (-45deg).
|
110
111
|
// See: alphagov/govuk_elements/issues/518
|
111
112
|
border-top-color: transparent;
|
@@ -238,8 +239,8 @@
|
|
238
239
|
.govuk-checkboxes__label::after {
|
239
240
|
top: 15px;
|
240
241
|
left: 6px;
|
241
|
-
width:
|
242
|
-
height:
|
242
|
+
width: 12px;
|
243
|
+
height: 6.5px;
|
243
244
|
border-width: 0 0 3px 3px;
|
244
245
|
}
|
245
246
|
|
@@ -1033,44 +1033,91 @@ function Checkboxes ($module) {
|
|
1033
1033
|
this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
|
1034
1034
|
}
|
1035
1035
|
|
1036
|
+
/**
|
1037
|
+
* Initialise Checkboxes
|
1038
|
+
*
|
1039
|
+
* Checkboxes can be associated with a 'conditionally revealed' content block –
|
1040
|
+
* for example, a checkbox for 'Phone' could reveal an additional form field for
|
1041
|
+
* the 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 checkbox state.
|
1049
|
+
*/
|
1036
1050
|
Checkboxes.prototype.init = function () {
|
1037
1051
|
var $module = this.$module;
|
1038
1052
|
var $inputs = this.$inputs;
|
1039
1053
|
|
1040
|
-
/**
|
1041
|
-
* Loop over all items with [data-controls]
|
1042
|
-
* Check if they have a matching conditional reveal
|
1043
|
-
* If they do, assign attributes.
|
1044
|
-
**/
|
1045
1054
|
nodeListForEach($inputs, function ($input) {
|
1046
|
-
var
|
1055
|
+
var target = $input.getAttribute('data-aria-controls');
|
1047
1056
|
|
1048
|
-
//
|
1049
|
-
//
|
1050
|
-
if (!
|
1057
|
+
// Skip checkboxes without data-aria-controls attributes, or where the
|
1058
|
+
// target element does not exist.
|
1059
|
+
if (!target || !$module.querySelector('#' + target)) {
|
1051
1060
|
return
|
1052
1061
|
}
|
1053
1062
|
|
1054
|
-
//
|
1055
|
-
|
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);
|
1056
1066
|
$input.removeAttribute('data-aria-controls');
|
1057
|
-
|
1058
|
-
|
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();
|
1059
1083
|
|
1060
|
-
// Handle events
|
1061
1084
|
$module.addEventListener('click', this.handleClick.bind(this));
|
1062
1085
|
};
|
1063
1086
|
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1087
|
+
/**
|
1088
|
+
* Sync the conditional reveal states for all inputs in this $module.
|
1089
|
+
*/
|
1090
|
+
Checkboxes.prototype.syncAllConditionalReveals = function () {
|
1091
|
+
nodeListForEach(this.$inputs, this.syncConditionalRevealWithInputState.bind(this));
|
1092
|
+
};
|
1093
|
+
|
1094
|
+
/**
|
1095
|
+
* Sync conditional reveal with the input state
|
1096
|
+
*
|
1097
|
+
* Synchronise the visibility of the conditional reveal, and its accessible
|
1098
|
+
* state, with the input's checked state.
|
1099
|
+
*
|
1100
|
+
* @param {HTMLInputElement} $input Checkbox input
|
1101
|
+
*/
|
1102
|
+
Checkboxes.prototype.syncConditionalRevealWithInputState = function ($input) {
|
1103
|
+
var $target = this.$module.querySelector('#' + $input.getAttribute('aria-controls'));
|
1067
1104
|
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1105
|
+
if ($target && $target.classList.contains('govuk-checkboxes__conditional')) {
|
1106
|
+
var inputIsChecked = $input.checked;
|
1107
|
+
|
1108
|
+
$input.setAttribute('aria-expanded', inputIsChecked);
|
1109
|
+
$target.classList.toggle('govuk-checkboxes__conditional--hidden', !inputIsChecked);
|
1071
1110
|
}
|
1072
1111
|
};
|
1073
1112
|
|
1113
|
+
/**
|
1114
|
+
* Click event handler
|
1115
|
+
*
|
1116
|
+
* Handle a click within the $module – if the click occurred on a checkbox, sync
|
1117
|
+
* the state of any associated conditional reveal with the checkbox state.
|
1118
|
+
*
|
1119
|
+
* @param {MouseEvent} event Click event
|
1120
|
+
*/
|
1074
1121
|
Checkboxes.prototype.handleClick = function (event) {
|
1075
1122
|
var $target = event.target;
|
1076
1123
|
|
@@ -1078,7 +1125,7 @@ Checkboxes.prototype.handleClick = function (event) {
|
|
1078
1125
|
var isCheckbox = $target.getAttribute('type') === 'checkbox';
|
1079
1126
|
var hasAriaControls = $target.getAttribute('aria-controls');
|
1080
1127
|
if (isCheckbox && hasAriaControls) {
|
1081
|
-
this.
|
1128
|
+
this.syncConditionalRevealWithInputState($target);
|
1082
1129
|
}
|
1083
1130
|
};
|
1084
1131
|
|
@@ -45,7 +45,7 @@
|
|
45
45
|
"name": "autocomplete",
|
46
46
|
"type": "string",
|
47
47
|
"required": false,
|
48
|
-
"description": "Attribute to [identify input purpose](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html), for instance \"
|
48
|
+
"description": "Attribute to [identify input purpose](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html), for instance \"bday-day\". See [autofill](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) for full list of attributes that can be used."
|
49
49
|
},
|
50
50
|
{
|
51
51
|
"name": "pattern",
|
@@ -47,31 +47,4 @@
|
|
47
47
|
box-shadow: inset 0 0 0 4px $govuk-input-border-colour;
|
48
48
|
}
|
49
49
|
}
|
50
|
-
|
51
|
-
.govuk-file-upload--error {
|
52
|
-
// As `upload--error` has border, it needs to have the same padding as
|
53
|
-
// the standard focused element.
|
54
|
-
margin-right: -$component-padding;
|
55
|
-
margin-left: -$component-padding;
|
56
|
-
padding-right: $component-padding;
|
57
|
-
padding-left: $component-padding;
|
58
|
-
border: $govuk-border-width-form-element-error solid $govuk-error-colour;
|
59
|
-
|
60
|
-
&:focus {
|
61
|
-
border-color: $govuk-input-border-colour;
|
62
|
-
// Remove `box-shadow` inherited from `:focus` as `file-upload--error`
|
63
|
-
// already has the thicker border.
|
64
|
-
box-shadow: none;
|
65
|
-
}
|
66
|
-
|
67
|
-
// Repeat `:focus` styles to prevent error styles from being applied when
|
68
|
-
// input button is pressed as this moves the focus to "within".
|
69
|
-
// This can't be set together with `:focus` as all versions of IE fail
|
70
|
-
// to recognise `focus-within` and don't set any styles from the block
|
71
|
-
// when it's a selector.
|
72
|
-
&:focus-within {
|
73
|
-
border-color: $govuk-input-border-colour;
|
74
|
-
box-shadow: none;
|
75
|
-
}
|
76
|
-
}
|
77
50
|
}
|
@@ -210,20 +210,17 @@
|
|
210
210
|
padding: 0;
|
211
211
|
list-style: none;
|
212
212
|
-webkit-column-gap: $govuk-gutter;
|
213
|
-
-moz-column-gap: $govuk-gutter;
|
214
213
|
column-gap: $govuk-gutter; // Support: Columns
|
215
214
|
}
|
216
215
|
|
217
216
|
@include govuk-media-query ($from: desktop) {
|
218
217
|
.govuk-footer__list--columns-2 {
|
219
218
|
-webkit-column-count: 2;
|
220
|
-
-moz-column-count: 2;
|
221
219
|
column-count: 2; // Support: Columns
|
222
220
|
}
|
223
221
|
|
224
222
|
.govuk-footer__list--columns-3 {
|
225
223
|
-webkit-column-count: 3;
|
226
|
-
-moz-column-count: 3;
|
227
224
|
column-count: 3; // Support: Columns
|
228
225
|
}
|
229
226
|
}
|
@@ -16,7 +16,7 @@
|
|
16
16
|
// is unlikely that the default or govuk-label--s class would be used in this
|
17
17
|
// case.
|
18
18
|
|
19
|
-
// This adjustment will not work in browsers that do not support :not().
|
19
|
+
// This adjustment will not work in browsers that do not support :not().
|
20
20
|
// Users with these browsers will see the default size margin (5px larger).
|
21
21
|
|
22
22
|
.govuk-label:not(.govuk-label--m):not(.govuk-label--l):not(.govuk-label--xl) + .govuk-hint {
|
@@ -30,7 +30,7 @@
|
|
30
30
|
// it is unlikely that the default or govuk-fieldset__legend--s class would be
|
31
31
|
// used in this case.
|
32
32
|
|
33
|
-
// This adjustment will not work in browsers that do not support :not().
|
33
|
+
// This adjustment will not work in browsers that do not support :not().
|
34
34
|
// Users with these browsers will see the default size margin (5px larger).
|
35
35
|
|
36
36
|
.govuk-fieldset__legend:not(.govuk-fieldset__legend--m):not(.govuk-fieldset__legend--l):not(.govuk-fieldset__legend--xl) + .govuk-hint {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<
|
1
|
+
<div {%- if params.id %} id="{{ params.id }}"{% endif %} class="govuk-hint {%- if params.classes %} {{ params.classes }}{% endif %}"
|
2
2
|
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}>
|
3
3
|
{{ params.html | safe if params.html else params.text }}
|
4
|
-
</
|
4
|
+
</div>
|
@@ -88,6 +88,12 @@
|
|
88
88
|
"required": false,
|
89
89
|
"description": "Attribute to [provide a regular expression pattern](https://www.w3.org/TR/html51/sec-forms.html#the-pattern-attribute), used to match allowed character combinations for the input value."
|
90
90
|
},
|
91
|
+
{
|
92
|
+
"name": "spellcheck",
|
93
|
+
"type": "boolean",
|
94
|
+
"required": false,
|
95
|
+
"description": "Optional field to enable or disable the spellcheck attribute on the input."
|
96
|
+
},
|
91
97
|
{
|
92
98
|
"name": "attributes",
|
93
99
|
"type": "object",
|
@@ -38,6 +38,7 @@
|
|
38
38
|
}) | indent(2) | trim }}
|
39
39
|
{% endif %}
|
40
40
|
<input class="govuk-input {%- if params.classes %} {{ params.classes }}{% endif %} {%- if params.errorMessage %} govuk-input--error{% endif %}" id="{{ params.id }}" name="{{ params.name }}" type="{{ params.type | default('text') }}"
|
41
|
+
{%- if (params.spellcheck === false) or (params.spellcheck === true) %} spellcheck="{{ params.spellcheck }}"{% endif %}
|
41
42
|
{%- if params.value %} value="{{ params.value}}"{% endif %}
|
42
43
|
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
|
43
44
|
{%- if params.autocomplete %} autocomplete="{{ params.autocomplete}}"{% endif %}
|
@@ -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 =
|
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
|
1055
|
+
var target = $input.getAttribute('data-aria-controls');
|
1046
1056
|
|
1047
|
-
//
|
1048
|
-
//
|
1049
|
-
if (!
|
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
|
-
//
|
1054
|
-
|
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
|
-
|
1057
|
-
|
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
|
-
|
1064
|
-
|
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
|
-
|
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
|
-
|
1126
|
+
|
1127
|
+
// Ignore clicks on things that aren't radio buttons
|
1078
1128
|
if ($clickedInput.type !== 'radio') {
|
1079
1129
|
return
|
1080
1130
|
}
|
1081
|
-
|
1082
|
-
//
|
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.
|
1141
|
+
this.syncConditionalRevealWithInputState($input);
|
1094
1142
|
}
|
1095
1143
|
}.bind(this));
|
1096
1144
|
};
|