hof 21.0.0-instrumentation-beta.0 → 21.0.2-axios-beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. package/.github/workflows/automate-publish.yml +1 -1
  2. package/.github/workflows/automate-tag.yml +4 -4
  3. package/.nyc_output/4fc007c9-d6c8-4614-89ce-04c7d6ce9fe5.json +1 -0
  4. package/.nyc_output/processinfo/4fc007c9-d6c8-4614-89ce-04c7d6ce9fe5.json +1 -0
  5. package/.nyc_output/processinfo/index.json +1 -1
  6. package/README.md +340 -256
  7. package/build/tasks/sass/index.js +3 -1
  8. package/build/tasks/watch/index.js +1 -1
  9. package/components/combine-and-loop-fields/Readme.md +42 -0
  10. package/components/combine-and-loop-fields/index.js +156 -0
  11. package/components/date/index.js +3 -1
  12. package/components/date/templates/date.html +15 -12
  13. package/components/homeoffice-countries/index.js +22 -0
  14. package/components/index.js +2 -0
  15. package/components/notify/notify.js +2 -2
  16. package/components/summary/index.js +3 -2
  17. package/config/builder-defaults.js +3 -1
  18. package/config/component-defaults.js +13 -0
  19. package/controller/controller.js +57 -1
  20. package/controller/formatting/formatters.js +12 -0
  21. package/controller/validation/index.js +2 -1
  22. package/controller/validation/validators.js +4 -0
  23. package/frontend/govuk-template/build/config.js +2 -2
  24. package/frontend/govuk-template/build/govuk_template.html +104 -0
  25. package/frontend/govuk-template/build/index.js +2 -2
  26. package/frontend/govuk-template/index.js +4 -4
  27. package/frontend/template-mixins/mixins/template-mixins.js +39 -11
  28. package/frontend/template-mixins/partials/forms/checkbox-group.html +47 -0
  29. package/frontend/template-mixins/partials/forms/checkbox.html +4 -4
  30. package/frontend/template-mixins/partials/forms/input-submit.html +1 -1
  31. package/frontend/template-mixins/partials/forms/input-text-date.html +37 -0
  32. package/frontend/template-mixins/partials/forms/input-text-group.html +15 -10
  33. package/frontend/template-mixins/partials/forms/option-group.html +42 -26
  34. package/frontend/template-mixins/partials/forms/select.html +10 -5
  35. package/frontend/template-mixins/partials/forms/textarea-group.html +37 -23
  36. package/frontend/template-mixins/partials/mixins/panel.html +3 -4
  37. package/frontend/template-partials/views/accessibility.html +4 -4
  38. package/frontend/template-partials/views/cookies.html +1 -1
  39. package/frontend/template-partials/views/layout.html +24 -17
  40. package/frontend/template-partials/views/partials/back.html +1 -1
  41. package/frontend/template-partials/views/partials/bullet-list.html +1 -1
  42. package/frontend/template-partials/views/partials/confirmation-alert.html +4 -3
  43. package/frontend/template-partials/views/partials/continue.html +1 -1
  44. package/frontend/template-partials/views/partials/cookie-banner.html +27 -24
  45. package/frontend/template-partials/views/partials/cookie-settings-radio.html +6 -6
  46. package/frontend/template-partials/views/partials/external-link.html +1 -1
  47. package/frontend/template-partials/views/partials/form.html +2 -1
  48. package/frontend/template-partials/views/partials/maincontent-left.html +4 -4
  49. package/frontend/template-partials/views/partials/navigation.html +7 -6
  50. package/frontend/template-partials/views/partials/session-cookies-table.html +6 -6
  51. package/frontend/template-partials/views/partials/summary-table-row.html +2 -2
  52. package/frontend/template-partials/views/partials/table.html +7 -7
  53. package/frontend/template-partials/views/partials/validation-list.html +2 -2
  54. package/frontend/template-partials/views/partials/validation-summary.html +14 -13
  55. package/frontend/template-partials/views/partials/warn.html +7 -0
  56. package/frontend/template-partials/views/session-timeout.html +3 -2
  57. package/frontend/themes/gov-uk/client-js/cookieSettings.js +1 -1
  58. package/frontend/themes/gov-uk/client-js/govuk-cookies.js +121 -0
  59. package/frontend/themes/gov-uk/client-js/index.js +6 -1
  60. package/frontend/themes/gov-uk/client-js/skip-to-main.js +19 -0
  61. package/frontend/themes/gov-uk/styles/_cookie-banner.scss +51 -1
  62. package/frontend/themes/gov-uk/styles/govuk.scss +4 -0
  63. package/frontend/themes/gov-uk/styles/modules/_validation.scss +5 -5
  64. package/frontend/toolkit/assets/javascript/character-count.js +4 -4
  65. package/frontend/toolkit/assets/javascript/progressive-reveal.js +3 -1
  66. package/frontend/toolkit/assets/javascript/validation.js +5 -1
  67. package/frontend/toolkit/assets/stylesheets/modules/_validation.scss +3 -3
  68. package/index.js +15 -2
  69. package/lib/ga-tag.js +1 -1
  70. package/lib/settings.js +18 -2
  71. package/middleware/errors.js +2 -3
  72. package/middleware/not-found.js +0 -3
  73. package/middleware/rate-limiter.js +1 -0
  74. package/model/apis/axios-settings.js +9 -0
  75. package/model/apis/html-to-pdf-converter.js +9 -8
  76. package/model/index.js +29 -28
  77. package/package.json +17 -14
  78. package/sandbox/README.md +3 -3
  79. package/sandbox/apps/sandbox/fields.js +33 -11
  80. package/sandbox/apps/sandbox/index.js +4 -0
  81. package/sandbox/apps/sandbox/sections/summary-data-sections.js +3 -0
  82. package/sandbox/apps/sandbox/translations/en/default.json +224 -0
  83. package/sandbox/apps/sandbox/translations/src/en/fields.json +11 -4
  84. package/sandbox/apps/sandbox/translations/src/en/journey.json +4 -1
  85. package/sandbox/apps/sandbox/translations/src/en/pages.json +7 -25
  86. package/sandbox/apps/sandbox/translations/src/en/validation.json +5 -1
  87. package/sandbox/assets/js/index.js +1 -1
  88. package/sandbox/assets/scss/app.scss +16 -16
  89. package/sandbox/package.json +6 -1
  90. package/sandbox/public/css/app.css +2793 -0
  91. package/sandbox/public/images/icons/icon-caret-left.png +0 -0
  92. package/sandbox/public/images/icons/icon-complete.png +0 -0
  93. package/sandbox/public/images/icons/icon-cross-remove-sign.png +0 -0
  94. package/sandbox/public/js/bundle.js +32888 -0
  95. package/sandbox/server.js +2 -1
  96. package/sandbox/yarn.lock +243 -1
  97. package/wizard/index.js +0 -13
  98. package/wizard/middleware/check-progress.js +36 -1
  99. package/.nyc_output/4d5a4574-78fc-4fcb-9412-3658f6ce33ff.json +0 -1
  100. package/.nyc_output/processinfo/4d5a4574-78fc-4fcb-9412-3658f6ce33ff.json +0 -1
  101. package/frontend/govuk-template/govuk_template.html +0 -109
  102. package/frontend/themes/gov-uk/views/partials/form.html +0 -9
  103. package/frontend/themes/gov-uk/views/partials/forms/option-group.html +0 -28
  104. package/frontend/themes/gov-uk/views/partials/mixins/panel.html +0 -3
  105. package/frontend/themes/gov-uk/views/partials/validation-summary.html +0 -24
  106. package/middleware/monitor.js +0 -20
  107. package/sandbox/apps/sandbox/views/confirmation.html +0 -15
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # HOF (Home Office Forms)
2
+
2
3
  [![NPM_Publish Actions Status](https://github.com/UKHomeOfficeForms/hof/workflows/Automate_Publish/badge.svg)](https://github.com/UKHomeOfficeForms/hof/actions)
3
4
  [![npm version](https://badge.fury.io/js/hof.svg)](https://badge.fury.io/js/hof)
4
5
  [![Known Vulnerabilities](https://snyk.io/test/npm/hof/badge.svg)](https://snyk.io/test/npm/hof)
@@ -6,6 +7,7 @@
6
7
  HOF (Home Office Forms) is a framework designed to assist developers in creating form-based workflows in a rapid, repeatable and secure way. It aims to reduce simple applications as much as possible to being configuration-only.
7
8
 
8
9
  ## Server Settings
10
+
9
11
  In your `hof.settings.json` file you can add `getTerms: false` and `getCookies: false` to turn off the default cookies, and terms and conditions information provided by the HOF framework. This is if you want to provide more specific material at the service level in regards to these subject matter otherwise the defaults should suffice.
10
12
 
11
13
  Also you can set `getAccessibility: true` to get the default accessibility document for this framework if one is not provided at the service level. It is assumed there should have been an accessibility audit carried out for a service already hence why the default setting for this is set to `false`. But if a generic placeholder is needed to ensure the service is legally compliant then this can be set to `true` to provide the default one presented within the framework.
@@ -17,9 +19,11 @@ Also you can set `getAccessibility: true` to get the default accessibility docum
17
19
  [https://ukhomeofficeforms.github.io/hof-guide/](https://ukhomeofficeforms.github.io/hof-guide/)
18
20
 
19
21
  ## Content Security Policy
22
+
20
23
  ### Inline JavaScript from 18.0.0
24
+
21
25
  From version 18.0.0, unsafe-inline has been removed from the content security policy by default. This means scripts
22
- must either be referenced using the src attribute, ```<script src='...'></script>``` or with a nonce value attribute. A nonce
26
+ must either be referenced using the src attribute, `<script src='...'></script>` or with a nonce value attribute. A nonce
23
27
  value is generated for every request. You can add this to your own templates' inline scripts as needed:
24
28
 
25
29
  ```
@@ -29,15 +33,17 @@ value is generated for every request. You can add this to your own templates' in
29
33
  ```
30
34
 
31
35
  ### Built with HOF
32
- * https://github.com/UKHomeOffice/gro
33
- * https://github.com/UKHomeOffice/end-tenancy
34
- * [Firearms Licensing (Home Office)](https://github.com/UKHomeOffice/firearms)
35
- * [Contact UK Trade & Investment (UK Trade & Investment)](https://github.com/UKTradeInvestment/contact-ukti)
36
- * [Biometric Residence Permit (Home Office)](https://github.com/UKHomeOffice/brp_app)
37
- * [Report terrorist material (Home Office)](https://github.com/UKHomeOffice/rotm)
38
- * [UKVI Complaints (Home Office)](https://github.com/UKHomeOffice/Complaints)
36
+
37
+ - https://github.com/UKHomeOffice/gro
38
+ - https://github.com/UKHomeOffice/end-tenancy
39
+ - [Firearms Licensing (Home Office)](https://github.com/UKHomeOffice/firearms)
40
+ - [Contact UK Trade & Investment (UK Trade & Investment)](https://github.com/UKTradeInvestment/contact-ukti)
41
+ - [Biometric Residence Permit (Home Office)](https://github.com/UKHomeOffice/brp_app)
42
+ - [Report terrorist material (Home Office)](https://github.com/UKHomeOffice/rotm)
43
+ - [UKVI Complaints (Home Office)](https://github.com/UKHomeOffice/Complaints)
39
44
 
40
45
  ## HOF BUILD
46
+
41
47
  Performs build workflow for hof apps in prod and development
42
48
 
43
49
  ## Usage
@@ -54,10 +60,14 @@ It is recommended to alias `hof-build` to an npm script in your package.json.
54
60
 
55
61
  ## Tasks
56
62
 
57
- * `browserify` - compiles client-side js with browserify
58
- * `sass` - compiles sass
59
- * `images` - copies images from ./assets/images directory to ./public/images
60
- * `translate` - compiles translation files
63
+ - `browserify` - compiles client-side js with browserify
64
+ - `sass` - compiles sass
65
+ - `images` - copies images from ./assets/images directory to ./public/images
66
+ - `translate` - compiles translation files
67
+
68
+ Note: For SASS compilation it's possible to additionally configure the following options via the hof.settings file (see the configuration section below)
69
+ - `outputStyle` - Controls whether the CSS output is compressed or not, expanded (default) = non compressed and compressed = compressed CSS output.
70
+ - `quietDeps` - This controls whether you get deprecation warning shown in the console output, if set to false (default) SASS deprecation warnings will be shown in the console, if set to true then deprecation warnings will not be shown in the console output.
61
71
 
62
72
  ## Watch
63
73
 
@@ -98,7 +108,7 @@ Any task can be disabled by setting its configuration to `false` (or any falsy v
98
108
 
99
109
  ```js
100
110
  module.exports = {
101
- browserify: false
111
+ browserify: false,
102
112
  };
103
113
  ```
104
114
 
@@ -106,15 +116,15 @@ module.exports = {
106
116
 
107
117
  Each task has a common configuration format with the following options:
108
118
 
109
- * `src` - defines the input file or files for the build task
110
- * `out` - defines the output location of the built code where relevant
111
- * `match` - defines the pattern for files to watch to trigger a rebuild of this task
112
- * `restart` - defines if this task should result in a server restart
119
+ - `src` - defines the input file or files for the build task
120
+ - `out` - defines the output location of the built code where relevant
121
+ - `match` - defines the pattern for files to watch to trigger a rebuild of this task
122
+ - `restart` - defines if this task should result in a server restart
113
123
 
114
124
  Additionally the server instance created by `watch` can be configured by setting `server` config. Available options are:
115
125
 
116
- * `cmd` - defines the command used to start the server
117
- * `extensions` - defines the file extensions which will be watched to trigger a restart
126
+ - `cmd` - defines the command used to start the server
127
+ - `extensions` - defines the file extensions which will be watched to trigger a restart
118
128
 
119
129
  ### Shared Translations
120
130
 
@@ -123,6 +133,7 @@ By default translations put in the commons directory in a HOF project, i.e. `app
123
133
  To override this behaviour you can add the following to your `hof.settings.json` file or to the settings possible to hof on your server.js file
124
134
 
125
135
  Hof.settings.json example
136
+
126
137
  ```
127
138
  "build": {
128
139
  "translate": {
@@ -132,6 +143,7 @@ Hof.settings.json example
132
143
  ```
133
144
 
134
145
  server.js example
146
+
135
147
  ```
136
148
  const hof = require('hof');
137
149
  const settings = { ...behaviours, ...routes };
@@ -155,9 +167,10 @@ hof-transpiler [source dir|glob] {OPTIONS}
155
167
 
156
168
  ## Example
157
169
 
158
- Lets say you have a directory such as: ```translations/src/en```
170
+ Lets say you have a directory such as: `translations/src/en`
159
171
 
160
172
  Which contains:
173
+
161
174
  ```
162
175
  buttons.json
163
176
  emails.json
@@ -165,9 +178,9 @@ errors.json
165
178
  validation.json
166
179
  ```
167
180
 
168
- If you run hof-transpiler against the directory ```hof-transpiler ./translations/src```
181
+ If you run hof-transpiler against the directory `hof-transpiler ./translations/src`
169
182
 
170
- It will iterate through src and for each directory it will create a new directory at the root level with a built default.json file ```translations/en/default.json```
183
+ It will iterate through src and for each directory it will create a new directory at the root level with a built default.json file `translations/en/default.json`
171
184
 
172
185
  Which will look something like
173
186
 
@@ -192,26 +205,30 @@ This is used further down the hof stack for application translations.
192
205
 
193
206
  ## Advanced example - duplicate keys between source folder and shared folder
194
207
 
195
- Lets say you have a directory such as: ```translations/src/en```
208
+ Lets say you have a directory such as: `translations/src/en`
196
209
 
197
210
  Which contains:
198
211
  buttons.json containing:
212
+
199
213
  ```json
200
214
  {
201
215
  "unusual-button": "Moo"
202
216
  }
203
217
  ```
218
+
204
219
  emails.json containing:
220
+
205
221
  ```json
206
222
  {
207
223
  "customer-email": "Hi how are you?"
208
224
  }
209
225
  ```
210
226
 
211
- And you also have a directory of shared translations such as: ```shared-translations/src/en```
227
+ And you also have a directory of shared translations such as: `shared-translations/src/en`
212
228
 
213
229
  Which contains:
214
230
  buttons.json containing:
231
+
215
232
  ```json
216
233
  {
217
234
  "common-button": "Click me"
@@ -219,11 +236,13 @@ buttons.json containing:
219
236
  ```
220
237
 
221
238
  If you then run:
239
+
222
240
  ```bash
223
241
  hof-transpiler translations/src --shared shared-translations/src
224
242
  ```
225
243
 
226
244
  Then transpiled translations should appear in translations/en/default.json as follows:
245
+
227
246
  ```json
228
247
  {
229
248
  "buttons": {
@@ -245,6 +264,7 @@ hof-transpiler supports multiple shared sources, extending them from left to rig
245
264
  If you have the following sources:
246
265
 
247
266
  node_modules/hof-template-partials/translations/src/en/buttons.json
267
+
248
268
  ```json
249
269
  {
250
270
  "continue": "Continue",
@@ -255,6 +275,7 @@ node_modules/hof-template-partials/translations/src/en/buttons.json
255
275
  ```
256
276
 
257
277
  common/translations/src/en/buttons.json
278
+
258
279
  ```json
259
280
  {
260
281
  "skip": "Skip this step",
@@ -263,6 +284,7 @@ common/translations/src/en/buttons.json
263
284
  ```
264
285
 
265
286
  my-application/translations/src/en/buttons.json
287
+
266
288
  ```json
267
289
  {
268
290
  "continue": "Go Forth!"
@@ -270,11 +292,13 @@ my-application/translations/src/en/buttons.json
270
292
  ```
271
293
 
272
294
  If you then run:
295
+
273
296
  ```bash
274
297
  hof-transpiler my-application/translations/src --shared node_modules/hof-template-partials/translations/src --shared common/translations/src
275
298
  ```
276
299
 
277
300
  my-application/translations/en/default.json
301
+
278
302
  ```json
279
303
  {
280
304
  "buttons": {
@@ -286,6 +310,7 @@ my-application/translations/en/default.json
286
310
  }
287
311
  }
288
312
  ```
313
+
289
314
  #HOF Controller
290
315
 
291
316
  Implements a request pipeline for GET and POST of forms, with input cleaning/formatting and validation.
@@ -295,18 +320,18 @@ Implements a request pipeline for GET and POST of forms, with input cleaning/for
295
320
  Basic usage:
296
321
 
297
322
  ```javascript
298
- var Form = require('./controller');
323
+ var Form = require("./controller");
299
324
 
300
325
  var form = new Form({
301
- template: 'form',
302
- fields: {
303
- name: {
304
- validate: 'required'
305
- }
306
- }
326
+ template: "form",
327
+ fields: {
328
+ name: {
329
+ validate: "required",
330
+ },
331
+ },
307
332
  });
308
333
 
309
- app.use('/', form.requestHandler());
334
+ app.use("/", form.requestHandler());
310
335
  ```
311
336
 
312
337
  This won't really be very useful though, since all it will do is render the "form" template on `/` and respond to GET and POST requests.
@@ -328,16 +353,16 @@ module.exports = MyForm;
328
353
 
329
354
  The Form class allows for a number of insertion points for extended functionality:
330
355
 
331
- * `configure` Allows for dynamic overwriting of particular points of form configuration based on user session
332
- * `process` Allows for custom formatting and processing of input prior to validation
333
- * `validate` Allows for custom input validation
334
- * `getValues` To define what values the fields are populated with on GET
335
- * `saveValues` To define what is done with successful form submissions
356
+ - `configure` Allows for dynamic overwriting of particular points of form configuration based on user session
357
+ - `process` Allows for custom formatting and processing of input prior to validation
358
+ - `validate` Allows for custom input validation
359
+ - `getValues` To define what values the fields are populated with on GET
360
+ - `saveValues` To define what is done with successful form submissions
336
361
 
337
362
  All of these methods take three arguments of the request, the response and a callback. In all cases the callback should be called with a first argument representing an error.
338
363
 
339
- * `getErrors/setErrors` Define how errors are persisted between the POST and subsequent GET of a form step.
340
- * `locals` Define what additional variables a controller exposes to its template
364
+ - `getErrors/setErrors` Define how errors are persisted between the POST and subsequent GET of a form step.
365
+ - `locals` Define what additional variables a controller exposes to its template
341
366
 
342
367
  These methods are synchronous and take only the request and response obejct as arguments.
343
368
 
@@ -352,6 +377,7 @@ By default the application of a validator is optional on empty strings. If you n
352
377
  Custom validator functions can be passed in field config. These must be named functions and the name is used as the error.type for looking up validation error messages.
353
378
 
354
379
  fields.js
380
+
355
381
  ```js
356
382
  {
357
383
  'field-1': {
@@ -435,9 +461,10 @@ For example, for a dynamic address selection component:
435
461
 
436
462
  ```js
437
463
  MyForm.prototype.configure = function configure(req, res, next) {
438
- req.form.options.fields['address-select'].options = req.sessionModel.get('addresses');
439
- next();
440
- }
464
+ req.form.options.fields["address-select"].options =
465
+ req.sessionModel.get("addresses");
466
+ next();
467
+ };
441
468
  ```
442
469
 
443
470
  ### The FormError class
@@ -445,15 +472,14 @@ MyForm.prototype.configure = function configure(req, res, next) {
445
472
  FormError can be used as a façade to normalise different types of error one may receive / trigger, and to be subsequently returned from a controller.
446
473
  Its constructor takes a series of options. `title` and `message` have both getters and public methods to define default values.
447
474
 
448
-
449
475
  ```js
450
-
451
476
  let error = new ErrorClass(this.missingDoB, {
452
- key: this.missingDob,
453
- type: 'required',
454
- redirect: '/missingData',
455
- title: 'Something went wrong',
456
- message: 'Please supply a valid date of birth'});
477
+ key: this.missingDob,
478
+ type: "required",
479
+ redirect: "/missingData",
480
+ title: "Something went wrong",
481
+ message: "Please supply a valid date of birth",
482
+ });
457
483
  ```
458
484
 
459
485
  ##hof-behaviour-session
@@ -473,6 +499,7 @@ class MyController extends mix(BaseController).with(Session) {
473
499
  ...
474
500
  }
475
501
  ```
502
+
476
503
  `MyController` now extends `hof-form-controller` and has `hof-behaviour-session` functionality mixed in.
477
504
 
478
505
  ##Functionality
@@ -481,14 +508,13 @@ This mixin extends `hof-form-controller` by persisting the form data to the `ses
481
508
 
482
509
  The following form controller methods are used:
483
510
 
484
- * `getValues(req, res, cb)` - calls callback with `null` and a map of all items in the `sessionModel`, extended with `errorValues` - to persist entered values on current step if validation fails
485
- * `saveValues(req, res, cb)` - Called on success. Sets all step fields in `req.form.values` to the sessionModel, unsets `errorValues`.
486
- * `getErrors(req)` - returns all errors for fields on the current step (`req.form.options.fields`), excluding redirects. Set to `req.form.errors` in `hof-form-controller`.
487
- * `setErrors(err, req)` - called on validation error(s). Sets the current step field values as `errorValues` in sessionModel to be used in `getValues`. Sets `errors` to sessionModel - a map of `field-name: error` to be used in `getErrors`.
488
- * `locals(req, res)` - Extends the result of `super.locals` with `baseUrl` (`req.baseUrl`) and `nextPage` (the result of `this.getNextStep(req, res)`).
489
- * `missingPrereqHandler(req, res)` - Error handler called when a `MISSING_PREREQ` error is thrown from the [check-progress](https://github.com/UKHomeOfficeForms/hof-form-wizard/blob/master/lib/middleware/check-progress.js) middleware. This occurs if a step is visited out of sequence. This error handler causes the user to be redirected to the last completed step, or the first step if none have been completed.
490
- * `errorHandler(err, req, res, next)` - checks if `err.code` is `MISSING_PREREQ`, if so calls `missingPrereqHandler`, if not calls `super` to hand over to parent error handler.
491
-
511
+ - `getValues(req, res, cb)` - calls callback with `null` and a map of all items in the `sessionModel`, extended with `errorValues` - to persist entered values on current step if validation fails
512
+ - `saveValues(req, res, cb)` - Called on success. Sets all step fields in `req.form.values` to the sessionModel, unsets `errorValues`.
513
+ - `getErrors(req)` - returns all errors for fields on the current step (`req.form.options.fields`), excluding redirects. Set to `req.form.errors` in `hof-form-controller`.
514
+ - `setErrors(err, req)` - called on validation error(s). Sets the current step field values as `errorValues` in sessionModel to be used in `getValues`. Sets `errors` to sessionModel - a map of `field-name: error` to be used in `getErrors`.
515
+ - `locals(req, res)` - Extends the result of `super.locals` with `baseUrl` (`req.baseUrl`) and `nextPage` (the result of `this.getNextStep(req, res)`).
516
+ - `missingPrereqHandler(req, res)` - Error handler called when a `MISSING_PREREQ` error is thrown from the [check-progress](https://github.com/UKHomeOfficeForms/hof-form-wizard/blob/master/lib/middleware/check-progress.js) middleware. This occurs if a step is visited out of sequence. This error handler causes the user to be redirected to the last completed step, or the first step if none have been completed.
517
+ - `errorHandler(err, req, res, next)` - checks if `err.code` is `MISSING_PREREQ`, if so calls `missingPrereqHandler`, if not calls `super` to hand over to parent error handler.
492
518
 
493
519
  ##behaviour-hooks
494
520
 
@@ -507,6 +533,7 @@ class MyController extends mix(BaseController).with(Hooks) {
507
533
  ...
508
534
  }
509
535
  ```
536
+
510
537
  `MyController` now extends `hof-form-controller` and has `hof-behaviour-hooks` functionality mixed in.
511
538
 
512
539
  ##Functionality
@@ -514,46 +541,52 @@ class MyController extends mix(BaseController).with(Hooks) {
514
541
  The following hooks are currently supported, the methods are GET/POST pipeline methods from `hof-form-controller`:
515
542
 
516
543
  ####GET
517
- * `_getErrors` - `'pre-getErrors', 'post-getErrors'`
518
- * `_getValues` - `'pre-getValues', 'post-getValues'`
519
- * `_locals` - `'pre-locals', 'post-locals'`
520
- * `render` - `'pre-render', 'post-render'`
544
+
545
+ - `_getErrors` - `'pre-getErrors', 'post-getErrors'`
546
+ - `_getValues` - `'pre-getValues', 'post-getValues'`
547
+ - `_locals` - `'pre-locals', 'post-locals'`
548
+ - `render` - `'pre-render', 'post-render'`
521
549
 
522
550
  ####POST
523
- * `_process` - `'pre-process', 'post-process'`
524
- * `_validate` - `'pre-validate', 'post-validate'`
525
- * `saveValues` - `'pre-saveValues', 'post-saveValues'`
526
- * `successHandler` - `'pre-successHandler', 'post-successHandler'`
551
+
552
+ - `_process` - `'pre-process', 'post-process'`
553
+ - `_validate` - `'pre-validate', 'post-validate'`
554
+ - `saveValues` - `'pre-saveValues', 'post-saveValues'`
555
+ - `successHandler` - `'pre-successHandler', 'post-successHandler'`
527
556
 
528
557
  ###In field config
529
558
 
530
559
  fields.js
560
+
531
561
  ```js
532
562
  module.exports = {
533
- 'field-1': {
563
+ "field-1": {
534
564
  hooks: {
535
- 'post-locals': (req, res, next) => {
565
+ "post-locals": (req, res, next) => {
536
566
  Object.assign(res.locals, {
537
- foo: 'bar'
567
+ foo: "bar",
538
568
  });
539
569
  next();
540
570
  },
541
- 'pre-process': (req, res, next) => {
542
- req.body['field-1'] = req.body['field-1'].toUpperCase();
571
+ "pre-process": (req, res, next) => {
572
+ req.body["field-1"] = req.body["field-1"].toUpperCase();
543
573
  next();
544
- }
545
- }
546
- }
547
- }
574
+ },
575
+ },
576
+ },
577
+ };
548
578
  ```
549
579
 
550
580
  # HOF Model
581
+
551
582
  Simple model for interacting with http/rest apis.
552
583
 
553
584
  ## Usage
585
+
554
586
  ```javascript
555
- const Model = require('./model');
587
+ const Model = require("./model");
556
588
  ```
589
+
557
590
  ## Data Storage
558
591
 
559
592
  Models can be used as basic data storage with set/get and change events.
@@ -566,10 +599,10 @@ Save a property to a model. Properties can be passed as a separate key/value arg
566
599
 
567
600
  ```javascript
568
601
  const model = new Model();
569
- model.set('key', 'value');
602
+ model.set("key", "value");
570
603
  model.set({
571
- firstname: 'John',
572
- lastname: 'Smith'
604
+ firstname: "John",
605
+ lastname: "Smith",
573
606
  });
574
607
  ```
575
608
 
@@ -578,7 +611,7 @@ model.set({
578
611
  Retrieve a property from a model:
579
612
 
580
613
  ```javascript
581
- const val = model.get('key');
614
+ const val = model.get("key");
582
615
  // val = 'value'
583
616
  ```
584
617
 
@@ -597,7 +630,7 @@ const json = model.toJSON();
597
630
 
598
631
  ```javascript
599
632
  const model = new Model();
600
- model.on('change', (changedFields) => {
633
+ model.on("change", (changedFields) => {
601
634
  // changedFields contains a map of the key/value pairs which have changed
602
635
  console.log(changedFields);
603
636
  });
@@ -607,10 +640,10 @@ model.on('change', (changedFields) => {
607
640
 
608
641
  ```javascript
609
642
  const model = new Model();
610
- model.on('change:name', (newValue, oldValue) => {
643
+ model.on("change:name", (newValue, oldValue) => {
611
644
  // handler is passed the new value and the old value as arguents
612
645
  });
613
- model.set('name', 'John Smith');
646
+ model.set("name", "John Smith");
614
647
  ```
615
648
 
616
649
  ### Referenced Fields
@@ -619,12 +652,12 @@ A field can be set to a reference to another field by setting it a value of `$re
619
652
 
620
653
  ```javascript
621
654
  const model = new Model();
622
- model.set('home-address', '1 Main Street');
623
- model.set('contact-address', '$ref:home-address');
655
+ model.set("home-address", "1 Main Street");
656
+ model.set("contact-address", "$ref:home-address");
624
657
 
625
- model.get('contact-address'); // => '1 Main Street';
626
- model.set('home-address', '2 Main Street');
627
- model.get('contact-address'); // => '2 Main Street';
658
+ model.get("contact-address"); // => '1 Main Street';
659
+ model.set("home-address", "2 Main Street");
660
+ model.get("contact-address"); // => '2 Main Street';
628
661
 
629
662
  model.toJSON(); // => { home-address: '2 Main Street', 'contact-address': '2 Main Street' }
630
663
  ```
@@ -633,26 +666,26 @@ Change events will be fired on the referenced field if the underlying value chan
633
666
 
634
667
  ```javascript
635
668
  const model = new Model();
636
- model.set('home-address', '1 Main Street');
637
- model.set('contact-address', '$ref:home-address');
638
- model.on('change:contact-address', (value, oldValue) => {
669
+ model.set("home-address", "1 Main Street");
670
+ model.set("contact-address", "$ref:home-address");
671
+ model.on("change:contact-address", (value, oldValue) => {
639
672
  // this is fired when home-address property changes
640
673
  });
641
674
 
642
- model.set('home-address', '2 Main Street');
675
+ model.set("home-address", "2 Main Street");
643
676
  ```
644
677
 
645
678
  A field can be unreferenced by setting its value to any other value.
646
679
 
647
680
  ```javascript
648
681
  const model = new Model();
649
- model.set('home-address', '1 Main Street');
682
+ model.set("home-address", "1 Main Street");
650
683
 
651
684
  // reference the field
652
- model.set('contact-address', '$ref:home-address');
685
+ model.set("contact-address", "$ref:home-address");
653
686
 
654
687
  // unreference the field
655
- model.set('contact-address', '1 Other Road');
688
+ model.set("contact-address", "1 Other Road");
656
689
  ```
657
690
 
658
691
  ## API Client
@@ -669,7 +702,7 @@ There are three methods for API interaction corresponding to GET, POST, and DELE
669
702
 
670
703
  ```javascript
671
704
  const model = new Model();
672
- model.fetch().then(data => {
705
+ model.fetch().then((data) => {
673
706
  console.log(data);
674
707
  });
675
708
  ```
@@ -679,9 +712,9 @@ model.fetch().then(data => {
679
712
  ```javascript
680
713
  const model = new Model();
681
714
  model.set({
682
- property: 'properties are sent as JSON request body by default'
715
+ property: "properties are sent as JSON request body by default",
683
716
  });
684
- model.save().then(data => {
717
+ model.save().then((data) => {
685
718
  console.log(data);
686
719
  });
687
720
  ```
@@ -691,9 +724,9 @@ The method can also be overwritten by passing options
691
724
  ```javascript
692
725
  const model = new Model();
693
726
  model.set({
694
- property: 'this will be sent as a PUT request'
727
+ property: "this will be sent as a PUT request",
695
728
  });
696
- model.save({ method: 'PUT' }).then(data => {
729
+ model.save({ method: "PUT" }).then((data) => {
697
730
  console.log(data);
698
731
  });
699
732
  ```
@@ -702,7 +735,7 @@ model.save({ method: 'PUT' }).then(data => {
702
735
 
703
736
  ```javascript
704
737
  const model = new Model();
705
- model.delete().then(data => {
738
+ model.delete().then((data) => {
706
739
  console.log(data);
707
740
  });
708
741
  ```
@@ -715,14 +748,16 @@ If no `url` method is defined then the model will use the options parameter and
715
748
  const model = new Model();
716
749
 
717
750
  // make a GET request to http://example.com:3000/foo/bar
718
- model.fetch({
719
- protocol: 'http',
720
- hostname: 'example.com',
721
- port: 3000,
722
- path: '/foo/bar'
723
- }).then(data => {
724
- console.log(data);
725
- });
751
+ model
752
+ .fetch({
753
+ protocol: "http",
754
+ hostname: "example.com",
755
+ port: 3000,
756
+ path: "/foo/bar",
757
+ })
758
+ .then((data) => {
759
+ console.log(data);
760
+ });
726
761
  ```
727
762
 
728
763
  ### Events
@@ -730,29 +765,36 @@ model.fetch({
730
765
  API requests will emit events as part of their lifecycle.
731
766
 
732
767
  `sync` is emitted when an API request is sent
768
+
733
769
  ```javascript
734
- model.on('sync', function (settings) { });
770
+ model.on("sync", function (settings) {});
735
771
  ```
736
772
 
737
773
  `success` is emitted when an API request successfully completes
774
+
738
775
  ```javascript
739
- model.on('success', function (data, settings, statusCode, responseTime) { });
776
+ model.on("success", function (data, settings, statusCode, responseTime) {});
740
777
  ```
741
778
 
742
779
  `fail` is emitted when an API request fails
780
+
743
781
  ```javascript
744
- model.on('fail', function (err, data, settings, statusCode, responseTime) { });
782
+ model.on("fail", function (err, data, settings, statusCode, responseTime) {});
745
783
  ```
746
784
 
747
785
  ### HOF Model APIs
786
+
748
787
  - `Html-To-Pdf Converter`: This extends the HOF model to interact with the html-to-pdf converter API https://github.com/UKHomeOffice/html-pdf-converter. The environmental variable `PDF_CONVERTER_URL` needs to be set to its local url when running in the same kube namespace to the service that wants to use it. This is then followed by the default port `10443` and then the URI for which part of the service you want to consume. For example:`https://html-pdf-converter:10443/convert` when the container is named `html-pdf-converter` in your kube deployment file. This has to be set to `https` for communication between services to work on ACP. However, `settings.rejectUnauthorized = false;` is set in the model to circumvent expired certificates due to this. This is preferable to using:
788
+
749
789
  ```
750
790
  name: NODE_TLS_REJECT_UNAUTHORIZED
751
791
  value: "0"
752
792
  ```
793
+
753
794
  which should NOT be used as it sets ignoring TLS at a global level which could present a MITM (Man-In-The-Middle) attack.
754
795
 
755
796
  Usage: Example below, as per the converter docs (link above) it accepts html and responds with Buffered data in pdf format which can then be either written to a file or attached to a Gov Notify message:
797
+
756
798
  ```
757
799
  const PDFModel = require('hof').apis.pdfConverter;
758
800
 
@@ -762,6 +804,7 @@ const pdfData = await pdfModel.save();
762
804
  ```
763
805
 
764
806
  # HOF Middleware
807
+
765
808
  A collection of commonly used HOF middleware, exports `cookies`, `notFound`, and `errors` on `middleware`
766
809
 
767
810
  ## Arranging the middleware in your app
@@ -772,16 +815,20 @@ The Not Found middleware should be placed after all routes and before the Error
772
815
  ## Cookies
773
816
 
774
817
  ### Usage
818
+
775
819
  ```js
776
- app.use(require('hof').middleware.cookies({
777
- 'cookie-name': 'my-application-cookie',
778
- 'param-name': 'my-query-param'
779
- }));
820
+ app.use(
821
+ require("hof").middleware.cookies({
822
+ "cookie-name": "my-application-cookie",
823
+ "param-name": "my-query-param",
824
+ })
825
+ );
780
826
  ```
781
827
 
782
828
  This middleware must be declared before your other routes.
783
829
 
784
830
  ### Options
831
+
785
832
  The `cookie-name` can be the same as your session cookie. (The
786
833
  middleware will not overwrite it.) Defaults to `hof-cookie-check`.
787
834
 
@@ -802,16 +849,22 @@ Kubernetes healthcheck URLs are provided as defaults if no overrides are supplie
802
849
  Expects there to be a view called 404 in your configured `/views` directory
803
850
 
804
851
  ### Usage
852
+
805
853
  ```js
806
- app.use(require('hof').middleware.notFound({
807
- logger: require('/logger'),
808
- translate: require('hof').i18n({path: path_to_translations/__lng__/__ns__.json}).translate
809
- }));
854
+ app.use(
855
+ require("hof").middleware.notFound({
856
+ logger: require("/logger"),
857
+ translate: require("hof").i18n({
858
+ path: path_to_translations / __lng__ / __ns__.json,
859
+ }).translate,
860
+ })
861
+ );
810
862
  ```
811
863
 
812
- This middleware should be declared *after* your other routes but *before* your errorhandler.
864
+ This middleware should be declared _after_ your other routes but _before_ your errorhandler.
813
865
 
814
866
  ### Options
867
+
815
868
  `logger` can be any object with a warn method.
816
869
 
817
870
  `translate` can be the HOF i18n translate function
@@ -819,42 +872,51 @@ This middleware should be declared *after* your other routes but *before* your e
819
872
  ## Errors
820
873
 
821
874
  ### Usage
875
+
822
876
  ```js
823
- app.use(require('hof').middleware.errors({
824
- logger: require('/logger'),
825
- translate: require('hof').i18n({path: path_to_translations/__lng__/__ns__.json}).translate,
826
- debug: true
827
- }));
877
+ app.use(
878
+ require("hof").middleware.errors({
879
+ logger: require("/logger"),
880
+ translate: require("hof").i18n({
881
+ path: path_to_translations / __lng__ / __ns__.json,
882
+ }).translate,
883
+ debug: true,
884
+ })
885
+ );
828
886
  ```
829
887
 
830
- This middleware must be declared *after* your other routes.
888
+ This middleware must be declared _after_ your other routes.
831
889
 
832
890
  ### Options
891
+
833
892
  `logger` can be any object with an error method.
834
893
 
835
894
  `translate` can be the HOF i18n translate function
836
895
 
837
896
  `debug` set to true will present the stack trace in the form and return the err as the content of the template.
838
897
 
839
- __Note__ If `debug === true` translations will not be served, but the error handler default messages
840
- =======
898
+ # **Note** If `debug === true` translations will not be served, but the error handler default messages
899
+
841
900
  ## Deep translate
842
901
 
843
- deepTranslate middleware supports nested conditional translations in order to show different content in different scenarios. The middleware adds a `translate` function to `req` which is used in various points throughout the architecture. This middleware must be applied before any other middleware which rely on the `req.translate` function. Also when initializing the form wizard, or template mixins, if a `translate` function is provided, this will be used rather than the deepTranslate middleware.
902
+ deepTranslate middleware supports nested conditional translations in order to show different content in different scenarios. The middleware adds a `translate` function to `req` which is used in various points throughout the architecture. This middleware must be applied before any other middleware which rely on the `req.translate` function. Also when initializing the form wizard, or template mixins, if a `translate` function is provided, this will be used rather than the deepTranslate middleware.
844
903
 
845
904
  ### Usage
846
905
 
847
906
  ```js
848
- const i18nFuture = require('hof').i18n;
907
+ const i18nFuture = require("hof").i18n;
849
908
  const i18n = i18nFuture({
850
- path: path.resolve(__dirname, './path/to/translations')
851
- })
852
- app.use(require('hof').middleware.deepTranslate({
853
- translate: i18n.translate.bind(i18n)
854
- }));
909
+ path: path.resolve(__dirname, "./path/to/translations"),
910
+ });
911
+ app.use(
912
+ require("hof").middleware.deepTranslate({
913
+ translate: i18n.translate.bind(i18n),
914
+ })
915
+ );
855
916
  ```
856
917
 
857
918
  locales
919
+
858
920
  ```json
859
921
  "fields": {
860
922
  "field-name": {
@@ -876,10 +938,10 @@ locales
876
938
 
877
939
  Using the translation key `fields.field-name.label` will return different values in different situations depending on the values of named fields. In the above example the following are true:
878
940
 
879
- * If both `dependent-field` and `dependent-field-2` have the value `"value-1"`, the label returned will be `"Label 1"`.
880
- * If the value of `dependent-field` is `"value-1"` and the value of `dependent-field-2` is `"value-2"`, the label returned will be `"Label 2"`.
881
- * If the value of `dependent-field` is `"value-2"` the label returned will be `"Label 3"` regardless of the value of `dependent-field-2`
882
- * The default label `"Fallback label"` will be used if value of `dependent-field` is neither of the given options, or it is `undefined`. It will also be used if the value of `dependent-field` is `"value-1"` and the value of `dependent-field-2` is neither of the given options or it is undefined.
941
+ - If both `dependent-field` and `dependent-field-2` have the value `"value-1"`, the label returned will be `"Label 1"`.
942
+ - If the value of `dependent-field` is `"value-1"` and the value of `dependent-field-2` is `"value-2"`, the label returned will be `"Label 2"`.
943
+ - If the value of `dependent-field` is `"value-2"` the label returned will be `"Label 3"` regardless of the value of `dependent-field-2`
944
+ - The default label `"Fallback label"` will be used if value of `dependent-field` is neither of the given options, or it is `undefined`. It will also be used if the value of `dependent-field` is `"value-1"` and the value of `dependent-field-2` is neither of the given options or it is undefined.
883
945
 
884
946
  # HOF Components
885
947
 
@@ -890,14 +952,15 @@ A component for handling the rendering and processing of 3-input date fields use
890
952
  ## Usage
891
953
 
892
954
  In your fields config:
955
+
893
956
  ```js
894
- const dateComponent = require('hof').components.date;
957
+ const dateComponent = require("hof").components.date;
895
958
 
896
959
  module.exports = {
897
- 'date-field': dateComponent('date-field', {
898
- validate: ['required', 'before']
899
- })
900
- }
960
+ "date-field": dateComponent("date-field", {
961
+ validate: ["required", "before"],
962
+ }),
963
+ };
901
964
  ```
902
965
 
903
966
  The above example will create a new date component with the key `'date-field'` and will apply the validators `required` and `before` (before today).
@@ -906,16 +969,17 @@ The above example will create a new date component with the key `'date-field'` a
906
969
 
907
970
  The following optional configuration options are supported:
908
971
 
909
- * `validate {String|Array}` - validators to use on the processed date field
910
- * `template` - an absolute path to an alternate template.
911
- * `dayOptional {Boolean}` - day defaults to `01` if omitted. Defaults to `false`
912
- * `monthOptional {Boolean}` - month defaults to `01` if omitted. If true then also forces `dayOptional` to be true. Defaults to `false`
972
+ - `validate {String|Array}` - validators to use on the processed date field
973
+ - `template` - an absolute path to an alternate template.
974
+ - `dayOptional {Boolean}` - day defaults to `01` if omitted. Defaults to `false`
975
+ - `monthOptional {Boolean}` - month defaults to `01` if omitted. If true then also forces `dayOptional` to be true. Defaults to `false`
913
976
 
914
977
  ## Labels
915
978
 
916
979
  The three intermedate fields have fallback labels of Day, Month and Year, however custom labels can be used by including the translation at the following path:
917
980
 
918
981
  fields.json
982
+
919
983
  ```json
920
984
  {
921
985
  "field-name": {
@@ -951,7 +1015,6 @@ If no sections config is passed, then the mixin will create a section for each s
951
1015
  }
952
1016
  ```
953
1017
 
954
-
955
1018
  Alternatively, sections can be defined manually as follows:
956
1019
 
957
1020
  ```js
@@ -990,9 +1053,9 @@ Fields can be defined as simple strings of the field key, in which case all defa
990
1053
 
991
1054
  Alternatively, a field can be passed as an object with a `field` property defining the field key, and any additional properties as follows:
992
1055
 
993
- * `step` - `String` defines the step which the user is returned to to edit the field value. By default this is the first step in the form's steps configuration which contains the field.
994
- * `parse` - `Function` can parse the value for the field from the session into a value for display.
995
- * `derivation` - `Object` allows for a new derived field based on a combination of other fields in the form. Note that
1056
+ - `step` - `String` defines the step which the user is returned to to edit the field value. By default this is the first step in the form's steps configuration which contains the field.
1057
+ - `parse` - `Function` can parse the value for the field from the session into a value for display.
1058
+ - `derivation` - `Object` allows for a new derived field based on a combination of other fields in the form. Note that
996
1059
  if both `derivation` and `parse` are specified then parse will be applied to the result of derivation. E.G.
997
1060
  ```javascript
998
1061
  derivation: {
@@ -1000,10 +1063,11 @@ Alternatively, a field can be passed as an object with a `field` property defini
1000
1063
  combiner: (values) => values.map(it => Number(it)).reduce((a, b) => a + b, 0)
1001
1064
  }
1002
1065
  ```
1003
- * `useOriginalValue` - `Object` uses original value of radio button or checkbox label rather than trying to find a translation in the `fields.json` file. This could be due to options that are generated by user input that can not be predicted in advance, which are subsequently used to populate a value in the summary page. One good example is using one of many addresses inputted by a user that is additionally a contact address. See example below:
1004
- ![Firearms Use Original Value Summary Page Example](docs/images/firearms_use_original_value_summary.png)
1066
+ - `useOriginalValue` - `Object` uses original value of radio button or checkbox label rather than trying to find a translation in the `fields.json` file. This could be due to options that are generated by user input that can not be predicted in advance, which are subsequently used to populate a value in the summary page. One good example is using one of many addresses inputted by a user that is additionally a contact address. See example below:
1067
+ ![Firearms Use Original Value Summary Page Example](docs/images/firearms_use_original_value_summary.png)
1068
+
1069
+ - `multipleRowsFromAggregate` - `Object` if this object exists on a field, it uses the `labelCategory`, `valueCategory` and `valueTranslation` values to populate the row's label and value name but also iterates over multiple rows that have been aggregated under one field name. There is one good reference of this in Firearms where the following example is used:
1005
1070
 
1006
- * `multipleRowsFromAggregate` - `Object` if this object exists on a field, it uses the `labelCategory`, `valueCategory` and `valueTranslation` values to populate the row's label and value name but also iterates over multiple rows that have been aggregated under one field name. There is one good reference of this in Firearms where the following example is used:
1007
1071
  ```javascript
1008
1072
  {
1009
1073
  field: 'location-addresses',
@@ -1016,6 +1080,7 @@ Alternatively, a field can be passed as an object with a `field` property defini
1016
1080
  }
1017
1081
  }
1018
1082
  ```
1083
+
1019
1084
  The `location-addresses` field is one that the application has setup to aggregate and store all addresses labelled with the `address` field. Each address is a storage location for firearms, and so there is a sub-category which lists what firearms type is listed under each address (i.e. Full-bore, small-bore, muzzle-loading), and these are stored under the `address-category` field. Along with translations to them in the `fields.json` file living under the `location-address-category` translation header. By utilising these three values one can achieve the following output on the summary page.
1020
1085
 
1021
1086
  ![Firearms Summary Page Example](docs/images/firearms_summary_page_example.png)
@@ -1030,18 +1095,19 @@ The content for section headings and field labels will be loaded from translatio
1030
1095
 
1031
1096
  Translations for section headings are looked for in the following order:
1032
1097
 
1033
- * `pages.confirm.sections.${key}.header`
1034
- * `pages.${key}.header`
1098
+ - `pages.confirm.sections.${key}.header`
1099
+ - `pages.${key}.header`
1035
1100
 
1036
1101
  ### Field labels
1037
1102
 
1038
1103
  Translations for field labels are looked for in the following order:
1039
1104
 
1040
- * `pages.confirm.fields.${key}.label`
1041
- * `fields.${key}.label`
1042
- * `fields.${key}.legend`
1105
+ - `pages.confirm.fields.${key}.label`
1106
+ - `fields.${key}.label`
1107
+ - `fields.${key}.legend`
1043
1108
 
1044
1109
  # Emailer Component
1110
+
1045
1111
  HOF behaviour to send emails
1046
1112
 
1047
1113
  ## Usage
@@ -1078,10 +1144,10 @@ steps: {
1078
1144
 
1079
1145
  In addition to the options passed to `hof-emailer`, the following options can be used:
1080
1146
 
1081
- * `recipient` - _Required_ - defines the address to which email will be sent. This can be set either as a key to retrieve an email address from the session, or explicitly to an email address.
1082
- * `template` - _Required_ - defines the mustache template used to render the email content.
1083
- * `subject` - defines the subject line of the email.
1084
- * `parse` - parses the session model into an object used to populate the template.
1147
+ - `recipient` - _Required_ - defines the address to which email will be sent. This can be set either as a key to retrieve an email address from the session, or explicitly to an email address.
1148
+ - `template` - _Required_ - defines the mustache template used to render the email content.
1149
+ - `subject` - defines the subject line of the email.
1150
+ - `parse` - parses the session model into an object used to populate the template.
1085
1151
 
1086
1152
  `recipient` and `subject` options can also be defined as functions, which will be passed a copy of the session model and a translation function as arguments, and should return a string value.
1087
1153
 
@@ -1089,7 +1155,7 @@ In addition to the options passed to `hof-emailer`, the following options can be
1089
1155
  // use a translated value for the email subject line
1090
1156
  const emailer = EmailBehaviour({
1091
1157
  // ...
1092
- subject: (model, translate) => translate('email.success.subject')
1158
+ subject: (model, translate) => translate("email.success.subject"),
1093
1159
  });
1094
1160
  ```
1095
1161
 
@@ -1107,24 +1173,23 @@ $ npm install hof-emailer --save
1107
1173
 
1108
1174
  ```js
1109
1175
  // first create an emailer instance
1110
- const Emailer = require('hof').components.email.emailer;
1176
+ const Emailer = require("hof").components.email.emailer;
1111
1177
  const emailer = new Emailer({
1112
- from: 'sender@example.com',
1113
- transport: 'smtp',
1178
+ from: "sender@example.com",
1179
+ transport: "smtp",
1114
1180
  transportOptions: {
1115
- host: 'my.smtp.host',
1116
- port: 25
1117
- }
1181
+ host: "my.smtp.host",
1182
+ port: 25,
1183
+ },
1118
1184
  });
1119
1185
 
1120
1186
  // then you can use your emailer to send emails
1121
- const to = 'recipient@example.com';
1122
- const body = 'This is the email body';
1123
- const subject = 'Important email!'
1124
- emailer.send(to, body, subject)
1125
- .then(() => {
1126
- console.log(`Email sent to ${to}!`);
1127
- });
1187
+ const to = "recipient@example.com";
1188
+ const body = "This is the email body";
1189
+ const subject = "Important email!";
1190
+ emailer.send(to, body, subject).then(() => {
1191
+ console.log(`Email sent to ${to}!`);
1192
+ });
1128
1193
  ```
1129
1194
 
1130
1195
  ## Options
@@ -1152,6 +1217,7 @@ The following transport options are available:
1152
1217
  - `auth.pass` <String>: Mailserver authorisation password.
1153
1218
 
1154
1219
  ### `ses`
1220
+
1155
1221
  [nodemailer-ses-transport](https://github.com/andris9/nodemailer-ses-transport)
1156
1222
 
1157
1223
  #### Options
@@ -1184,6 +1250,7 @@ transportOptions: {
1184
1250
  open: true
1185
1251
  }
1186
1252
  ```
1253
+
1187
1254
  ### `stub`
1188
1255
 
1189
1256
  Disables sending email. No options are required.
@@ -1191,6 +1258,7 @@ Disables sending email. No options are required.
1191
1258
  # UTILITIES
1192
1259
 
1193
1260
  # Autofill Utility
1261
+
1194
1262
  A webdriverio plugin to automate filling a form
1195
1263
 
1196
1264
  ## Usage
@@ -1198,10 +1266,10 @@ A webdriverio plugin to automate filling a form
1198
1266
  First, add the command to your webdriverio client:
1199
1267
 
1200
1268
  ```js
1201
- const webdriver = require('webdriverio');
1269
+ const webdriver = require("webdriverio");
1202
1270
  const client = webdriver.remote(options);
1203
1271
 
1204
- client.addCommand('goto', require('hof-util-autofill')(client));
1272
+ client.addCommand("goto", require("hof-util-autofill")(client));
1205
1273
  ```
1206
1274
 
1207
1275
  The command can be given any name you like, here we've called it `goto`.
@@ -1209,32 +1277,36 @@ The command can be given any name you like, here we've called it `goto`.
1209
1277
  Then you can use the command as normal as part of your webdriver command chain.
1210
1278
 
1211
1279
  ```js
1212
- it('completes a form to a certain step automatically', () => {
1213
- return browser.goto('/confirm')
1280
+ it("completes a form to a certain step automatically", () => {
1281
+ return browser
1282
+ .goto("/confirm")
1214
1283
  .getUrl()
1215
1284
  .then((url) => {
1216
- assert.ok(url.indexOf('/confirm') > -1);
1285
+ assert.ok(url.indexOf("/confirm") > -1);
1217
1286
  });
1218
1287
  });
1219
1288
 
1220
- it('uses any data passed as a second argument to fill out the form', () => {
1221
- const inputs = { 'first-name': 'David', 'last-name': 'Hasselhoff' };
1222
- return browser.goto('/confirm', inputs)
1223
- .$('span.full-name')
1289
+ it("uses any data passed as a second argument to fill out the form", () => {
1290
+ const inputs = { "first-name": "David", "last-name": "Hasselhoff" };
1291
+ return browser
1292
+ .goto("/confirm", inputs)
1293
+ .$("span.full-name")
1224
1294
  .getText()
1225
- .then(name => {
1226
- assert.equal(name, 'David HasselHoff');
1295
+ .then((name) => {
1296
+ assert.equal(name, "David HasselHoff");
1227
1297
  });
1228
1298
  });
1229
1299
 
1230
- it('saves screenshots of errors to specified screenshot location', () => {
1300
+ it("saves screenshots of errors to specified screenshot location", () => {
1231
1301
  const inputs = {};
1232
- return browser.goto('/confirm', inputs, { screenshots: '/path/to/output/dir' });
1302
+ return browser.goto("/confirm", inputs, {
1303
+ screenshots: "/path/to/output/dir",
1304
+ });
1233
1305
  });
1234
1306
 
1235
- it('tries a pre-specified number of times to get past stuck loops', () => {
1307
+ it("tries a pre-specified number of times to get past stuck loops", () => {
1236
1308
  const inputs = {};
1237
- return browser.goto('/confirm', inputs, { maxLoops: 1 });
1309
+ return browser.goto("/confirm", inputs, { maxLoops: 1 });
1238
1310
  });
1239
1311
  ```
1240
1312
 
@@ -1242,10 +1314,11 @@ it('tries a pre-specified number of times to get past stuck loops', () => {
1242
1314
 
1243
1315
  Options are passed as a third argument to the exposed method. The following options are available:
1244
1316
 
1245
- * `maxLoops` - determines how many times a step will retry if it resolves back to itself on submission before failing. Default: `3`
1246
- * `screenshots` - specifies a location to save screenshots of the page when it gets stuck. If not specified then no screenshots are saved.
1317
+ - `maxLoops` - determines how many times a step will retry if it resolves back to itself on submission before failing. Default: `3`
1318
+ - `screenshots` - specifies a location to save screenshots of the page when it gets stuck. If not specified then no screenshots are saved.
1247
1319
 
1248
1320
  # Test-Data Utility
1321
+
1249
1322
  Generator for test fixtures
1250
1323
 
1251
1324
  ## Usage
@@ -1255,7 +1328,7 @@ The library contains a number of generators for values of certain types. Values
1255
1328
  ### Example:
1256
1329
 
1257
1330
  ```js
1258
- const TestData = require('hof').utils.testData;
1331
+ const TestData = require("hof").utils.testData;
1259
1332
 
1260
1333
  console.log(TestData.name);
1261
1334
  // "David Fletcher"
@@ -1266,22 +1339,22 @@ console.log(TestData.name);
1266
1339
 
1267
1340
  ## Available generators
1268
1341
 
1269
- * `firstname`
1270
- * `lastname`
1271
- * `name`
1272
- * `email`
1273
- * `phone`
1274
- * `streetname`
1275
- * `streetsuffix`
1276
- * `address` - `${number(1,100)} ${streetname} ${streetsuffix}`
1277
- * `postcode`
1278
- * `country` - a random country from [homeoffice-countries](npmjs.com/homeoffice-countries)
1342
+ - `firstname`
1343
+ - `lastname`
1344
+ - `name`
1345
+ - `email`
1346
+ - `phone`
1347
+ - `streetname`
1348
+ - `streetsuffix`
1349
+ - `address` - `${number(1,100)} ${streetname} ${streetsuffix}`
1350
+ - `postcode`
1351
+ - `country` - a random country from [homeoffice-countries](npmjs.com/homeoffice-countries)
1279
1352
 
1280
1353
  ## Functions
1281
1354
 
1282
- * `number(min, max)` - returns an integer between `min` and `max`
1283
- * `number(max)` - returns an integer between 0 and `max`
1284
- * `number()` - returns an integer between 0 and 100
1355
+ - `number(min, max)` - returns an integer between `min` and `max`
1356
+ - `number(max)` - returns an integer between 0 and `max`
1357
+ - `number()` - returns an integer between 0 and 100
1285
1358
 
1286
1359
  # Countries Utility
1287
1360
 
@@ -1307,23 +1380,24 @@ In field configuration:
1307
1380
 
1308
1381
  If needed, the following options can be passed into the countries function:
1309
1382
 
1310
- * `filter` - `Function` - applies a filter to the list of country names before mapping them
1311
- * `parse` - `Function` - applies a transform to the country name before setting the label
1383
+ - `filter` - `Function` - applies a filter to the list of country names before mapping them
1384
+ - `parse` - `Function` - applies a transform to the country name before setting the label
1312
1385
 
1313
1386
  ## i18n
1314
1387
 
1315
1388
  If you wish to translate the countries into outher languages, you may want the labels to be in the form of translation keys. In this case you can use a `parse` option to convert the country names into a translation key:
1316
1389
 
1317
1390
  ```js
1318
- const countries = require('hof').utils.countries;
1391
+ const countries = require("hof").utils.countries;
1319
1392
  const options = countries({
1320
- parse: country => `countries.${country.toLowerCase().split(' ').join('-')}`
1393
+ parse: (country) => `countries.${country.toLowerCase().split(" ").join("-")}`,
1321
1394
  });
1322
1395
  ```
1323
1396
 
1324
1397
  You can then define a single translation for country names to be used for all country list instances.
1325
1398
 
1326
1399
  # FRONTEND
1400
+
1327
1401
  ## Template Mixins
1328
1402
 
1329
1403
  A middleware that exposes a series of Mustache mixins on `res.locals` to ease usage of forms, translations, and some other things.
@@ -1337,20 +1411,20 @@ npm install [--save] hof-template-mixins;
1337
1411
  ## Usage
1338
1412
 
1339
1413
  ```javascript
1340
- var express = require('express');
1414
+ var express = require("express");
1341
1415
 
1342
- var i18n = require('i18n-future');
1343
- var mixins = require('hof').frontend.mixins;
1416
+ var i18n = require("i18n-future");
1417
+ var mixins = require("hof").frontend.mixins;
1344
1418
 
1345
- app.set('view engine', 'html');
1346
- app.set('views', path.join(__dirname, '/views'));
1419
+ app.set("view engine", "html");
1420
+ app.set("views", path.join(__dirname, "/views"));
1347
1421
 
1348
1422
  app.use(i18n.middleware());
1349
1423
  app.use(mixins());
1350
1424
 
1351
1425
  app.use(function (req, res) {
1352
- // NOTE: res.locals.partials has been set.
1353
- res.render('example-template');
1426
+ // NOTE: res.locals.partials has been set.
1427
+ res.render("example-template");
1354
1428
  });
1355
1429
  ```
1356
1430
 
@@ -1414,6 +1488,7 @@ renderField
1414
1488
  ```
1415
1489
 
1416
1490
  ### qs
1491
+
1417
1492
  This mixin takes a `key=value` query string and returns a query string with the extra params appended. If the key is already present in the query string, the value passed to the mixin is used
1418
1493
 
1419
1494
  ```html
@@ -1425,34 +1500,29 @@ This mixin takes a `key=value` query string and returns a query string with the
1425
1500
  The renderField mixin can be called in your template to render all fields. This will lookup the field.mixin in res.locals and call it passing the field key.
1426
1501
 
1427
1502
  ```html
1428
- {{#fields}}
1429
- {{#renderField}}{{/renderField}}
1430
- {{/fields}}
1503
+ {{#fields}} {{#renderField}}{{/renderField}} {{/fields}}
1431
1504
  ```
1432
1505
 
1433
1506
  fields.js
1507
+
1434
1508
  ```js
1435
1509
  module.exports = {
1436
- 'my-field': {
1437
- mixin: 'input-text'
1438
- }
1439
- }
1510
+ "my-field": {
1511
+ mixin: "input-text",
1512
+ },
1513
+ };
1440
1514
  ```
1441
1515
 
1442
1516
  If mixin is omitted `input-text` will be used
1443
1517
 
1444
1518
  To disable auto-rendering of a field, set `disableRender: true` in the field config. This is required when using the `child` element rendering functionality to prevent the field being rendered multiple times.
1445
1519
 
1446
-
1447
- ### Render a single field ###
1520
+ ### Render a single field
1448
1521
 
1449
1522
  To render a specific fields in your templates use the mixin name (matching those above) and field name like so...
1450
1523
 
1451
1524
  ```html
1452
- {{#input-text}}myTextField{{/input-text}}
1453
-
1454
- {{#select}}mySelectMenu{{/select}}
1455
-
1525
+ {{#input-text}}myTextField{{/input-text}} {{#select}}mySelectMenu{{/select}}
1456
1526
  {{#radio-group}}myRadioGroup{{/radio-group}}
1457
1527
  ```
1458
1528
 
@@ -1464,6 +1534,7 @@ To render a specific fields in your templates use the mixin name (matching those
1464
1534
  - `required`: Value applied to `aria-required` HTML attribute.
1465
1535
  - `hint`: This adds context to the label, which it is a part of, for input text, radio groups and textarea. It is used within the input by aria-describedby for screen readers.
1466
1536
  - `maxlength`: Applicable to text-based fields and mapped to the `maxlength` HTML attribute.
1537
+ - `maxword`: Applicable to textarea fields.
1467
1538
  - `options`: Applicable to HTML `select` and `radio` controls and used to generate the items of either HTML element.
1468
1539
  - `selected`: Applicable to `select`, `checkbox`, and `radio` controls. Will render the selected HTML option/element selected or checked.
1469
1540
  - `legend`: Applicable to `radio` button controls, which are wrapped in a HTML `fieldset` with a `legend` element.
@@ -1471,11 +1542,12 @@ To render a specific fields in your templates use the mixin name (matching those
1471
1542
  - `toggle`: Can be used to toggle the display of the HTML element with a matching `id`. See [hof-frontend-toolkit](https://github.com/UKHomeOfficeForms/hof-frontend-toolkit/blob/master/assets/javascript/progressive-reveal.js) for details.
1472
1543
  - `attributes`: A hash of key/value pairs applicable to a HTML `textarea` field. Each key/value is assigned as an attribute of the `textarea`. For example `spellcheck="true"`.
1473
1544
  - `child`: Render a child partial beneath each option in an `optionGroup`. Accepts a custom mustache template string, a custom partial in the format `partials/{your-partial-name}`, `'html'` which is used to specify the html for the field has already been prerendered, such as in [hof-component-date](https://github.com/UKHomeOfficeForms/hof-component-date) or a template mixin key which will be rendered within a panel element partial.
1474
-
1545
+ - `isPageHeading`: Applicable to `checkbox` and `radio`, `text input` and `textarea` controls. Sets the legend as the page heading on single page questions.
1546
+ - `isWarning`: Applicable to `checkbox` and `radio` controls. Allows warning text to be placed after page headings on single page questions if required.
1475
1547
 
1476
1548
  # HOF-template-partials
1477
1549
 
1478
- Home Office Forms template partials is a collection of mustache partials commonly used in HOF applications. It also contains a collection of i18n translations used within the template partials. All contents are designed to be extended in your individual applications.
1550
+ Home Office Forms template partials is a collection of mustache partials commonly used in HOF applications. It also contains a collection of i18n translations used within the template partials. All contents are designed to be extended in your individual applications.
1479
1551
 
1480
1552
  ## Usage
1481
1553
 
@@ -1486,14 +1558,14 @@ Home Office Forms template partials is a collection of mustache partials commonl
1486
1558
  Template partials can be used by adding the route to the views directory to your express application views setting. You will need to be using the HTML view engine with Hogan and Mustache.
1487
1559
 
1488
1560
  ```js
1489
- var app = require('express')();
1561
+ var app = require("express")();
1490
1562
 
1491
- app.set('view engine', 'html');
1492
- app.set('views', [
1563
+ app.set("view engine", "html");
1564
+ app.set("views", [
1493
1565
  // your application shared views
1494
- path.resolve(__dirname, './path/to/views'),
1566
+ path.resolve(__dirname, "./path/to/views"),
1495
1567
  // the module exports paths to views and translations directories
1496
- require('hof').frontend.partials.views
1568
+ require("hof").frontend.partials.views,
1497
1569
  ]);
1498
1570
  ```
1499
1571
 
@@ -1504,14 +1576,14 @@ The views are now available when calling `res.render('view-name')` from express.
1504
1576
  When used in a hof application in conjunction with [express-partial-templates](https://github.com/UKHomeOffice/express-partial-templates) the contents of the views directory are added to `res.locals.partials`. These are added right to left so conflicting views are resolved from the left-most directory.
1505
1577
 
1506
1578
  ```js
1507
- var app = require('express')();
1579
+ var app = require("express")();
1508
1580
 
1509
- app.set('view engine', 'html');
1510
- app.set('views', [
1511
- path.resolve(__dirname, './path/to/views'),
1512
- require('hof').frontend.partials.views
1581
+ app.set("view engine", "html");
1582
+ app.set("views", [
1583
+ path.resolve(__dirname, "./path/to/views"),
1584
+ require("hof").frontend.partials.views,
1513
1585
  ]);
1514
- app.use(require('express-partial-templates')(app));
1586
+ app.use(require("express-partial-templates")(app));
1515
1587
 
1516
1588
  app.use(function (req, res, next) {
1517
1589
  // res.locals.partials contains all views from the views dir in this repo
@@ -1527,8 +1599,8 @@ The provided translations are designed to be used in conjunction with a translat
1527
1599
  The exported `resources` method will return a compiled object containing the translations, which can be passed to an `i18n` instance as a pre-compiled resource.
1528
1600
 
1529
1601
  ```js
1530
- const translate = require('i18n-future').middleware({
1531
- resources: require('hof').frontend.partials.resources()
1602
+ const translate = require("i18n-future").middleware({
1603
+ resources: require("hof").frontend.partials.resources(),
1532
1604
  });
1533
1605
  app.use(translate);
1534
1606
  ```
@@ -1536,19 +1608,19 @@ app.use(translate);
1536
1608
  By default the namespace for this translation is `default`. A custom namespace can be specified by passing it as an argument to the `resources` function.
1537
1609
 
1538
1610
  ```js
1539
- const translate = require('i18n-future').middleware({
1540
- resources: require('hof').frontend.partials.resources('hof-common'),
1541
- fallbackNamespace: 'hof-common'
1611
+ const translate = require("i18n-future").middleware({
1612
+ resources: require("hof").frontend.partials.resources("hof-common"),
1613
+ fallbackNamespace: "hof-common",
1542
1614
  });
1543
1615
  app.use(translate);
1544
1616
  ```
1617
+
1545
1618
  ### Cookie Banner
1546
1619
 
1547
1620
  The cookie banner has a placeholder named serviceName that you can set within the locals of your hof application so that the appropriate value is displayed.
1548
1621
 
1549
1622
  Set `appName` if your hof settings being passed to hof to take advantage of this.
1550
1623
 
1551
-
1552
1624
  # HOF FRONTEND THEME
1553
1625
 
1554
1626
  ## Usage
@@ -1600,11 +1672,13 @@ When used as part of an express app, a middleware is returned which will add a s
1600
1672
  It will also add the template as a mustache partial with a name of "govuk-template".
1601
1673
 
1602
1674
  ### To configure express middleware
1675
+
1603
1676
  ```
1604
1677
  app.use(require('hof').frontend.govUKTemplate([options]);
1605
1678
  ```
1606
1679
 
1607
1680
  ### To use the mustache partial
1681
+
1608
1682
  ```
1609
1683
  {{< govuk-template}}
1610
1684
  {{$pageTitle}}An example page{{/pageTitle}}
@@ -1618,11 +1692,12 @@ app.use(require('hof').frontend.govUKTemplate([options]);
1618
1692
 
1619
1693
  A number of options can be passed with the app into the setup method:
1620
1694
 
1621
- * `path` - Sets the base path for the location of static assets - Default: `/govuk-assets`
1695
+ - `path` - Sets the base path for the location of static assets - Default: `/govuk-assets`
1622
1696
 
1623
1697
  Other options are passed onto the [serve-static](https://www.npmjs.com/package/serve-static) configuration, and more details can be found in [the serve-static documentation](https://www.npmjs.com/package/serve-static)
1624
1698
 
1625
1699
  # Nonce values
1700
+
1626
1701
  Version 18.0.0 and above of HOF provides and requires a nonce value for all inline javascript, as unsafe-inline is disabled.
1627
1702
  Older versions (pre 18.0.0) will work with the hof-govuk-template templates as expected as the nonce value fields will only be added
1628
1703
  if a nonce value is provided by the version of HOF.
@@ -1636,16 +1711,25 @@ There is an example implementation in [demo application](https://github.com/UKHo
1636
1711
  There is a sandbox application for developers to test components directly in hof called [sandbox](/sandbox)
1637
1712
 
1638
1713
  # HOF FRONTEND TOOLKIT
1714
+
1639
1715
  Set of common UI patterns/styles for HOF projects
1640
1716
 
1641
1717
  ## Images
1718
+
1642
1719
  Copy `assets/images/hmpo` to your image directory. Images are loaded by using the `file-url` function provided by [GOV.UK frontend toolkit](https://github.com/alphagov/govuk_frontend_toolkit). The `file-url` function uses the `$path` variable which is set before the toolkit's modules are loaded.
1643
1720
 
1644
1721
  ## Vendor JavaScript
1722
+
1645
1723
  Additional vendor JavaScript files are included. These are:
1646
1724
 
1647
- * details.polyfill.js
1648
- * indexof.polyfill.js
1649
- * safari-cachebuster.js
1725
+ - details.polyfill.js
1726
+ - indexof.polyfill.js
1727
+ - safari-cachebuster.js
1650
1728
 
1651
1729
  Copy `assets/javascript/vendor` into your javascript directory (ie `hmpo/vendor`) and compile them with your JavaScript.
1730
+
1731
+ ## Journey Header Navigation.html page
1732
+
1733
+ - Navigation.html contains a journeyHeaderURL, which is set in the controller.
1734
+ - getJourneyHeaderURL within the controller translates an empty baseURL to '/'.
1735
+ - The above helps fix broken journey header URLs in the GRO and UKVIC services which both have a baseURL's set to '/'.