hof 20.0.0-beta.3 → 20.0.0-beta.31

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 (63) hide show
  1. package/.github/workflows/automate-publish.yml +1 -1
  2. package/.github/workflows/automate-tag.yml +1 -1
  3. package/README.md +329 -256
  4. package/build/lib/mkdir.js +2 -2
  5. package/components/date/index.js +37 -26
  6. package/components/date/templates/date.html +3 -3
  7. package/components/emailer/index.js +49 -41
  8. package/components/emailer/transports/debug.js +1 -2
  9. package/components/index.js +2 -1
  10. package/components/notify/index.js +60 -0
  11. package/components/notify/notify.js +25 -0
  12. package/components/summary/index.js +18 -0
  13. package/config/hof-defaults.js +5 -3
  14. package/config/rate-limits.js +20 -0
  15. package/config/sanitisation-rules.js +29 -0
  16. package/controller/base-controller.js +26 -8
  17. package/controller/controller.js +23 -17
  18. package/frontend/govuk-template/build/config.js +1 -1
  19. package/frontend/template-mixins/mixins/template-mixins.js +12 -8
  20. package/frontend/template-mixins/partials/forms/checkbox-group.html +13 -4
  21. package/frontend/template-mixins/partials/forms/input-text-date.html +1 -1
  22. package/frontend/template-mixins/partials/forms/input-text-group.html +6 -4
  23. package/frontend/template-mixins/partials/forms/option-group.html +12 -3
  24. package/frontend/template-mixins/partials/forms/select.html +3 -3
  25. package/frontend/template-mixins/partials/forms/textarea-group.html +3 -3
  26. package/frontend/template-mixins/partials/mixins/panel.html +1 -2
  27. package/frontend/template-partials/translations/src/en/errors.json +12 -0
  28. package/frontend/template-partials/views/layout.html +10 -3
  29. package/frontend/template-partials/views/partials/cookie-banner.html +1 -1
  30. package/frontend/template-partials/views/partials/form.html +2 -1
  31. package/frontend/template-partials/views/partials/warn.html +7 -0
  32. package/frontend/template-partials/views/rate-limit-error.html +10 -0
  33. package/frontend/themes/gov-uk/client-js/govuk-cookies.js +43 -44
  34. package/frontend/themes/gov-uk/client-js/index.js +2 -2
  35. package/frontend/themes/gov-uk/client-js/skip-to-main.js +18 -17
  36. package/frontend/themes/gov-uk/styles/govuk.scss +4 -0
  37. package/frontend/themes/gov-uk/styles/modules/_validation.scss +2 -2
  38. package/frontend/toolkit/assets/javascript/form-focus.js +10 -1
  39. package/frontend/toolkit/assets/javascript/validation.js +6 -1
  40. package/index.js +9 -4
  41. package/lib/router.js +2 -1
  42. package/lib/settings.js +9 -8
  43. package/middleware/errors.js +32 -0
  44. package/middleware/index.js +2 -1
  45. package/middleware/rate-limiter.js +98 -0
  46. package/package.json +6 -6
  47. package/sandbox/apps/sandbox/fields.js +12 -12
  48. package/sandbox/apps/sandbox/index.js +1 -5
  49. package/sandbox/apps/sandbox/translations/en/default.json +24 -0
  50. package/sandbox/assets/scss/app.scss +0 -52
  51. package/sandbox/package.json +2 -0
  52. package/sandbox/public/css/app.css +4908 -4965
  53. package/sandbox/public/js/bundle.js +79 -65
  54. package/sandbox/server.js +7 -1
  55. package/sandbox/yarn.lock +39 -564
  56. package/transpiler/lib/write-files.js +1 -2
  57. package/utilities/helpers/index.js +16 -1
  58. package/wizard/index.js +1 -0
  59. package/.nyc_output/65af88d9-aebe-4d1b-a21d-6fbf7f2bbda4.json +0 -1
  60. package/.nyc_output/processinfo/65af88d9-aebe-4d1b-a21d-6fbf7f2bbda4.json +0 -1
  61. package/.nyc_output/processinfo/index.json +0 -1
  62. package/.vscode/settings.json +0 -6
  63. package/sandbox/.env +0 -1
@@ -213,8 +213,9 @@ module.exports = function (options) {
213
213
  date: extension.date,
214
214
  autocomplete: autocomplete,
215
215
  child: field.child,
216
- noHeading: field.noHeading,
216
+ isPageHeading: field.isPageHeading,
217
217
  attributes: field.attributes,
218
+ isPrefixOrSuffix: _.map(field.attributes, item => {if (item.prefix || item.suffix !== undefined) return true;}),
218
219
  renderChild: renderChild.bind(this)
219
220
  });
220
221
  }
