katalyst-govuk-formbuilder 1.4.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -0
  3. data/app/assets/builds/katalyst/govuk/formbuilder.css +87 -5
  4. data/app/assets/builds/katalyst/govuk/formbuilder.js +98 -64
  5. data/app/assets/builds/katalyst/govuk/formbuilder.min.js +1 -1
  6. data/app/assets/stylesheets/katalyst/govuk/components/richtextarea/_index.scss +7 -6
  7. data/lib/katalyst/govuk/formbuilder/version.rb +1 -1
  8. data/vendor/assets/stylesheets/govuk-frontend/govuk/all-ie8.scss +8 -0
  9. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/_all.scss +2 -1
  10. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/accordion/_index.scss +3 -3
  11. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/back-link/_index.scss +9 -1
  12. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/breadcrumbs/_index.scss +13 -1
  13. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/button/_index.scss +49 -9
  14. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/checkboxes/_index.scss +6 -6
  15. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/exit-this-page/_exit-this-page.scss +2 -0
  16. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/exit-this-page/_index.scss +97 -0
  17. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/file-upload/_index.scss +6 -1
  18. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/footer/_index.scss +0 -7
  19. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/input/_index.scss +15 -3
  20. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/radios/_index.scss +5 -5
  21. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/select/_index.scss +7 -1
  22. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/tag/_index.scss +18 -18
  23. data/vendor/assets/stylesheets/govuk-frontend/govuk/components/textarea/_index.scss +8 -1
  24. data/vendor/assets/stylesheets/govuk-frontend/govuk/core/_all.scss +1 -0
  25. data/vendor/assets/stylesheets/govuk-frontend/govuk/core/_govuk-frontend-version.scss +5 -0
  26. data/vendor/assets/stylesheets/govuk-frontend/govuk/helpers/_colour.scss +5 -2
  27. data/vendor/assets/stylesheets/govuk-frontend/govuk/helpers/_focused.scss +1 -1
  28. data/vendor/assets/stylesheets/govuk-frontend/govuk/helpers/_font-faces.scss +1 -1
  29. data/vendor/assets/stylesheets/govuk-frontend/govuk/helpers/_visually-hidden.scss +12 -0
  30. data/vendor/assets/stylesheets/govuk-frontend/govuk/objects/_template.scss +20 -0
  31. data/vendor/assets/stylesheets/govuk-frontend/govuk/objects/_width-container.scss +1 -1
  32. data/vendor/assets/stylesheets/govuk-frontend/govuk/settings/_colours-organisations.scss +4 -0
  33. data/vendor/assets/stylesheets/govuk-frontend/govuk/settings/_ie8.scss +16 -0
  34. data/vendor/assets/stylesheets/govuk-frontend/govuk/settings/_links.scss +5 -1
  35. data/vendor/assets/stylesheets/govuk-frontend/govuk/tools/_ie8.scss +38 -2
  36. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9df88d9d5abc58da448ed9fd96a45ef1924a27dcda9939ef0596b9e21ff3d06
4
- data.tar.gz: c824d95a58018d8376b8cc9de329ef21b1e8d06d9fca460f9683072a625a0fb9
3
+ metadata.gz: b4255667e305b3281cd8cc212d66cb9f3dd3fb90217ad4610854d9c5eb99bda8
4
+ data.tar.gz: 186cfd97c4994d09a463f40dbd15747dd249a6fca3af391117bdcabb03bb6d03
5
5
  SHA512:
6
- metadata.gz: 9c7bf61b527e1092fb8327b2ba88d9832d45e99d46a445a8f1a6d1428d81ddc154aa79af57c5e9fb0892ea2da77482bdb0df396b50bc1ef0bd3e8cab6e9b7213
7
- data.tar.gz: 02c92b8b8822995c73bff3851ce55b418b36e11ff5fd25bbf59021a664602802338104a19c752744edcf2f77e1c79471ce7b6ade424d07f7bf2664135e6cf5dc
6
+ metadata.gz: 565c0b92dabe9090c904f5095faee594fb792591c3b435953d28cfc8ea5b10103c4273dfcf9f320234469fc5ce8eab79e93be13ad2660c74e8e671773830ac9f
7
+ data.tar.gz: f4172456fee33876936ea05efb3b2dd3ed6077b3abf4b6cfcc80ecd8babfd8dfe116267ff59f89b9d14000ec765f8f51119b8b32d7e72da959d4fa8f5b4aa758
data/README.md CHANGED
@@ -47,6 +47,14 @@ helper Katalyst::GOVUK::Formbuilder::Frontend
47
47
 
