hof 20.0.0-beta.1 → 20.0.0-beta.12

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 (58) hide show
  1. package/.github/workflows/automate-publish.yml +1 -1
  2. package/.github/workflows/automate-tag.yml +1 -1
  3. package/.nyc_output/e2fdc3eb-4fd2-47e0-a392-fe5f665776a4.json +1 -0
  4. package/.nyc_output/processinfo/e2fdc3eb-4fd2-47e0-a392-fe5f665776a4.json +1 -0
  5. package/.nyc_output/processinfo/index.json +1 -1
  6. package/build/lib/mkdir.js +2 -2
  7. package/components/date/index.js +37 -24
  8. package/components/date/templates/date.html +3 -3
  9. package/components/emailer/index.js +49 -41
  10. package/components/emailer/transports/debug.js +1 -2
  11. package/components/summary/index.js +18 -0
  12. package/config/hof-defaults.js +5 -3
  13. package/config/rate-limits.js +20 -0
  14. package/config/sanitisation-rules.js +29 -0
  15. package/controller/base-controller.js +26 -8
  16. package/controller/controller.js +11 -15
  17. package/frontend/govuk-template/build/config.js +1 -1
  18. package/frontend/template-mixins/mixins/template-mixins.js +8 -8
  19. package/frontend/template-mixins/partials/forms/checkbox-group.html +3 -3
  20. package/frontend/template-mixins/partials/forms/input-text-group.html +3 -3
  21. package/frontend/template-mixins/partials/forms/option-group.html +3 -3
  22. package/frontend/template-mixins/partials/forms/select.html +2 -2
  23. package/frontend/template-mixins/partials/forms/textarea-group.html +2 -2
  24. package/frontend/template-mixins/partials/mixins/panel.html +3 -4
  25. package/frontend/template-partials/translations/src/en/errors.json +12 -0
  26. package/frontend/template-partials/views/partials/form.html +2 -1
  27. package/frontend/template-partials/views/rate-limit-error.html +10 -0
  28. package/frontend/themes/gov-uk/client-js/govuk-cookies.js +43 -44
  29. package/frontend/themes/gov-uk/client-js/index.js +2 -2
  30. package/frontend/themes/gov-uk/client-js/skip-to-main.js +18 -17
  31. package/frontend/themes/gov-uk/styles/_cookie-banner.scss +51 -1
  32. package/frontend/themes/gov-uk/styles/govuk.scss +5 -0
  33. package/frontend/toolkit/assets/javascript/form-focus.js +10 -1
  34. package/frontend/toolkit/assets/javascript/validation.js +6 -1
  35. package/index.js +9 -4
  36. package/lib/router.js +2 -1
  37. package/lib/settings.js +18 -2
  38. package/middleware/errors.js +32 -0
  39. package/middleware/index.js +2 -1
  40. package/middleware/rate-limiter.js +98 -0
  41. package/package.json +5 -6
  42. package/sandbox/.env +1 -1
  43. package/sandbox/apps/sandbox/fields.js +14 -9
  44. package/sandbox/apps/sandbox/index.js +1 -5
  45. package/sandbox/apps/sandbox/translations/en/default.json +4 -13
  46. package/sandbox/apps/sandbox/translations/src/en/fields.json +3 -2
  47. package/sandbox/apps/sandbox/translations/src/en/pages.json +2 -12
  48. package/sandbox/assets/scss/app.scss +0 -55
  49. package/sandbox/package.json +1 -0
  50. package/sandbox/public/css/app.css +4898 -4908
  51. package/sandbox/public/js/bundle.js +79 -65
  52. package/sandbox/server.js +7 -1
  53. package/sandbox/yarn.lock +20 -1
  54. package/transpiler/lib/write-files.js +1 -2
  55. package/utilities/helpers/index.js +16 -1
  56. package/wizard/index.js +1 -0
  57. package/.nyc_output/65af88d9-aebe-4d1b-a21d-6fbf7f2bbda4.json +0 -1
  58. package/.nyc_output/processinfo/65af88d9-aebe-4d1b-a21d-6fbf7f2bbda4.json +0 -1