@@ -224,6 +225,7 @@ module.exports = function (options) {
224
225
  const field = Object.assign({}, this.options.fields[key] || options.fields[key]);
225
226
  const legend = field.legend;
226
227
  const detail = field.detail;
228
+ const warningValue = 'fields.' + key + '.warning';
227
229
  let legendClassName;
228
230
  let legendValue = 'fields.' + key + '.legend';
229
231
  if (legend) {
@@ -240,7 +242,9 @@ module.exports = function (options) {
240
242
  legend: t(legendValue),
241
243
  legendClassName: legendClassName,
242
244
  role: opts.type === 'radio' ? 'radiogroup' : 'group',
243
- noHeading: field.noHeading,
245
+ isPageHeading: field.isPageHeading,
246
+ isWarning: field.isWarning,
247
+ warning: t(warningValue),
244
248
  detail: detail ? detail : '',
245
249
  hint: conditionalTranslate(getTranslationKey(field, key, 'hint')),
246
250
  options: _.map(field.options, function (obj) {
@@ -303,7 +307,7 @@ module.exports = function (options) {
303
307
  invalid: this.errors && this.errors[key] && opts.required,
304
308
  label: t(fieldLabel || 'fields.' + key + '.label'),
305
309
  selected: selected,
306
- className: classNames(field) || 'block-label',
310
+ className: classNames(field) || 'govuk-label govuk-checkboxes__label',
307
311
  child: field.child,
308
312
  renderChild: renderChild.bind(this)
309
313
  });
@@ -431,8 +435,8 @@ module.exports = function (options) {
431
435
  year: autocomplete + '-year'
432
436
  };
433
437
  }
434
- const isRequired = field.validate ? field.validate.indexOf('required') > -1 : false;
435
- const formGroupClassName = (field.formGroup && field.formGroup.className) ? field.formGroup.className : ''
438
+ const isThisRequired = field.validate ? field.validate.indexOf('required') > -1 : false;
439
+ const formGroupClassName = (field.formGroup && field.formGroup.className) ? field.formGroup.className : '';
436
440
  const classNameDay = (field.controlsClass && field.controlsClass.day) ? field.controlsClass.day : 'govuk-date-input__input govuk-input--width-2';
437
441
  const classNameMonth = (field.controlsClass && field.controlsClass.month) ? field.controlsClass.month : 'govuk-date-input__input govuk-input--width-2';
438
442
  const classNameYear = (field.controlsClass && field.controlsClass.year) ? field.controlsClass.year : 'govuk-date-input__input govuk-input--width-4';
@@ -440,12 +444,12 @@ module.exports = function (options) {
440
444
  const parts = [];
441
445
 
442
446
  if (isExact) {
443
- const dayPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-day', { pattern: '[0-9]*', min: 1, max: 31, maxlength: 2, hintId: key + '-hint', date: true, autocomplete: autocomplete.day, formGroupClassName, className: classNameDay, isRequired }));
447
+ const dayPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-day', { pattern: '[0-9]*', min: 1, max: 31, maxlength: 2, hintId: key + '-hint', date: true, autocomplete: autocomplete.day, formGroupClassName, className: classNameDay, isThisRequired }));
444
448
  parts.push(dayPart);
445
449
  }
446
450
 
447
- const monthPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-month', { pattern: '[0-9]*', min: 1, max: 12, maxlength: 2, hintId: key + '-hint', date: true, autocomplete: autocomplete.month, formGroupClassName, className: classNameMonth, isRequired }));
448
- const yearPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-year', { pattern: '[0-9]*', maxlength: 4, hintId: key + '-hint', date: true, autocomplete: autocomplete.year, formGroupClassName, className: classNameYear, isRequired }));
451
+ const monthPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-month', { pattern: '[0-9]*', min: 1, max: 12, maxlength: 2, hintId: key + '-hint', date: true, autocomplete: autocomplete.month, formGroupClassName, className: classNameMonth, isThisRequired }));
452
+ const yearPart = compiled['partials/forms/input-text-date'].render(inputText.call(this, key + '-year', { pattern: '[0-9]*', maxlength: 4, hintId: key + '-hint', date: true, autocomplete: autocomplete.year, formGroupClassName, className: classNameYear, isThisRequired }));
449
453
 
450
454
  return parts.concat(monthPart, yearPart).join('\n');
451
455
  };
@@ -1,10 +1,19 @@
1
1
  <div id="{{key}}-group" class="govuk-form-group{{#className}} {{className}} {{/className}}{{#formGroupClassName}} {{formGroupClassName}}{{/formGroupClassName}}{{#error}} govuk-form-group--error{{/error}}">
2
2
  <fieldset class="govuk-fieldset" {{#hint}} aria-describedby="{{key}}-hint"{{/hint}}>
3
- <legend class="govuk-fieldset__legend {{^noHeading}}govuk-fieldset__legend--l{{/noHeading}}{{#legendClassName}} {{legendClassName}}{{/legendClassName}}">
4
- {{^noHeading}}<h1 class="govuk-fieldset__heading">{{/noHeading}}
3
+ <legend class="govuk-fieldset__legend {{#isPageHeading}}govuk-fieldset__legend--l{{/isPageHeading}}{{#legendClassName}} {{legendClassName}}{{/legendClassName}}">
4
+ {{#isPageHeading}}<h1 class="govuk-fieldset__heading">{{/isPageHeading}}
5
5
  {{legend}}
6
- {{^noHeading}}</h1>{{/noHeading}}
6
+ {{#isPageHeading}}</h1>{{/isPageHeading}}
7
7
  </legend>
8
+ {{#isWarning}}
9
+ <div class="govuk-warning-text">
10
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
11
+ <strong class="govuk-warning-text__text">
12
+ <span class="govuk-warning-text__assistive">Warning</span>
13
+ {{warning}}
14
+ </strong>
15
+ </div>
16
+ {{/isWarning}}
8
17
  {{#hint}}<div id="{{key}}-hint" class="govuk-hint">{{hint}}</div>{{/hint}}
9
18
  {{#error}}
10
19
  <p id="{{key}}-error" class="govuk-error-message">
@@ -28,7 +37,7 @@
28
37
  >
29
38
  <label class="govuk-label govuk-checkboxes__label" for="{{key}}-{{value}}">
30
39
  {{{label}}}
31
- {{#optionHint}}<div id="{{key}}-{{value}}-item-hint" class="govuk-hint govuk-radios__hint">{{optionHint}}</div>{{/optionHint}}
40
+ {{#optionHint}}<div id="{{key}}-{{value}}-item-hint" class="govuk-hint">{{optionHint}}</div>{{/optionHint}}
32
41
  </label>
33
42
  </div>
34
43
  {{#renderChild}}{{/renderChild}}
@@ -14,7 +14,7 @@
14
14
  type="{{type}}"
15
15
  name="{{id}}"
16
16
  id="{{id}}"
17
- class="govuk-input{{#className}} {{className}}{{/className}}{{#error}} invalid-input{{/error}}"
17
+ class="govuk-input{{#className}} {{className}}{{/className}}{{#error}} govuk-input--error{{/error}}"
18
18
  aria-required="{{required}}"
19
19
  {{#value}} value="{{value}}"{{/value}}
20
20
  {{#min}} min="{{min}}"{{/min}}
@@ -1,8 +1,8 @@
1
1
  <div id="{{id}}-group" class="{{#compound}} form-group-compound{{/compound}}{{#formGroupClassName}}{{formGroupClassName}}{{/formGroupClassName}}{{#error}} govuk-form-group--error{{/error}}">
2
- {{^noHeading}}<h1 class="govuk-label-wrapper">{{/noHeading}}<label for="{{id}}" class="{{labelClassName}}">
2
+ {{#isPageHeading}}<h1 class="govuk-label-wrapper">{{/isPageHeading}}<label for="{{id}}" class="{{labelClassName}}{{#isPageHeading}}govuk-label--l{{/isPageHeading}}">
3
3
  {{{label}}}
4
4
  </label>
5
- {{^noHeading}}</h1>{{/noHeading}}
5
+ {{#isPageHeading}}</h1>{{/isPageHeading}}
6
6
  {{#hint}}<span {{$hintId}}id="{{hintId}}" {{/hintId}}class="govuk-hint">{{hint}}</span>{{/hint}}
7
7
  {{#error}}
8
8
  <p class="govuk-error-message">
@@ -10,6 +10,7 @@
10
10
  </p>
11
11
  {{/error}}
12
12
  {{#renderChild}}{{/renderChild}}
13
+ {{#isPrefixOrSuffix}}<div class="govuk-input__wrapper">{{/isPrefixOrSuffix}}
13
14
  {{#attributes}}
14
15
  {{#prefix}}
15
16
  <div class="govuk-input__prefix" aria-hidden="true">{{prefix}}</div>
@@ -19,7 +20,7 @@
19
20
  type="{{type}}"
20
21
  name="{{id}}"
21
22
  id="{{id}}"
22
- class="{{^className}}govuk-input{{/className}}{{#className}}{{className}}{{/className}}{{#error}} invalid-input{{/error}}"
23
+ class="{{^className}}govuk-input{{/className}}{{#className}}{{className}}{{/className}}{{#error}} govuk-input--error{{/error}}"
23
24
  aria-required="{{required}}"
24
25
  {{#value}} value="{{value}}"{{/value}}
25
26
  {{#min}} min="{{min}}"{{/min}}
@@ -35,7 +36,8 @@
35
36
  >
36
37
  {{#attributes}}
37
38
  {{#suffix}}
38
- <div class="govuk-input__prefix" aria-hidden="true">{{suffix}}</div>
39
+ <div class="govuk-input__suffix" aria-hidden="true">{{suffix}}</div>
39
40
  {{/suffix}}
40
41
  {{/attributes}}
42
+ {{#isPrefixOrSuffix}}</div>{{/isPrefixOrSuffix}}
41
43
  </div>
@@ -1,10 +1,19 @@
1
1
  <div id="{{key}}-group" class="govuk-form-group{{#className}} {{className}} {{/className}}{{#formGroupClassName}} {{formGroupClassName}}{{/formGroupClassName}}{{#error}} govuk-form-group--error{{/error}}">
2
2
  <fieldset class="govuk-fieldset" {{#hint}} aria-describedby="{{key}}-hint"{{/hint}}>
3
- <legend class="govuk-fieldset__legend {{^noHeading}}govuk-fieldset__legend--l{{/noHeading}}{{#legendClassName}} {{legendClassName}}{{/legendClassName}}">
4
- {{^noHeading}}<h1 class="govuk-fieldset__heading">{{/noHeading}}
3
+ <legend class="govuk-fieldset__legend {{#isPageHeading}}govuk-fieldset__legend--l{{/isPageHeading}}{{#legendClassName}} {{legendClassName}}{{/legendClassName}}">
4
+ {{#isPageHeading}}<h1 class="govuk-fieldset__heading">{{/isPageHeading}}
5
5
  {{legend}}
6
- {{^noHeading}}</h1>{{/noHeading}}
6
+ {{#isPageHeading}}</h1>{{/isPageHeading}}
7
7
  </legend>
8
+ {{#isWarning}}
9
+ <div class="govuk-warning-text">
10
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
11
+ <strong class="govuk-warning-text__text">
12
+ <span class="govuk-warning-text__assistive">Warning</span>
13
+ {{warning}}
14
+ </strong>
15
+ </div>
16
+ {{/isWarning}}
8
17
  {{#hint}}<div id="{{key}}-hint" class="govuk-hint">{{hint}}</div>{{/hint}}
9
18
  {{#error}}<p id="{{key}}-error" class="govuk-error-message"><span class="govuk-visually-hidden">Error:</span> {{error.message}}</p>{{/error}}
10
19
  {{{detail}}}
@@ -1,5 +1,5 @@
1
1
  <div id="{{id}}-group" class="{{#compound}} form-group-compound{{/compound}}{{#formGroupClassName}} {{formGroupClassName}}{{/formGroupClassName}}{{#error}} govuk-form-group--error{{/error}}">
2
- {{^noHeading}}<h1 class="govuk-label-wrapper">{{/noHeading}}<label for="{{id}}" class="{{labelClassName}}{{^noHeading}}govuk-label--l{{/noHeading}}">
2
+ {{#isPageHeading}}<h1 class="govuk-label-wrapper">{{/isPageHeading}}<label for="{{id}}" class="{{labelClassName}}{{#isPageHeading}}govuk-label--l{{/isPageHeading}}">
3
3
  {{{label}}}
4
4
  {{#hint}}<span {{$hintId}}id="{{hintId}}" {{/hintId}}class="govuk-hint">{{hint}}</span>{{/hint}}
5
5
  {{#error}}
@@ -8,8 +8,8 @@
8
8
  </p>
9
9
  {{/error}}
10
10
  </label>
11
- {{^noHeading}}</h1>{{/noHeading}}
12
- <select id="{{id}}" class="govuk-select{{#className}} {{className}}{{/className}}{{#error}} invalid-input{{/error}}" name="{{id}}" aria-required="{{required}}">
11
+ {{#isPageHeading}}</h1>{{/isPageHeading}}
12
+ <select id="{{id}}" class="govuk-select{{#className}} {{className}}{{/className}}{{#error}} govuk-select--error{{/error}}" name="{{id}}" aria-required="{{required}}">
13
13
  {{#options}}
14
14
  <option value="{{value}}" {{#selected}}selected{{/selected}}>{{label}}</option>
15
15
  {{/options}}
@@ -2,7 +2,7 @@
2
2
  <div class="govuk-character-count" data-module="govuk-character-count" data-maxlength="{{maxlength}}">
3
3
  {{/maxlength}}
4
4
  <div id="{{id}}-group" class="{{#compound}}form-group-compound {{/compound}}{{#formGroupClassName}}{{formGroupClassName}}{{/formGroupClassName}}{{#error}} govuk-form-group--error{{/error}}">
5
- {{^noHeading}}<h1 class="govuk-label-wrapper">{{/noHeading}}<label for="{{id}}" class="{{labelClassName}}">
5
+ {{#isPageHeading}}<h1 class="govuk-label-wrapper">{{/isPageHeading}}<label for="{{id}}" class="{{labelClassName}}{{#isPageHeading}}govuk-label--l{{/isPageHeading}}">
6
6
  {{{label}}}
7
7
  {{#error}}
8
8
  <p id="{{id}}-error" class="govuk-error-message">
@@ -10,13 +10,13 @@
10
10
  </p>
11
11
  {{/error}}
12
12
  </label>
13
- {{^noHeading}}</h1>{{/noHeading}}
13
+ {{#isPageHeading}}</h1>{{/isPageHeading}}
14
14
  {{#hint}}<div {{$hintId}}id="{{hintId}}" {{/hintId}}class="govuk-hint">{{hint}}</div>{{/hint}}
15
15
  {{#renderChild}}{{/renderChild}}
16
16
  <textarea
17
17
  name="{{id}}"
18
18
  id="{{id}}"
19
- class="govuk-textarea{{#className}} {{className}}{{/className}} {{#maxlength}}maxlength{{/maxlength}}{{#error}} invalid-input{{/error}}"
19
+ class="govuk-textarea{{#className}} {{className}}{{/className}} {{#maxlength}}maxlength{{/maxlength}}{{#error}} govuk-input--error{{/error}}"
20
20
  aria-required="{{required}}"
21
21
  {{#maxlength}} maxlength="{{maxlength}}"{{/maxlength}}
22
22
  {{#attributes}}
@@ -1,5 +1,4 @@
1
- <div id="{{toggle}}-panel"
2
- class="{{#radioOption}}govuk-radios__conditional govuk-radios__conditional--hidden{{/radioOption}}
1
+ <div id="{{toggle}}-panel" class="{{#radioOption}}govuk-radios__conditional govuk-radios__conditional--hidden{{/radioOption}}
3
2
  {{^radioOption}}govuk-checkboxes__conditional govuk-checkboxes__conditional--hidden{{/radioOption}}">
4
3
  {{#renderMixin}}{{/renderMixin}}
5
4
  </div>
@@ -14,5 +14,17 @@
14
14
  "cookies-required": {
15
15
  "title": "Cookies are required to use this service",
16
16
  "message": "Cookies are required in order to use this service.<br /><br /> Please <a href=\"http://www.aboutcookies.org/how-to-control-cookies/\" rel=\"external\">enable cookies</a> and try again. Find out <a href=\"/cookies\">how to we use cookies</a>."
17
+ },
18
+ "ddos-rate-limit": {
19
+ "title": "Too many requests submitted",
20
+ "message": "You have submitted too many requests in quick succession.",
21
+ "pre-time-to-wait": "Please try again in ",
22
+ "post-time-to-wait": " minutes."
23
+ },
24
+ "submission-rate-limit": {
25
+ "title": "Too many submissions",
26
+ "message": "You have submitted too many applications in a short space of time.",
27
+ "pre-time-to-wait": "Please try again in ",
28
+ "post-time-to-wait": " minutes."
17
29
  }
18
30
  }
@@ -44,9 +44,16 @@
44
44
  {{/gaTagId}}
45
45
  {{/cookieMessage}}
46
46
  {{$footerSupportLinks}}
47
- <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/cookies">{{#t}}base.cookies{{/t}}</a></li>
48
- <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/accessibility">{{#t}}base.accessibility{{/t}}</a></li>
49
- <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/terms-and-conditions">{{#t}}base.terms{{/t}}</a></li>
47
+ <ul>
48
+ {{#footerSupportLinks}}
49
+ <li class="govuk-footer__inline-list-item"><a href="{{path}}">{{#t}}{{property}}{{/t}}</a></li>
50
+ {{/footerSupportLinks}}
51
+ {{^footerSupportLinks}}
52
+ <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/cookies">{{#t}}base.cookies{{/t}}</a></li>
53
+ <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/accessibility">{{#t}}base.accessibility{{/t}}</a></li>
54
+ <li class="govuk-footer__inline-list-item"><a class="govuk-footer__link" href="/terms-and-conditions">{{#t}}base.terms{{/t}}</a></li>
55
+ {{/footerSupportLinks}}
56
+ </ul>
50
57
  {{/footerSupportLinks}}
51
58
  {{$bodyEnd}}
52
59
  {{> partials-gatag}}
@@ -20,7 +20,7 @@
20
20
  </div>
21
21
  <div class="gem-c-cookie-banner__confirmation govuk-width-container" tabindex="0" hidden="" id="cookie-banner-submitted" >
22
22
  <p class="gem-c-cookie-banner__confirmation-message" role="alert">
23
- Your cookie preferences have been saved. You can <a class="govuk-link" data-module="gem-track-click" data-track-category="cookieBanner" data-track-action="Cookie banner settings clicked from confirmation" href="/student-help/cookies">change your cookie settings</a> at any time.
23
+ Your cookie preferences have been saved. You can <a class="govuk-link" data-module="gem-track-click" data-track-category="cookieBanner" data-track-action="Cookie banner settings clicked from confirmation" href="/cookies">change your cookie settings</a> at any time.
24
24
  </p>
25
25
  <div class="govuk-button-group">
26
26
  <button class="gem-c-cookie-banner__hide-button govuk-button" id="hide-cookie-banner">Hide this message</button>
@@ -1,7 +1,8 @@
1
1
  <form action="" method="POST" {{$encoding}}{{/encoding}} autocomplete="off" novalidate="true" spellcheck="false">
2
2
  {{$intro}}
3
- {{#intro}}<span class="govuk-hint" >{{intro}}</span>{{/intro}}
3
+ {{#intro}}<p>{{intro}}</p>{{/intro}}
4
4
  {{/intro}}
5
+
5
6
  {{$form}}{{/form}}
6
7
  {{#csrf-token}}
7
8
  <input type="hidden" name="x-csrf-token" value="{{csrf-token}}" />
@@ -0,0 +1,7 @@
1
+ <div class="govuk-warning-text">
2
+ <span class="govuk-warning-text__icon" aria-hidden="true">!</span>
3
+ <strong class="govuk-warning-text__text">
4
+ <span class="govuk-warning-text__assistive">Warning</span>
5
+ {{warning}}
6
+ </strong>
7
+ </div>
@@ -0,0 +1,10 @@
1
+ {{<layout}}
2
+ {{$header}}
3
+ {{content.title}}
4
+ {{/header}}
5
+ {{$content}}
6
+ <p>{{content.message}}</p>
7
+ <p>{{content.preTimeToWait}}{{content.timeToWait}}{{content.postTimeToWait}}</p>
8
+ <a href="/" class="button" role="button">{{#t}}buttons.try-again{{/t}}</a>
9
+ {{/content}}
10
+ {{/layout}}
@@ -1,6 +1,7 @@
1
+ /* eslint-disable no-undef, no-param-reassign, no-unused-vars */
1
2
  (function () {
2
- "use strict"
3
- var root = this;
3
+ 'use strict';
4
+ const root = this;
4
5
  if(typeof root.GOVUK === 'undefined') { root.GOVUK = {}; }
5
6
 
6
7
  /*
@@ -19,37 +20,35 @@
19
20
  GOVUK.cookie('hobnob', null);
20
21
  */
21
22
  GOVUK.cookie = function (name, value, options) {
22
- if(typeof value !== 'undefined'){
23
+ if(typeof value !== 'undefined') {
23
24
  if(value === false || value === null) {
24
25
  return GOVUK.setCookie(name, '', { days: -1 });
25
- } else {
26
- return GOVUK.setCookie(name, value, options);
27
26
  }
28
- } else {
29
- return GOVUK.getCookie(name);
27
+ return GOVUK.setCookie(name, value, options);
30
28
  }
29
+ return GOVUK.getCookie(name);
31
30
  };
32
31
  GOVUK.setCookie = function (name, value, options) {
33
32
  if(typeof options === 'undefined') {
34
33
  options = {};
35
34
  }
36
- var cookieString = name + "=" + value + "; path=/";
35
+ let cookieString = name + '=' + value + '; path=/';
37
36
  if (options.days) {
38
- var date = new Date();
37
+ const date = new Date();
39
38
  date.setTime(date.getTime() + (options.days * 24 * 60 * 60 * 1000));
40
- cookieString = cookieString + "; expires=" + date.toGMTString();
39
+ cookieString = cookieString + '; expires=' + date.toGMTString();
41
40
  }
42
- if (document.location.protocol == 'https:'){
43
- cookieString = cookieString + "; Secure";
41
+ if (document.location.protocol === 'https:') {
42
+ cookieString = cookieString + '; Secure';
44
43
  }
45
44
  document.cookie = cookieString;
46
45
  };
47
46
  GOVUK.getCookie = function (name) {
48
- var nameEQ = name + "=";
49
- var cookies = document.cookie.split(';');
50
- for(var i = 0, len = cookies.length; i < len; i++) {
51
- var cookie = cookies[i];
52
- while (cookie.charAt(0) == ' ') {
47
+ const nameEQ = name + '=';
48
+ const cookies = document.cookie.split(';');
49
+ for(let i = 0, len = cookies.length; i < len; i++) {
50
+ let cookie = cookies[i];
51
+ while (cookie.charAt(0) === ' ') {
53
52
  cookie = cookie.substring(1, cookie.length);
54
53
  }
55
54
  if (cookie.indexOf(nameEQ) === 0) {
@@ -60,33 +59,33 @@
60
59
  };
61
60
  }).call(this);
62
61
  (function () {
63
- 'use strict'
64
- var root = this
65
- if (typeof root.GOVUK === 'undefined') { root.GOVUK = {} }
62
+ 'use strict';
63
+ const root = this;
64
+ if (typeof root.GOVUK === 'undefined') { root.GOVUK = {}; }
66
65
 
67
66
  GOVUK.addCookieMessage = function () {
68
- var message = document.getElementById('global-cookie-message')
67
+ const message = document.getElementById('global-cookie-message');
69
68
 
70
- var hasCookieMessage = (message && GOVUK.cookie('seen_cookie_message') === null)
69
+ const hasCookieMessage = (message && GOVUK.cookie('seen_cookie_message') === null);
71
70
 
72
71
  if (hasCookieMessage) {
73
- message.style.display = 'block'
74
- GOVUK.cookie('seen_cookie_message', 'yes', { days: 28 })
72
+ message.style.display = 'block';
73
+ GOVUK.cookie('seen_cookie_message', 'yes', { days: 28 });
75
74
 
76
75
  document.addEventListener('DOMContentLoaded', function (event) {
77
76
  if (GOVUK.analytics && typeof GOVUK.analytics.trackEvent === 'function') {
78
77
  GOVUK.analytics.trackEvent('cookieBanner', 'Cookie banner shown', {
79
78
  value: 1,
80
79
  nonInteraction: true
81
- })
80
+ });
82
81
  }
83
- })
84
- };
85
- }
82
+ });
83
+ }
84
+ };
86
85
  }).call(this)
87
86
  ;
88
- (function() {
89
- "use strict"
87
+ (function () {
88
+ 'use strict';
90
89
 
91
90
  // add cookie message
92
91
  if (window.GOVUK && GOVUK.addCookieMessage) {
@@ -94,28 +93,28 @@
94
93
  }
95
94
 
96
95
  // header navigation toggle
97
- if (document.querySelectorAll && document.addEventListener){
98
- var els = document.querySelectorAll('.js-header-toggle'),
99
- i, _i;
100
- for(i=0,_i=els.length; i<_i; i++){
101
- els[i].addEventListener('click', function(e){
96
+ if (document.querySelectorAll && document.addEventListener) {
97
+ const els = document.querySelectorAll('.js-header-toggle');
98
+ let i; let _i;
99
+ for(i = 0, _i = els.length; i < _i; i++) {
100
+ els[i].addEventListener('click', function (e) {
102
101
  e.preventDefault();
103
- var target = document.getElementById(this.getAttribute('href').substr(1)),
104
- targetClass = target.getAttribute('class') || '',
105
- sourceClass = this.getAttribute('class') || '';
102
+ const target = document.getElementById(this.getAttribute('href').substr(1));
103
+ const targetClass = target.getAttribute('class') || '';
104
+ const sourceClass = this.getAttribute('class') || '';
106
105
 
107
- if(targetClass.indexOf('js-visible') !== -1){
106
+ if(targetClass.indexOf('js-visible') !== -1) {
108
107
  target.setAttribute('class', targetClass.replace(/(^|\s)js-visible(\s|$)/, ''));
109
108
  } else {
110
- target.setAttribute('class', targetClass + " js-visible");
109
+ target.setAttribute('class', targetClass + ' js-visible');
111
110
  }
112
- if(sourceClass.indexOf('js-visible') !== -1){
111
+ if(sourceClass.indexOf('js-visible') !== -1) {
113
112
  this.setAttribute('class', sourceClass.replace(/(^|\s)js-visible(\s|$)/, ''));
114
113
  } else {
115
- this.setAttribute('class', sourceClass + " js-visible");
114
+ this.setAttribute('class', sourceClass + ' js-visible');
116
115
  }
117
- this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') !== "true");
118
- target.setAttribute('aria-hidden', target.getAttribute('aria-hidden') === "false");
116
+ this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') !== 'true');
117
+ target.setAttribute('aria-hidden', target.getAttribute('aria-hidden') === 'false');
119
118
  });
120
119
  }
121
120
  }
@@ -1,4 +1,4 @@
1
- /* eslint-disable no-var */
1
+ /* eslint-disable no-var, vars-on-top, no-unused-vars */
2
2
  'use strict';
3
3
 
4
4
  var toolkit = require('../../../toolkit');
@@ -8,7 +8,7 @@ var formFocus = toolkit.formFocus;
8
8
  var characterCount = toolkit.characterCount;
9
9
  var validation = toolkit.validation;
10
10
 
11
- var GOVUK = require('govuk-frontend')
11
+ var GOVUK = require('govuk-frontend');
12
12
  GOVUK.initAll();
13
13
  window.GOVUK = GOVUK;
14
14
  var skipToMain = require('./skip-to-main');
@@ -1,18 +1,19 @@
1
1
  const skipToMain = function () {
2
- const skipToMainLink = document.getElementById("skip-to-main");
3
- const firstControlId = skipToMainLink.hash.split('#')[1] ? skipToMainLink.hash.split('#')[1] : "main-content";
4
- if(firstControlId === "main-content"){
5
- skipToMainLink.setAttribute("href", "#main-content");
6
- }
7
- if(firstControlId) {
8
- skipToMainLink.onclick = function(e) {
9
- //here timeout added just to make this functionality asynchronous
10
- //to focus on form as well as non form contents
11
- setTimeout(() => {
12
- const firstControl = document.getElementById(firstControlId);
13
- firstControl.focus();
14
- }, 10);
15
- }
16
- }
17
- };
18
- skipToMain();
2
+ const skipToMainLink = document.getElementById('skip-to-main');
3
+ const firstControlId = skipToMainLink.hash.split('#')[1] ? skipToMainLink.hash.split('#')[1] : 'main-content';
4
+ if(firstControlId === 'main-content') {
5
+ skipToMainLink.setAttribute('href', '#main-content');
6
+ }
7
+ if(firstControlId) {
8
+ // eslint-disable-next-line no-unused-vars
9
+ skipToMainLink.onclick = function (e) {
10
+ // here timeout added just to make this functionality asynchronous
11
+ // to focus on form as well as non form contents
12
+ setTimeout(() => {
13
+ const firstControl = document.getElementById(firstControlId);
14
+ firstControl.focus();
15
+ }, 10);
16
+ };
17
+ }
18
+ };
19
+ skipToMain();
@@ -12,6 +12,10 @@ $path: "/public/images/" !default;
12
12
  // https://github.com/alphagov/govuk_elements/blob/master/packages/govuk-elements-sass/public/sass/_elements.scss
13
13
  @import "govuk-elements-sass/public/sass/elements";
14
14
 
15
+ // Govuk frontend
16
+ // https://github.com/alphagov/govuk-frontend-docs
17
+ @import "govuk-frontend";
18
+
15
19
  // Custom
16
20
  @import "base";
17
21
  @import "layout";
@@ -25,7 +25,7 @@
25
25
  .govuk-form-group--error {
26
26
  box-sizing: border-box;
27
27
  padding-left: $gutter-half - $validation-bdr-size;
28
- border-left: $validation-bdr-size-lg solid $error-colour;
28
+ //border-left: $validation-bdr-size-lg solid $error-colour;
29
29
 
30
30
  &:focus {
31
31
  outline: $focus-outline;
@@ -42,7 +42,7 @@
42
42
  margin-bottom: 0.5em;
43
43
  }
44
44
  @include bold-19;
45
- color: $error-colour;
45
+ //color: $error-colour;
46
46
  }
47
47
 
48
48
  .invalid-input,
@@ -71,11 +71,20 @@ function formFocus() {
71
71
  var labels;
72
72
  var summaries;
73
73
 
74
- if (getElementFromSummaryLink && getEditPath === 'edit') {
74
+ var editMode = getElementFromSummaryLink && getEditPath === 'edit';
75
+
76
+ if (getElementFromSummaryLink && document.getElementById(getElementFromSummaryLink) && editMode) {
75
77
  document.getElementById(getElementFromSummaryLink).focus();
78
+ }
79
+
80
+ if (getElementFromSummaryLink && document.getElementById(getElementFromSummaryLink + '-group') && editMode) {
76
81
  document.getElementById(getElementFromSummaryLink + '-group').scrollIntoView();
77
82
  }
78
83
 
84
+ if (document.getElementById(getElementFromSummaryLink + '-day') && forms.length === 1 && editMode) {
85
+ document.getElementById(getElementFromSummaryLink + '-day').focus();
86
+ }
87
+
79
88
  if (forms.length > 0) {
80
89
  labels = document.getElementsByTagName('label');
81
90
  if (labels) {
@@ -24,7 +24,12 @@ function clicked(e) {
24
24
  }
25
25
 
26
26
  if (inputs) {
27
- inputs[0].focus();
27
+ if (inputs[0].getAttribute('type') === 'hidden') {
28
+ var getVisibleElements = group.querySelectorAll('input[type=text]');
29
+ getVisibleElements[0].focus();
30
+ } else {
31
+ inputs[0].focus();
32
+ }
28
33
  }
29
34
  }
30
35
  }
package/index.js CHANGED
@@ -120,8 +120,9 @@ const getContentSecurityPolicy = (config, res) => {
120
120
  * @param options.getTerms {boolean} Optional boolean - whether to mount the /terms endpoint
121
121
  * @param options.getCookies {boolean} Optional boolean - whether to mount the /cookies endpoint
122
122
  * @param options.noCache {boolean} Optional boolean - whether to disable caching
123
- * @param options.getAccessibilityStatement {boolean} Optional boolean - whether to mount the /accessibility-statement endpoint
124
- *
123
+ * @param options.getAccessibilityStatement {boolean} Optional boolean - whether to mount the
124
+ * /accessibility-statement endpoint
125
+ *
125
126
  * @returns {object} A new HOF application using the configuration supplied in options
126
127
  */
127
128
  function bootstrap(options) {
@@ -205,9 +206,13 @@ function bootstrap(options) {
205
206
  }));
206
207
  app.use(mixins());
207
208
  app.use(markdown(config.markdown));
208
-
209
+ // rate limits have to be loaded before all routes so it is applied to them
210
+ if (config.rateLimits.requests.active) {
211
+ app.use(hofMiddleware.rateLimiter(config, 'requests'));
212
+ }
213
+
209
214
  // Set up routing so <YOUR-SITE-URL>/assets are served from /node_modules/govuk-frontend/govuk/assets
210
- app.use('/assets', express.static(path.join(__dirname, '/node_modules/govuk-frontend/govuk/assets')))
215
+ app.use('/assets', express.static(path.join(__dirname, '/node_modules/govuk-frontend/govuk/assets')));
211
216
 
212
217
  if (config.getAccessibility === true) {
213
218
  deprecate(
package/lib/router.js CHANGED
@@ -19,7 +19,8 @@ function getWizardConfig(config) {
19
19
  const wizardConfig = {
20
20
  name: config.route.name || (config.route.baseUrl || '').replace('/', ''),
21
21
  protocol: config.protocol,
22
- env: config.env
22
+ env: config.env,
23
+ sanitiseInputs: config.sanitiseInputs
23
24
  };
24
25
 
25
26
  if (config.appConfig) {