48
48
  Bug reports and pull requests are welcome on GitHub at https://github.com/katalyst/govuk-formbuilder.
49
49
 
50
+ ## Release
51
+
52
+ Update the version number in `lib/katalyst/govuk/formbuilder/version.rb` and run:
53
+
54
+ ```bash
55
+ bundle exec rake release
56
+ ```
57
+
50
58
  ## License
51
59
 
52
60
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,3 +1,8 @@
1
+ @charset "UTF-8";
2
+ :root {
3
+ --govuk-frontend-version: "4.7.0";
4
+ }
5
+
1
6
  .govuk-link {
2
7
  font-family: "Open Sans", sans-serif;
3
8
  -webkit-font-smoothing: antialiased;
@@ -978,6 +983,14 @@
978
983
  -moz-text-size-adjust: 100%;
979
984
  text-size-adjust: 100%;
980
985
  }
986
+ @supports (position: -webkit-sticky) or (position: sticky) {
987
+ .govuk-template {
988
+ scroll-padding-top: 60px;
989
+ }
990
+ .govuk-template:not(:has(.govuk-exit-this-page)) {
991
+ scroll-padding-top: 0;
992
+ }
993
+ }
981
994
  @media screen {
982
995
  .govuk-template {
983
996
  overflow-y: scroll;
@@ -1128,7 +1141,7 @@
1128
1141
  .govuk-button[disabled=disabled]:hover,
1129
1142
  .govuk-button[disabled]:hover {
1130
1143
  background-color: #00703c;
1131
- cursor: default;
1144
+ cursor: not-allowed;
1132
1145
  }
1133
1146
  .govuk-button--disabled:active,
1134
1147
  .govuk-button[disabled=disabled]:active,
@@ -1165,6 +1178,20 @@
1165
1178
  background-color: #d4351c;
1166
1179
  }
1167
1180
 
1181
+ .govuk-button--inverse {
1182
+ background-color: #ffffff;
1183
+ box-shadow: 0 2px 0 #144e81;
1184
+ }
1185
+ .govuk-button--inverse, .govuk-button--inverse:link, .govuk-button--inverse:visited, .govuk-button--inverse:active, .govuk-button--inverse:hover {
1186
+ color: #1d70b8;
1187
+ }
1188
+ .govuk-button--inverse:hover {
1189
+ background-color: #e8f1f8;
1190
+ }
1191
+ .govuk-button--inverse:hover[disabled] {
1192
+ background-color: #ffffff;
1193
+ }
1194
+
1168
1195
  .govuk-button--start {
1169
1196
  font-weight: 700;
1170
1197
  font-size: 18px;
@@ -1728,7 +1755,7 @@
1728
1755
 
1729
1756
  .govuk-checkboxes__input:disabled,
1730
1757
  .govuk-checkboxes__input:disabled + .govuk-checkboxes__label {
1731
- cursor: default;
1758
+ cursor: not-allowed;
1732
1759
  }
1733
1760
 
1734
1761
  .govuk-checkboxes__input:disabled + .govuk-checkboxes__label,
@@ -1893,6 +1920,12 @@
1893
1920
  outline-offset: 0;
1894
1921
  box-shadow: inset 0 0 0 2px;
1895
1922
  }
1923
+ .govuk-input:disabled {
1924
+ opacity: 0.5;
1925
+ color: inherit;
1926
+ background-color: transparent;
1927
+ cursor: not-allowed;
1928
+ }
1896
1929
 
1897
1930
  .govuk-input::-webkit-outer-spin-button,
1898
1931
  .govuk-input::-webkit-inner-spin-button {
@@ -1911,6 +1944,28 @@
1911
1944
  border-color: #0b0c0c;
1912
1945
  }
1913
1946
 
1947
+ .govuk-input--extra-letter-spacing {
1948
+ font-family: "Open Sans", sans-serif;
1949
+ -webkit-font-smoothing: antialiased;
1950
+ -moz-osx-font-smoothing: grayscale;
1951
+ -webkit-font-feature-settings: "tnum" 1;
1952
+ font-feature-settings: "tnum" 1;
1953
+ font-weight: 400;
1954
+ letter-spacing: 0.05em;
1955
+ }
1956
+ @media print {
1957
+ .govuk-input--extra-letter-spacing {
1958
+ font-family: sans-serif;
1959
+ }
1960
+ }
1961
+ @supports (font-variant-numeric: tabular-nums) {
1962
+ .govuk-input--extra-letter-spacing {
1963
+ -webkit-font-feature-settings: normal;
1964
+ font-feature-settings: normal;
1965
+ font-variant-numeric: tabular-nums;
1966
+ }
1967
+ }
1968
+
1914
1969
  .govuk-input--width-30 {
1915
1970
  max-width: 29.5em;
1916
1971
  }
@@ -2249,6 +2304,10 @@
2249
2304
  outline: 3px solid #ffdd00;
2250
2305
  box-shadow: inset 0 0 0 4px #0b0c0c;
2251
2306
  }
