hof 23.0.0-vite-sourcemap-beta → 23.0.0
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.
- package/CHANGELOG.md +24 -0
- package/README.md +97 -6
- package/build/tasks/vite/index.js +4 -1
- package/build/tasks/vite/vite.config.js +1 -4
- package/components/amount-with-unit-select/fields.js +15 -0
- package/components/amount-with-unit-select/hooks.js +168 -0
- package/components/amount-with-unit-select/index.js +107 -0
- package/components/amount-with-unit-select/templates/amount-with-unit-select.html +20 -0
- package/components/amount-with-unit-select/utils.js +197 -0
- package/components/amount-with-unit-select/validation.js +175 -0
- package/components/index.js +1 -0
- package/controller/controller.js +5 -3
- package/controller/validation/index.js +1 -1
- package/controller/validation/validators.js +0 -1
- package/frontend/template-mixins/mixins/template-mixins.js +55 -5
- package/frontend/template-mixins/partials/forms/grouped-inputs-select.html +13 -0
- package/frontend/template-mixins/partials/forms/grouped-inputs-text.html +37 -0
- package/frontend/themes/gov-uk/styles/_grouped-input.scss +5 -0
- package/frontend/themes/gov-uk/styles/govuk.scss +1 -0
- package/frontend/toolkit/assets/javascript/form-focus.js +4 -0
- package/package.json +8 -3
- package/sandbox/apps/sandbox/fields.js +18 -1
- package/sandbox/apps/sandbox/index.js +4 -0
- package/sandbox/apps/sandbox/sections/summary-data-sections.js +7 -1
- package/sandbox/apps/sandbox/translations/en/default.json +33 -0
- package/sandbox/apps/sandbox/translations/src/en/fields.json +10 -0
- package/sandbox/apps/sandbox/translations/src/en/pages.json +3 -0
- package/sandbox/apps/sandbox/translations/src/en/validation.json +12 -0
- package/sandbox/public/assets/index-CsI1K_CH.js +60 -0
- package/sandbox/public/css/app.css +7 -3
- package/sandbox/public/js/bundle.js +1 -1
- package/sandbox/public/js/bundle.js.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,30 @@
|
|
|
9
9
|
- Updated engine requirements to use node to `>=20.19.0`
|
|
10
10
|
- Vite uses Rollup in production and requires optional rollup dependencies to be loaded. Setting `--ignore-optional flag` in Dockerfiles will result in "Module not found" errors in CI/CD or Docker.
|
|
11
11
|
|
|
12
|
+
## 2026-02-23, Version 22.14.1 (Stable), @vivekkumar-ho
|
|
13
|
+
|
|
14
|
+
### Security
|
|
15
|
+
|
|
16
|
+
- Upgraded Jest to address a security issue: uncontrolled resource consumption in `braces`.
|
|
17
|
+
- Previous dependency chain (via transitive deps) could pin `braces` to `2.3.2` (from `jest@26.6.3` → `micromatch@3.1.10` → `braces@^2.3.1`), while the earliest fixed `braces` version is `3.0.3`.
|
|
18
|
+
- Jest upgrade updates the transitive dependency chain so `braces` can be resolved to a fixed version (`>= 3.0.3`).
|
|
19
|
+
- Updates patch and minor dependency versions
|
|
20
|
+
|
|
21
|
+
## 2026-01-27, v22.14.0 (Stable), @rayhannurrohmanho
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- Created the amountWithUnitSelect component.
|
|
25
|
+
- Separated the amountWithUnitSelect component logic into into hooks, utils, and validators - all documented via JSDoc.
|
|
26
|
+
- Created templates and partials for the amountWithUnitSelect component.
|
|
27
|
+
- Configured template mixin for amountWithUnitSelect component.
|
|
28
|
+
- Added sandbox example for the amountWithUnitSelect component.
|
|
29
|
+
- Documented the amountWithUnitSelect component in readme.
|
|
30
|
+
- Added tests for the amountWithUnitSelect components.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- Added optional parent key ('pKey') parameter to the template-mixins.js 'optionGroup' function to allow the assignment of a group component's parent's properties.
|
|
34
|
+
- Modified validation to check if a "groupedFieldsWithOptions" property exists (and is set to true) for a component with "options" before the "equals" validator is applied to the component.
|
|
35
|
+
|
|
12
36
|
## 2025-12-09, Version 22.13.0 (Stable), @Rhodine-orleans-lindsay
|
|
13
37
|
### Changed
|
|
14
38
|
- Updated cookie banner view to follow GOV.UK design system. Updated cookieSettings.js to allow for different confirmation text based on whether cookies were accepted or rejected
|
package/README.md
CHANGED
|
@@ -60,7 +60,8 @@ It is recommended to alias `hof-build` to an npm script in your package.json.
|
|
|
60
60
|
|
|
61
61
|
## Tasks
|
|
62
62
|
|
|
63
|
-
- `vite` - compiles client-side js with vite
|
|
63
|
+
- `vite` - compiles client-side js with vite.
|
|
64
|
+
Requires node version `^20.19.0 || >=22.12.0`.
|
|
64
65
|
- `sass` - compiles sass
|
|
65
66
|
- `images` - copies images from ./assets/images directory to ./public/images
|
|
66
67
|
- `translate` - compiles translation files
|
|
@@ -69,18 +70,21 @@ Note: For SASS compilation it's possible to additionally configure the following
|
|
|
69
70
|
- `outputStyle` - Controls whether the CSS output is compressed or not, expanded (default) = non compressed and compressed = compressed CSS output.
|
|
70
71
|
- `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
72
|
- `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
|
-
|
|
74
|
-
|
|
73
|
+
|
|
74
|
+
Vite outputs JavaScript sourcemaps as a .js.map file to the same directory as the js bundle.
|
|
75
|
+
|
|
76
|
+
Debugging example (in hof.settings or your build config)
|
|
77
|
+
```js
|
|
75
78
|
"build": {
|
|
76
79
|
"sass": {
|
|
77
80
|
"sourceMaps": true
|
|
78
81
|
},
|
|
79
|
-
|
|
82
|
+
"js": {
|
|
80
83
|
"sourceMaps": true
|
|
81
|
-
}
|
|
84
|
+
}
|
|
82
85
|
}
|
|
83
86
|
```
|
|
87
|
+
|
|
84
88
|
## Watch
|
|
85
89
|
|
|
86
90
|
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.
|
|
@@ -115,6 +119,13 @@ Alternatively you can define a path to a local config file by passing a `--confi
|
|
|
115
119
|
```
|
|
116
120
|
hof-build --config /path/to/my/config.js
|
|
117
121
|
```
|
|
122
|
+
Any task can be disabled by setting its configuration to `false` (or any falsy value).
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
module.exports = {
|
|
126
|
+
sass: false,
|
|
127
|
+
};
|
|
128
|
+
```
|
|
118
129
|
|
|
119
130
|
### Configuration options
|
|
120
131
|
|
|
@@ -1001,6 +1012,85 @@ Using the translation key `fields.field-name.label` will return different values
|
|
|
1001
1012
|
|
|
1002
1013
|
# HOF Components
|
|
1003
1014
|
|
|
1015
|
+
## AmountWithUnitSelect Component
|
|
1016
|
+
|
|
1017
|
+
> **Available from version 22.14.0**
|
|
1018
|
+
|
|
1019
|
+
A component for handling the rendering, processing, and validation of a text input (amount) field and a select-dropdown input field (unit) used in HOF applications.
|
|
1020
|
+
|
|
1021
|
+
### Usage
|
|
1022
|
+
|
|
1023
|
+
In your fields config:
|
|
1024
|
+
|
|
1025
|
+
```js
|
|
1026
|
+
const amountWithUnitSelectComponent = require("hof").components.amountWithUnitSelect;
|
|
1027
|
+
|
|
1028
|
+
module.exports = {
|
|
1029
|
+
"amountWithUnitSelect-field": amountWithUnitSelectComponent("amountWithUnitSelect", {
|
|
1030
|
+
mixin: 'input-amount-with-unit-select',
|
|
1031
|
+
amountLabel: "Amount:", // If not specified, defaults to 'Amount'
|
|
1032
|
+
unitLabel: "Unit:", // If not specified, defaults to 'Unit'
|
|
1033
|
+
options: [
|
|
1034
|
+
{ "null": "Select..." }, // If a null option is not specified, a default null option with the label 'Select...' is included in the options
|
|
1035
|
+
{ "label": "untranslated option label 1", "value": "1" },
|
|
1036
|
+
{ "label": "untranslated option label 2", "value": "2" }
|
|
1037
|
+
],
|
|
1038
|
+
hint: "E.g: 5 Kilogram",
|
|
1039
|
+
legend: 'Enter An Amount',
|
|
1040
|
+
isPageHeading: 'true',
|
|
1041
|
+
amountOptional: 'false', // If not specified, defaults to false if the required validator is not applied, otherwise true
|
|
1042
|
+
unitOptional: 'true', // If not specified, defaults to false if the required validator is not applied, otherwise true
|
|
1043
|
+
validate: ['alphanum']
|
|
1044
|
+
}),
|
|
1045
|
+
};
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
The above example will create a new AmountWithUnitSelect component with the key `'amountWithUnitSelect-field'`.
|
|
1049
|
+
It will set the AmountWithUnitSelect component's text input label to `'Amount:'` (instead of the default `'Amount'`) and the select input label to `'Unit:'` (instead of the default `'Unit'`).
|
|
1050
|
+
The component's Select input will have the dropdown options `'Select...'` (mapping to the value `'null'`), `'untranslated option label 1'` (mapping to the value `'1'`), and `'untranslated option label 2'` (mapping to the value `'2'`).
|
|
1051
|
+
The component's hint text will be set to `'E.G: 5 Kilogram'`, the field title/legend will be set to `'Enter An Amount'`, and the page heading will be the field's title.
|
|
1052
|
+
In terms of validation, the text input (amount) will have the `'required'` validator applied, but the select input (unit) will not (a value will not be required to be selected), and the text field will have the `'alphanum'` validator applied.
|
|
1053
|
+
|
|
1054
|
+
### Configuration
|
|
1055
|
+
|
|
1056
|
+
The following optional configuration options are supported:
|
|
1057
|
+
|
|
1058
|
+
- `validate {String|Array}` – Validators to use on the text input field. The `'alphanum'` and `'required'` validators are likely to be used.
|
|
1059
|
+
- `template` – An absolute path to an alternate template.
|
|
1060
|
+
- `amountLabel {String}` – A custom label for the text input field (amount). Defaults to `'Amount'` if omitted. This can also be specified and defined in the field translations.
|
|
1061
|
+
- `unitLabel {String}` – A custom label for the select input field (unit). Defaults to `'Unit'` if omitted. This can also be specified and defined in the field translations.
|
|
1062
|
+
- `options {Array}` – A list of labels and corresponding values (options) for the select input field to present. Each option has the format `{ "label": "", "value": ""}`. The default/null option is defined with the format `{ "null": "Select" }` (where the text `'Select'` is the label and can be modified). If the null option is not defined, a default null option will be included in the options with the label `'Select...'`. This can also be specified and defined in the field translations.
|
|
1063
|
+
- `hint {String}` – Hint text displayed for both fields. This can also be specified and defined in the field translations.
|
|
1064
|
+
- `legend {String}` – Legend text displayed for both fields. This can also be specified and defined in the field translations.
|
|
1065
|
+
- `isPageHeading {Boolean}` – Sets the legend as the page heading on single-page questions.
|
|
1066
|
+
- `amountOptional {Boolean}` – The text input (amount) defaults to `''` (empty string) if omitted. Defaults to `false`. If the `'required'` validator is defined in the `validate` configuration option, then this configuration is ignored (both fields are made mandatory).
|
|
1067
|
+
- `unitOptional {Boolean}` – The select input (unit) defaults to `null` if omitted. Defaults to `false`. If the `'required'` validator is defined in the `validate` configuration option, then this configuration is ignored (both fields are made mandatory).
|
|
1068
|
+
|
|
1069
|
+
### Validation Error Messages
|
|
1070
|
+
|
|
1071
|
+
In Validation.json (within the translations):
|
|
1072
|
+
|
|
1073
|
+
```js
|
|
1074
|
+
"amountWithUnitSelect": {
|
|
1075
|
+
"default": "Enter the amount in the correct format; for example, 10 Litres",
|
|
1076
|
+
"alphanum": "The amount must not contain any special characters",
|
|
1077
|
+
"required": "Enter an amount and a unit value"
|
|
1078
|
+
},
|
|
1079
|
+
"amountWithUnitSelect-unit": {
|
|
1080
|
+
"default": "A valid value must be selected as the amount unit",
|
|
1081
|
+
"required": "A unit must be selected for the amount"
|
|
1082
|
+
},
|
|
1083
|
+
"amountWithUnitSelect-amount": {
|
|
1084
|
+
"alphanum": "The amount must not be an alphanum"
|
|
1085
|
+
}
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
Validation error messages can be defined for a specific child component that errored by adding a JSON object with a key that has the component's name (I.E. `'amountWithUnitSelect'`) followed by a hyphen and the child component's name (I.E. '-amount' or '-unit'). So to define an error message, for the `'required'` validation error, for specifically the unit component, an `'amountWithUnitSelect-unit'` object can be created (like in the example above) with a validator's name and the error message to show for it respectively, set as a key:value pair in the object (E.G. `"required": "A unit must be selected for the amount" within "amountWithUnitSelect-unit"` - like in the example).
|
|
1089
|
+
Validation error messages defined specifically for child components, for a given type of validation error, (such as `'required'` for `'amountWithUnitSelect-unit'`) will take precedence over error messages defined for the same validation error in the parent. So in this case, the `"required": "Enter an amount and a unit value"` validation message defined in the `"amountWithUnitSelect"` JSON object in the above example will not show when the `"amountWithUnitSelect-unit"` `'required'` validation error message is defined. If there was no `'required'` error message defined for, say, the `"amountWithUnitSelect-amount"` object (like in the example above), the `"amountWithUnitSelect"` object's `'required'` error message would show if the `'required'` validation error is triggered on the 'amount' child component (I.E. When an amount value is not provided).
|
|
1090
|
+
The `'default'` catch all validation error message can also be defined in a similar manner for the child components to override the parent component's defined `'default'` error message.
|
|
1091
|
+
|
|
1092
|
+
So the example above will create a scenario where `'required'` validation errors triggered on the 'unit' field will display the error message `"A unit must be selected for the amount"` (specified in the `"amountWithUnitSelect-unit"` JSON object). Any `'required'` validation errors triggered on the 'amount' field will display the error message `"Enter an amount and a unit value"` (specified in the `"amountWithUnitSelect"` JSON object - as there is no `'required'` error message defined specifically for the 'amount' field (withing `"amountWithUnitSelect-amount"`)).
|
|
1093
|
+
|
|
1004
1094
|
## Date Component
|
|
1005
1095
|
|
|
1006
1096
|
A component for handling the rendering and processing of 3-input date fields used in HOF Applications.
|
|
@@ -1632,6 +1722,7 @@ currency
|
|
|
1632
1722
|
select
|
|
1633
1723
|
input-text
|
|
1634
1724
|
input-date
|
|
1725
|
+
input-amount-with-unit-select
|
|
1635
1726
|
input-text-compound
|
|
1636
1727
|
input-text-code
|
|
1637
1728
|
input-number
|
|
@@ -6,7 +6,6 @@ import { resolve } from 'path';
|
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
8
8
|
import commonjs from '@rollup/plugin-commonjs';
|
|
9
|
-
import config from '../../../config/builder-defaults';
|
|
10
9
|
|
|
11
10
|
const publicDirectory = resolve(process.cwd(), 'public');
|
|
12
11
|
const entryFile = (() => {
|
|
@@ -16,7 +15,6 @@ const entryFile = (() => {
|
|
|
16
15
|
throw new Error(`vite: entry file not found. Checked: ${src}`);
|
|
17
16
|
})();
|
|
18
17
|
|
|
19
|
-
|
|
20
18
|
export default defineConfig({
|
|
21
19
|
plugins: [
|
|
22
20
|
commonjs({
|
|
@@ -53,7 +51,7 @@ export default defineConfig({
|
|
|
53
51
|
build: {
|
|
54
52
|
outDir: publicDirectory,
|
|
55
53
|
emptyOutDir: false,
|
|
56
|
-
sourcemap:
|
|
54
|
+
sourcemap: false,
|
|
57
55
|
rollupOptions: {
|
|
58
56
|
input: {
|
|
59
57
|
index: entryFile
|
|
@@ -71,7 +69,6 @@ export default defineConfig({
|
|
|
71
69
|
}
|
|
72
70
|
},
|
|
73
71
|
css: {
|
|
74
|
-
// devSourcemap: isDev,
|
|
75
72
|
preprocessorOptions: {
|
|
76
73
|
scss: {
|
|
77
74
|
includes: ['node_modules']
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const utils = require('./utils');
|
|
5
|
+
const validation = require('./validation');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pre-process hook. This function:
|
|
9
|
+
* - Splits the amountWithUnitSelect value into its parts (amount and unit in the format [Amount]-[Unit],
|
|
10
|
+
* E.G. 5-Kilograms) and assigns them to the request body (req.body).
|
|
11
|
+
* @param {Object} req - The form's request object.
|
|
12
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
13
|
+
* @param {string} key - The parent component's key.
|
|
14
|
+
*/
|
|
15
|
+
const preProcess = (req, fields, key) => {
|
|
16
|
+
const parts = utils.getParts(req.body, fields, key);
|
|
17
|
+
if (_.some(parts, part => part !== '')) {
|
|
18
|
+
req.body[key] = `${(parts.amount || '')}-${(parts.unit || '')}`;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Post-process hook. This function:
|
|
24
|
+
* - Copies the field value from the request body (req.body) to the form values (req.form.values)
|
|
25
|
+
* if a reference to the field exists in the form values.
|
|
26
|
+
* @param {Object} req - The form's request object.
|
|
27
|
+
* @param {string} key - The parent component's key.
|
|
28
|
+
*/
|
|
29
|
+
const postProcess = (req, key) => {
|
|
30
|
+
if (req.form.values[key]) {
|
|
31
|
+
req.form.values[key] = req.body[key];
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Pre-validate hook. This function:
|
|
37
|
+
* - Prevents default select component assignment of 'equal' validator to the parent component.
|
|
38
|
+
* - Resolves required validators and optional configurations for child components.
|
|
39
|
+
* - Propagates child component field data and values to the request to enable their validation.
|
|
40
|
+
* - Adds a custom 'equal' validator to the unit child component.
|
|
41
|
+
* - Adds a custom 'twoHyphenSeparatedValues' validator to the parent component to validate value format.
|
|
42
|
+
* - Moves excess validators that do not apply to the parent component to the 'amount' child component.
|
|
43
|
+
* @param {Object} req - The form's request object.
|
|
44
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
45
|
+
* @param {string} key - The parent component's key.
|
|
46
|
+
* @param {Object} options - The component's configuration options.
|
|
47
|
+
*/
|
|
48
|
+
const preValidate = (req, fields, key, options) => {
|
|
49
|
+
// Prevents auto assignment of 'equal' validator to parent component
|
|
50
|
+
validation.addGroupedFieldsWithOptionsProperty(req.form.options.fields[key]);
|
|
51
|
+
// resolves required validators and optional configurations for child components
|
|
52
|
+
validation.resolveOptionalFields(req.form.options.fields, fields, options.validate, key);
|
|
53
|
+
// propagates child component field data and values to the request to enable validation
|
|
54
|
+
validation.propagateChildFieldValidation(req.form, fields, key);
|
|
55
|
+
// adds custom 'equal' validator to the unit child component
|
|
56
|
+
validation.addValidator(fields[`${key}-unit`], validation.createCustomEqualValidator(fields[`${key}-unit`].options));
|
|
57
|
+
// adds custom 'twoHyphenSeparatedValues' validator to the parent component to validate overall value format
|
|
58
|
+
validation.addValidator(options, validation.isTwoHyphenSeparatedValues);
|
|
59
|
+
// moves excess validators that do not apply to the parent component to the 'amount' child component
|
|
60
|
+
validation.moveExcessValidatorToChildComponent(req.form.options.fields, fields, key);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Pre-getErrors hook. This function:
|
|
65
|
+
* - If the parent component has a flagged error, this extends the session model's error values with
|
|
66
|
+
* the child components' error values.
|
|
67
|
+
* @param {Object} req - The form's request object.
|
|
68
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
69
|
+
* @param {string} key - The parent component's key.
|
|
70
|
+
*/
|
|
71
|
+
const preGetErrors = (req, fields, key) => {
|
|
72
|
+
// if the amountWithUnitSelect field is included in errorValues (E.G. if there was a validation error),
|
|
73
|
+
// extend errorValues with the individual components
|
|
74
|
+
// (I.E. add the child components' K:V pair to the request sessionModel's attributes)
|
|
75
|
+
const errorValues = req.sessionModel.get('errorValues');
|
|
76
|
+
if (errorValues && errorValues[key]) {
|
|
77
|
+
req.sessionModel.set('errorValues',
|
|
78
|
+
Object.assign({}, errorValues, utils.getPartsFromAmountWithUnitSelect(errorValues[key], Object.keys(fields)))
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Post-getErrors hook. This function:
|
|
85
|
+
* - Ensures only one error is associated with the components in the request form errors
|
|
86
|
+
* (by setting excess errors' type to null) when either the parent or child components have
|
|
87
|
+
* (jointly) multiple errors in the session model.
|
|
88
|
+
* - If there is no parent component error, one of the child component errors (if any) is inserted.
|
|
89
|
+
* @param {Object} req - The form's request object.
|
|
90
|
+
* @param {Object} res - The form's response object.
|
|
91
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
92
|
+
* @param {string} key - The parent component's key.
|
|
93
|
+
*/
|
|
94
|
+
const postGetErrors = (req, res, fields, key) => {
|
|
95
|
+
// if the amountWithUnitSelect field or its child fields have any recorded validation error,
|
|
96
|
+
// the remaining errors are added to req.form.errors
|
|
97
|
+
// and their type is set to null to avoid duplicate error messages
|
|
98
|
+
const errors = req.sessionModel.get('errors');
|
|
99
|
+
if (errors && (errors[key] || errors[`${key}-amount`] || errors[`${key}-unit`])) {
|
|
100
|
+
Object.assign(req.form.errors, Object.keys(fields).reduce((obj, field) =>
|
|
101
|
+
Object.assign({}, obj, { [field]: { type: null } })
|
|
102
|
+
, {}));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// inserts child component validation errors into req.form.errors
|
|
106
|
+
validation.insertChildValidationErrors(req, res, key, errors);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Post-getValues hook. This function:
|
|
111
|
+
* - Splits the component's value into its parts and assigns them to the request object's form values (req.form.values).
|
|
112
|
+
* @param {Object} req - The form's request object.
|
|
113
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
114
|
+
* @param {string} key - The parent component's key.
|
|
115
|
+
*/
|
|
116
|
+
const postGetValues = (req, fields, key) => {
|
|
117
|
+
// if amountWithUnitSelect value is set, split it into its parts and assign to req.form.values
|
|
118
|
+
// extends the session model's error values, if any
|
|
119
|
+
const amountWithUnitSelect = req.form.values[key];
|
|
120
|
+
if (amountWithUnitSelect) {
|
|
121
|
+
Object.assign(
|
|
122
|
+
req.form.values,
|
|
123
|
+
utils.getPartsFromAmountWithUnitSelect(amountWithUnitSelect, Object.keys(fields)),
|
|
124
|
+
req.sessionModel.get('errorValues') || {}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Pre-render hook. This function:
|
|
131
|
+
* - Translates the unit options and child component labels.
|
|
132
|
+
* - Renders the component's template to a string
|
|
133
|
+
* and assigns the HTML output to the component field in res.locals.fields.
|
|
134
|
+
* @param {Object} req - The form's request object.
|
|
135
|
+
* @param {Object} res - The form's response object.
|
|
136
|
+
* @param {Object} fields - The component's child field definitions and configurations.
|
|
137
|
+
* @param {Object} options - The component's configuration options.
|
|
138
|
+
* @param {string} template - The component's template path.
|
|
139
|
+
* @param {string} key - The parent component's key.
|
|
140
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
141
|
+
*/
|
|
142
|
+
const preRender = (req, res, fields, options, template, key, next) => {
|
|
143
|
+
// applies translations
|
|
144
|
+
utils.translateUnitOptions(req, fields, options, key);
|
|
145
|
+
utils.translateLabels(req, fields, key, ['amount', 'unit']);
|
|
146
|
+
|
|
147
|
+
// renders the template to a string and assign the html output
|
|
148
|
+
// to the amountWithUnitSelect field (in res.locals.fields)
|
|
149
|
+
res.render(template, utils.constructFieldToRender(req, fields, options, key), (err, html) => {
|
|
150
|
+
if (err) {
|
|
151
|
+
next(err);
|
|
152
|
+
} else {
|
|
153
|
+
const field = res.locals.fields.find(f => f.key === key);
|
|
154
|
+
Object.assign(field, { html });
|
|
155
|
+
next();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
preProcess,
|
|
162
|
+
postProcess,
|
|
163
|
+
preValidate,
|
|
164
|
+
preGetErrors,
|
|
165
|
+
postGetErrors,
|
|
166
|
+
postGetValues,
|
|
167
|
+
preRender
|
|
168
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const hooks = require('./hooks');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const getFields = require('./fields');
|
|
6
|
+
|
|
7
|
+
const TEMPLATE = path.resolve(__dirname, './templates/amount-with-unit-select.html');
|
|
8
|
+
|
|
9
|
+
module.exports = (key, opts) => {
|
|
10
|
+
if (!key) {
|
|
11
|
+
throw new Error('Key must be passed to amountWithUnitSelect component');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const fields = getFields(key); // the child field definitions and configurations
|
|
15
|
+
const options = opts || {}; // the component's configuration options
|
|
16
|
+
const template = options.template ? // the field template path
|
|
17
|
+
path.resolve(__dirname, options.template) :
|
|
18
|
+
TEMPLATE;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pre-process hook.
|
|
22
|
+
* @param {Object} req - The form's request object.
|
|
23
|
+
* @param {Object} res - The form's response object.
|
|
24
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
25
|
+
*/
|
|
26
|
+
const preProcess = (req, res, next) => {
|
|
27
|
+
hooks.preProcess(req, fields, key);
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Post-process hook.
|
|
33
|
+
* @param {Object} req - The form's request object.
|
|
34
|
+
* @param {Object} res - The form's response object.
|
|
35
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
36
|
+
*/
|
|
37
|
+
const postProcess = (req, res, next) => {
|
|
38
|
+
hooks.postProcess(req, key);
|
|
39
|
+
next();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Pre-validate hook.
|
|
44
|
+
* @param {Object} req - The form's request object.
|
|
45
|
+
* @param {Object} res - The form's response object.
|
|
46
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
47
|
+
*/
|
|
48
|
+
const preValidate = (req, res, next) => {
|
|
49
|
+
hooks.preValidate(req, fields, key, options);
|
|
50
|
+
next();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Pre-getErrors hook.
|
|
55
|
+
* @param {Object} req - The form's request object.
|
|
56
|
+
* @param {Object} res - The form's response object.
|
|
57
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
58
|
+
*/
|
|
59
|
+
const preGetErrors = (req, res, next) => {
|
|
60
|
+
hooks.preGetErrors(req, fields, key);
|
|
61
|
+
next();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Post-getErrors hook.
|
|
66
|
+
* @param {Object} req - The form's request object.
|
|
67
|
+
* @param {Object} res - The form's response object.
|
|
68
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
69
|
+
*/
|
|
70
|
+
const postGetErrors = (req, res, next) => {
|
|
71
|
+
hooks.postGetErrors(req, res, fields, key);
|
|
72
|
+
next();
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Post-getValues hook.
|
|
77
|
+
* @param {Object} req - The form's request object.
|
|
78
|
+
* @param {Object} res - The form's response object.
|
|
79
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
80
|
+
*/
|
|
81
|
+
const postGetValues = (req, res, next) => {
|
|
82
|
+
hooks.postGetValues(req, fields, key);
|
|
83
|
+
next();
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pre-render hook.
|
|
88
|
+
* @param {Object} req - The form's request object.
|
|
89
|
+
* @param {Object} res - The form's response object.
|
|
90
|
+
* @param {Function} next - The next middleware function in the chain.
|
|
91
|
+
*/
|
|
92
|
+
const preRender = (req, res, next) => {
|
|
93
|
+
hooks.preRender(req, res, fields, options, template, key, next);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return Object.assign({}, options, {
|
|
97
|
+
hooks: {
|
|
98
|
+
'pre-process': preProcess,
|
|
99
|
+
'post-process': postProcess,
|
|
100
|
+
'pre-validate': preValidate,
|
|
101
|
+
'pre-getErrors': preGetErrors,
|
|
102
|
+
'post-getErrors': postGetErrors,
|
|
103
|
+
'post-getValues': postGetValues,
|
|
104
|
+
'pre-render': preRender
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<div class="govuk-form-group {{#error}}govuk-form-group--error{{/error}}">
|
|
2
|
+
<fieldset id="{{key}}-group" class="govuk-fieldset{{#className}} {{className}}{{/className}}" role="group">
|
|
3
|
+
<legend class="govuk-fieldset__legend {{#isPageHeading}}govuk-fieldset__legend--l{{/isPageHeading}}{{#legendClassName}} {{legendClassName}}{{/legendClassName}}">
|
|
4
|
+
{{#isPageHeading}}<h1 class="govuk-fieldset__heading">{{/isPageHeading}}
|
|
5
|
+
{{legend}}
|
|
6
|
+
{{#isPageHeading}}</h1>{{/isPageHeading}}
|
|
7
|
+
</legend>
|
|
8
|
+
{{#hint}}
|
|
9
|
+
<span id="{{key}}-hint" class="govuk-hint">{{hint}}</span>
|
|
10
|
+
{{/hint}}
|
|
11
|
+
{{#error}}
|
|
12
|
+
<p id="{{key}}-error" class="govuk-error-message">
|
|
13
|
+
<span class="govuk-visually-hidden">Error:</span> {{error.message}}
|
|
14
|
+
</p>
|
|
15
|
+
{{/error}}
|
|
16
|
+
<div id="{{key}}" class="govuk-amount-with-unit-select-input">
|
|
17
|
+
{{#input-amount-with-unit-select}}{{key}}{{/input-amount-with-unit-select}}
|
|
18
|
+
</div>
|
|
19
|
+
</fieldset>
|
|
20
|
+
</div>
|