@defra/forms-model 3.0.447 → 3.0.449
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/dist/module/form/form-definition/index.js +1 -1
- package/dist/module/form/form-definition/index.js.map +1 -1
- package/dist/module/form/form-editor/__stubs__/preview.js +105 -0
- package/dist/module/form/form-editor/__stubs__/preview.js.map +1 -0
- package/dist/module/form/form-editor/index.js +14 -0
- package/dist/module/form/form-editor/index.js.map +1 -1
- package/dist/module/form/form-editor/preview/date-input.js +17 -0
- package/dist/module/form/form-editor/preview/date-input.js.map +1 -0
- package/dist/module/form/form-editor/preview/email-address.js +6 -0
- package/dist/module/form/form-editor/preview/email-address.js.map +1 -0
- package/dist/module/form/form-editor/preview/index.js +11 -0
- package/dist/module/form/form-editor/preview/index.js.map +1 -0
- package/dist/module/form/form-editor/preview/list-sortable.js +40 -0
- package/dist/module/form/form-editor/preview/list-sortable.js.map +1 -0
- package/dist/module/form/form-editor/preview/list.js +182 -0
- package/dist/module/form/form-editor/preview/list.js.map +1 -0
- package/dist/module/form/form-editor/preview/phone-number.js +10 -0
- package/dist/module/form/form-editor/preview/phone-number.js.map +1 -0
- package/dist/module/form/form-editor/preview/question.js +197 -0
- package/dist/module/form/form-editor/preview/question.js.map +1 -0
- package/dist/module/form/form-editor/preview/radio-sortable.js +5 -0
- package/dist/module/form/form-editor/preview/radio-sortable.js.map +1 -0
- package/dist/module/form/form-editor/preview/radio.js +5 -0
- package/dist/module/form/form-editor/preview/radio.js.map +1 -0
- package/dist/module/form/form-editor/preview/short-answer.js +3 -0
- package/dist/module/form/form-editor/preview/short-answer.js.map +1 -0
- package/dist/module/form/form-editor/preview/types.js +2 -0
- package/dist/module/form/form-editor/preview/types.js.map +1 -0
- package/dist/module/form/form-editor/preview/uk-address.js +6 -0
- package/dist/module/form/form-editor/preview/uk-address.js.map +1 -0
- package/dist/module/form/form-editor/types.js.map +1 -1
- package/dist/module/form/form-manager/types.js.map +1 -1
- package/dist/module/index.js +1 -1
- package/dist/module/index.js.map +1 -1
- package/dist/types/form/form-definition/index.d.ts +2 -1
- package/dist/types/form/form-definition/index.d.ts.map +1 -1
- package/dist/types/form/form-editor/__stubs__/preview.d.ts +72 -0
- package/dist/types/form/form-editor/__stubs__/preview.d.ts.map +1 -0
- package/dist/types/form/form-editor/index.d.ts +7 -1
- package/dist/types/form/form-editor/index.d.ts.map +1 -1
- package/dist/types/form/form-editor/preview/date-input.d.ts +10 -0
- package/dist/types/form/form-editor/preview/date-input.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/email-address.d.ts +4 -0
- package/dist/types/form/form-editor/preview/email-address.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/index.d.ts +11 -0
- package/dist/types/form/form-editor/preview/index.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/list-sortable.d.ts +17 -0
- package/dist/types/form/form-editor/preview/list-sortable.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/list.d.ts +81 -0
- package/dist/types/form/form-editor/preview/list.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/phone-number.d.ts +4 -0
- package/dist/types/form/form-editor/preview/phone-number.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/question.d.ts +119 -0
- package/dist/types/form/form-editor/preview/question.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/radio-sortable.d.ts +4 -0
- package/dist/types/form/form-editor/preview/radio-sortable.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/radio.d.ts +4 -0
- package/dist/types/form/form-editor/preview/radio.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/short-answer.d.ts +4 -0
- package/dist/types/form/form-editor/preview/short-answer.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/types.d.ts +52 -0
- package/dist/types/form/form-editor/preview/types.d.ts.map +1 -0
- package/dist/types/form/form-editor/preview/uk-address.d.ts +4 -0
- package/dist/types/form/form-editor/preview/uk-address.d.ts.map +1 -0
- package/dist/types/form/form-editor/types.d.ts +36 -6
- package/dist/types/form/form-editor/types.d.ts.map +1 -1
- package/dist/types/form/form-manager/types.d.ts +2 -2
- package/dist/types/form/form-manager/types.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/form/form-definition/index.ts +1 -1
- package/src/form/form-editor/__stubs__/preview.js +101 -0
- package/src/form/form-editor/index.ts +43 -1
- package/src/form/form-editor/preview/date-input.js +18 -0
- package/src/form/form-editor/preview/email-address.js +6 -0
- package/src/form/form-editor/preview/index.js +10 -0
- package/src/form/form-editor/preview/list-sortable.js +39 -0
- package/src/form/form-editor/preview/list.js +202 -0
- package/src/form/form-editor/preview/phone-number.js +10 -0
- package/src/form/form-editor/preview/question.js +199 -0
- package/src/form/form-editor/preview/radio-sortable.js +5 -0
- package/src/form/form-editor/preview/radio.js +5 -0
- package/src/form/form-editor/preview/short-answer.js +3 -0
- package/src/form/form-editor/preview/types.ts +60 -0
- package/src/form/form-editor/preview/uk-address.js +6 -0
- package/src/form/form-editor/types.ts +47 -2
- package/src/form/form-manager/types.ts +2 -2
- package/src/index.ts +2 -1
- package/dist/module/form/form-manager/index.js +0 -7
- package/dist/module/form/form-manager/index.js.map +0 -1
- package/dist/types/form/form-manager/index.d.ts +0 -3
- package/dist/types/form/form-manager/index.d.ts.map +0 -1
- package/schemas/patch-page-schema.json +0 -26
- package/src/form/form-manager/index.ts +0 -21
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qCAAqC,CAAA;AACnD,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,qCAAqC,CAAA;AACnD,cAAc,2BAA2B,CAAA;AACzC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qCAAqC,CAAA;AACnD,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,qCAAqC,CAAA;AACnD,cAAc,2BAA2B,CAAA;AACzC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA;AACvD,cAAc,kCAAkC,CAAA;AAChD,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AAEvC,mBAAmB,uBAAuB,CAAA;AAC1C,mBAAmB,kCAAkC,CAAA;AACrD,mBAAmB,8BAA8B,CAAA;AACjD,mBAAmB,+BAA+B,CAAA;AAClD,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,2BAA2B,CAAA;AAC9C,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,mCAAmC,CAAA;AACtD,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yCAAyC,CAAA;AAC5D,mBAAmB,iCAAiC,CAAA"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@defra/forms-model",
|
3
|
-
"version": "3.0.
|
3
|
+
"version": "3.0.449",
|
4
4
|
"description": "A hapi plugin providing the model for Defra forms",
|
5
5
|
"homepage": "https://github.com/DEFRA/forms-designer/tree/main/model#readme",
|
6
6
|
"repository": {
|
@@ -15,7 +15,7 @@
|
|
15
15
|
"types": "dist/types/index.d.ts",
|
16
16
|
"scripts": {
|
17
17
|
"build": "npm run build:types && npm run build:node && npm run build:schemas",
|
18
|
-
"build:node": "babel --delete-dir-on-start --extensions \".ts\" --ignore \"**/*.test.*\" --copy-files --no-copy-ignored --source-maps --out-dir ./dist/module ./src",
|
18
|
+
"build:node": "babel --delete-dir-on-start --extensions \".ts,.js\" --ignore \"**/*.test.*\" --copy-files --no-copy-ignored --source-maps --out-dir ./dist/module ./src",
|
19
19
|
"build:types": "tsc --build --force tsconfig.build.json && tsc-alias --project tsconfig.build.json",
|
20
20
|
"build:schemas": "node scripts/generate-schemas.js",
|
21
21
|
"test": "jest --color --coverage --verbose",
|
@@ -361,7 +361,7 @@ const repeatSchema = Joi.object<RepeatSchema>()
|
|
361
361
|
.description('Maximum number of repetitions allowed')
|
362
362
|
})
|
363
363
|
|
364
|
-
const pageRepeatSchema = Joi.object<Repeat>()
|
364
|
+
export const pageRepeatSchema = Joi.object<Repeat>()
|
365
365
|
.description('Complete configuration for a repeatable page')
|
366
366
|
.keys({
|
367
367
|
options: repeatOptions
|
@@ -0,0 +1,101 @@
|
|
1
|
+
/**
|
2
|
+
* @implements {QuestionRenderer}
|
3
|
+
*/
|
4
|
+
export class QuestionRendererStub {
|
5
|
+
/**
|
6
|
+
* @type {jest.Mock<void, [string, QuestionBaseModel]>}
|
7
|
+
*/
|
8
|
+
renderMock
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @param {jest.Mock<void, [string, QuestionBaseModel]>} renderMock
|
12
|
+
*/
|
13
|
+
constructor(renderMock) {
|
14
|
+
this.renderMock = renderMock
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @param {string} questionTemplate
|
19
|
+
* @param {QuestionBaseModel} questionBaseModel
|
20
|
+
*/
|
21
|
+
render(questionTemplate, questionBaseModel) {
|
22
|
+
this.renderMock(questionTemplate, questionBaseModel)
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @returns {string}
|
27
|
+
* @param {string} _questionTemplate
|
28
|
+
* @param {RenderContext} _renderContext
|
29
|
+
*/
|
30
|
+
static buildHTML(_questionTemplate, _renderContext) {
|
31
|
+
return '**** BUILT HTML ****'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @implements {ListElements}
|
37
|
+
*/
|
38
|
+
export class QuestionPreviewElements {
|
39
|
+
/**
|
40
|
+
* @protected
|
41
|
+
*/
|
42
|
+
_question = ''
|
43
|
+
/** @protected */
|
44
|
+
_hintText = ''
|
45
|
+
/** @protected */
|
46
|
+
_optional = false
|
47
|
+
/**
|
48
|
+
* @type {string}
|
49
|
+
* @protected
|
50
|
+
*/
|
51
|
+
_shortDesc = ''
|
52
|
+
/**
|
53
|
+
*
|
54
|
+
* @type {ListElement[]}
|
55
|
+
* @private
|
56
|
+
*/
|
57
|
+
_items = []
|
58
|
+
|
59
|
+
afterInputsHTML = '<div class="govuk-inset-text">No items added yet.</div>'
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @param {BaseSettings} baseSettings
|
63
|
+
*/
|
64
|
+
constructor({ question, hintText, optional, shortDesc, items }) {
|
65
|
+
this._question = question
|
66
|
+
this._hintText = hintText
|
67
|
+
this._optional = optional
|
68
|
+
this._shortDesc = shortDesc
|
69
|
+
this._items = items
|
70
|
+
}
|
71
|
+
|
72
|
+
get values() {
|
73
|
+
return {
|
74
|
+
question: this._question,
|
75
|
+
hintText: this._hintText,
|
76
|
+
optional: this._optional,
|
77
|
+
shortDesc: this._shortDesc,
|
78
|
+
items: this._items
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* @param {string} _value
|
84
|
+
*/
|
85
|
+
setPreviewHTML(_value) {
|
86
|
+
// Not implemented for server side render
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
export const baseElements = /** @type {BaseSettings} */ ({
|
91
|
+
items: [],
|
92
|
+
optional: false,
|
93
|
+
question: 'Which quest would you like to pick?',
|
94
|
+
hintText: 'Choose one adventure that best suits you.',
|
95
|
+
shortDesc: ''
|
96
|
+
})
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @import { ListElement } from '~/src/form/form-editor/types.js'
|
100
|
+
* @import { BaseSettings, ListElements, RenderContext, QuestionBaseModel, QuestionElements, QuestionRenderer } from '~/src/form/form-editor/preview/types.js'
|
101
|
+
*/
|
@@ -5,7 +5,10 @@ import {
|
|
5
5
|
type FormEditorInputCheckAnswersSettings,
|
6
6
|
type FormEditorInputPage,
|
7
7
|
type FormEditorInputPageSettings,
|
8
|
-
type FormEditorInputQuestion
|
8
|
+
type FormEditorInputQuestion,
|
9
|
+
type GovukField,
|
10
|
+
type GovukFieldQuestionOptional,
|
11
|
+
type GovukStringField
|
9
12
|
} from '~/src/form/form-editor/types.js'
|
10
13
|
|
11
14
|
export enum QuestionTypeSubGroup {
|
@@ -227,6 +230,27 @@ export const guidanceTextSchema = Joi.string()
|
|
227
230
|
.trim()
|
228
231
|
.description('Guidance text to assist users in completing the page')
|
229
232
|
|
233
|
+
export const repeaterSchema = Joi.string()
|
234
|
+
.trim()
|
235
|
+
.optional()
|
236
|
+
.description(
|
237
|
+
'Combined min/max items and question set name for the repeater page'
|
238
|
+
)
|
239
|
+
|
240
|
+
export const minItemsSchema = Joi.number()
|
241
|
+
.empty('')
|
242
|
+
.min(1)
|
243
|
+
.description('The minimum number of repeater items')
|
244
|
+
|
245
|
+
export const maxItemsSchema = Joi.number()
|
246
|
+
.empty('')
|
247
|
+
.max(25)
|
248
|
+
.description('The maximum number of repeater items')
|
249
|
+
|
250
|
+
export const questionSetNameSchema = Joi.string()
|
251
|
+
.trim()
|
252
|
+
.description('The repeater question set name')
|
253
|
+
|
230
254
|
export const needDeclarationSchema = Joi.string()
|
231
255
|
.trim()
|
232
256
|
.required()
|
@@ -559,3 +583,21 @@ export const formEditorInputPageSettingsSchema =
|
|
559
583
|
.keys(formEditorInputPageSettingsKeys)
|
560
584
|
.required()
|
561
585
|
.description('Settings for page content and display in the form editor')
|
586
|
+
|
587
|
+
export function govukFieldValueIsString(
|
588
|
+
govukField: GovukField
|
589
|
+
): govukField is GovukStringField {
|
590
|
+
return ['question', 'hintText', 'shortDescription'].includes(
|
591
|
+
`${govukField.name}`
|
592
|
+
)
|
593
|
+
}
|
594
|
+
|
595
|
+
export function govukFieldIsQuestionOptional(
|
596
|
+
govukField: GovukField
|
597
|
+
): govukField is GovukFieldQuestionOptional {
|
598
|
+
if (govukField.name !== 'questionOptional') {
|
599
|
+
return false
|
600
|
+
}
|
601
|
+
const checkedValue = govukField.items?.[0].checked
|
602
|
+
return typeof checkedValue === 'boolean'
|
603
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Question } from '~/src/form/form-editor/preview/question.js'
|
2
|
+
|
3
|
+
export class DateInputQuestion extends Question {
|
4
|
+
/**
|
5
|
+
* @type {string}
|
6
|
+
* @protected
|
7
|
+
*/
|
8
|
+
_questionTemplate = 'date-input.njk'
|
9
|
+
|
10
|
+
get renderInput() {
|
11
|
+
return {
|
12
|
+
id: 'dateInput',
|
13
|
+
name: 'dateInputField',
|
14
|
+
fieldset: this.fieldSet,
|
15
|
+
hint: this.hint
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
export * from '~/src/form/form-editor/preview/date-input.js'
|
2
|
+
export * from '~/src/form/form-editor/preview/email-address.js'
|
3
|
+
export * from '~/src/form/form-editor/preview/list.js'
|
4
|
+
export * from '~/src/form/form-editor/preview/list-sortable.js'
|
5
|
+
export * from '~/src/form/form-editor/preview/phone-number.js'
|
6
|
+
export * from '~/src/form/form-editor/preview/question.js'
|
7
|
+
export * from '~/src/form/form-editor/preview/radio.js'
|
8
|
+
export * from '~/src/form/form-editor/preview/radio-sortable.js'
|
9
|
+
export * from '~/src/form/form-editor/preview/short-answer.js'
|
10
|
+
export * from '~/src/form/form-editor/preview/uk-address.js'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { ListQuestion } from '~/src/form/form-editor/preview/list.js'
|
2
|
+
|
3
|
+
export class ListSortableQuestion extends ListQuestion {
|
4
|
+
/**
|
5
|
+
* @param {ListElements} listElements
|
6
|
+
* @param {QuestionRenderer} questionRenderer
|
7
|
+
*/
|
8
|
+
constructor(listElements, questionRenderer) {
|
9
|
+
super(listElements, questionRenderer)
|
10
|
+
const items = /** @type {ListElement[]} */ (listElements.values.items)
|
11
|
+
this._list = this.createListFromElements(items)
|
12
|
+
this._listElements = listElements
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @returns {Map<string, ListElement>}
|
17
|
+
*/
|
18
|
+
resyncPreviewAfterReorder() {
|
19
|
+
const newList = this._listElements.values.items
|
20
|
+
this._list = this.createListFromElements(newList)
|
21
|
+
this.render()
|
22
|
+
return this._list
|
23
|
+
}
|
24
|
+
|
25
|
+
get listElementObjects() {
|
26
|
+
return Array.from(this._list).map(([, value]) => ({
|
27
|
+
id: value.id,
|
28
|
+
text: value.text,
|
29
|
+
hint: value.hint?.text ? { text: value.hint.text } : undefined,
|
30
|
+
value: value.value
|
31
|
+
}))
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @import {ListElement} from '~/src/form/form-editor/types.js'
|
37
|
+
* @import { QuestionRenderer, HTMLBuilder, ListElements, BaseSettings } from '~/src/form/form-editor/preview/types.js'
|
38
|
+
* @import { SortableEvent, SortableOptions } from 'sortablejs'
|
39
|
+
*/
|
@@ -0,0 +1,202 @@
|
|
1
|
+
import { Question } from '~/src/form/form-editor/preview/question.js'
|
2
|
+
|
3
|
+
const DefaultListConst = {
|
4
|
+
TextElementId: 'radioText',
|
5
|
+
HintElementId: 'radioHint',
|
6
|
+
Template: 'radios.njk',
|
7
|
+
Input: 'listInput',
|
8
|
+
RenderName: 'listInputField'
|
9
|
+
}
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @param {ListElement} listElement
|
13
|
+
* @returns {[string, ListElement]}
|
14
|
+
*/
|
15
|
+
export function listItemMapper(listElement) {
|
16
|
+
return [listElement.id, listElement]
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
*
|
21
|
+
* @param { ListElement[]| undefined } listElements
|
22
|
+
* @returns {Map<string, ListElement>}
|
23
|
+
*/
|
24
|
+
export function listsElementToMap(listElements) {
|
25
|
+
const entries = listElements ? listElements.map(listItemMapper) : []
|
26
|
+
return new Map(entries)
|
27
|
+
}
|
28
|
+
|
29
|
+
export class ListQuestion extends Question {
|
30
|
+
/**
|
31
|
+
* @type {string}
|
32
|
+
* @protected
|
33
|
+
*/
|
34
|
+
_questionTemplate = DefaultListConst.Template
|
35
|
+
/** @type {ListElements} */
|
36
|
+
_listElements
|
37
|
+
listRenderId = DefaultListConst.Input
|
38
|
+
listRenderName = DefaultListConst.RenderName
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @type {Map<string, ListElement>}
|
42
|
+
* @protected
|
43
|
+
*/
|
44
|
+
_list
|
45
|
+
|
46
|
+
/**
|
47
|
+
* @param {ListElements} listElements
|
48
|
+
* @param {QuestionRenderer} questionRenderer
|
49
|
+
*/
|
50
|
+
constructor(listElements, questionRenderer) {
|
51
|
+
super(listElements, questionRenderer)
|
52
|
+
|
53
|
+
const items = /** @type {ListElement[]} */ (listElements.values.items)
|
54
|
+
this._list = this.createListFromElements(items)
|
55
|
+
this._listElements = listElements
|
56
|
+
}
|
57
|
+
|
58
|
+
get renderInput() {
|
59
|
+
const afterInputs =
|
60
|
+
/** @type {{ formGroup?: { afterInputs: { html: string } } }} */ (
|
61
|
+
this.list.length
|
62
|
+
? {}
|
63
|
+
: {
|
64
|
+
formGroup: {
|
65
|
+
afterInputs: {
|
66
|
+
html: this._listElements.afterInputsHTML
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
)
|
71
|
+
|
72
|
+
return {
|
73
|
+
id: this.listRenderId,
|
74
|
+
name: this.listRenderName,
|
75
|
+
fieldset: this.fieldSet,
|
76
|
+
hint: this.hint,
|
77
|
+
items: this.list,
|
78
|
+
...afterInputs
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
*
|
84
|
+
* @param {ListElement} listElement
|
85
|
+
*/
|
86
|
+
push(listElement) {
|
87
|
+
this._list.set(listElement.id, listElement)
|
88
|
+
this.render()
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* @param {string} key
|
93
|
+
*/
|
94
|
+
delete(key) {
|
95
|
+
this._list.delete(key)
|
96
|
+
this.render()
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* @param {ListElement[]} listElements
|
101
|
+
* @returns {Map<string, ListElement>}
|
102
|
+
*/
|
103
|
+
createListFromElements(listElements) {
|
104
|
+
this._list = listsElementToMap(listElements)
|
105
|
+
return this._list
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* @returns {ListItemReadonly[]}
|
110
|
+
* @readonly
|
111
|
+
*/
|
112
|
+
get list() {
|
113
|
+
const iterator = /** @type {MapIterator<ListElement>} */ (
|
114
|
+
this._list.values()
|
115
|
+
)
|
116
|
+
return Array.from(iterator).map((listItem) => {
|
117
|
+
const hintText =
|
118
|
+
this._highlight === `${listItem.id}-hint` && !listItem.hint?.text.length
|
119
|
+
? 'Hint text'
|
120
|
+
: (listItem.hint?.text ?? '')
|
121
|
+
|
122
|
+
const hint = {
|
123
|
+
hint: hintText
|
124
|
+
? {
|
125
|
+
text: hintText,
|
126
|
+
classes: this.getHighlight(listItem.id + '-hint')
|
127
|
+
}
|
128
|
+
: undefined
|
129
|
+
}
|
130
|
+
|
131
|
+
const text = listItem.text.length ? listItem.text : 'Item text'
|
132
|
+
|
133
|
+
return {
|
134
|
+
...listItem,
|
135
|
+
text,
|
136
|
+
...hint,
|
137
|
+
label: {
|
138
|
+
text: listItem.text,
|
139
|
+
classes: this.getHighlight(listItem.id + '-label')
|
140
|
+
}
|
141
|
+
}
|
142
|
+
})
|
143
|
+
}
|
144
|
+
|
145
|
+
/**
|
146
|
+
*
|
147
|
+
* @param {string | undefined} id
|
148
|
+
* @param {string} text
|
149
|
+
*/
|
150
|
+
updateText(id, text) {
|
151
|
+
if (!id) {
|
152
|
+
return
|
153
|
+
}
|
154
|
+
|
155
|
+
const listItem = this._list.get(id)
|
156
|
+
if (listItem) {
|
157
|
+
listItem.text = text
|
158
|
+
this.render()
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
/**
|
163
|
+
*
|
164
|
+
* @param {string | undefined} id
|
165
|
+
* @param {string} hint
|
166
|
+
*/
|
167
|
+
updateHint(id, hint) {
|
168
|
+
if (!id) {
|
169
|
+
return
|
170
|
+
}
|
171
|
+
|
172
|
+
const listItem = this._list.get(id)
|
173
|
+
if (listItem) {
|
174
|
+
listItem.hint = {
|
175
|
+
...listItem.hint,
|
176
|
+
text: hint
|
177
|
+
}
|
178
|
+
this.render()
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
* @param {string | undefined} id
|
184
|
+
* @param {string} value
|
185
|
+
*/
|
186
|
+
updateValue(id, value) {
|
187
|
+
if (!id) {
|
188
|
+
return
|
189
|
+
}
|
190
|
+
|
191
|
+
const listItem = this._list.get(id)
|
192
|
+
if (listItem) {
|
193
|
+
listItem.value = value
|
194
|
+
this.render()
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
/**
|
200
|
+
* @import { ListElement, ListItemReadonly } from '~/src/form/form-editor/types.js'
|
201
|
+
* @import { ListenerRow, ListElements, QuestionRenderer, HTMLBuilder } from '~/src/form/form-editor/preview/types.js'
|
202
|
+
*/
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { Question } from '~/src/form/form-editor/preview/question.js'
|
2
|
+
|
3
|
+
export class PhoneNumberQuestion extends Question {
|
4
|
+
_questionTemplate = 'telephonenumberfield.njk'
|
5
|
+
_fieldName = 'phoneNumberField'
|
6
|
+
}
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @import { QuestionBaseModel } from '~/src/form/form-editor/preview/question.js'
|
10
|
+
*/
|
@@ -0,0 +1,199 @@
|
|
1
|
+
/**
|
2
|
+
* @class Question
|
3
|
+
* @classdesc
|
4
|
+
* A data object that has access to the underlying data via the QuestionElements object interface
|
5
|
+
* and the templating mechanism to render the HTML for the data.
|
6
|
+
*
|
7
|
+
* It does not have access to the DOM, but has access to QuestionElements.setPreviewHTML to update
|
8
|
+
* the HTML. Question classes should only be responsible for data and rendering as are reused in the
|
9
|
+
* server side.
|
10
|
+
*/
|
11
|
+
export class Question {
|
12
|
+
/**
|
13
|
+
* @type {string}
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
_questionTemplate = 'textfield.njk'
|
17
|
+
/**
|
18
|
+
* @type { string|null }
|
19
|
+
* @protected
|
20
|
+
*/
|
21
|
+
_highlight = null
|
22
|
+
/**
|
23
|
+
* @type {string}
|
24
|
+
* @protected
|
25
|
+
*/
|
26
|
+
_fieldName = 'inputField'
|
27
|
+
/**
|
28
|
+
* @type {QuestionRenderer}
|
29
|
+
* @protected
|
30
|
+
*/
|
31
|
+
_questionRenderer
|
32
|
+
|
33
|
+
/**
|
34
|
+
* @param {QuestionElements} htmlElements
|
35
|
+
* @param {QuestionRenderer} questionRenderer
|
36
|
+
*/
|
37
|
+
constructor(htmlElements, questionRenderer) {
|
38
|
+
const { question, hintText, optional } = htmlElements.values
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @type {QuestionElements}
|
42
|
+
* @private
|
43
|
+
*/
|
44
|
+
this._htmlElements = htmlElements
|
45
|
+
/**
|
46
|
+
* @type {string}
|
47
|
+
* @private
|
48
|
+
*/
|
49
|
+
this._question = question
|
50
|
+
/**
|
51
|
+
* @type {string}
|
52
|
+
* @private
|
53
|
+
*/
|
54
|
+
this._hintText = hintText
|
55
|
+
/**
|
56
|
+
* @type {boolean}
|
57
|
+
* @private
|
58
|
+
*/
|
59
|
+
this._optional = optional
|
60
|
+
/**
|
61
|
+
*
|
62
|
+
* @type {QuestionRenderer}
|
63
|
+
* @protected
|
64
|
+
*/
|
65
|
+
this._questionRenderer = questionRenderer
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* @param {string} element
|
70
|
+
* @returns {string}
|
71
|
+
* @protected
|
72
|
+
*/
|
73
|
+
getHighlight(element) {
|
74
|
+
return this._highlight === element ? ' highlight' : ''
|
75
|
+
}
|
76
|
+
|
77
|
+
get titleText() {
|
78
|
+
const optionalText = this._optional ? ' (optional)' : ''
|
79
|
+
return (!this._question ? 'Question' : this._question) + optionalText
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* @protected
|
84
|
+
* @type {DefaultComponent}
|
85
|
+
*/
|
86
|
+
get label() {
|
87
|
+
return {
|
88
|
+
text: this.titleText,
|
89
|
+
classes: 'govuk-label--l' + this.getHighlight('question')
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @protected
|
95
|
+
* @type {GovukFieldset}
|
96
|
+
*/
|
97
|
+
get fieldSet() {
|
98
|
+
return {
|
99
|
+
legend: {
|
100
|
+
text: this.titleText,
|
101
|
+
classes: 'govuk-fieldset__legend--l' + this.getHighlight('question')
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* @type {DefaultComponent}
|
108
|
+
* @protected
|
109
|
+
*/
|
110
|
+
get hint() {
|
111
|
+
const text =
|
112
|
+
this._highlight === 'hintText' && !this._hintText.length
|
113
|
+
? 'Hint text'
|
114
|
+
: this._hintText
|
115
|
+
|
116
|
+
return {
|
117
|
+
text,
|
118
|
+
classes: this.getHighlight('hintText')
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* @type {QuestionBaseModel}
|
124
|
+
*/
|
125
|
+
get renderInput() {
|
126
|
+
return {
|
127
|
+
id: this._fieldName,
|
128
|
+
name: this._fieldName,
|
129
|
+
label: this.label,
|
130
|
+
hint: this.hint
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
render() {
|
135
|
+
this._questionRenderer.render(this._questionTemplate, this.renderInput)
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
* @type {string}
|
140
|
+
*/
|
141
|
+
get question() {
|
142
|
+
return this._question
|
143
|
+
}
|
144
|
+
|
145
|
+
/**
|
146
|
+
* @param {string} value
|
147
|
+
*/
|
148
|
+
set question(value) {
|
149
|
+
this._question = value
|
150
|
+
this.render()
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* @type {string}
|
155
|
+
*/
|
156
|
+
get hintText() {
|
157
|
+
return this._hintText
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* @param {string} value
|
162
|
+
*/
|
163
|
+
set hintText(value) {
|
164
|
+
this._hintText = value
|
165
|
+
this.render()
|
166
|
+
}
|
167
|
+
|
168
|
+
get optional() {
|
169
|
+
return this._optional
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* @param {boolean} value
|
174
|
+
*/
|
175
|
+
set optional(value) {
|
176
|
+
this._optional = value
|
177
|
+
this.render()
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* @type {string | null}
|
182
|
+
*/
|
183
|
+
get highlight() {
|
184
|
+
return this._highlight
|
185
|
+
}
|
186
|
+
|
187
|
+
/**
|
188
|
+
* @param {string | null} value
|
189
|
+
*/
|
190
|
+
set highlight(value) {
|
191
|
+
this._highlight = value
|
192
|
+
this.render()
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* @import { ListenerRow, BaseSettings, QuestionElements, QuestionBaseModel, GovukFieldset, DefaultComponent, QuestionRenderer } from '~/src/form/form-editor/preview/types.js'
|
198
|
+
* @import { ListElement, ListItemReadonly } from '~/src/form/form-editor/types.js'
|
199
|
+
*/
|