2307
+ .govuk-file-upload:disabled {
2308
+ opacity: 0.5;
2309
+ cursor: not-allowed;
2310
+ }
2252
2311
 
2253
2312
  .govuk-radios__item {
2254
2313
  font-family: "Open Sans", sans-serif;
@@ -2360,7 +2419,7 @@
2360
2419
 
2361
2420
  .govuk-radios__input:disabled,
2362
2421
  .govuk-radios__input:disabled + .govuk-radios__label {
2363
- cursor: default;
2422
+ cursor: not-allowed;
2364
2423
  }
2365
2424
 
2366
2425
  .govuk-radios__input:disabled + .govuk-radios__label,
@@ -2540,6 +2599,11 @@
2540
2599
  outline-offset: 0;
2541
2600
  box-shadow: inset 0 0 0 2px;
2542
2601
  }
2602
+ .govuk-select:disabled {
2603
+ opacity: 0.5;
2604
+ color: inherit;
2605
+ cursor: not-allowed;
2606
+ }
2543
2607
 
2544
2608
  .govuk-select option:active,
2545
2609
  .govuk-select option:checked,
@@ -2602,6 +2666,12 @@
2602
2666
  outline-offset: 0;
2603
2667
  box-shadow: inset 0 0 0 2px;
2604
2668
  }
2669
+ .govuk-textarea:disabled {
2670
+ opacity: 0.5;
2671
+ color: inherit;
2672
+ background-color: transparent;
2673
+ cursor: not-allowed;
2674
+ }
2605
2675
 
2606
2676
  .govuk-textarea--error {
2607
2677
  border-color: #d4351c;
@@ -2629,6 +2699,12 @@
2629
2699
  border: 0 !important;
2630
2700
  white-space: nowrap !important;
2631
2701
  }
2702
+ .govuk-visually-hidden:before {
2703
+ content: " ";
2704
+ }
2705
+ .govuk-visually-hidden:after {
2706
+ content: " ";
2707
+ }
2632
2708
 
2633
2709
  .govuk-visually-hidden-focusable {
2634
2710
  position: absolute !important;
@@ -4141,10 +4217,16 @@
4141
4217
  outline-offset: 0;
4142
4218
  box-shadow: inset 0 0 0 2px;
4143
4219
  }
4220
+ .govuk-richtextarea:disabled {
4221
+ opacity: 0.5;
4222
+ color: inherit;
4223
+ background-color: transparent;
4224
+ cursor: not-allowed;
4225
+ }
4144
4226
 
