hof 22.9.0-beta.v1 → 22.9.0-beta.v2

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 (312) hide show
  1. package/package.json +1 -1
  2. package/package/.eslintignore +0 -1
  3. package/package/CHANGELOG.md +0 -232
  4. package/package/LICENSE +0 -21
  5. package/package/README.md +0 -1887
  6. package/package/bin/hof-build +0 -10
  7. package/package/bin/hof-transpiler +0 -12
  8. package/package/build/helpers/importer.js +0 -29
  9. package/package/build/helpers/local.js +0 -35
  10. package/package/build/helpers/resolver/import.js +0 -32
  11. package/package/build/helpers/resolver/nearest-package-root.js +0 -33
  12. package/package/build/helpers/resolver/package.js +0 -29
  13. package/package/build/helpers/resolver.js +0 -16
  14. package/package/build/index.js +0 -49
  15. package/package/build/lib/env.js +0 -36
  16. package/package/build/lib/mkdir.js +0 -9
  17. package/package/build/lib/run.js +0 -17
  18. package/package/build/lib/spawn.js +0 -18
  19. package/package/build/tasks/browserify/compress.js +0 -15
  20. package/package/build/tasks/browserify/index.js +0 -48
  21. package/package/build/tasks/build/index.js +0 -6
  22. package/package/build/tasks/images/index.js +0 -27
  23. package/package/build/tasks/index.js +0 -8
  24. package/package/build/tasks/sass/index.js +0 -67
  25. package/package/build/tasks/translate/index.js +0 -20
  26. package/package/build/tasks/watch/index.js +0 -161
  27. package/package/components/address-lookup/default-model.js +0 -76
  28. package/package/components/address-lookup/defaults.js +0 -25
  29. package/package/components/address-lookup/index.js +0 -251
  30. package/package/components/address-lookup/templates/address-lookup.html +0 -14
  31. package/package/components/address-lookup/templates/address.html +0 -22
  32. package/package/components/address-lookup/templates/postcode.html +0 -9
  33. package/package/components/clear-session/Readme.md +0 -46
  34. package/package/components/clear-session/index.js +0 -26
  35. package/package/components/combine-and-loop-fields/Readme.md +0 -42
  36. package/package/components/combine-and-loop-fields/index.js +0 -156
  37. package/package/components/date/fields.js +0 -16
  38. package/package/components/date/index.js +0 -172
  39. package/package/components/date/templates/date.html +0 -20
  40. package/package/components/emailer/assets/images/govuk_logotype_email.png +0 -0
  41. package/package/components/emailer/assets/images/ho_crest_27px.png +0 -0
  42. package/package/components/emailer/assets/images/spacer.gif +0 -0
  43. package/package/components/emailer/email-service.js +0 -51
  44. package/package/components/emailer/emailer.js +0 -53
  45. package/package/components/emailer/index.js +0 -74
  46. package/package/components/emailer/transports/debug.js +0 -74
  47. package/package/components/emailer/transports/index.js +0 -8
  48. package/package/components/emailer/transports/ses.js +0 -36
  49. package/package/components/emailer/transports/smtp.js +0 -26
  50. package/package/components/emailer/transports/stub.js +0 -5
  51. package/package/components/emailer/views/layout.html +0 -63
  52. package/package/components/homeoffice-countries/index.js +0 -22
  53. package/package/components/index.js +0 -13
  54. package/package/components/notify/index.js +0 -62
  55. package/package/components/notify/notify.js +0 -51
  56. package/package/components/session-timeout-warning/index.js +0 -67
  57. package/package/components/summary/index.js +0 -237
  58. package/package/config/builder-defaults.js +0 -45
  59. package/package/config/component-defaults.js +0 -13
  60. package/package/config/hof-defaults.js +0 -65
  61. package/package/config/rate-limits.js +0 -20
  62. package/package/config/sanitisation-rules.js +0 -32
  63. package/package/controller/base-controller.js +0 -296
  64. package/package/controller/behaviour-hooks.js +0 -51
  65. package/package/controller/behaviour-session.js +0 -64
  66. package/package/controller/controller.js +0 -258
  67. package/package/controller/deprecate-error.js +0 -10
  68. package/package/controller/formatting/formatters.js +0 -70
  69. package/package/controller/formatting/index.js +0 -32
  70. package/package/controller/index.js +0 -17
  71. package/package/controller/validation/email.js +0 -30
  72. package/package/controller/validation/index.js +0 -101
  73. package/package/controller/validation/validators.js +0 -181
  74. package/package/controller/validation-error.js +0 -14
  75. package/package/frontend/govuk-template/build/config.js +0 -24
  76. package/package/frontend/govuk-template/build/govuk_template.html +0 -102
  77. package/package/frontend/govuk-template/build/index.js +0 -23
  78. package/package/frontend/govuk-template/govuk_template_generated.html +0 -102
  79. package/package/frontend/govuk-template/index.js +0 -29
  80. package/package/frontend/index.js +0 -9
  81. package/package/frontend/template-mixins/mixins/helpers.js +0 -103
  82. package/package/frontend/template-mixins/mixins/index.js +0 -37
  83. package/package/frontend/template-mixins/mixins/render.js +0 -12
  84. package/package/frontend/template-mixins/mixins/template-mixins.js +0 -520
  85. package/package/frontend/template-mixins/partials/forms/checkbox-group.html +0 -47
  86. package/package/frontend/template-mixins/partials/forms/checkbox.html +0 -16
  87. package/package/frontend/template-mixins/partials/forms/input-submit.html +0 -1
  88. package/package/frontend/template-mixins/partials/forms/input-text-date.html +0 -37
  89. package/package/frontend/template-mixins/partials/forms/input-text-group.html +0 -45
  90. package/package/frontend/template-mixins/partials/forms/option-group.html +0 -43
  91. package/package/frontend/template-mixins/partials/forms/select.html +0 -17
  92. package/package/frontend/template-mixins/partials/forms/textarea-group.html +0 -37
  93. package/package/frontend/template-mixins/partials/mixins/panel.html +0 -4
  94. package/package/frontend/template-partials/index.js +0 -9
  95. package/package/frontend/template-partials/translations/index.js +0 -26
  96. package/package/frontend/template-partials/translations/src/cy/base.json +0 -4
  97. package/package/frontend/template-partials/translations/src/cy/buttons.json +0 -6
  98. package/package/frontend/template-partials/translations/src/cy/cookies.json +0 -104
  99. package/package/frontend/template-partials/translations/src/cy/errorlist.json +0 -6
  100. package/package/frontend/template-partials/translations/src/cy/errors.json +0 -18
  101. package/package/frontend/template-partials/translations/src/cy/terms.json +0 -28
  102. package/package/frontend/template-partials/translations/src/en/accessibility.json +0 -43
  103. package/package/frontend/template-partials/translations/src/en/base.json +0 -5
  104. package/package/frontend/template-partials/translations/src/en/buttons.json +0 -10
  105. package/package/frontend/template-partials/translations/src/en/cookies.json +0 -116
  106. package/package/frontend/template-partials/translations/src/en/errorlist.json +0 -7
  107. package/package/frontend/template-partials/translations/src/en/errors.json +0 -35
  108. package/package/frontend/template-partials/translations/src/en/exit.json +0 -5
  109. package/package/frontend/template-partials/translations/src/en/fields.json +0 -5
  110. package/package/frontend/template-partials/translations/src/en/journey.json +0 -6
  111. package/package/frontend/template-partials/translations/src/en/save-and-exit.json +0 -4
  112. package/package/frontend/template-partials/translations/src/en/terms.json +0 -28
  113. package/package/frontend/template-partials/views/404.html +0 -9
  114. package/package/frontend/template-partials/views/accessibility.html +0 -55
  115. package/package/frontend/template-partials/views/confirm.html +0 -8
  116. package/package/frontend/template-partials/views/confirmation.html +0 -19
  117. package/package/frontend/template-partials/views/content/en/what-happens-next.md +0 -0
  118. package/package/frontend/template-partials/views/cookie-error.html +0 -1
  119. package/package/frontend/template-partials/views/cookies.html +0 -84
  120. package/package/frontend/template-partials/views/email/data-row.html +0 -4
  121. package/package/frontend/template-partials/views/email/formatted.html +0 -12
  122. package/package/frontend/template-partials/views/email/layout.html +0 -63
  123. package/package/frontend/template-partials/views/email/raw.html +0 -11
  124. package/package/frontend/template-partials/views/email/section-row.html +0 -3
  125. package/package/frontend/template-partials/views/error.html +0 -20
  126. package/package/frontend/template-partials/views/exit.html +0 -9
  127. package/package/frontend/template-partials/views/feedback-submitted.html +0 -11
  128. package/package/frontend/template-partials/views/layout.html +0 -55
  129. package/package/frontend/template-partials/views/partials/analytics-table.html +0 -25
  130. package/package/frontend/template-partials/views/partials/back.html +0 -5
  131. package/package/frontend/template-partials/views/partials/bullet-list.html +0 -7
  132. package/package/frontend/template-partials/views/partials/confirmation-alert.html +0 -6
  133. package/package/frontend/template-partials/views/partials/continue.html +0 -5
  134. package/package/frontend/template-partials/views/partials/cookie-banner.html +0 -29
  135. package/package/frontend/template-partials/views/partials/cookie-notification.html +0 -4
  136. package/package/frontend/template-partials/views/partials/cookie-settings-button.html +0 -1
  137. package/package/frontend/template-partials/views/partials/cookie-settings-radio.html +0 -8
  138. package/package/frontend/template-partials/views/partials/details-summary.html +0 -8
  139. package/package/frontend/template-partials/views/partials/external-link.html +0 -1
  140. package/package/frontend/template-partials/views/partials/form.html +0 -10
  141. package/package/frontend/template-partials/views/partials/gatag.html +0 -60
  142. package/package/frontend/template-partials/views/partials/head.html +0 -31
  143. package/package/frontend/template-partials/views/partials/heading.html +0 -11
  144. package/package/frontend/template-partials/views/partials/items-table.html +0 -32
  145. package/package/frontend/template-partials/views/partials/maincontent-left.html +0 -10
  146. package/package/frontend/template-partials/views/partials/navigation.html +0 -8
  147. package/package/frontend/template-partials/views/partials/page.html +0 -23
  148. package/package/frontend/template-partials/views/partials/panel-indent.html +0 -3
  149. package/package/frontend/template-partials/views/partials/session-cookies-table.html +0 -28
  150. package/package/frontend/template-partials/views/partials/session-timeout-warning.html +0 -38
  151. package/package/frontend/template-partials/views/partials/summary-table-row.html +0 -14
  152. package/package/frontend/template-partials/views/partials/summary-table.html +0 -8
  153. package/package/frontend/template-partials/views/partials/table.html +0 -18
  154. package/package/frontend/template-partials/views/partials/validation-list.html +0 -3
  155. package/package/frontend/template-partials/views/partials/validation-summary.html +0 -25
  156. package/package/frontend/template-partials/views/partials/warn.html +0 -7
  157. package/package/frontend/template-partials/views/rate-limit-error.html +0 -10
  158. package/package/frontend/template-partials/views/save-and-exit.html +0 -17
  159. package/package/frontend/template-partials/views/service-unavailable.html +0 -13
  160. package/package/frontend/template-partials/views/session-timeout.html +0 -7
  161. package/package/frontend/template-partials/views/step.html +0 -14
  162. package/package/frontend/template-partials/views/terms.html +0 -26
  163. package/package/frontend/themes/gov-uk/client-js/cookieSettings.js +0 -145
  164. package/package/frontend/themes/gov-uk/client-js/govuk-cookies.js +0 -121
  165. package/package/frontend/themes/gov-uk/client-js/index.js +0 -27
  166. package/package/frontend/themes/gov-uk/client-js/session-timeout-dialog.js +0 -348
  167. package/package/frontend/themes/gov-uk/client-js/skip-to-main.js +0 -19
  168. package/package/frontend/themes/gov-uk/index.js +0 -9
  169. package/package/frontend/themes/gov-uk/styles/_base.scss +0 -17
  170. package/package/frontend/themes/gov-uk/styles/_check_your_answers.scss +0 -155
  171. package/package/frontend/themes/gov-uk/styles/_cookie-banner.scss +0 -111
  172. package/package/frontend/themes/gov-uk/styles/_cookie-settings.scss +0 -33
  173. package/package/frontend/themes/gov-uk/styles/_govuk_frontend_toolkit.scss +0 -23
  174. package/package/frontend/themes/gov-uk/styles/_helpers.scss +0 -5
  175. package/package/frontend/themes/gov-uk/styles/_layout.scss +0 -125
  176. package/package/frontend/themes/gov-uk/styles/_panel-indent.scss +0 -27
  177. package/package/frontend/themes/gov-uk/styles/_pdf.scss +0 -42
  178. package/package/frontend/themes/gov-uk/styles/_session-timeout-dialog.scss +0 -121
  179. package/package/frontend/themes/gov-uk/styles/_typography.scss +0 -27
  180. package/package/frontend/themes/gov-uk/styles/_variables.scss +0 -11
  181. package/package/frontend/themes/gov-uk/styles/govuk.scss +0 -43
  182. package/package/frontend/themes/gov-uk/styles/mixins.scss +0 -16
  183. package/package/frontend/themes/gov-uk/styles/modules/_alerts.scss +0 -73
  184. package/package/frontend/themes/gov-uk/styles/modules/_buttons.scss +0 -5
  185. package/package/frontend/themes/gov-uk/styles/modules/_character-count.scss +0 -8
  186. package/package/frontend/themes/gov-uk/styles/modules/_confirm-page.scss +0 -20
  187. package/package/frontend/themes/gov-uk/styles/modules/_lists.scss +0 -5
  188. package/package/frontend/themes/gov-uk/styles/modules/_progressive-reveal.scss +0 -17
  189. package/package/frontend/themes/gov-uk/styles/modules/_validation.scss +0 -51
  190. package/package/frontend/themes/index.js +0 -5
  191. package/package/frontend/toolkit/assets/images/passports/new-window-link-blue.png +0 -0
  192. package/package/frontend/toolkit/assets/images/passports/new-window-link.png +0 -0
  193. package/package/frontend/toolkit/assets/images/spinner.gif +0 -0
  194. package/package/frontend/toolkit/assets/javascript/character-count.js +0 -99
  195. package/package/frontend/toolkit/assets/javascript/form-focus.js +0 -101
  196. package/package/frontend/toolkit/assets/javascript/helpers.js +0 -177
  197. package/package/frontend/toolkit/assets/javascript/progressive-reveal.js +0 -72
  198. package/package/frontend/toolkit/assets/javascript/validation.js +0 -71
  199. package/package/frontend/toolkit/assets/javascript/vendor/details.polyfill.js +0 -189
  200. package/package/frontend/toolkit/assets/javascript/vendor/indexof.polyfill.js +0 -39
  201. package/package/frontend/toolkit/assets/javascript/vendor/safari-cachebuster.js +0 -6
  202. package/package/frontend/toolkit/assets/stylesheets/_base.scss +0 -17
  203. package/package/frontend/toolkit/assets/stylesheets/_helpers.scss +0 -5
  204. package/package/frontend/toolkit/assets/stylesheets/_layout.scss +0 -118
  205. package/package/frontend/toolkit/assets/stylesheets/_typography.scss +0 -27
  206. package/package/frontend/toolkit/assets/stylesheets/_variables.scss +0 -11
  207. package/package/frontend/toolkit/assets/stylesheets/app.scss +0 -30
  208. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_buttons.scss +0 -47
  209. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_details.scss +0 -38
  210. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_elements-typography.scss +0 -175
  211. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_forms.scss +0 -167
  212. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_helpers.scss +0 -39
  213. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_layout.scss +0 -67
  214. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_lists.scss +0 -40
  215. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_panels.scss +0 -29
  216. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_reset.scss +0 -33
  217. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/_tables.scss +0 -33
  218. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-block-labels.scss +0 -63
  219. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-date.scss +0 -39
  220. package/package/frontend/toolkit/assets/stylesheets/govuk-elements/forms/_form-validation.scss +0 -63
  221. package/package/frontend/toolkit/assets/stylesheets/mixins.scss +0 -16
  222. package/package/frontend/toolkit/assets/stylesheets/modules/_alerts.scss +0 -73
  223. package/package/frontend/toolkit/assets/stylesheets/modules/_buttons.scss +0 -5
  224. package/package/frontend/toolkit/assets/stylesheets/modules/_confirm-page.scss +0 -20
  225. package/package/frontend/toolkit/assets/stylesheets/modules/_lists.scss +0 -5
  226. package/package/frontend/toolkit/assets/stylesheets/modules/_progressive-reveal.scss +0 -17
  227. package/package/frontend/toolkit/assets/stylesheets/modules/_validation.scss +0 -51
  228. package/package/frontend/toolkit/index.js +0 -10
  229. package/package/index.js +0 -351
  230. package/package/lib/deindex.js +0 -18
  231. package/package/lib/encryption.js +0 -23
  232. package/package/lib/ga-tag.js +0 -89
  233. package/package/lib/health.js +0 -26
  234. package/package/lib/helpers.js +0 -66
  235. package/package/lib/logger.js +0 -65
  236. package/package/lib/markdown.js +0 -46
  237. package/package/lib/router.js +0 -111
  238. package/package/lib/serve-static.js +0 -12
  239. package/package/lib/sessions.js +0 -82
  240. package/package/lib/settings.js +0 -74
  241. package/package/lib/which.js +0 -28
  242. package/package/middleware/cookies.js +0 -43
  243. package/package/middleware/deep-translate.js +0 -32
  244. package/package/middleware/errors.js +0 -119
  245. package/package/middleware/index.js +0 -10
  246. package/package/middleware/not-found.js +0 -38
  247. package/package/middleware/rate-limiter.js +0 -98
  248. package/package/middleware/service-unavailable.js +0 -64
  249. package/package/model/apis/axios-settings.js +0 -21
  250. package/package/model/apis/html-to-pdf-converter.js +0 -35
  251. package/package/model/apis/index.js +0 -5
  252. package/package/model/index.js +0 -348
  253. package/package/package.json +0 -147
  254. package/package/sandbox/README.md +0 -66
  255. package/package/sandbox/apps/sandbox/behaviours/clear-session.js +0 -8
  256. package/package/sandbox/apps/sandbox/behaviours/country-select.js +0 -10
  257. package/package/sandbox/apps/sandbox/behaviours/international-number.js +0 -22
  258. package/package/sandbox/apps/sandbox/fields.js +0 -128
  259. package/package/sandbox/apps/sandbox/index.js +0 -99
  260. package/package/sandbox/apps/sandbox/lib/staticAppealStages.js +0 -189
  261. package/package/sandbox/apps/sandbox/sections/summary-data-sections.js +0 -43
  262. package/package/sandbox/apps/sandbox/translations/src/en/errors.json +0 -5
  263. package/package/sandbox/apps/sandbox/translations/src/en/exit.json +0 -4
  264. package/package/sandbox/apps/sandbox/translations/src/en/fields.json +0 -101
  265. package/package/sandbox/apps/sandbox/translations/src/en/journey.json +0 -7
  266. package/package/sandbox/apps/sandbox/translations/src/en/pages.json +0 -72
  267. package/package/sandbox/apps/sandbox/translations/src/en/validation.json +0 -54
  268. package/package/sandbox/apps/sandbox/views/form-guidance-link.html +0 -8
  269. package/package/sandbox/apps/sandbox/views/save-and-exit.html +0 -19
  270. package/package/sandbox/assets/images/icons/icon-caret-left.png +0 -0
  271. package/package/sandbox/assets/images/icons/icon-complete.png +0 -0
  272. package/package/sandbox/assets/images/icons/icon-cross-remove-sign.png +0 -0
  273. package/package/sandbox/assets/js/index.js +0 -70
  274. package/package/sandbox/assets/scss/app.scss +0 -27
  275. package/package/sandbox/codecept.conf.js +0 -15
  276. package/package/sandbox/config.js +0 -17
  277. package/package/sandbox/package.json +0 -26
  278. package/package/sandbox/server.js +0 -23
  279. package/package/sandbox/yarn.lock +0 -262
  280. package/package/transpiler/index.js +0 -2
  281. package/package/transpiler/lib/aggregate.js +0 -32
  282. package/package/transpiler/lib/build.js +0 -15
  283. package/package/transpiler/lib/compile.js +0 -12
  284. package/package/transpiler/lib/expand-dirs.js +0 -14
  285. package/package/transpiler/lib/write-files.js +0 -24
  286. package/package/utilities/autofill/index.js +0 -189
  287. package/package/utilities/autofill/inputs.js +0 -60
  288. package/package/utilities/countries.js +0 -12
  289. package/package/utilities/helpers/index.js +0 -189
  290. package/package/utilities/index.js +0 -9
  291. package/package/utilities/reqres/index.js +0 -18
  292. package/package/utilities/test-data/data/domain.json +0 -7
  293. package/package/utilities/test-data/data/firstname.json +0 -16
  294. package/package/utilities/test-data/data/lastname.json +0 -10
  295. package/package/utilities/test-data/data/postcode.json +0 -12
  296. package/package/utilities/test-data/data/streetname.json +0 -8
  297. package/package/utilities/test-data/data/streetsuffix.json +0 -7
  298. package/package/utilities/test-data/data/town.json +0 -9
  299. package/package/utilities/test-data/index.js +0 -67
  300. package/package/wizard/behaviours/complete.js +0 -20
  301. package/package/wizard/behaviours/index.js +0 -5
  302. package/package/wizard/index.js +0 -124
  303. package/package/wizard/middleware/back-links.js +0 -68
  304. package/package/wizard/middleware/check-complete.js +0 -13
  305. package/package/wizard/middleware/check-progress.js +0 -139
  306. package/package/wizard/middleware/check-session.js +0 -17
  307. package/package/wizard/middleware/csrf.js +0 -47
  308. package/package/wizard/middleware/session-model.js +0 -11
  309. package/package/wizard/middleware/session.js +0 -9
  310. package/package/wizard/model.js +0 -29
  311. package/package/wizard/util/constants.js +0 -5
  312. package/package/wizard/util/helpers.js +0 -19
