@defra/forms-engine-plugin 4.0.5 → 4.0.7
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/.public/stylesheets/application.min.css +2 -2
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/stylesheets/_location-input.scss +60 -0
- package/.server/client/stylesheets/application.scss +1 -6
- package/.server/client/stylesheets/shared.scss +8 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +28 -0
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +121 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.js +166 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -0
- package/.server/server/plugins/engine/components/LatLongField.d.ts +121 -0
- package/.server/server/plugins/engine/components/LatLongField.js +164 -0
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +134 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js +85 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +108 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +96 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +19 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +40 -0
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -0
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +19 -0
- package/.server/server/plugins/engine/components/OsGridRefField.js +56 -0
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/components.d.ts +3 -4
- package/.server/server/plugins/engine/components/helpers/components.js +21 -29
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +4 -0
- package/.server/server/plugins/engine/components/index.js +4 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/components/markdownParser.d.ts +2 -0
- package/.server/server/plugins/engine/components/markdownParser.js +28 -0
- package/.server/server/plugins/engine/components/markdownParser.js.map +1 -0
- package/.server/server/plugins/engine/components/types.d.ts +10 -0
- package/.server/server/plugins/engine/components/types.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js +7 -0
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
- package/.server/server/plugins/engine/types/index.d.ts +1 -1
- package/.server/server/plugins/engine/types/index.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +2 -2
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/_location-field-base.html +53 -0
- package/.server/server/plugins/engine/views/components/eastingnorthingfield.html +5 -0
- package/.server/server/plugins/engine/views/components/latlongfield.html +5 -0
- package/.server/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +13 -0
- package/.server/server/plugins/engine/views/components/osgridreffield.html +13 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/package.json +3 -3
- package/src/client/stylesheets/_location-input.scss +60 -0
- package/src/client/stylesheets/application.scss +1 -6
- package/src/client/stylesheets/shared.scss +8 -0
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +28 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +1 -1
- package/src/server/plugins/engine/components/EastingNorthingField.test.ts +665 -0
- package/src/server/plugins/engine/components/EastingNorthingField.ts +224 -0
- package/src/server/plugins/engine/components/LatLongField.test.ts +700 -0
- package/src/server/plugins/engine/components/LatLongField.ts +213 -0
- package/src/server/plugins/engine/components/LocationFieldBase.test.ts +253 -0
- package/src/server/plugins/engine/components/LocationFieldBase.ts +152 -0
- package/src/server/plugins/engine/components/LocationFieldHelpers.test.ts +338 -0
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +123 -0
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +438 -0
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +52 -0
- package/src/server/plugins/engine/components/OsGridRefField.test.ts +469 -0
- package/src/server/plugins/engine/components/OsGridRefField.ts +71 -0
- package/src/server/plugins/engine/components/helpers/components.test.ts +270 -0
- package/src/server/plugins/engine/components/helpers/components.ts +39 -47
- package/src/server/plugins/engine/components/helpers/helpers.test.ts +71 -1
- package/src/server/plugins/engine/components/index.ts +4 -0
- package/src/server/plugins/engine/components/markdownParser.ts +40 -0
- package/src/server/plugins/engine/components/types.ts +14 -0
- package/src/server/plugins/engine/outputFormatters/adapter/v1.location.test.ts +356 -0
- package/src/server/plugins/engine/pageControllers/helpers/helpers.test.ts +4 -0
- package/src/server/plugins/engine/pageControllers/helpers/pages.ts +8 -0
- package/src/server/plugins/engine/types/index.ts +2 -0
- package/src/server/plugins/engine/types.ts +4 -0
- package/src/server/plugins/engine/views/components/_location-field-base.html +53 -0
- package/src/server/plugins/engine/views/components/eastingnorthingfield.html +5 -0
- package/src/server/plugins/engine/views/components/latlongfield.html +5 -0
- package/src/server/plugins/engine/views/components/nationalgridfieldnumberfield.html +13 -0
- package/src/server/plugins/engine/views/components/osgridreffield.html +13 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentType,
|
|
3
|
+
type EastingNorthingFieldComponent,
|
|
4
|
+
type LatLongFieldComponent,
|
|
5
|
+
type NationalGridFieldNumberFieldComponent,
|
|
6
|
+
type OsGridRefFieldComponent
|
|
7
|
+
} from '@defra/forms-model'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
getAnswer,
|
|
11
|
+
getAnswerMarkdown
|
|
12
|
+
} from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
13
|
+
import {
|
|
14
|
+
EastingNorthingField,
|
|
15
|
+
LatLongField,
|
|
16
|
+
NationalGridFieldNumberField,
|
|
17
|
+
OsGridRefField
|
|
18
|
+
} from '~/src/server/plugins/engine/components/index.js'
|
|
19
|
+
import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
20
|
+
import definition from '~/test/form/definitions/blank.js'
|
|
21
|
+
|
|
22
|
+
describe('Location field formatting', () => {
|
|
23
|
+
let model: FormModel
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
model = new FormModel(definition, {
|
|
27
|
+
basePath: 'test'
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('EastingNorthingField', () => {
|
|
32
|
+
let field: EastingNorthingField
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
const def: EastingNorthingFieldComponent = {
|
|
36
|
+
type: ComponentType.EastingNorthingField,
|
|
37
|
+
name: 'locationEN',
|
|
38
|
+
title: 'Location',
|
|
39
|
+
options: {}
|
|
40
|
+
}
|
|
41
|
+
field = new EastingNorthingField(def, { model })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('formats for email output with labels on separate lines', () => {
|
|
45
|
+
const state = {
|
|
46
|
+
locationEN__easting: 123456,
|
|
47
|
+
locationEN__northing: 654321
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
51
|
+
expect(answer).toBe('Northing: 654321\nEasting: 123456\n')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('formats for data output', () => {
|
|
55
|
+
const state = {
|
|
56
|
+
locationEN__easting: 123456,
|
|
57
|
+
locationEN__northing: 654321
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const answer = getAnswer(field, state, { format: 'data' })
|
|
61
|
+
expect(answer).toBe('Northing: 654321\nEasting: 123456')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('formats for summary display', () => {
|
|
65
|
+
const state = {
|
|
66
|
+
locationEN__easting: 123456,
|
|
67
|
+
locationEN__northing: 654321
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const answer = getAnswer(field, state, { format: 'summary' })
|
|
71
|
+
// Should render as HTML from markdown
|
|
72
|
+
expect(answer).toContain('Northing: 654321')
|
|
73
|
+
expect(answer).toContain('Easting: 123456')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('returns empty string when no values', () => {
|
|
77
|
+
const state = {}
|
|
78
|
+
|
|
79
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
80
|
+
expect(answer).toBe('')
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('LatLongField', () => {
|
|
85
|
+
let field: LatLongField
|
|
86
|
+
|
|
87
|
+
beforeEach(() => {
|
|
88
|
+
const def: LatLongFieldComponent = {
|
|
89
|
+
type: ComponentType.LatLongField,
|
|
90
|
+
name: 'locationLL',
|
|
91
|
+
title: 'Coordinates',
|
|
92
|
+
options: {}
|
|
93
|
+
}
|
|
94
|
+
field = new LatLongField(def, { model })
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('formats for email output with labels on separate lines', () => {
|
|
98
|
+
const state = {
|
|
99
|
+
locationLL__latitude: 51.51945,
|
|
100
|
+
locationLL__longitude: -0.127758
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
104
|
+
expect(answer).toBe('Lat: 51.51945\nLong: -0.127758\n')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('formats for data output', () => {
|
|
108
|
+
const state = {
|
|
109
|
+
locationLL__latitude: 51.51945,
|
|
110
|
+
locationLL__longitude: -0.127758
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const answer = getAnswer(field, state, { format: 'data' })
|
|
114
|
+
expect(answer).toBe('Lat: 51.51945\nLong: -0.127758')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('formats for summary display', () => {
|
|
118
|
+
const state = {
|
|
119
|
+
locationLL__latitude: 51.51945,
|
|
120
|
+
locationLL__longitude: -0.127758
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const answer = getAnswer(field, state, { format: 'summary' })
|
|
124
|
+
// Should render as HTML from markdown
|
|
125
|
+
expect(answer).toContain('Lat: 51.51945')
|
|
126
|
+
expect(answer).toContain('Long: -0.127758')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('returns empty string when no values', () => {
|
|
130
|
+
const state = {}
|
|
131
|
+
|
|
132
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
133
|
+
expect(answer).toBe('')
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
describe('OsGridRefField', () => {
|
|
138
|
+
let field: OsGridRefField
|
|
139
|
+
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
const def: OsGridRefFieldComponent = {
|
|
142
|
+
type: ComponentType.OsGridRefField,
|
|
143
|
+
name: 'gridRef',
|
|
144
|
+
title: 'OS Grid Reference',
|
|
145
|
+
options: {}
|
|
146
|
+
}
|
|
147
|
+
field = new OsGridRefField(def, { model })
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('formats for email output as single value', () => {
|
|
151
|
+
const state = {
|
|
152
|
+
gridRef: 'TQ123456'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
156
|
+
expect(answer).toBe('TQ123456\n')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('formats for data output', () => {
|
|
160
|
+
const state = {
|
|
161
|
+
gridRef: 'TQ123456'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const answer = getAnswer(field, state, { format: 'data' })
|
|
165
|
+
expect(answer).toBe('TQ123456')
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('formats for summary display', () => {
|
|
169
|
+
const state = {
|
|
170
|
+
gridRef: 'TQ123456'
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const answer = getAnswer(field, state, { format: 'summary' })
|
|
174
|
+
expect(answer).toBe('TQ123456')
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('NationalGridFieldNumberField', () => {
|
|
179
|
+
let field: NationalGridFieldNumberField
|
|
180
|
+
|
|
181
|
+
beforeEach(() => {
|
|
182
|
+
const def: NationalGridFieldNumberFieldComponent = {
|
|
183
|
+
type: ComponentType.NationalGridFieldNumberField,
|
|
184
|
+
name: 'ngField',
|
|
185
|
+
title: 'National Grid Field Number',
|
|
186
|
+
options: {}
|
|
187
|
+
}
|
|
188
|
+
field = new NationalGridFieldNumberField(def, { model })
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('formats for email output as single value', () => {
|
|
192
|
+
const state = {
|
|
193
|
+
ngField: 'NG12345678'
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const answer = getAnswer(field, state, { format: 'email' })
|
|
197
|
+
expect(answer).toBe('NG12345678\n')
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('formats for data output', () => {
|
|
201
|
+
const state = {
|
|
202
|
+
ngField: 'NG12345678'
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const answer = getAnswer(field, state, { format: 'data' })
|
|
206
|
+
expect(answer).toBe('NG12345678')
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('formats for summary display', () => {
|
|
210
|
+
const state = {
|
|
211
|
+
ngField: 'NG12345678'
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const answer = getAnswer(field, state, { format: 'summary' })
|
|
215
|
+
expect(answer).toBe('NG12345678')
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe('getAnswerMarkdown', () => {
|
|
220
|
+
it('formats EastingNorthingField correctly', () => {
|
|
221
|
+
const def: EastingNorthingFieldComponent = {
|
|
222
|
+
type: ComponentType.EastingNorthingField,
|
|
223
|
+
name: 'locationEN',
|
|
224
|
+
title: 'Location',
|
|
225
|
+
options: {}
|
|
226
|
+
}
|
|
227
|
+
const field = new EastingNorthingField(def, { model })
|
|
228
|
+
const state = {
|
|
229
|
+
locationEN__easting: 123456,
|
|
230
|
+
locationEN__northing: 654321
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const answer = getAnswerMarkdown(field, state, { format: 'email' })
|
|
234
|
+
expect(answer).toBe('Northing: 654321\nEasting: 123456\n')
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('formats LatLongField correctly', () => {
|
|
238
|
+
const def: LatLongFieldComponent = {
|
|
239
|
+
type: ComponentType.LatLongField,
|
|
240
|
+
name: 'locationLL',
|
|
241
|
+
title: 'Coordinates',
|
|
242
|
+
options: {}
|
|
243
|
+
}
|
|
244
|
+
const field = new LatLongField(def, { model })
|
|
245
|
+
const state = {
|
|
246
|
+
locationLL__latitude: 51.51945,
|
|
247
|
+
locationLL__longitude: -0.127758
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const answer = getAnswerMarkdown(field, state, { format: 'email' })
|
|
251
|
+
expect(answer).toBe('Lat: 51.51945\nLong: -0.127758\n')
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it('formats simple location fields correctly', () => {
|
|
255
|
+
const def: OsGridRefFieldComponent = {
|
|
256
|
+
type: ComponentType.OsGridRefField,
|
|
257
|
+
name: 'gridRef',
|
|
258
|
+
title: 'OS Grid Reference',
|
|
259
|
+
options: {}
|
|
260
|
+
}
|
|
261
|
+
const field = new OsGridRefField(def, { model })
|
|
262
|
+
const state = {
|
|
263
|
+
gridRef: 'TQ123456'
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const answer = getAnswerMarkdown(field, state, { format: 'email' })
|
|
267
|
+
expect(answer).toBe('TQ123456\n')
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
})
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ComponentType, type ComponentDef } from '@defra/forms-model'
|
|
2
|
-
import { Marked, type Token } from 'marked'
|
|
3
2
|
|
|
4
3
|
import { config } from '~/src/config/index.js'
|
|
5
4
|
import { type ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'
|
|
6
5
|
import { ListFormComponent } from '~/src/server/plugins/engine/components/ListFormComponent.js'
|
|
7
6
|
import { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
8
7
|
import * as Components from '~/src/server/plugins/engine/components/index.js'
|
|
8
|
+
import { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'
|
|
9
9
|
import { type FormState } from '~/src/server/plugins/engine/types.js'
|
|
10
10
|
|
|
11
11
|
// All component instances
|
|
@@ -20,10 +20,14 @@ export type Field = InstanceType<
|
|
|
20
20
|
| typeof Components.YesNoField
|
|
21
21
|
| typeof Components.CheckboxesField
|
|
22
22
|
| typeof Components.DatePartsField
|
|
23
|
+
| typeof Components.EastingNorthingField
|
|
23
24
|
| typeof Components.EmailAddressField
|
|
25
|
+
| typeof Components.LatLongField
|
|
24
26
|
| typeof Components.MonthYearField
|
|
25
27
|
| typeof Components.MultilineTextField
|
|
28
|
+
| typeof Components.NationalGridFieldNumberField
|
|
26
29
|
| typeof Components.NumberField
|
|
30
|
+
| typeof Components.OsGridRefField
|
|
27
31
|
| typeof Components.SelectField
|
|
28
32
|
| typeof Components.TelephoneNumberField
|
|
29
33
|
| typeof Components.TextField
|
|
@@ -32,13 +36,12 @@ export type Field = InstanceType<
|
|
|
32
36
|
>
|
|
33
37
|
|
|
34
38
|
// Guidance component instances only
|
|
35
|
-
export type Guidance =
|
|
36
|
-
| typeof Components.Details
|
|
37
|
-
| typeof Components.Html
|
|
38
|
-
| typeof Components.Markdown
|
|
39
|
-
| typeof Components.InsetText
|
|
40
|
-
| typeof Components.List
|
|
41
|
-
>
|
|
39
|
+
export type Guidance =
|
|
40
|
+
| InstanceType<typeof Components.Details>
|
|
41
|
+
| InstanceType<typeof Components.Html>
|
|
42
|
+
| InstanceType<typeof Components.Markdown>
|
|
43
|
+
| InstanceType<typeof Components.InsetText>
|
|
44
|
+
| InstanceType<typeof Components.List>
|
|
42
45
|
|
|
43
46
|
// List component instances only
|
|
44
47
|
export type ListField = InstanceType<
|
|
@@ -51,43 +54,8 @@ export type ListField = InstanceType<
|
|
|
51
54
|
|
|
52
55
|
export const designerUrl = config.get('designerUrl')
|
|
53
56
|
|
|
54
|
-
export
|
|
55
|
-
|
|
56
|
-
gfm: true,
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Render paragraphs without `<p>` wrappers
|
|
60
|
-
* for check answers summary list `<dd>`
|
|
61
|
-
*/
|
|
62
|
-
extensions: [
|
|
63
|
-
{
|
|
64
|
-
name: 'paragraph',
|
|
65
|
-
renderer({ tokens = [] }) {
|
|
66
|
-
const text = this.parser.parseInline(tokens)
|
|
67
|
-
return tokens.length > 1 ? `${text}<br>` : text
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Restrict allowed Markdown tokens
|
|
74
|
-
*/
|
|
75
|
-
walkTokens(token) {
|
|
76
|
-
const tokens: Token['type'][] = [
|
|
77
|
-
'br',
|
|
78
|
-
'escape',
|
|
79
|
-
'list',
|
|
80
|
-
'list_item',
|
|
81
|
-
'paragraph',
|
|
82
|
-
'space',
|
|
83
|
-
'text'
|
|
84
|
-
]
|
|
85
|
-
|
|
86
|
-
if (!tokens.includes(token.type)) {
|
|
87
|
-
token.type = 'text'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
})
|
|
57
|
+
// Re-export markdown from its own module to avoid circular dependencies
|
|
58
|
+
export { markdown } from '~/src/server/plugins/engine/components/markdownParser.js'
|
|
91
59
|
|
|
92
60
|
/**
|
|
93
61
|
* Filter known components with lists
|
|
@@ -95,7 +63,7 @@ export const markdown = new Marked({
|
|
|
95
63
|
export function hasListFormField(
|
|
96
64
|
field?: Partial<Component>
|
|
97
65
|
): field is ListFormComponent {
|
|
98
|
-
return !!field && isListFieldType(field.type)
|
|
66
|
+
return !!field && field.type !== undefined && isListFieldType(field.type)
|
|
99
67
|
}
|
|
100
68
|
|
|
101
69
|
export function isListFieldType(
|
|
@@ -197,6 +165,22 @@ export function createComponent(
|
|
|
197
165
|
case ComponentType.FileUploadField:
|
|
198
166
|
component = new Components.FileUploadField(def, options)
|
|
199
167
|
break
|
|
168
|
+
|
|
169
|
+
case ComponentType.EastingNorthingField:
|
|
170
|
+
component = new Components.EastingNorthingField(def, options)
|
|
171
|
+
break
|
|
172
|
+
|
|
173
|
+
case ComponentType.OsGridRefField:
|
|
174
|
+
component = new Components.OsGridRefField(def, options)
|
|
175
|
+
break
|
|
176
|
+
|
|
177
|
+
case ComponentType.NationalGridFieldNumberField:
|
|
178
|
+
component = new Components.NationalGridFieldNumberField(def, options)
|
|
179
|
+
break
|
|
180
|
+
|
|
181
|
+
case ComponentType.LatLongField:
|
|
182
|
+
component = new Components.LatLongField(def, options)
|
|
183
|
+
break
|
|
200
184
|
}
|
|
201
185
|
|
|
202
186
|
if (typeof component === 'undefined') {
|
|
@@ -234,7 +218,9 @@ export function getAnswer(
|
|
|
234
218
|
if (
|
|
235
219
|
field instanceof ListFormComponent ||
|
|
236
220
|
field instanceof Components.MultilineTextField ||
|
|
237
|
-
field instanceof Components.UkAddressField
|
|
221
|
+
field instanceof Components.UkAddressField ||
|
|
222
|
+
field instanceof Components.EastingNorthingField ||
|
|
223
|
+
field instanceof Components.LatLongField
|
|
238
224
|
) {
|
|
239
225
|
return markdown
|
|
240
226
|
.parse(getAnswerMarkdown(field, state), { async: false })
|
|
@@ -325,6 +311,12 @@ export function getAnswerMarkdown(
|
|
|
325
311
|
.map(escapeMarkdown)
|
|
326
312
|
.join('\n')
|
|
327
313
|
.concat('\n')
|
|
314
|
+
} else if (
|
|
315
|
+
field instanceof Components.EastingNorthingField ||
|
|
316
|
+
field instanceof Components.LatLongField
|
|
317
|
+
) {
|
|
318
|
+
const contextValue = field.getContextValueFromState(state)
|
|
319
|
+
answerEscaped = contextValue ? `${contextValue}\n` : ''
|
|
328
320
|
}
|
|
329
321
|
|
|
330
322
|
return answerEscaped
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { type ComponentDef } from '@defra/forms-model'
|
|
1
|
+
import { ComponentType, type ComponentDef } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'
|
|
4
|
+
import { EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'
|
|
5
|
+
import { LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'
|
|
6
|
+
import { NationalGridFieldNumberField } from '~/src/server/plugins/engine/components/NationalGridFieldNumberField.js'
|
|
7
|
+
import { OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'
|
|
4
8
|
import { createComponent } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
5
9
|
import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
6
10
|
import definition from '~/test/form/definitions/basic.js'
|
|
@@ -22,6 +26,72 @@ describe('helpers tests', () => {
|
|
|
22
26
|
)
|
|
23
27
|
).toThrow('Component type invalid-type does not exist')
|
|
24
28
|
})
|
|
29
|
+
|
|
30
|
+
test('should create EastingNorthingField component', () => {
|
|
31
|
+
const component = createComponent(
|
|
32
|
+
{
|
|
33
|
+
type: ComponentType.EastingNorthingField,
|
|
34
|
+
name: 'testField',
|
|
35
|
+
title: 'Test Easting Northing',
|
|
36
|
+
options: {},
|
|
37
|
+
schema: {}
|
|
38
|
+
},
|
|
39
|
+
{ model: formModel }
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
expect(component).toBeInstanceOf(EastingNorthingField)
|
|
43
|
+
expect(component.name).toBe('testField')
|
|
44
|
+
expect(component.title).toBe('Test Easting Northing')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('should create LatLongField component', () => {
|
|
48
|
+
const component = createComponent(
|
|
49
|
+
{
|
|
50
|
+
type: ComponentType.LatLongField,
|
|
51
|
+
name: 'testField',
|
|
52
|
+
title: 'Test Lat Long',
|
|
53
|
+
options: {},
|
|
54
|
+
schema: {}
|
|
55
|
+
},
|
|
56
|
+
{ model: formModel }
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
expect(component).toBeInstanceOf(LatLongField)
|
|
60
|
+
expect(component.name).toBe('testField')
|
|
61
|
+
expect(component.title).toBe('Test Lat Long')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('should create OsGridRefField component', () => {
|
|
65
|
+
const component = createComponent(
|
|
66
|
+
{
|
|
67
|
+
type: ComponentType.OsGridRefField,
|
|
68
|
+
name: 'testField',
|
|
69
|
+
title: 'Test OS Grid Ref',
|
|
70
|
+
options: {}
|
|
71
|
+
},
|
|
72
|
+
{ model: formModel }
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
expect(component).toBeInstanceOf(OsGridRefField)
|
|
76
|
+
expect(component.name).toBe('testField')
|
|
77
|
+
expect(component.title).toBe('Test OS Grid Ref')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('should create NationalGridFieldNumberField component', () => {
|
|
81
|
+
const component = createComponent(
|
|
82
|
+
{
|
|
83
|
+
type: ComponentType.NationalGridFieldNumberField,
|
|
84
|
+
name: 'testField',
|
|
85
|
+
title: 'Test National Grid',
|
|
86
|
+
options: {}
|
|
87
|
+
},
|
|
88
|
+
{ model: formModel }
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
expect(component).toBeInstanceOf(NationalGridFieldNumberField)
|
|
92
|
+
expect(component.name).toBe('testField')
|
|
93
|
+
expect(component.title).toBe('Test National Grid')
|
|
94
|
+
})
|
|
25
95
|
})
|
|
26
96
|
|
|
27
97
|
describe('ComponentBase tests', () => {
|
|
@@ -23,3 +23,7 @@ export { TelephoneNumberField } from '~/src/server/plugins/engine/components/Tel
|
|
|
23
23
|
export { TextField } from '~/src/server/plugins/engine/components/TextField.js'
|
|
24
24
|
export { UkAddressField } from '~/src/server/plugins/engine/components/UkAddressField.js'
|
|
25
25
|
export { YesNoField } from '~/src/server/plugins/engine/components/YesNoField.js'
|
|
26
|
+
export { EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'
|
|
27
|
+
export { OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'
|
|
28
|
+
export { NationalGridFieldNumberField } from '~/src/server/plugins/engine/components/NationalGridFieldNumberField.js'
|
|
29
|
+
export { LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Marked, type Token } from 'marked'
|
|
2
|
+
|
|
3
|
+
export const markdown = new Marked({
|
|
4
|
+
breaks: true,
|
|
5
|
+
gfm: true,
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Render paragraphs without `<p>` wrappers
|
|
9
|
+
* for check answers summary list `<dd>`
|
|
10
|
+
*/
|
|
11
|
+
extensions: [
|
|
12
|
+
{
|
|
13
|
+
name: 'paragraph',
|
|
14
|
+
renderer({ tokens = [] }) {
|
|
15
|
+
const text = this.parser.parseInline(tokens)
|
|
16
|
+
return tokens.length > 1 ? `${text}<br>` : text
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Restrict allowed Markdown tokens
|
|
23
|
+
*/
|
|
24
|
+
walkTokens(token) {
|
|
25
|
+
const tokens: Token['type'][] = [
|
|
26
|
+
'br',
|
|
27
|
+
'escape',
|
|
28
|
+
'link',
|
|
29
|
+
'list',
|
|
30
|
+
'list_item',
|
|
31
|
+
'paragraph',
|
|
32
|
+
'space',
|
|
33
|
+
'text'
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
if (!tokens.includes(token.type)) {
|
|
37
|
+
token.type = 'text'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
})
|
|
@@ -60,6 +60,10 @@ export interface DateInputItem {
|
|
|
60
60
|
name?: string
|
|
61
61
|
value?: Item['value']
|
|
62
62
|
classes?: string
|
|
63
|
+
// Prefix/suffix are used by location fields (e.g., LatLong, EastingNorthing) for units like "°"
|
|
64
|
+
// but not by date fields. This interface is reused by both component types.
|
|
65
|
+
prefix?: ComponentText
|
|
66
|
+
suffix?: ComponentText
|
|
63
67
|
condition?: undefined
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -126,3 +130,13 @@ export interface MonthYearState extends Record<string, number> {
|
|
|
126
130
|
month: number
|
|
127
131
|
year: number
|
|
128
132
|
}
|
|
133
|
+
|
|
134
|
+
export interface EastingNorthingState extends Record<string, number> {
|
|
135
|
+
easting: number
|
|
136
|
+
northing: number
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface LatLongState extends Record<string, number> {
|
|
140
|
+
latitude: number
|
|
141
|
+
longitude: number
|
|
142
|
+
}
|