4145
- .govuk-richtextarea--error {
4227
+ .govuk-textarea--error {
4146
4228
  border-color: #d4351c;
4147
4229
  }
4148
- .govuk-richtextarea--error:focus {
4230
+ .govuk-textarea--error:focus {
4149
4231
  border-color: #0b0c0c;
4150
4232
  }
@@ -276,7 +276,7 @@ function normaliseString(value) {
276
276
  if (trimmedValue === "false") {
277
277
  return false;
278
278
  }
279
- if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
279
+ if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
280
280
  return Number(trimmedValue);
281
281
  }
282
282
  return value;
@@ -551,7 +551,7 @@ var KEY_SPACE = 32;
551
551
  var DEBOUNCE_TIMEOUT_IN_SECONDS = 1;
552
552
 
553
553
  function Button($module, config) {
554
- if (!$module) {
554
+ if (!($module instanceof HTMLElement)) {
555
555
  return this;
556
556
  }
557
557
  this.$module = $module;
@@ -572,7 +572,10 @@ Button.prototype.init = function() {
572
572
 
573
573
  Button.prototype.handleKeyDown = function(event) {
574
574
  var $target = event.target;
575
- if ($target.getAttribute("role") === "button" && event.keyCode === KEY_SPACE) {
575
+ if (event.keyCode !== KEY_SPACE) {
576
+ return;
577
+ }
578
+ if ($target instanceof HTMLElement && $target.getAttribute("role") === "button") {
576
579
  event.preventDefault();
577
580
  $target.click();
578
581
  }
@@ -618,10 +621,8 @@ Button.prototype.debounce = function(event) {
618
621
  }).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
619
622
 
620
623
  function closestAttributeValue($element, attributeName) {
621
- var closestElementWithAttribute = $element.closest("[" + attributeName + "]");
622
- if (closestElementWithAttribute) {
623
- return closestElementWithAttribute.getAttribute(attributeName);
624
- }
624
+ var $closestElementWithAttribute = $element.closest("[" + attributeName + "]");
625
+ return $closestElementWithAttribute ? $closestElementWithAttribute.getAttribute(attributeName) : null;
625
626
  }
626
627
 
627
628
  function I18n(translations, config) {
@@ -633,11 +634,11 @@ I18n.prototype.t = function(lookupKey, options) {
633
634
  if (!lookupKey) {
634
635
  throw new Error("i18n: lookup key missing");
635
636
  }
636
- if (options && typeof options.count !== "undefined") {
637
+ if (options && typeof options.count === "number") {
637
638
  lookupKey = lookupKey + "." + this.getPluralSuffix(lookupKey, options.count);
638
639
  }
639
- if (lookupKey in this.translations) {
640
- var translationString = this.translations[lookupKey];
640
+ var translationString = this.translations[lookupKey];
641
+ if (typeof translationString === "string") {
641
642
  if (translationString.match(/%{(.\S+)}/)) {
642
643
  if (!options) {
643
644
  throw new Error("i18n: cannot replace placeholders in string if no option data provided");
@@ -659,11 +660,11 @@ I18n.prototype.replacePlaceholders = function(translationString, options) {
659
660
  return translationString.replace(/%{(.\S+)}/g, (function(placeholderWithBraces, placeholderKey) {
660
661
  if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
661
662
  var placeholderValue = options[placeholderKey];
662
- if (placeholderValue === false) {
663
+ if (placeholderValue === false || typeof placeholderValue !== "number" && typeof placeholderValue !== "string") {
663
664
  return "";
664
665
  }
665
- if (typeof placeholderValue === "number" && formatter) {
666
- return formatter.format(placeholderValue);
666
+ if (typeof placeholderValue === "number") {
667
+ return formatter ? formatter.format(placeholderValue) : placeholderValue.toString();
667
668
  }
668
669
  return placeholderValue;
669
670
  } else {
@@ -1108,7 +1109,11 @@ var CHARACTER_COUNT_TRANSLATIONS = {
1108
1109
  };
1109
1110
 
1110
1111
  function CharacterCount($module, config) {
1111
- if (!$module) {
1112
+ if (!($module instanceof HTMLElement)) {
1113
+ return this;
1114
+ }
1115
+ var $textarea = $module.querySelector(".govuk-js-character-count");
1116
+ if (!($textarea instanceof HTMLTextAreaElement || $textarea instanceof HTMLInputElement)) {
1112
1117
  return this;
1113
1118
  }
1114
1119
  var defaultConfig = {
@@ -1127,26 +1132,32 @@ function CharacterCount($module, config) {
1127
1132
  this.i18n = new I18n(extractConfigByNamespace(this.config, "i18n"), {
1128
1133
  locale: closestAttributeValue($module, "lang")
1129
1134
  });
1130
- if (this.config.maxwords) {
1135
+ this.maxLength = Infinity;
1136
+ if ("maxwords" in this.config && this.config.maxwords) {
1131
1137
  this.maxLength = this.config.maxwords;
1132
- } else if (this.config.maxlength) {
1138
+ } else if ("maxlength" in this.config && this.config.maxlength) {
1133
1139
  this.maxLength = this.config.maxlength;
1134
1140
  } else {
1135
1141
  return;
1136
1142
  }
1137
1143
  this.$module = $module;
1138
- this.$textarea = $module.querySelector(".govuk-js-character-count");
1144
+ this.$textarea = $textarea;
1139
1145
  this.$visibleCountMessage = null;
1140
1146
  this.$screenReaderCountMessage = null;
1141
1147
  this.lastInputTimestamp = null;
1148
+ this.lastInputValue = "";
1149
+ this.valueChecker = null;
1142
1150
  }
1143
1151
 
1144
1152
  CharacterCount.prototype.init = function() {
1145
- if (!this.$textarea) {
1153
+ if (!this.$module || !this.$textarea) {
1146
1154
  return;
1147
1155
  }
1148
1156
  var $textarea = this.$textarea;
1149
1157
  var $textareaDescription = document.getElementById($textarea.id + "-info");
1158
+ if (!$textareaDescription) {
1159
+ return;
1160
+ }
1150
1161
  if ($textareaDescription.innerText.match(/^\s*$/)) {
1151
1162
  $textareaDescription.innerText = this.i18n.t("textareaDescription", {
1152
1163
  count: this.maxLength
@@ -1167,11 +1178,7 @@ CharacterCount.prototype.init = function() {
1167
1178
  $textareaDescription.classList.add("govuk-visually-hidden");
1168
1179
  $textarea.removeAttribute("maxlength");
1169
1180
  this.bindChangeEvents();
1170
- if ("onpageshow" in window) {
1171
- window.addEventListener("pageshow", this.updateCountMessage.bind(this));
1172
- } else {
1173
- window.addEventListener("DOMContentLoaded", this.updateCountMessage.bind(this));
1174
- }
1181
+ window.addEventListener("onpageshow" in window ? "pageshow" : "DOMContentLoaded", this.updateCountMessage.bind(this));
1175
1182
  this.updateCountMessage();
1176
1183
  };
1177
1184
 
@@ -1200,9 +1207,8 @@ CharacterCount.prototype.handleBlur = function() {
1200
1207
  };
1201
1208
 
1202
1209
  CharacterCount.prototype.updateIfValueChanged = function() {
1203
- if (!this.$textarea.oldValue) this.$textarea.oldValue = "";
1204
- if (this.$textarea.value !== this.$textarea.oldValue) {
1205
- this.$textarea.oldValue = this.$textarea.value;
1210
+ if (this.$textarea.value !== this.lastInputValue) {
1211
+ this.lastInputValue = this.$textarea.value;
1206
1212
  this.updateCountMessage();
1207
1213
  }
1208
1214
  };
@@ -1238,13 +1244,13 @@ CharacterCount.prototype.updateScreenReaderCountMessage = function() {
1238
1244
  if (this.isOverThreshold()) {
1239
1245
  $screenReaderCountMessage.removeAttribute("aria-hidden");
1240
1246
  } else {
1241
- $screenReaderCountMessage.setAttribute("aria-hidden", true);
1247
+ $screenReaderCountMessage.setAttribute("aria-hidden", "true");
1242
1248
  }
1243
1249
  $screenReaderCountMessage.innerText = this.getCountMessage();
1244
1250
  };
1245
1251
 
1246
1252
  CharacterCount.prototype.count = function(text) {
1247
- if (this.config.maxwords) {
1253
+ if ("maxwords" in this.config && this.config.maxwords) {
1248
1254
  var tokens = text.match(/\S+/g) || [];
1249
1255
  return tokens.length;
1250
1256
  } else {
@@ -1254,7 +1260,7 @@ CharacterCount.prototype.count = function(text) {
1254
1260
 
1255
1261
  CharacterCount.prototype.getCountMessage = function() {
1256
1262
  var remainingNumber = this.maxLength - this.count(this.$textarea.value);
1257
- var countType = this.config.maxwords ? "words" : "characters";
1263
+ var countType = "maxwords" in this.config && this.config.maxwords ? "words" : "characters";
1258
1264
  return this.formatCountMessage(remainingNumber, countType);
1259
1265
  };
1260
1266
 
@@ -1280,11 +1286,21 @@ CharacterCount.prototype.isOverThreshold = function() {
1280
1286
  };
1281
1287
 
1282
1288
  function Checkboxes($module) {
1289
+ if (!($module instanceof HTMLElement)) {
1290
+ return this;
1291
+ }
1292
+ var $inputs = $module.querySelectorAll('input[type="checkbox"]');
1293
+ if (!$inputs.length) {
1294
+ return this;
1295
+ }
1283
1296
  this.$module = $module;
1284
- this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
1297
+ this.$inputs = $inputs;
1285
1298
  }
1286
1299
 
1287
1300
  Checkboxes.prototype.init = function() {
1301
+ if (!this.$module || !this.$inputs) {
1302
+ return;
1303
+ }
1288
1304
  var $module = this.$module;
1289
1305
  var $inputs = this.$inputs;
1290
1306
  nodeListForEach($inputs, (function($input) {
@@ -1295,11 +1311,7 @@ Checkboxes.prototype.init = function() {
1295
1311
  $input.setAttribute("aria-controls", targetId);
1296
1312
  $input.removeAttribute("data-aria-controls");
1297
1313
  }));
1298
- if ("onpageshow" in window) {
1299
- window.addEventListener("pageshow", this.syncAllConditionalReveals.bind(this));
1300
- } else {
1301
- window.addEventListener("DOMContentLoaded", this.syncAllConditionalReveals.bind(this));
1302
- }
1314
+ window.addEventListener("onpageshow" in window ? "pageshow" : "DOMContentLoaded", this.syncAllConditionalReveals.bind(this));
1303
1315
  this.syncAllConditionalReveals();
1304
1316
  $module.addEventListener("click", this.handleClick.bind(this));
1305
1317
  };
@@ -1309,39 +1321,45 @@ Checkboxes.prototype.syncAllConditionalReveals = function() {
1309
1321
  };
1310
1322
 
1311
1323
  Checkboxes.prototype.syncConditionalRevealWithInputState = function($input) {
1312
- var $target = document.getElementById($input.getAttribute("aria-controls"));
1324
+ var targetId = $input.getAttribute("aria-controls");
1325
+ if (!targetId) {
1326
+ return;
1327
+ }
1328
+ var $target = document.getElementById(targetId);
1313
1329
  if ($target && $target.classList.contains("govuk-checkboxes__conditional")) {
1314
1330
  var inputIsChecked = $input.checked;
1315
- $input.setAttribute("aria-expanded", inputIsChecked);
1331
+ $input.setAttribute("aria-expanded", inputIsChecked.toString());
1316
1332
  $target.classList.toggle("govuk-checkboxes__conditional--hidden", !inputIsChecked);
1317
1333
  }
1318
1334
  };
1319
1335
 
1320
1336
  Checkboxes.prototype.unCheckAllInputsExcept = function($input) {
1337
+ var $component = this;
1321
1338
  var allInputsWithSameName = document.querySelectorAll('input[type="checkbox"][name="' + $input.name + '"]');
1322
- nodeListForEach(allInputsWithSameName, function($inputWithSameName) {
1339
+ nodeListForEach(allInputsWithSameName, (function($inputWithSameName) {
1323
1340
  var hasSameFormOwner = $input.form === $inputWithSameName.form;
1324
1341
  if (hasSameFormOwner && $inputWithSameName !== $input) {
1325
1342
  $inputWithSameName.checked = false;
1326
- this.syncConditionalRevealWithInputState($inputWithSameName);
1343
+ $component.syncConditionalRevealWithInputState($inputWithSameName);
1327
1344
  }
1328
- }.bind(this));
1345
+ }));
1329
1346
  };
1330
1347
 
1331
1348
  Checkboxes.prototype.unCheckExclusiveInputs = function($input) {
1349
+ var $component = this;
1332
1350
  var allInputsWithSameNameAndExclusiveBehaviour = document.querySelectorAll('input[data-behaviour="exclusive"][type="checkbox"][name="' + $input.name + '"]');
1333
- nodeListForEach(allInputsWithSameNameAndExclusiveBehaviour, function($exclusiveInput) {
1351
+ nodeListForEach(allInputsWithSameNameAndExclusiveBehaviour, (function($exclusiveInput) {
1334
1352
  var hasSameFormOwner = $input.form === $exclusiveInput.form;
1335
1353
  if (hasSameFormOwner) {
1336
1354
  $exclusiveInput.checked = false;
1337
- this.syncConditionalRevealWithInputState($exclusiveInput);
1355
+ $component.syncConditionalRevealWithInputState($exclusiveInput);
1338
1356
  }
1339
- }.bind(this));
1357
+ }));
1340
1358
  };
1341
1359
 
1342
1360
  Checkboxes.prototype.handleClick = function(event) {
1343
1361
  var $clickedInput = event.target;
1344
- if ($clickedInput.type !== "checkbox") {
1362
+ if (!($clickedInput instanceof HTMLInputElement) || $clickedInput.type !== "checkbox") {
1345
1363
  return;
1346
1364
  }
1347
1365
  var hasAriaControls = $clickedInput.getAttribute("aria-controls");
@@ -1360,7 +1378,7 @@ Checkboxes.prototype.handleClick = function(event) {
1360
1378
  };
1361
1379
 
1362
1380
  function ErrorSummary($module, config) {
1363
- if (!$module) {
1381
+ if (!($module instanceof HTMLElement)) {
1364
1382
  return this;
1365
1383
  }
1366
1384
  this.$module = $module;
@@ -1371,10 +1389,10 @@ function ErrorSummary($module, config) {
1371
1389
  }
1372
1390
 
1373
1391
  ErrorSummary.prototype.init = function() {
1374
- var $module = this.$module;
1375
- if (!$module) {
1392
+ if (!this.$module) {
1376
1393
  return;
1377
1394
  }
1395
+ var $module = this.$module;
1378
1396
  this.setFocus();
1379
1397
  $module.addEventListener("click", this.handleClick.bind(this));
1380
1398
  };
@@ -1399,10 +1417,13 @@ ErrorSummary.prototype.handleClick = function(event) {
1399
1417
  };
1400
1418
 
1401
1419
  ErrorSummary.prototype.focusTarget = function($target) {
1402
- if ($target.tagName !== "A" || $target.href === false) {
1420
+ if (!($target instanceof HTMLAnchorElement)) {
1403
1421
  return false;
1404
1422
  }
1405
1423
  var inputId = this.getFragmentFromUrl($target.href);
1424
+ if (!inputId) {
1425
+ return false;
1426
+ }
1406
1427
  var $input = document.getElementById(inputId);
1407
1428
  if (!$input) {
1408
1429
  return false;
@@ -1420,7 +1441,7 @@ ErrorSummary.prototype.focusTarget = function($target) {
1420
1441
 
1421
1442
  ErrorSummary.prototype.getFragmentFromUrl = function(url) {
1422
1443
  if (url.indexOf("#") === -1) {
1423
- return false;
1444
+ return undefined;
1424
1445
  }
1425
1446
  return url.split("#").pop();
1426
1447
  };
@@ -1431,7 +1452,7 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function($input) {
1431
1452
  var $legends = $fieldset.getElementsByTagName("legend");
1432
1453
  if ($legends.length) {
1433
1454
  var $candidateLegend = $legends[0];
1434
- if ($input.type === "checkbox" || $input.type === "radio") {
1455
+ if ($input instanceof HTMLInputElement && ($input.type === "checkbox" || $input.type === "radio")) {
1435
1456
  return $candidateLegend;
1436
1457
  }
1437
1458
  var legendTop = $candidateLegend.getBoundingClientRect().top;
@@ -1448,11 +1469,21 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function($input) {
1448
1469
  };
1449
1470
 
1450
1471
  function Radios($module) {
1472
+ if (!($module instanceof HTMLElement)) {
1473
+ return this;
1474
+ }
1475
+ var $inputs = $module.querySelectorAll('input[type="radio"]');
1476
+ if (!$inputs.length) {
1477
+ return this;
1478
+ }
1451
1479
  this.$module = $module;
1452
- this.$inputs = $module.querySelectorAll('input[type="radio"]');
1480
+ this.$inputs = $inputs;
1453
1481
  }
1454
1482
 
1455
1483
  Radios.prototype.init = function() {
1484
+ if (!this.$module || !this.$inputs) {
1485
+ return;
1486
+ }
1456
1487
  var $module = this.$module;
1457
1488
  var $inputs = this.$inputs;
1458
1489
  nodeListForEach($inputs, (function($input) {
@@ -1463,11 +1494,7 @@ Radios.prototype.init = function() {
1463
1494
  $input.setAttribute("aria-controls", targetId);
1464
1495
  $input.removeAttribute("data-aria-controls");
1465
1496
  }));
1466
- if ("onpageshow" in window) {
1467
- window.addEventListener("pageshow", this.syncAllConditionalReveals.bind(this));
1468
- } else {
1469
- window.addEventListener("DOMContentLoaded", this.syncAllConditionalReveals.bind(this));
1470
- }
1497
+ window.addEventListener("onpageshow" in window ? "pageshow" : "DOMContentLoaded", this.syncAllConditionalReveals.bind(this));
1471
1498
  this.syncAllConditionalReveals();
1472
1499
  $module.addEventListener("click", this.handleClick.bind(this));
1473
1500
  };
@@ -1477,27 +1504,34 @@ Radios.prototype.syncAllConditionalReveals = function() {
1477
1504
  };
1478
1505
 
1479
1506
  Radios.prototype.syncConditionalRevealWithInputState = function($input) {
1480
- var $target = document.getElementById($input.getAttribute("aria-controls"));
1507
+ var targetId = $input.getAttribute("aria-controls");
1508
+ if (!targetId) {
1509
+ return;
1510
+ }
1511
+ var $target = document.getElementById(targetId);
1481
1512
  if ($target && $target.classList.contains("govuk-radios__conditional")) {
1482
1513
  var inputIsChecked = $input.checked;
1483
- $input.setAttribute("aria-expanded", inputIsChecked);
1514
+ $input.setAttribute("aria-expanded", inputIsChecked.toString());
1484
1515
  $target.classList.toggle("govuk-radios__conditional--hidden", !inputIsChecked);
1485
1516
  }
1486
1517
  };
1487
1518
 
1488
1519
  Radios.prototype.handleClick = function(event) {
1520
+ var $component = this;
1489
1521
  var $clickedInput = event.target;
1490
- if ($clickedInput.type !== "radio") {
1522
+ if (!($clickedInput instanceof HTMLInputElement) || $clickedInput.type !== "radio") {
1491
1523
  return;
1492
1524
  }
1493
1525
  var $allInputs = document.querySelectorAll('input[type="radio"][aria-controls]');
1494
- nodeListForEach($allInputs, function($input) {
1495
- var hasSameFormOwner = $input.form === $clickedInput.form;
1496
- var hasSameName = $input.name === $clickedInput.name;
1526
+ var $clickedInputForm = $clickedInput.form;
1527
+ var $clickedInputName = $clickedInput.name;
1528
+ nodeListForEach($allInputs, (function($input) {
1529
+ var hasSameFormOwner = $input.form === $clickedInputForm;
1530
+ var hasSameName = $input.name === $clickedInputName;
1497
1531
  if (hasSameName && hasSameFormOwner) {
1498
- this.syncConditionalRevealWithInputState($input);
1532
+ $component.syncConditionalRevealWithInputState($input);
1499
1533
  }
1500
- }.bind(this));
1534
+ }));
1501
1535
  };
1502
1536
 
1503
1537
  function initAll(options) {