package/package/README.md DELETED
@@ -1,1887 +0,0 @@
1
- # HOF (Home Office Forms)
2
-
3
- [![NPM_Publish Actions Status](https://github.com/UKHomeOfficeForms/hof/workflows/Automate_Publish/badge.svg)](https://github.com/UKHomeOfficeForms/hof/actions)
4
- [![npm version](https://badge.fury.io/js/hof.svg)](https://badge.fury.io/js/hof)
5
- [![Known Vulnerabilities](https://snyk.io/test/npm/hof/badge.svg)](https://snyk.io/test/npm/hof)
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.
8
-
9
- ## Server Settings
10
-
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.
12
-
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.
14
-
15
- ## Resources
16
-
17
- ### HOF documentation
18
-
19
- [https://ukhomeofficeforms.github.io/hof-guide/](https://ukhomeofficeforms.github.io/hof-guide/)
20
-
21
- ## Content Security Policy
22
-
23
- ### Inline JavaScript from 18.0.0
24
-
25
- From version 18.0.0, unsafe-inline has been removed from the content security policy by default. This means scripts
26
- must either be referenced using the src attribute, `<script src='...'></script>` or with a nonce value attribute. A nonce
27
- value is generated for every request. You can add this to your own templates' inline scripts as needed:
28
-
29
- ```
30
- <script {{#nonce}}nonce="{{nonce}}"{{/nonce}}>
31
- ...
32
- </script>
33
- ```
34
-
35
- ### Built with HOF
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)
44
-
45
- ## HOF BUILD
46
-
47
- Performs build workflow for hof apps in prod and development
48
-
49
- ## Usage
50
-
51
- Run a build by running `hof-build` from the command line in your project directory.
52
-
53
- ```
54
- hof-build [task]
55
- ```
56
-
57
- If no task is specified then all tasks will run.
58
-
59
- It is recommended to alias `hof-build` to an npm script in your package.json.
60
-
61
- ## Tasks
62
-
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.
71
- - `sourceMaps` - This controls whether the build will output css sourcemaps to help with debugging. These will be output to the same directory as the css output as a .map file. This option is not currently available in production.
72
-
73
- For JavaScript compilation, browserify can be set to debug mode by setting the `debug` option to true. This will cause browserify to output JavaScript sourcemaps as a .js.map file to the same directory as the js bundle.
74
-
75
- Debugging example (in hof.settings or your build config)
76
- ```
77
- "build": {
78
- "sass": {
79
- "sourceMaps": true
80
- },
81
- "browserify": {
82
- "debug": true
83
- }
84
- }
85
- ```
86
-
87
- ## Watch
88
-
89
- You can additionally run a `watch` task to start a server instance, which will automatically restart based on changes to files. This will also re-perform the tasks above when relevant files change.
90
-
91
- By default files inside `node_modules` directories and dotfiles will not trigger a restart. If you want to include these files then you can set `--watch-node-modules` and `--watch-dotfiles` flags respectively.
92
-
93
- ### Local environment variables
94
-
95
- You can load local environment variables from a file by passing an `--env` flag to `hof-build watch` and creating a `.env` file in your project root that defines your local variables as follows:
96
-
97
- ```
98
- MY_LOCAL_ENVVAR=foo
99
- MY_OTHER_ENVVAR=bar
100
- ```
101
-
102
- _Note: `export` is not required, and values should not be quoted._
103
-
104
- To load variables from a file other than `.env` you should pass the location of the file as a value on the `--env` flag.
105
-
106
- ```
107
- hof-build watch --env .envdev
108
- ```
109
-
110
- ## Configuration
111
-
112
- The default settings will match those for an app generated using [`hof-generator`](https://npmjs.com/hof-generator).
113
-
114
- If a `hof.settings.json` file is found in the application root, then the `build` section of the settings file will be used to override [the default configuration](./defaults.js).
115
-
116
- Alternatively you can define a path to a local config file by passing a `--config` option
117
-
118
- ```
119
- hof-build --config /path/to/my/config.js
120
- ```
121
-
122
- Any task can be disabled by setting its configuration to `false` (or any falsy value).
123
-
124
- ```js
125
- module.exports = {
126
- browserify: false,
127
- };
128
- ```
129
-
130
- ### Configuration options
131
-
132
- Each task has a common configuration format with the following options:
133
-
134
- - `src` - defines the input file or files for the build task
135
- - `out` - defines the output location of the built code where relevant
136
- - `match` - defines the pattern for files to watch to trigger a rebuild of this task
137
- - `restart` - defines if this task should result in a server restart
138
-
139
- Additionally the server instance created by `watch` can be configured by setting `server` config. Available options are:
140
-
141
- - `cmd` - defines the command used to start the server
142
- - `extensions` - defines the file extensions which will be watched to trigger a restart
143
-
144
- ### Shared Translations
145
-
146
- By default translations put in the commons directory in a HOF project, i.e. `app/common/translations/src`, are bundles together and shared with other translation files of the same name, e.g. fields.json, buttons.json etc. Any other files will have their own json file created in the default.json translation file of a sub application. E.g. in `app/<sub_app>/translations/en/default.json`.
147
-
148
- 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
149
-
150
- Hof.settings.json example
151
-
152
- ```
153
- "build": {
154
- "translate": {
155
- "shared": "./apps/another_common_directory/translations/src"
156
- }
157
- }
158
- ```
159
-
160
- server.js example
161
-
162
- ```
163
- const hof = require('hof');
164
- const settings = { ...behaviours, ...routes };
165
-
166
- settings.build = { translate: { shared: "./apps/another_common_directory/translations/src" } };
167
-
168
- const app = hof(settings);
169
- ```
170
-
171
- ## HOF TRANSPILER
172
-
173
- Home office forms transpiler is a tiny tool that can be used as part of a build or manually to convert multipart locales files into one default.json. This is used in our stack for translations of form applications.
174
-
175
- ## Usage
176
-
177
- ```
178
- hof-transpiler [source dir|glob] {OPTIONS}
179
-
180
- --shared, -s A path or glob to a directory of shared translations
181
- ```
182
-
183
- ## Example
184
-
185
- Lets say you have a directory such as: `translations/src/en`
186
-
187
- Which contains:
188
-
189
- ```
190
- buttons.json
191
- emails.json
192
- errors.json
193
- validation.json
194
- ```
195
-
196
- If you run hof-transpiler against the directory `hof-transpiler ./translations/src`
197
-
198
- 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`
199
-
200
- Which will look something like
201
-
202
- ```
203
- {
204
- "buttons": {
205
- json blob from buttons.json
206
- },
207
- "emails": {
208
- json blob from emails.json
209
- },
210
- "errors": {
211
- json blob from errors.json
212
- },
213
- "validation": {
214
- json blob from validation.json
215
- }
216
- }
217
- ```
218
-
219
- This is used further down the hof stack for application translations.
220
-
221
- ## Advanced example - duplicate keys between source folder and shared folder
222
-
223
- Lets say you have a directory such as: `translations/src/en`
224
-
225
- Which contains:
226
- buttons.json containing:
227
-
228
- ```json
229
- {
230
- "unusual-button": "Moo"
231
- }
232
- ```
233
-
234
- emails.json containing:
235
-
236
- ```json
237
- {
238
- "customer-email": "Hi how are you?"
239
- }
240
- ```
241
-
242
- And you also have a directory of shared translations such as: `shared-translations/src/en`
243
-
244
- Which contains:
245
- buttons.json containing:
246
-
247
- ```json
248
- {
249
- "common-button": "Click me"
250
- }
251
- ```
252
-
253
- If you then run:
254
-
255
- ```bash
256
- hof-transpiler translations/src --shared shared-translations/src
257
- ```
258
-
259
- Then transpiled translations should appear in translations/en/default.json as follows:
260
-
261
- ```json
262
- {
263
- "buttons": {
264
- "unusual-button": "Moo",
265
- "common-button": "Click me"
266
- },
267
- "emails": {
268
- "customer-email": "Hi how are you?"
269
- }
270
- }
271
- ```
272
-
273
- Note how a deep merge is performed between the json, with key value pairs from "buttons" being included from both files.
274
-
275
- ## Multiple shared sources
276
-
277
- hof-transpiler supports multiple shared sources, extending them from left to right. This is useful if you have translations shared between applications, and additional shared translations between routes within an application.
278
-
279
- If you have the following sources:
280
-
281
- node_modules/hof-template-partials/translations/src/en/buttons.json
282
-
283
- ```json
284
- {
285
- "continue": "Continue",
286
- "skip": "Skip",
287
- "submit": "Submit",
288
- "abort": "Abort"
289
- }
290
- ```
291
-
292
- common/translations/src/en/buttons.json
293
-
294
- ```json
295
- {
296
- "skip": "Skip this step",
297
- "cancel": "Cancel"
298
- }
299
- ```
300
-
301
- my-application/translations/src/en/buttons.json
302
-
303
- ```json
304
- {
305
- "continue": "Go Forth!"
306
- }
307
- ```
308
-
309
- If you then run:
310
-
311
- ```bash
312
- hof-transpiler my-application/translations/src --shared node_modules/hof-template-partials/translations/src --shared common/translations/src
313
- ```
314
-
315
- my-application/translations/en/default.json
316
-
317
- ```json
318
- {
319
- "buttons": {
320
- "continue": "Go Forth!",
321
- "skip": "Skip this step",
322
- "submit": "Submit",
323
- "abort": "Abort",
324
- "cancel": "Cancel"
325
- }
326
- }
327
- ```
328
-
329
- #HOF Controller
330
-
331
- Implements a request pipeline for GET and POST of forms, with input cleaning/formatting and validation.
332
-
333
- ## Usage
334
-
335
- Basic usage:
336
-
337
- ```javascript
338
- var Form = require("./controller");
339
-
340
- var form = new Form({
341
- template: "form",
342
- fields: {
343
- name: {
344
- validate: "required",
345
- },
346
- },
347
- });
348
-
349
- app.use("/", form.requestHandler());
350
- ```
351
-
352
- 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.
353
-
354
- For real-world usage you will probably want to extend the Form class to create your own controllers.
355
-
356
- ```javascript
357
- var Form = require('./controller''),
358
- util = require('util');
359
-
360
- var MyForm = function (options) {
361
- Form.call(this, options);
362
- };
363
-
364
- util.inherits(MyForm, Form);
365
-
366
- module.exports = MyForm;
367
- ```
368
-
369
- The Form class allows for a number of insertion points for extended functionality:
370
-
371
- - `configure` Allows for dynamic overwriting of particular points of form configuration based on user session
372
- - `process` Allows for custom formatting and processing of input prior to validation
373
- - `validate` Allows for custom input validation
374
- - `getValues` To define what values the fields are populated with on GET
375
- - `saveValues` To define what is done with successful form submissions
376
-
377
- 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.
378
-
379
- - `getErrors/setErrors` Define how errors are persisted between the POST and subsequent GET of a form step.
380
- - `locals` Define what additional variables a controller exposes to its template
381
-
382
- These methods are synchronous and take only the request and response obejct as arguments.
383
-
384
- ### Validators
385
-
386
- The library [supports a number of validators](https://github.com/UKHomeOffice/passports-form-controller/blob/master/lib/validation/validators.js).
387
-
388
- By default the application of a validator is optional on empty strings. If you need to ensure a field is validated as being 9 characters long and exists then you need to use both an `exactlength` and a `required` validator.
389
-
390
- #### Custom Validators
391
-
392
- 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.
393
-
394
- fields.js
395
-
396
- ```js
397
- {
398
- 'field-1': {
399
- validate: ['required', function isTrue(val) {
400
- return val === true;
401
- }]
402
- }
403
- }
404
- ```
405
-
406
- ### steps config
407
-
408
- #### Handles journey forking
409
-
410
- Each step definition accepts a `next` property, the value of which is the next route in the journey. By default, when the form is successfully submitted, the next steps will load. However, there are times when it is necessary to fork from the current journey based on a users response to certain questions in a form. For such circumstances there exists the `forks` property.
411
-
412
- In this example, when the submits the form, if the field called 'example-radio' has the value 'superman', the page at '/fork-page' will load, otherwise '/next-page' will be loaded.
413
-
414
- ```js
415
-
416
- '/my-page': {
417
- next: '/next-page',
418
- forks: [{
419
- target: '/fork-page',
420
- condition: {
421
- field: 'example-radio',
422
- value: 'superman'
423
- }
424
- }]
425
- }
426
- ```
427
-
428
- The condition property can also take a function. In the following example, if the field called 'name' is more than 30 characters in length, the page at '/fork-page' will be loaded.
429
-
430
- ```js
431
-
432
- '/my-page': {
433
- next: '/next-page',
434
- forks: [{
435
- target: '/fork-page',
436
- condition: function (req, res) {
437
- return req.form.values['name'].length > 30;
438
- }
439
- }]
440
- }
441
- ```
442
-
443
- Forks is an array and therefore each fork is interrogated in order from top to bottom. The last fork whose condition is met will assign its target to the next page variable.
444
-
445
- In this example, if the last condition resolves to true - even if the others also resolve to true - then the page at '/fork-page-three' will be loaded. The last condition to be met is always the fork used to determine the next step.
446
-
447
- ```js
448
-
449
- '/my-page': {
450
- next: '/next-page',
451
- forks: [{
452
- target: '/fork-page-one',
453
- condition: function (req, res) {
454
- return req.form.values['name'].length > 30;
455
- }
456
- }, {
457
- target: '/fork-page-two',
458
- condition: {
459
- field: 'example-radio',
460
- value: 'superman'
461
- }
462
- }, {
463
- target: '/fork-page-three',
464
- condition: function (req, res) {
465
- return typeof req.form.values['email'] === 'undefined';
466
- }
467
- }]
468
- }
469
- ```
470
-
471
- ### Dynamic field options
472
-
473
- If the options for a particular field are dependent on aspects of the user session, then these can be extended on a per-session basis using the `configure` method.
474
-
475
- For example, for a dynamic address selection component:
476
-
477
- ```js
478
- MyForm.prototype.configure = function configure(req, res, next) {
479
- req.form.options.fields["address-select"].options =
480
- req.sessionModel.get("addresses");
481
- next();
482
- };
483
- ```
484
-
485
- ### The FormError class
486
-
487
- 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.
488
- Its constructor takes a series of options. `title` and `message` have both getters and public methods to define default values.
489
-
490
- ```js
491
- let error = new ErrorClass(this.missingDoB, {
492
- key: this.missingDob,
493
- type: "required",
494
- redirect: "/missingData",
495
- title: "Something went wrong",
496
- message: "Please supply a valid date of birth",
497
- });
498
- ```
499
-
500
- ##hof-behaviour-session
501
-
502
- HOF Behaviour for reading and writing to the session
503
-
504
- ##Usage
505
-
506
- ###With [mixwith.js](https://github.com/justinfagnani/mixwith.js)
507
-
508
- ```js
509
- const mix = require('mixwith').mix;
510
- const Session = require('./controller/behaviour-session');
511
- const BaseController = require('./controller');
512
-
513
- class MyController extends mix(BaseController).with(Session) {
514
- ...
515
- }
516
- ```
517
-
518
- `MyController` now extends `hof-form-controller` and has `hof-behaviour-session` functionality mixed in.
519
-
520
- ##Functionality
521
-
522
- This mixin extends `hof-form-controller` by persisting the form data to the `sessionModel` - assuming the [session-model](https://github.com/UKHomeOfficeForms/hof-form-wizard/blob/master/lib/middleware/session-model.js) middleware has been applied.
523
-
524
- The following form controller methods are used:
525
-
526
- - `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
527
- - `saveValues(req, res, cb)` - Called on success. Sets all step fields in `req.form.values` to the sessionModel, unsets `errorValues`.
528
- - `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`.
529
- - `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`.
530
- - `locals(req, res)` - Extends the result of `super.locals` with `baseUrl` (`req.baseUrl`) and `nextPage` (the result of `this.getNextStep(req, res)`).
531
- - `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.
532
- - `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.
533
-
534
- ##behaviour-hooks
535
-
536
- HOF Behaviour enabling lifecycle hooks for extending functionality in main form pipeline.
537
-
538
- ##Usage
539
-
540
- ###With [mixwith.js](https://github.com/justinfagnani/mixwith.js)
541
-
542
- ```js
543
- const mix = require('mixwith').mix;
544
- const Hooks = require('./controller/behaviour-hooks');
545
- const BaseController = require('./controller');
546
-
547
- class MyController extends mix(BaseController).with(Hooks) {
548
- ...
549
- }
550
- ```
551
-
552
- `MyController` now extends `hof-form-controller` and has `hof-behaviour-hooks` functionality mixed in.
553
-
554
- ##Functionality
555
-
556
- The following hooks are currently supported, the methods are GET/POST pipeline methods from `hof-form-controller`:
557
-
558
- ####GET
559
-
560
- - `_getErrors` - `'pre-getErrors', 'post-getErrors'`
561
- - `_getValues` - `'pre-getValues', 'post-getValues'`
562
- - `_locals` - `'pre-locals', 'post-locals'`
563
- - `render` - `'pre-render', 'post-render'`
564
-
565
- ####POST
566
-
567
- - `_process` - `'pre-process', 'post-process'`
568
- - `_validate` - `'pre-validate', 'post-validate'`
569
- - `saveValues` - `'pre-saveValues', 'post-saveValues'`
570
- - `successHandler` - `'pre-successHandler', 'post-successHandler'`
571
-
572
- ###In field config
573
-
574
- fields.js
575
-
576
- ```js
577
- module.exports = {
578
- "field-1": {
579
- hooks: {
580
- "post-locals": (req, res, next) => {
581
- Object.assign(res.locals, {
582
- foo: "bar",
583
- });
584
- next();
585
- },
586
- "pre-process": (req, res, next) => {
587
- req.body["field-1"] = req.body["field-1"].toUpperCase();
588
- next();
589
- },
590
- },
591
- },
592
- };
593
- ```
594
-
595
- # HOF Model
596
-
597
- Simple model for interacting with http/rest apis.
598
-
599
- ## Usage
600
-
601
- ```javascript
602
- const Model = require("./model");
603
- ```
604
-
605
- ## Data Storage
606
-
607
- Models can be used as basic data storage with set/get and change events.
608
-
609
- ### Methods
610
-
611
- #### `set`
612
-
613
- Save a property to a model. Properties can be passed as a separate key/value arguments, or with multiple properties as an object.
614
-
615
- ```javascript
616
- const model = new Model();
617
- model.set("key", "value");
618
- model.set({
619
- firstname: "John",
620
- lastname: "Smith",
621
- });
622
- ```
623
-
624
- #### `get`
625
-
626
- Retrieve a property from a model:
627
-
628
- ```javascript
629
- const val = model.get("key");
630
- // val = 'value'
631
- ```
632
-
633
- #### `toJSON`
634
-
635
- Returns a map of all properties on a model:
636
-
637
- ```javascript
638
- const json = model.toJSON();
639
- // json = { key: 'value' }
640
- ```
641
-
642
- ### Events
643
-
644
- `change` is emitted when a property on a model changes
645
-
646
- ```javascript
647
- const model = new Model();
648
- model.on("change", (changedFields) => {
649
- // changedFields contains a map of the key/value pairs which have changed
650
- console.log(changedFields);
651
- });
652
- ```
653
-
654
- `change:<key>` is emitted when a particular property - with a key of `<key>` - on a model changes
655
-
656
- ```javascript
657
- const model = new Model();
658
- model.on("change:name", (newValue, oldValue) => {
659
- // handler is passed the new value and the old value as arguents
660
- });
661
- model.set("name", "John Smith");
662
- ```
663
-
664
- ### Referenced Fields
665
-
666
- A field can be set to a reference to another field by setting it a value of `$ref:<key>` where `<key>` is the field to be reference. The field will then behave exactly like a normal field except that its value will always appear as the value of the referenced field.
667
-
668
- ```javascript
669
- const model = new Model();
670
- model.set("home-address", "1 Main Street");
671
- model.set("contact-address", "$ref:home-address");
672
-
673
- model.get("contact-address"); // => '1 Main Street';
674
- model.set("home-address", "2 Main Street");
675
- model.get("contact-address"); // => '2 Main Street';
676
-
677
- model.toJSON(); // => { home-address: '2 Main Street', 'contact-address': '2 Main Street' }
678
- ```
679
-
680
- Change events will be fired on the referenced field if the underlying value changes.
681
-
682
- ```javascript
683
- const model = new Model();
684
- model.set("home-address", "1 Main Street");
685
- model.set("contact-address", "$ref:home-address");
686
- model.on("change:contact-address", (value, oldValue) => {
687
- // this is fired when home-address property changes
688
- });
689
-
690
- model.set("home-address", "2 Main Street");
691
- ```
692
-
693
- A field can be unreferenced by setting its value to any other value.
694
-
695
- ```javascript
696
- const model = new Model();
697
- model.set("home-address", "1 Main Street");
698
-
699
- // reference the field
700
- model.set("contact-address", "$ref:home-address");
701
-
702
- // unreference the field
703
- model.set("contact-address", "1 Other Road");
704
- ```
705
-
706
- ## API Client
707
-
708
- Normally this would be used as an abstract class and extended with your own implementation.
709
-
710
- Implementations would normally define at least a `url` method to define the target of API calls.
711
-
712
- There are three methods for API interaction corresponding to GET, POST, and DELETE http methods. These methods all return a Promise.
713
-
714
- ### Methods
715
-
716
- #### `fetch`
717
-
718
- ```javascript
719
- const model = new Model();
720
- model.fetch().then((data) => {
721
- console.log(data);
722
- });
723
- ```
724
-
725
- #### `save`
726
-
727
- ```javascript
728
- const model = new Model();
729
- model.set({
730
- property: "properties are sent as JSON request body by default",
731
- });
732
- model.save().then((data) => {
733
- console.log(data);
734
- });
735
- ```
736
-
737
- The method can also be overwritten by passing options
738
-
739
- ```javascript
740
- const model = new Model();
741
- model.set({
742
- property: "this will be sent as a PUT request",
743
- });
744
- model.save({ method: "PUT" }).then((data) => {
745
- console.log(data);
746
- });
747
- ```
748
-
749
- #### `delete`
750
-
751
- ```javascript
752
- const model = new Model();
753
- model.delete().then((data) => {
754
- console.log(data);
755
- });
756
- ```
757
-
758
- ### Options
759
-
760
- If no `url` method is defined then the model will use the options parameter and [Node's url.format method](https://nodejs.org/api/url.html#url_url_format_urlobj) to construct a URL.
761
-
762
- ```javascript
763
- const model = new Model();
764
-
765
- // make a GET request to http://example.com:3000/foo/bar
766
- model
767
- .fetch({
768
- protocol: "http",
769
- hostname: "example.com",
770
- port: 3000,
771
- path: "/foo/bar",
772
- })
773
- .then((data) => {
774
- console.log(data);
775
- });
776
- ```
777
-
778
- ### Events
779
-
780
- API requests will emit events as part of their lifecycle.
781
-
782
- `sync` is emitted when an API request is sent
783
-
784
- ```javascript
785
- model.on("sync", function (settings) {});
786
- ```
787
-
788
- `success` is emitted when an API request successfully completes
789
-
790
- ```javascript
791
- model.on("success", function (data, settings, statusCode, responseTime) {});
792
- ```
793
-
794
- `fail` is emitted when an API request fails
795
-
796
- ```javascript
797
- model.on("fail", function (err, data, settings, statusCode, responseTime) {});
798
- ```
799
-
800
- ### HOF Model APIs
801
-
802
- - `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:
803
-
804
- ```
805
- name: NODE_TLS_REJECT_UNAUTHORIZED
806
- value: "0"
807
- ```
808
-
809
- which should NOT be used as it sets ignoring TLS at a global level which could present a MITM (Man-In-The-Middle) attack.
810
-
811
- 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:
812
-
813
- ```
814
- const PDFModel = require('hof').apis.pdfConverter;
815
-
816
- const pdfModel = new PDFModel();
817
- pdfModel.set({ template: html });
818
- const pdfData = await pdfModel.save();
819
- ```
820
-
821
- # HOF Middleware
822
-
823
- A collection of commonly used HOF middleware, exports `cookies`, `notFound`, `serviceUnavailable` and `errors` on `middleware`
824
-
825
- ## Arranging the middleware in your app
826
-
827
- Cookies middleware should be placed before any other routes, this guarantees that any data gathered in the form will be saved to the session.
828
- The Not Found middleware should be placed after all routes and before the Error handler middleware. This arrangement ensures that if an error is thrown it will be caught.
829
-
830
- ## Cookies
831
-
832
- ### Usage
833
-
834
- ```js
835
- app.use(
836
- require("hof").middleware.cookies({
837
- "cookie-name": "my-application-cookie",
838
- "param-name": "my-query-param",
839
- })
840
- );
841
- ```
842
-
843
- This middleware must be declared before your other routes.
844
-
845
- ### Options
846
-
847
- The `cookie-name` can be the same as your session cookie. (The
848
- middleware will not overwrite it.) Defaults to `hof-cookie-check`.
849
-
850
- The `param-name` should be chosen so that it does not clash with names
851
- you are using elsewhere. In almost all cases the default value of
852
- `hof-cookie-check` will suffice.
853
-
854
- The error raised when cookies are not supported by the client can then
855
- be handled in you error handler by identifying it using its `code`
856
- property which will be set to `NO_COOKIES`.
857
-
858
- You can also provide an array of healthcheck URLs with `healthcheckUrls`,
859
- should you not want to throw a Cookies required error when requesting the app with specific URLs.
860
- Kubernetes healthcheck URLs are provided as defaults if no overrides are supplied.
861
-
862
- ### Cookie Banner Control
863
-
864
- > **Available from version 22.9.1**
865
-
866
- | Variable | Description | Default | Example |
867
- |----------|-------------|---------|---------|
868
- | `SHOW_COOKIES_BANNER` | Controls whether the cookies banner is displayed | Auto-detected based on GA tags | `true`, `false` |
869
-
870
- **Behavior:**
871
- - If `SHOW_COOKIES_BANNER` is explicitly set, that value is used
872
- - If not set, banner is automatically shown when `GA_TAG` or `GA_4_TAG` is present
873
- - If no GA tags are configured, banner is hidden by default
874
-
875
- **Examples:**
876
- ```bash
877
- # Explicitly show banner regardless of GA configuration
878
- SHOW_COOKIES_BANNER=true
879
-
880
- # Hide banner even when GA tags are present
881
- SHOW_COOKIES_BANNER=false
882
- GA_TAG=UA-12345678-1
883
-
884
- # Auto-detect (recommended) - shows banner when GA is configured
885
- GA_TAG=UA-12345678-1 # Banner will show
886
- GA_4_TAG=G-XXXXXXXXXX # Banner will show
887
- # (no GA tags) # Banner will be hidden
888
- ```
889
-
890
- **Note:** If you have a custom layout template that overrides the default HOF layout, you'll need to update it to include the new `showCookiesBanner` logic. Projects that inherit from the default HOF layout template will automatically receive this functionality.
891
-
892
- ## Service Unavailable
893
- Allows a service to be paused when required and then resumed. It ensures that anyone using the service that lands on any part of the form is diverted to a "Service Unavailable" page which will communicate to the user that the service is not available at this time.
894
-
895
- ### Usage
896
- - Set the `SERVICE_UNAVAILABLE` env to `true` in your service.
897
- - Set the`ERROR_REDIRECT_CODES` env to `500 501 502 504` in your service to override the default nginx error page for error `503`.
898
-
899
-
900
- ### Page Content Customisation
901
- There is default text for this page. Default text can be overridden by setting the `message` and `answers-saved` properties in the `errors.json` file of the service. Note that information relating to who to contact and alternatives to using the form is optional and so there is no default text for these unless the properties `contact` and `alternative` are set in errors.json:
902
-
903
- ```json
904
- {
905
- "service-unavailable" : {
906
- "message": "This service will be unavailble for a week.",
907
- "answers-saved": "Your answers have not been saved.",
908
- "contact": "You can contact test@test.com for more information",
909
- "alternative": "You can access the www.test.com website instead"
910
- }
911
- }
912
- ```
913
-
914
- ## Not found (404)
915
-
916
- Expects there to be a view called 404 in your configured `/views` directory
917
-
918
- ### Usage
919
-
920
- ```js
921
- app.use(
922
- require("hof").middleware.notFound({
923
- logger: require("/logger"),
924
- translate: require("hof").i18n({
925
- path: path_to_translations / __lng__ / __ns__.json,
926
- }).translate,
927
- })
928
- );
929
- ```
930
-
931
- This middleware should be declared _after_ your other routes but _before_ your errorhandler.
932
-
933
- ### Options
934
-
935
- `logger` can be any object with a warn method.
936
-
937
- `translate` can be the HOF i18n translate function
938
-
939
- ## Errors
940
-
941
- ### Usage
942
-
943
- ```js
944
- app.use(
945
- require("hof").middleware.errors({
946
- logger: require("/logger"),
947
- translate: require("hof").i18n({
948
- path: path_to_translations / __lng__ / __ns__.json,
949
- }).translate,
950
- debug: true,
951
- })
952
- );
953
- ```
954
-
955
- This middleware must be declared _after_ your other routes.
956
-
957
- ### Options
958
-
959
- `logger` can be any object with an error method.
960
-
961
- `translate` can be the HOF i18n translate function
962
-
963
- `debug` set to true will present the stack trace in the form and return the err as the content of the template.
964
-
965
- # **Note** If `debug === true` translations will not be served, but the error handler default messages
966
-
967
- ## Deep translate
968
-
969
- 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.
970
-
971
- ### Usage
972
-
973
- ```js
974
- const i18nFuture = require("hof").i18n;
975
- const i18n = i18nFuture({
976
- path: path.resolve(__dirname, "./path/to/translations"),
977
- });
978
- app.use(
979
- require("hof").middleware.deepTranslate({
980
- translate: i18n.translate.bind(i18n),
981
- })
982
- );
983
- ```
984
-
985
- locales
986
-
987
- ```json
988
- "fields": {
989
- "field-name": {
990
- "label": {
991
- "dependent-field": {
992
- "value-1": {
993
- "dependent-field-2": {
994
- "value-1": "Label 1",
995
- "value-2": "Label 2"
996
- }
997
- },
998
- "value-2": "Label 3"
999
- },
1000
- "default": "Fallback label"
1001
- }
1002
- }
1003
- }
1004
- ```
1005
-
1006
- 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:
1007
-
1008
- - If both `dependent-field` and `dependent-field-2` have the value `"value-1"`, the label returned will be `"Label 1"`.
1009
- - 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"`.
1010
- - If the value of `dependent-field` is `"value-2"` the label returned will be `"Label 3"` regardless of the value of `dependent-field-2`
1011
- - 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.
1012
-
1013
- # HOF Components
1014
-
1015
- ## Date Component
1016
-
1017
- A component for handling the rendering and processing of 3-input date fields used in HOF Applications.
1018
-
1019
- ### Usage
1020
-
1021
- In your fields config:
1022
-
1023
- ```js
1024
- const dateComponent = require("hof").components.date;
1025
-
1026
- module.exports = {
1027
- "date-field": dateComponent("date-field", {
1028
- validate: ["required", "before"],
1029
- }),
1030
- };
1031
- ```
1032
-
1033
- The above example will create a new date component with the key `'date-field'` and will apply the validators `required` and `before` (before today).
1034
-
1035
- ### Configuration
1036
-
1037
- The following optional configuration options are supported:
1038
-
1039
- - `validate {String|Array}` - validators to use on the processed date field
1040
- - `template` - an absolute path to an alternate template.
1041
- - `dayOptional {Boolean}` - day defaults to `01` if omitted. Defaults to `false`
1042
- - `monthOptional {Boolean}` - month defaults to `01` if omitted. If true then also forces `dayOptional` to be true. Defaults to `false`
1043
-
1044
- ### Labels
1045
-
1046
- 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:
1047
-
1048
- fields.json
1049
-
1050
- ```json
1051
- {
1052
- "field-name": {
1053
- "parts": {
1054
- "day": {
1055
- "label": "Custom Day Label"
1056
- },
1057
- "month": {
1058
- "label": "Custom Month Label"
1059
- },
1060
- "year": {
1061
- "label": "Custom Year Label"
1062
- }
1063
- }
1064
- }
1065
- }
1066
- ```
1067
-
1068
- ## Summary Page Component
1069
-
1070
- HOF behaviour for showing summary pages
1071
-
1072
- The behaviour mixin will create a set of "locals" data which is compatible with [the `confirm` view from `hof-template-partials`](https://github.com/UKHomeOfficeForms/hof-template-partials/blob/master/views/confirm.html).
1073
-
1074
- ### Usage
1075
-
1076
- If no sections config is passed, then the mixin will create a section for each step that has fields, and a row within each section for each field on that step.
1077
-
1078
- ```js
1079
- '/confirm': {
1080
- behaviours: require('hof').components.summary,
1081
- ...
1082
- }
1083
- ```
1084
-
1085
- Alternatively, sections can be defined manually as follows:
1086
-
1087
- ```js
1088
- '/confirm': {
1089
- behaviours: require('hof').components.summary,
1090
- sections: {
1091
- 'museum-details': [
1092
- 'name',
1093
- {
1094
- field: 'exhibit-addresses',
1095
- parse: (value) => value.map(a => a.address),
1096
- step: '/exhibit-add-another-address'
1097
- }
1098
- ],
1099
- 'contact': [
1100
- 'contact-name',
1101
- 'contact-email',
1102
- 'contact-phone',
1103
- {
1104
- field: 'contact-address',
1105
- step: '/contact-address'
1106
- }
1107
- ]
1108
- },
1109
- ...
1110
- }
1111
- ```
1112
-
1113
- ### Configuration
1114
-
1115
- The `sections` configuration should be a map of arrays, where the entries in the array are the fields that should be shown within that section.
1116
-
1117
- #### Field configuration
1118
-
1119
- Fields can be defined as simple strings of the field key, in which case all default configuration will be used.
1120
-
1121
- Alternatively, a field can be passed as an object with a `field` property defining the field key, and any additional properties as follows:
1122
-
1123
- - `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.
1124
- - `parse` - `Function` can parse the value for the field from the session into a value for display.
1125
- - `derivation` - `Object` allows for a new derived field based on a combination of other fields in the form. Note that
1126
- if both `derivation` and `parse` are specified then parse will be applied to the result of derivation. E.G.
1127
- ```javascript
1128
- derivation: {
1129
- fromFields: ['field-one', 'field-two'],
1130
- combiner: (values) => values.map(it => Number(it)).reduce((a, b) => a + b, 0)
1131
- }
1132
- ```
1133
- - `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:
1134
- ![Firearms Use Original Value Summary Page Example](docs/images/firearms_use_original_value_summary.png)
1135
-
1136
- - `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:
1137
-
1138
- ```javascript
1139
- {
1140
- field: 'location-addresses',
1141
- step: '/location-add-another-address',
1142
- multipleRowsFromAggregate: {
1143
- labelCategory: 'address',
1144
- valueCategory: 'address-category',
1145
- // Optional: uses valueCategory name if not specified
1146
- valueTranslation: 'location-address-category'
1147
- }
1148
- }
1149
- ```
1150
-
1151
- 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.
1152
-
1153
- ![Firearms Summary Page Example](docs/images/firearms_summary_page_example.png)
1154
-
1155
- This allows the creation of summary rows based on unknown dynamic user input, i.e. we can not predict in advance how many addresses a user wants to input, what the addresses are and how many categories the user wants to attach to each address. This allows you to easily list them this way.
1156
-
1157
- ### Translations
1158
-
1159
- The content for section headings and field labels will be loaded from translation files based on the keys.
1160
-
1161
- #### Section headings
1162
-
1163
- Translations for section headings are looked for in the following order:
1164
-
1165
- - `pages.confirm.sections.${key}.header`
1166
- - `pages.${key}.header`
1167
-
1168
- #### Field labels
1169
-
1170
- Translations for field labels are looked for in the following order:
1171
-
1172
- - `pages.confirm.fields.${key}.label`
1173
- - `fields.${key}.label`
1174
- - `fields.${key}.legend`
1175
-
1176
- ## Emailer Component
1177
-
1178
- HOF behaviour to send emails
1179
-
1180
- ### Usage
1181
-
1182
- ```js
1183
- const EmailBehaviour = require('hof').components.emailer;
1184
-
1185
- // configure email behaviour
1186
- const emailer = EmailBehaviour({
1187
- transport: 'ses',
1188
- transportOptions: {
1189
- accessKeyId: '...',
1190
- secretAccessKey: '...'
1191
- },
1192
- template: path.resolve(__dirname, './views/emails/confirm.html'),
1193
- from: 'confirmation@homeoffice.gov.uk',
1194
- recipient: 'customer-email',
1195
- subject: 'Application Successful'
1196
- });
1197
-
1198
- // in steps config
1199
- steps: {
1200
- ...
1201
- '/confirm': {
1202
- behaviours: ['complete', emailer],
1203
- next: '/confirmation',
1204
- ...
1205
- },
1206
- ...
1207
- }
1208
- ```
1209
-
1210
- ### Options
1211
-
1212
- In addition to the options passed to `hof-emailer`, the following options can be used:
1213
-
1214
- - `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.
1215
- - `template` - _Required_ - defines the mustache template used to render the email content.
1216
- - `subject` - defines the subject line of the email.
1217
- - `parse` - parses the session model into an object used to populate the template.
1218
-
1219
- `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.
1220
-
1221
- ```js
1222
- // use a translated value for the email subject line
1223
- const emailer = EmailBehaviour({
1224
- // ...
1225
- subject: (model, translate) => translate("email.success.subject"),
1226
- });
1227
- ```
1228
-
1229
- ## HOF Emailer
1230
-
1231
- An emailer service for HOF applications.
1232
-
1233
- ### Installation
1234
-
1235
- ```bash
1236
- $ npm install hof-emailer --save
1237
- ```
1238
-
1239
- ### Usage
1240
-
1241
- ```js
1242
- // first create an emailer instance
1243
- const Emailer = require("hof").components.email.emailer;
1244
- const emailer = new Emailer({
1245
- from: "sender@example.com",
1246
- transport: "smtp",
1247
- transportOptions: {
1248
- host: "my.smtp.host",
1249
- port: 25,
1250
- },
1251
- });
1252
-
1253
- // then you can use your emailer to send emails
1254
- const to = "recipient@example.com";
1255
- const body = "This is the email body";
1256
- const subject = "Important email!";
1257
- emailer.send(to, body, subject).then(() => {
1258
- console.log(`Email sent to ${to}!`);
1259
- });
1260
- ```
1261
-
1262
- ### Options
1263
-
1264
- - `from`: <String>: Address to send emails from. Required.
1265
- - `transport`: <String>: Select what mechanism to use to send emails. Defaults: 'smtp'.
1266
- - `transportOptions`: <Object>: Set the options for the chosen transport, as defined below. Required.
1267
- - `layout`: <String>: Optional path to use a custom layout for email content.
1268
-
1269
- ### Transports
1270
-
1271
- The following transport options are available:
1272
-
1273
- #### `smtp`
1274
-
1275
- [nodemailer](https://github.com/nodemailer/nodemailer)
1276
-
1277
- ##### Options
1278
-
1279
- - `host` <String>: Address of the mailserver. Required.
1280
- - `port` <String|Number>: Port of the mailserver. Required.
1281
- - `ignoreTLS` <Boolean>: Defaults to false.
1282
- - `secure` <Boolean>: Defaults to true.
1283
- - `auth.user` <String>: Mailserver authorisation username.
1284
- - `auth.pass` <String>: Mailserver authorisation password.
1285
-
1286
- #### `ses`
1287
-
1288
- [nodemailer-ses-transport](https://github.com/andris9/nodemailer-ses-transport)
1289
-
1290
- ##### Options
1291
-
1292
- - `accessKeyId` <String>: AWS accessKeyId. Required.
1293
- - `secretAccessKey` <String>: AWS accessKeyId. Required.
1294
- - `sessionToken` <String>
1295
- - `region` <String>. Defaults to 'eu-west-1'.
1296
- - `httpOptions` <String>
1297
- - `rateLimit` <String>
1298
- - `maxConnections` <String>
1299
-
1300
- #### `debug`
1301
-
1302
- A development option to write the html content of the email to a file for inspection.
1303
-
1304
- `transport: 'debug'`
1305
-
1306
- ##### debug options
1307
-
1308
- - `dir` <String>: The location to save html to. Default: `./.emails`. This directory will be created if it does not exist.
1309
- - `open` <Boolean>: If set to true, will automatically open the created html file in a browser.
1310
-
1311
- ##### debug example
1312
-
1313
- ```
1314
- transport: 'debug'
1315
- transportOptions: {
1316
- dir: './emails',
1317
- open: true
1318
- }
1319
- ```
1320
-
1321
- #### `stub`
1322
-
1323
- Disables sending email. No options are required.
1324
-
1325
- ## Session Timeout Warning Component
1326
- HOF component for customising session timeout related pages
1327
- This feature allows you to customise the content related to the session timeout warning, including the messages displayed in the session timeout warning dialog and on the exit page after a user exits the form due to a session timeout.
1328
-
1329
- ### Usage
1330
-
1331
- To enable and customise the session timeout behavior, you need to set the component in your project's `hof.settings.json` file:
1332
- ```js
1333
- "behaviours": [
1334
- "hof/components/session-timeout-warning"
1335
- ]
1336
- ```
1337
-
1338
- By default, the framework uses the standard content provided by HOF. If you wish to override this with custom content at the project level, you must set the following variables to `true` in `hof.settings.json`:
1339
-
1340
- ```js
1341
- behaviours: [
1342
- require('../').components.sessionTimeoutWarning
1343
- ],
1344
- sessionTimeoutWarningContent: true, // allows you to customise the content in the session timeout dialog box
1345
- exitFormContent: true // allows you to customise the content on the exit page
1346
- saveExitFormContent: true // allows you to customise the content on the save-and-exit page
1347
- ```
1348
-
1349
- ### Customising content in `pages.json`
1350
- Once the variables are set, you can customise the session timeout warning and exit messages in your project's pages.json:
1351
-
1352
- ```json
1353
- "exit": {
1354
- "message": "We have cleared your information to keep it secure. Your information has not been saved."
1355
- },
1356
- "session-timeout-warning": {
1357
- "dialog-title": "Your application will close soon",
1358
- "dialog-text": "If that happens, your progress will not be saved.",
1359
- "timeout-continue-button": "Stay on this page",
1360
- "dialog-exit-link": "Exit this form"
1361
- }
1362
- "save-and-exit": {
1363
- "message": "Any answers you saved have not been affected. You can sign back in to your application at any time by returning to the start page."
1364
- },
1365
- ```
1366
-
1367
- ### Editing content on the Exit and Save-and-exit Page Header and Title
1368
- To edit the exit or save-and-exit pages' header and title, create an `exit.json` or `save-and-exit.json` file in your project and set the desired content:
1369
- ```json
1370
- {
1371
- "header": "You have left this form",
1372
- "title": "You have left this form"
1373
- }
1374
- ```
1375
-
1376
- ### Customising exit and save-and-exit steps
1377
- You can customise the `exit` and `save-and-exit` steps by setting the `exitStep` or `saveAndExitStep` properties in the `apps/<app_name>/index.js` to the desired path name:
1378
-
1379
- ```js
1380
- // customising exit step name
1381
- module.exports = {
1382
- name: 'sandbox',
1383
- exitStep: '/leave',
1384
- steps: {
1385
- ...
1386
- '/leave': {
1387
- template: 'exit'
1388
- }
1389
- }
1390
- ...
1391
- }
1392
- ```
1393
-
1394
- ```js
1395
- // customising save-and-exit step name
1396
- module.exports = {
1397
- name: 'sandbox',
1398
- saveAndExitStep: '/sign-out',
1399
- steps: {
1400
- ...
1401
- '/sign-out': {
1402
- template: 'save-and-exit'
1403
- }
1404
- }
1405
- ...
1406
- }
1407
- ```
1408
-
1409
- # UTILITIES
1410
-
1411
- # Autofill Utility
1412
-
1413
- A webdriverio plugin to automate filling a form
1414
-
1415
- ## Usage
1416
-
1417
- First, add the command to your webdriverio client:
1418
-
1419
- ```js
1420
- const webdriver = require("webdriverio");
1421
- const client = webdriver.remote(options);
1422
-
1423
- client.addCommand("goto", require("hof-util-autofill")(client));
1424
- ```
1425
-
1426
- The command can be given any name you like, here we've called it `goto`.
1427
-
1428
- Then you can use the command as normal as part of your webdriver command chain.
1429
-
1430
- ```js
1431
- it("completes a form to a certain step automatically", () => {
1432
- return browser
1433
- .goto("/confirm")
1434
- .getUrl()
1435
- .then((url) => {
1436
- assert.ok(url.indexOf("/confirm") > -1);
1437
- });
1438
- });
1439
-
1440
- it("uses any data passed as a second argument to fill out the form", () => {
1441
- const inputs = { "first-name": "David", "last-name": "Hasselhoff" };
1442
- return browser
1443
- .goto("/confirm", inputs)
1444
- .$("span.full-name")
1445
- .getText()
1446
- .then((name) => {
1447
- assert.equal(name, "David HasselHoff");
1448
- });
1449
- });
1450
-
1451
- it("saves screenshots of errors to specified screenshot location", () => {
1452
- const inputs = {};
1453
- return browser.goto("/confirm", inputs, {
1454
- screenshots: "/path/to/output/dir",
1455
- });
1456
- });
1457
-
1458
- it("tries a pre-specified number of times to get past stuck loops", () => {
1459
- const inputs = {};
1460
- return browser.goto("/confirm", inputs, { maxLoops: 1 });
1461
- });
1462
- ```
1463
-
1464
- ## Options
1465
-
1466
- Options are passed as a third argument to the exposed method. The following options are available:
1467
-
1468
- - `maxLoops` - determines how many times a step will retry if it resolves back to itself on submission before failing. Default: `3`
1469
- - `screenshots` - specifies a location to save screenshots of the page when it gets stuck. If not specified then no screenshots are saved.
1470
-
1471
- # Test-Data Utility
1472
-
1473
- Generator for test fixtures
1474
-
1475
- ## Usage
1476
-
1477
- The library contains a number of generators for values of certain types. Values are generators on accessing the type property.
1478
-
1479
- ### Example:
1480
-
1481
- ```js
1482
- const TestData = require("hof").utils.testData;
1483
-
1484
- console.log(TestData.name);
1485
- // "David Fletcher"
1486
-
1487
- console.log(TestData.name);
1488
- // "Irene O'Grady"
1489
- ```
1490
-
1491
- ## Available generators
1492
-
1493
- - `firstname`
1494
- - `lastname`
1495
- - `name`
1496
- - `email`
1497
- - `phone`
1498
- - `streetname`
1499
- - `streetsuffix`
1500
- - `address` - `${number(1,100)} ${streetname} ${streetsuffix}`
1501
- - `postcode`
1502
- - `country` - a random country from [homeoffice-countries](npmjs.com/homeoffice-countries)
1503
-
1504
- ## Functions
1505
-
1506
- - `number(min, max)` - returns an integer between `min` and `max`
1507
- - `number(max)` - returns an integer between 0 and `max`
1508
- - `number()` - returns an integer between 0 and 100
1509
-
1510
- # Countries Utility
1511
-
1512
- A utility to parse `homeoffice-countries` into a usable format for hof select elements
1513
-
1514
- By default hof select elements expect a list of options as an objet with `value` and `label` properties. If passed an array of strings as options it will attempt to translate the strings with some field-specific keys attached.
1515
-
1516
- ## Usage
1517
-
1518
- In field configuration:
1519
-
1520
- ```js
1521
- {
1522
- country: {
1523
- mixin: 'select',
1524
- validate: 'required',
1525
- options: require('hof').utils.countries()
1526
- }
1527
- }
1528
- ```
1529
-
1530
- ## Options
1531
-
1532
- If needed, the following options can be passed into the countries function:
1533
-
1534
- - `filter` - `Function` - applies a filter to the list of country names before mapping them
1535
- - `parse` - `Function` - applies a transform to the country name before setting the label
1536
-
1537
- ## i18n
1538
-
1539
- 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:
1540
-
1541
- ```js
1542
- const countries = require("hof").utils.countries;
1543
- const options = countries({
1544
- parse: (country) => `countries.${country.toLowerCase().split(" ").join("-")}`,
1545
- });
1546
- ```
1547
-
1548
- You can then define a single translation for country names to be used for all country list instances.
1549
-
1550
- # FRONTEND
1551
-
1552
- ## Template Mixins
1553
-
1554
- A middleware that exposes a series of Mustache mixins on `res.locals` to ease usage of forms, translations, and some other things.
1555
-
1556
- ## Installation
1557
-
1558
- ```javascript
1559
- npm install [--save] hof-template-mixins;
1560
- ```
1561
-
1562
- ## Usage
1563
-
1564
- ```javascript
1565
- var express = require("express");
1566
-
1567
- var i18n = require("i18n-future");
1568
- var mixins = require("hof").frontend.mixins;
1569
-
1570
- app.set("view engine", "html");
1571
- app.set("views", path.join(__dirname, "/views"));
1572
-
1573
- app.use(i18n.middleware());
1574
- app.use(mixins());
1575
-
1576
- app.use(function (req, res) {
1577
- // NOTE: res.locals.partials has been set.
1578
- res.render("example-template");
1579
- });
1580
- ```
1581
-
1582
- If rendering as part of a hof controller's middleware chain then the field configuration will automatically be set to `res.locals.options.fields` by the controller, and will be loaded from here by the mixins.
1583
-
1584
- Alternatively, if not using hof controllers, you can explicitly set field configuration with instantiating the middleware by passing a `fields` option. This should not be used for dynamic field configuration.
1585
-
1586
- ## Translation
1587
-
1588
- By default any function set to `req.translate` will be used for translation if it exists. For example, that generated using [i18n-future](https://npmjs.com/package/i18n-future) middleware.
1589
-
1590
- ## Options
1591
-
1592
- ### viewsDirectory
1593
-
1594
- Allows you override the directory that the module checks for partials in - Default: the root of this project
1595
-
1596
- ### viewEngine
1597
-
1598
- Allows you to alter the file extension of the templates - Default: 'html'
1599
-
1600
- ### sharedTranslationsKey
1601
-
1602
- Prefixes keys for translation - Default: ''
1603
-
1604
- ### translate
1605
-
1606
- Defines a custom translation method - Default: `req.translate`
1607
-
1608
- ### fields
1609
-
1610
- Allows for manually setting static field configuration - Default: null
1611
-
1612
- ## Mustache mixins available
1613
-
1614
- ```
1615
- t
1616
- time
1617
- selected
1618
- lowercase
1619
- uppercase
1620
- hyphenate
1621
- date
1622
- currency
1623
- select
1624
- input-text
1625
- input-date
1626
- input-text-compound
1627
- input-text-code
1628
- input-number
1629
- input-phone
1630
- radio-group
1631
- checkbox
1632
- checkbox-compound
1633
- checkbox-required
1634
- checkbox-group
1635
- input-submit
1636
- textarea
1637
- qs
1638
- renderField
1639
- ```
1640
-
1641
- ### qs
1642
-
1643
- 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
1644
-
1645
- ```html
1646
- <a href="{{#qs}}key=value{{/qs}}">Click to append query</a>
1647
- ```
1648
-
1649
- ### renderField
1650
-
1651
- 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.
1652
-
1653
- ```html
1654
- {{#fields}} {{#renderField}}{{/renderField}} {{/fields}}
1655
- ```
1656
-
1657
- fields.js
1658
-
1659
- ```js
1660
- module.exports = {
1661
- "my-field": {
1662
- mixin: "input-text",
1663
- },
1664
- };
1665
- ```
1666
-
1667
- If mixin is omitted `input-text` will be used
1668
-
1669
- 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.
1670
-
1671
- ### Render a single field
1672
-
1673
- To render a specific fields in your templates use the mixin name (matching those above) and field name like so...
1674
-
1675
- ```html
1676
- {{#input-text}}myTextField{{/input-text}} {{#select}}mySelectMenu{{/select}}
1677
- {{#radio-group}}myRadioGroup{{/radio-group}}
1678
- ```
1679
-
1680
- ## Options
1681
-
1682
- - `className`: A string or array of string class names.
1683
- - `label`: The intended value of the HTML `label` attribute.
1684
- - `type`: The value of the HTML input `type` attribute.
1685
- - `required`: Value applied to `aria-required` HTML attribute.
1686
- - `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.
1687
- - `maxlength`: Applicable to text-based fields and mapped to the `maxlength` HTML attribute.
1688
- - `maxlengthAttribute`: Applicable to text-based fields. When maxlengthAttribute is set to true, it activates conditional rendering for the maxlength HTML attribute.
1689
- - `maxword`: Applicable to textarea fields.
1690
- - `options`: Applicable to HTML `select` and `radio` controls and used to generate the items of either HTML element.
1691
- - `selected`: Applicable to `select`, `checkbox`, and `radio` controls. Will render the selected HTML option/element selected or checked.
1692
- - `legend`: Applicable to `radio` button controls, which are wrapped in a HTML `fieldset` with a `legend` element.
1693
- - `legendClassName`: Applied as a class name to HTML `legend` attribute.
1694
- - `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.
1695
- - `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"`.
1696
- - `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.
1697
- - `isPageHeading`: Applicable to `checkbox` and `radio`, `text input` and `textarea` controls. Sets the legend as the page heading on single page questions.
1698
- - `isWarning`: Applicable to `checkbox` and `radio` controls. Allows warning text to be placed after page headings on single page questions if required.
1699
-
1700
- # HOF-template-partials
1701
-
1702
- 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.
1703
-
1704
- ## Usage
1705
-
1706
- ### Template partials
1707
-
1708
- #### Standalone
1709
-
1710
- 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.
1711
-
1712
- ```js
1713
- var app = require("express")();
1714
-
1715
- app.set("view engine", "html");
1716
- app.set("views", [
1717
- // your application shared views
1718
- path.resolve(__dirname, "./path/to/views"),
1719
- // the module exports paths to views and translations directories
1720
- require("hof").frontend.partials.views,
1721
- ]);
1722
- ```
1723
-
1724
- The views are now available when calling `res.render('view-name')` from express.
1725
-
1726
- #### HOF Application
1727
-
1728
- 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.
1729
-
1730
- ```js
1731
- var app = require("express")();
1732
-
1733
- app.set("view engine", "html");
1734
- app.set("views", [
1735
- path.resolve(__dirname, "./path/to/views"),
1736
- require("hof").frontend.partials.views,
1737
- ]);
1738
- app.use(require("express-partial-templates")(app));
1739
-
1740
- app.use(function (req, res, next) {
1741
- // res.locals.partials contains all views from the views dir in this repo
1742
- // which are extended by any local views in ./path/to/views
1743
- next();
1744
- });
1745
- ```
1746
-
1747
- ### Translations
1748
-
1749
- The provided translations are designed to be used in conjunction with a translations library such as [i18n-future](https://github.com/lennym/i18n-future).
1750
-
1751
- 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.
1752
-
1753
- ```js
1754
- const translate = require("i18n-future").middleware({
1755
- resources: require("hof").frontend.partials.resources(),
1756
- });
1757
- app.use(translate);
1758
- ```
1759
-
1760
- 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.
1761
-
1762
- ```js
1763
- const translate = require("i18n-future").middleware({
1764
- resources: require("hof").frontend.partials.resources("hof-common"),
1765
- fallbackNamespace: "hof-common",
1766
- });
1767
- app.use(translate);
1768
- ```
1769
-
1770
- ### Cookie Banner
1771
-
1772
- 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.
1773
-
1774
- Set `appName` if your hof settings being passed to hof to take advantage of this.
1775
-
1776
- # HOF FRONTEND THEME
1777
-
1778
- ## Usage
1779
-
1780
- If you are using `hof-build` to build assets then you can add the following to your applications sass file.
1781
-
1782
- ```
1783
- @import "$$theme";
1784
- ```
1785
-
1786
- Otherwise add:
1787
-
1788
- ```
1789
- @import "hof/frontend/themes/gov-uk/styles/govuk";
1790
- ```
1791
-
1792
- ## Configuration
1793
-
1794
- By default the compiled sass will attempt to load referenced images from `/public/images`. To override this, add the following to the top of your sass file (noting trailing slash):
1795
-
1796
- ```
1797
- $path: "/path/to/your/images/";
1798
- ```
1799
-
1800
- # HOF FRONTEND GOVUK-TEMPLATE
1801
-
1802
- Compiles govuk mustache template into a more usable format and provide middleware for use in apps.
1803
-
1804
- Existing [govuk mustache template](https://www.npmjs.com/package/govuk_template_mustache) has simple mustache placeholders for content sections, which necessitates a two step compile process where sections are compiled individually and then again into the parent template.
1805
-
1806
- Compiling the template to replace these placeholders with variables allows for templates to implement the govuk template as a parent partial.
1807
-
1808
- ## Example
1809
-
1810
- ```
1811
- {{< govuk-template}}
1812
-
1813
- {{$main}}
1814
- <h1>Page Content</h1>
1815
- {{/main}}
1816
-
1817
- {{/ govuk-template}}
1818
- ```
1819
-
1820
- ## Usage
1821
-
1822
- When used as part of an express app, a middleware is returned which will add a static fileserver (using [serve-static](https://www.npmjs.com/package/serve-static)) to serve the template assets without needing to copy them to any other location.
1823
-
1824
- It will also add the template as a mustache partial with a name of "govuk-template".
1825
-
1826
- ### To configure express middleware
1827
-
1828
- ```
1829
- app.use(require('hof').frontend.govUKTemplate([options]);
1830
- ```
1831
-
1832
- ### To use the mustache partial
1833
-
1834
- ```
1835
- {{< govuk-template}}
1836
- {{$pageTitle}}An example page{{/pageTitle}}
1837
- {{$main}}
1838
- <h1>Page Content</h1>
1839
- {{/main}}
1840
- {{/ govuk-template}}
1841
- ```
1842
-
1843
- ## Options
1844
-
1845
- A number of options can be passed with the app into the setup method:
1846
-
1847
- - `path` - Sets the base path for the location of static assets - Default: `/govuk-assets`
1848
-
1849
- 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)
1850
-
1851
- # Nonce values
1852
-
1853
- Version 18.0.0 and above of HOF provides and requires a nonce value for all inline javascript, as unsafe-inline is disabled.
1854
- 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
1855
- if a nonce value is provided by the version of HOF.
1856
-
1857
- ## Example
1858
-
1859
- There is an example implementation in [demo application](https://github.com/UKHomeOffice/home-office-forms-demo).
1860
-
1861
- ## Sandbox
1862
-
1863
- There is a sandbox application for developers to test components directly in hof called [sandbox](/sandbox)
1864
-
1865
- # HOF FRONTEND TOOLKIT
1866
-
1867
- Set of common UI patterns/styles for HOF projects
1868
-
1869
- ## Images
1870
-
1871
- 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.
1872
-
1873
- ## Vendor JavaScript
1874
-
1875
- Additional vendor JavaScript files are included. These are:
1876
-
1877
- - details.polyfill.js
1878
- - indexof.polyfill.js
1879
- - safari-cachebuster.js
1880
-
1881
- Copy `assets/javascript/vendor` into your javascript directory (ie `hmpo/vendor`) and compile them with your JavaScript.
1882
-
1883
- ## Journey Header Navigation.html page
1884
-
1885
- - Navigation.html contains a journeyHeaderURL, which is set in the controller.
1886
- - getJourneyHeaderURL within the controller translates an empty baseURL to '/'.
1887
- - The above helps fix broken journey header URLs in the GRO and UKVIC services which both have a baseURL's set to '/'.