@@ -146,9 +146,10 @@ module.exports = {
146
146
  };
147
147
 
148
148
  },{}],2:[function(require,module,exports){
149
+ /* eslint-disable no-undef, no-param-reassign, no-unused-vars */
149
150
  (function () {
150
- "use strict"
151
- var root = this;
151
+ 'use strict';
152
+ const root = this;
152
153
  if(typeof root.GOVUK === 'undefined') { root.GOVUK = {}; }
153
154
 
154
155
  /*
@@ -167,37 +168,35 @@ module.exports = {
167
168
  GOVUK.cookie('hobnob', null);
168
169
  */
169
170
  GOVUK.cookie = function (name, value, options) {
170
- if(typeof value !== 'undefined'){
171
+ if(typeof value !== 'undefined') {
171
172
  if(value === false || value === null) {
172
173
  return GOVUK.setCookie(name, '', { days: -1 });
173
- } else {
174
- return GOVUK.setCookie(name, value, options);
175
174
  }
176
- } else {
177
- return GOVUK.getCookie(name);
175
+ return GOVUK.setCookie(name, value, options);
178
176
  }
177
+ return GOVUK.getCookie(name);
179
178
  };
180
179
  GOVUK.setCookie = function (name, value, options) {
181
180
  if(typeof options === 'undefined') {
182
181
  options = {};
183
182
  }
184
- var cookieString = name + "=" + value + "; path=/";
183
+ let cookieString = name + '=' + value + '; path=/';
185
184
  if (options.days) {
186
- var date = new Date();
185
+ const date = new Date();
187
186
  date.setTime(date.getTime() + (options.days * 24 * 60 * 60 * 1000));
188
- cookieString = cookieString + "; expires=" + date.toGMTString();
187
+ cookieString = cookieString + '; expires=' + date.toGMTString();
189
188
  }
190
- if (document.location.protocol == 'https:'){
191
- cookieString = cookieString + "; Secure";
189
+ if (document.location.protocol === 'https:') {
190
+ cookieString = cookieString + '; Secure';
192
191
  }
193
192
  document.cookie = cookieString;
194
193
  };
195
194
  GOVUK.getCookie = function (name) {
196
- var nameEQ = name + "=";
197
- var cookies = document.cookie.split(';');
198
- for(var i = 0, len = cookies.length; i < len; i++) {
199
- var cookie = cookies[i];
200
- while (cookie.charAt(0) == ' ') {
195
+ const nameEQ = name + '=';
196
+ const cookies = document.cookie.split(';');
197
+ for(let i = 0, len = cookies.length; i < len; i++) {
198
+ let cookie = cookies[i];
199
+ while (cookie.charAt(0) === ' ') {
201
200
  cookie = cookie.substring(1, cookie.length);
202
201
  }
203
202
  if (cookie.indexOf(nameEQ) === 0) {
@@ -208,33 +207,33 @@ module.exports = {
208
207
  };
209
208
  }).call(this);
210
209
  (function () {
211
- 'use strict'
212
- var root = this
213
- if (typeof root.GOVUK === 'undefined') { root.GOVUK = {} }
210
+ 'use strict';
211
+ const root = this;
212
+ if (typeof root.GOVUK === 'undefined') { root.GOVUK = {}; }
214
213
 
215
214
  GOVUK.addCookieMessage = function () {
216
- var message = document.getElementById('global-cookie-message')
215
+ const message = document.getElementById('global-cookie-message');
217
216
 
218
- var hasCookieMessage = (message && GOVUK.cookie('seen_cookie_message') === null)
217
+ const hasCookieMessage = (message && GOVUK.cookie('seen_cookie_message') === null);
219
218
 
220
219
  if (hasCookieMessage) {
221
- message.style.display = 'block'
222
- GOVUK.cookie('seen_cookie_message', 'yes', { days: 28 })
220
+ message.style.display = 'block';
221
+ GOVUK.cookie('seen_cookie_message', 'yes', { days: 28 });
223
222
 
224
223
  document.addEventListener('DOMContentLoaded', function (event) {
225
224
  if (GOVUK.analytics && typeof GOVUK.analytics.trackEvent === 'function') {
226
225
  GOVUK.analytics.trackEvent('cookieBanner', 'Cookie banner shown', {
227
226
  value: 1,
228
227
  nonInteraction: true
229
- })
228
+ });
230
229
  }
231
- })
232
- };
233
- }
230
+ });
231
+ }
232
+ };
234
233
  }).call(this)
235
234
  ;
236
- (function() {
237
- "use strict"
235
+ (function () {
236
+ 'use strict';
238
237
 
239
238
  // add cookie message
240
239
  if (window.GOVUK && GOVUK.addCookieMessage) {
@@ -242,35 +241,35 @@ module.exports = {
242
241
  }
243
242
 
244
243
  // header navigation toggle
245
- if (document.querySelectorAll && document.addEventListener){
246
- var els = document.querySelectorAll('.js-header-toggle'),
247
- i, _i;
248
- for(i=0,_i=els.length; i<_i; i++){
249
- els[i].addEventListener('click', function(e){
244
+ if (document.querySelectorAll && document.addEventListener) {
245
+ const els = document.querySelectorAll('.js-header-toggle');
246
+ let i; let _i;
247
+ for(i = 0, _i = els.length; i < _i; i++) {
248
+ els[i].addEventListener('click', function (e) {
250
249
  e.preventDefault();
251
- var target = document.getElementById(this.getAttribute('href').substr(1)),
252
- targetClass = target.getAttribute('class') || '',
253
- sourceClass = this.getAttribute('class') || '';
250
+ const target = document.getElementById(this.getAttribute('href').substr(1));
251
+ const targetClass = target.getAttribute('class') || '';
252
+ const sourceClass = this.getAttribute('class') || '';
254
253
 
255
- if(targetClass.indexOf('js-visible') !== -1){
254
+ if(targetClass.indexOf('js-visible') !== -1) {
256
255
  target.setAttribute('class', targetClass.replace(/(^|\s)js-visible(\s|$)/, ''));
257
256
  } else {
258
- target.setAttribute('class', targetClass + " js-visible");
257
+ target.setAttribute('class', targetClass + ' js-visible');
259
258
  }
260
- if(sourceClass.indexOf('js-visible') !== -1){
259
+ if(sourceClass.indexOf('js-visible') !== -1) {
261
260
  this.setAttribute('class', sourceClass.replace(/(^|\s)js-visible(\s|$)/, ''));
262
261
  } else {
263
- this.setAttribute('class', sourceClass + " js-visible");
262
+ this.setAttribute('class', sourceClass + ' js-visible');
264
263
  }
265
- this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') !== "true");
266
- target.setAttribute('aria-hidden', target.getAttribute('aria-hidden') === "false");
264
+ this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') !== 'true');
265
+ target.setAttribute('aria-hidden', target.getAttribute('aria-hidden') === 'false');
267
266
  });
268
267
  }
269
268
  }
270
269
  }).call(this);
271
270
 
272
271
  },{}],3:[function(require,module,exports){
273
- /* eslint-disable no-var */
272
+ /* eslint-disable no-var, vars-on-top, no-unused-vars */
274
273
  'use strict';
275
274
 
276
275
  var toolkit = require('../../../toolkit');
@@ -280,7 +279,7 @@ var formFocus = toolkit.formFocus;
280
279
  var characterCount = toolkit.characterCount;
281
280
  var validation = toolkit.validation;
282
281
 
283
- var GOVUK = require('govuk-frontend')
282
+ var GOVUK = require('govuk-frontend');
284
283
  GOVUK.initAll();
285
284
  window.GOVUK = GOVUK;
286
285
  var skipToMain = require('./skip-to-main');
@@ -299,23 +298,24 @@ helpers.documentReady(validation);
299
298
 
300
299
  },{"../../../toolkit":11,"./cookieSettings":1,"./govuk-cookies":2,"./skip-to-main":4,"govuk-frontend":12}],4:[function(require,module,exports){
301
300
  const skipToMain = function () {
302
- const skipToMainLink = document.getElementById("skip-to-main");
303
- const firstControlId = skipToMainLink.hash.split('#')[1] ? skipToMainLink.hash.split('#')[1] : "main-content";
304
- if(firstControlId === "main-content"){
305
- skipToMainLink.setAttribute("href", "#main-content");
306
- }
307
- if(firstControlId) {
308
- skipToMainLink.onclick = function(e) {
309
- //here timeout added just to make this functionality asynchronous
310
- //to focus on form as well as non form contents
311
- setTimeout(() => {
312
- const firstControl = document.getElementById(firstControlId);
313
- firstControl.focus();
314
- }, 10);
315
- }
316
- }
317
- };
318
- skipToMain();
301
+ const skipToMainLink = document.getElementById('skip-to-main');
302
+ const firstControlId = skipToMainLink.hash.split('#')[1] ? skipToMainLink.hash.split('#')[1] : 'main-content';
303
+ if(firstControlId === 'main-content') {
304
+ skipToMainLink.setAttribute('href', '#main-content');
305
+ }
306
+ if(firstControlId) {
307
+ // eslint-disable-next-line no-unused-vars
308
+ skipToMainLink.onclick = function (e) {
309
+ // here timeout added just to make this functionality asynchronous
310
+ // to focus on form as well as non form contents
311
+ setTimeout(() => {
312
+ const firstControl = document.getElementById(firstControlId);
313
+ firstControl.focus();
314
+ }, 10);
315
+ };
316
+ }
317
+ };
318
+ skipToMain();
319
319
 
320
320
  },{}],5:[function(require,module,exports){
321
321
  /* eslint-disable max-len, no-var, no-use-before-define, no-param-reassign, vars-on-top, radix */
@@ -492,11 +492,20 @@ function formFocus() {
492
492
  var labels;
493
493
  var summaries;
494
494
 
495
- if (getElementFromSummaryLink && getEditPath === 'edit') {
495
+ var editMode = getElementFromSummaryLink && getEditPath === 'edit';
496
+
497
+ if (getElementFromSummaryLink && document.getElementById(getElementFromSummaryLink) && editMode) {
496
498
  document.getElementById(getElementFromSummaryLink).focus();
499
+ }
500
+
501
+ if (getElementFromSummaryLink && document.getElementById(getElementFromSummaryLink + '-group') && editMode) {
497
502
  document.getElementById(getElementFromSummaryLink + '-group').scrollIntoView();
498
503
  }
499
504
 
505
+ if (document.getElementById(getElementFromSummaryLink + '-day') && forms.length === 1 && editMode) {
506
+ document.getElementById(getElementFromSummaryLink + '-day').focus();
507
+ }
508
+
500
509
  if (forms.length > 0) {
501
510
  labels = document.getElementsByTagName('label');
502
511
  if (labels) {
@@ -790,7 +799,12 @@ function clicked(e) {
790
799
  }
791
800
 
792
801
  if (inputs) {
793
- inputs[0].focus();
802
+ if (inputs[0].getAttribute('type') === 'hidden') {
803
+ var getVisibleElements = group.querySelectorAll('input[type=text]');
804
+ getVisibleElements[0].focus();
805
+ } else {
806
+ inputs[0].focus();
807
+ }
794
808
  }
795
809
  }
796
810
  }
package/sandbox/server.js CHANGED
@@ -8,5 +8,11 @@ bootstrap({
8
8
  routes: [
9
9
  require('./apps/sandbox')
10
10
  ],
11
- getAccessibility: true
11
+ rateLimits: {
12
+ requests: {
13
+ active: true
14
+ }
15
+ },
16
+ getAccessibility: true,
17
+ "port": 8082
12
18
  });
package/sandbox/yarn.lock CHANGED
@@ -111,7 +111,7 @@ chalk@^4.1.0:
111
111
  ansi-styles "^4.1.0"
112
112
  supports-color "^7.1.0"
113
113
 
114
- chokidar@^3.5.2:
114
+ "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.2:
115
115
  version "3.5.3"
116
116
  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
117
117
  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@@ -317,6 +317,11 @@ ignore-by-default@^1.0.1:
317
317
  resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
318
318
  integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
319
319
 
320
+ immutable@^4.0.0:
321
+ version "4.1.0"
322
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef"
323
+ integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==
324
+
320
325
  import-lazy@^2.1.0:
321
326
  version "2.1.0"
322
327
  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
@@ -599,6 +604,15 @@ responselike@^1.0.2:
599
604
  dependencies:
600
605
  lowercase-keys "^1.0.0"
601
606
 
607
+ sass@^1.53.0:
608
+ version "1.53.0"
609
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.53.0.tgz#eab73a7baac045cc57ddc1d1ff501ad2659952eb"
610
+ integrity sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==
611
+ dependencies:
612
+ chokidar ">=3.0.0 <4.0.0"
613
+ immutable "^4.0.0"
614
+ source-map-js ">=0.6.2 <2.0.0"
615
+
602
616
  semver-diff@^3.1.1:
603
617
  version "3.1.1"
604
618
  resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
@@ -628,6 +642,11 @@ signal-exit@^3.0.2:
628
642
  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
629
643
  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
630
644
 
645
+ "source-map-js@>=0.6.2 <2.0.0":
646
+ version "1.0.2"
647
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
648
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
649
+
631
650
  string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.2:
632
651
  version "4.2.3"
633
652
  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -2,7 +2,6 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const mkdir = require('mkdirp').sync;
6
5
  const rm = require('rimraf').sync;
7
6
 
8
7
  const debug = require('debug')('hof:transpiler');
@@ -16,7 +15,7 @@ module.exports = (dir, data) => {
16
15
  const outputDir = path.resolve(dir, '..', lang);
17
16
  rm(outputDir);
18
17
  debug(`Emptied directory ${outputDir}`);
19
- mkdir(outputDir);
18
+ fs.mkdirSync(outputDir);
20
19
  debug(`Made directory ${outputDir}`);
21
20
  Object.keys(data[lang]).forEach(namespace => {
22
21
  fs.writeFileSync(path.resolve(outputDir, `${namespace}.json`), JSON.stringify(data[lang][namespace], null, ' '));
@@ -94,7 +94,7 @@ module.exports = class Helpers {
94
94
  /**
95
95
  * utility function which returns undefined on
96
96
  * failed translations instead of returning the key
97
- * @param {Function} translate - the translate funtion
97
+ * @param {Function} translate - the translate function
98
98
  * @param {String} key - the key to translate
99
99
  * @returns {String|undefined} the string result if successful, undefined if not
100
100
  */
@@ -131,4 +131,19 @@ module.exports = class Helpers {
131
131
  `pages.${key}.header`
132
132
  ]) || key;
133
133
  }
134
+ /**
135
+ * utility function which returns true or false on
136
+ * forks depending on whether a value exists on the page
137
+ * @param {Object} req - an http request object
138
+ * @param {Object} res - an http response object
139
+ * @param {Function|Object} condition - a field condition that is either a function or object
140
+ * @returns {Boolean} the boolean result of whether a field value is set on the page or session for a fork
141
+ */
142
+ static isFieldValueInPageOrSessionValid(req, res, condition) {
143
+ return _.isFunction(condition) ?
144
+ condition(req, res) :
145
+ condition.value === (req.form.values[condition.field] ||
146
+ (!Object.keys(req.form.values).includes(condition.field) &&
147
+ _.get(req, `form.historicalValues[${condition.field}]`)));
148
+ }
134
149
  };
package/wizard/index.js CHANGED
@@ -69,6 +69,7 @@ const Wizard = (steps, fields, setts) => {
69
69
  options.confirmStep = settings.confirmStep;
70
70
  options.clearSession = options.clearSession || false;
71
71
  options.fieldsConfig = _.cloneDeep(fields);
72
+ options.sanitiseInputs = settings.sanitiseInputs;
72
73
 
73
74
  options.defaultFormatters = [].concat(settings.formatters);
74
75