@defra/forms-engine-plugin 5.0.0-alpha.12 → 5.0.0-alpha.13
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/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.server/client/javascripts/geospatial-map.d.ts +153 -5
- package/.server/client/javascripts/geospatial-map.js +147 -46
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/location-map.d.ts +38 -0
- package/.server/client/javascripts/location-map.js +42 -2
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/javascripts/map-constants.d.ts +3 -0
- package/.server/client/javascripts/map-constants.js +4 -0
- package/.server/client/javascripts/map-constants.js.map +1 -0
- package/.server/client/javascripts/map.d.ts +4 -0
- package/.server/client/javascripts/map.js +5 -0
- package/.server/client/javascripts/map.js.map +1 -1
- package/.server/server/plugins/engine/__stubs__/definitions.d.ts +29 -0
- package/.server/server/plugins/engine/__stubs__/definitions.js +125 -0
- package/.server/server/plugins/engine/__stubs__/definitions.js.map +1 -0
- package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +2 -0
- package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
- package/.server/server/plugins/engine/components/GeospatialField.js +1 -0
- package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
- package/.server/server/plugins/engine/components/LatLongField.d.ts +2 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js +3 -0
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +2 -0
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js +2 -1
- package/.server/server/plugins/engine/components/LocationFieldHelpers.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +2 -1
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/errors.d.ts +49 -0
- package/.server/server/plugins/engine/errors.js +75 -0
- package/.server/server/plugins/engine/errors.js.map +1 -0
- package/.server/server/plugins/engine/i18n/translations/cy.json +51 -1
- package/.server/server/plugins/engine/i18n/translations/en-GB.json +51 -1
- package/.server/server/plugins/engine/models/FormModel.js +10 -2
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js +2 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
- package/.server/server/plugins/engine/views/components/_location-field-base.html +1 -0
- package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -0
- package/.server/server/plugins/engine/views/components/osgridreffield.html +3 -1
- package/package.json +1 -1
- package/src/client/javascripts/geospatial-map.js +169 -47
- package/src/client/javascripts/location-map.js +50 -2
- package/src/client/javascripts/map-constants.js +3 -0
- package/src/client/javascripts/map.js +5 -0
- package/src/server/plugins/engine/__stubs__/definitions.ts +155 -0
- package/src/server/plugins/engine/components/GeospatialField.ts +1 -0
- package/src/server/plugins/engine/components/LocationFieldBase.ts +4 -0
- package/src/server/plugins/engine/components/LocationFieldHelpers.ts +2 -1
- package/src/server/plugins/engine/components/helpers/components.ts +2 -1
- package/src/server/plugins/engine/errors.ts +78 -0
- package/src/server/plugins/engine/i18n/translations/cy.json +51 -1
- package/src/server/plugins/engine/i18n/translations/en-GB.json +51 -1
- package/src/server/plugins/engine/models/FormModel.ts +12 -2
- package/src/server/plugins/engine/pageControllers/helpers/pages.ts +2 -1
- package/src/server/plugins/engine/views/components/_location-field-base.html +1 -0
- package/src/server/plugins/engine/views/components/geospatialfield.html +1 -0
- package/src/server/plugins/engine/views/components/osgridreffield.html +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ControllerType, controllerNameFromPath } from '@defra/forms-model';
|
|
2
|
+
import { UnknownPageControllerError } from "../../errors.js";
|
|
2
3
|
import * as PageControllers from "../index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Creates page instance for each {@link Page} type
|
|
@@ -44,7 +45,7 @@ export function createPage(model, pageDef) {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
if (typeof controller === 'undefined') {
|
|
47
|
-
throw new
|
|
48
|
+
throw new UnknownPageControllerError(pageDef.controller);
|
|
48
49
|
}
|
|
49
50
|
return controller;
|
|
50
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","names":["ControllerType","controllerNameFromPath","PageControllers","createPage","model","pageDef","controllerName","controller","QuestionPageController","Start","StartPageController","Page","Terminal","TerminalPageController","Summary","SummaryPageController","Status","StatusPageController","FileUpload","FileUploadPageController","Repeat","RepeatPageController","controllers","Ctrl"
|
|
1
|
+
{"version":3,"file":"pages.js","names":["ControllerType","controllerNameFromPath","UnknownPageControllerError","PageControllers","createPage","model","pageDef","controllerName","controller","QuestionPageController","Start","StartPageController","Page","Terminal","TerminalPageController","Summary","SummaryPageController","Status","StatusPageController","FileUpload","FileUploadPageController","Repeat","RepeatPageController","controllers","Ctrl"],"sources":["../../../../../../src/server/plugins/engine/pageControllers/helpers/pages.ts"],"sourcesContent":["import {\n ControllerType,\n controllerNameFromPath,\n type Page\n} from '@defra/forms-model'\n\nimport { UnknownPageControllerError } from '~/src/server/plugins/engine/errors.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport * as PageControllers from '~/src/server/plugins/engine/pageControllers/index.js'\n\nexport type PageControllerClass = InstanceType<PageControllerType>\nexport type PageControllerType =\n (typeof PageControllers)[keyof typeof PageControllers]\n\n/**\n * Creates page instance for each {@link Page} type\n */\nexport function createPage(model: FormModel, pageDef: Page) {\n const controllerName = controllerNameFromPath(pageDef.controller)\n\n if (!pageDef.controller) {\n return new PageControllers.QuestionPageController(model, pageDef)\n }\n\n // Patch legacy controllers\n if (controllerName && pageDef.controller !== controllerName) {\n pageDef.controller = controllerName\n }\n\n let controller: PageControllerClass | undefined\n\n switch (pageDef.controller) {\n case ControllerType.Start:\n controller = new PageControllers.StartPageController(model, pageDef)\n break\n\n case ControllerType.Page:\n controller = new PageControllers.QuestionPageController(model, pageDef)\n break\n\n case ControllerType.Terminal:\n controller = new PageControllers.TerminalPageController(model, pageDef)\n break\n\n case ControllerType.Summary:\n controller = new PageControllers.SummaryPageController(model, pageDef)\n break\n\n case ControllerType.Status:\n controller = new PageControllers.StatusPageController(model, pageDef)\n break\n\n case ControllerType.FileUpload:\n controller = new PageControllers.FileUploadPageController(model, pageDef)\n break\n\n case ControllerType.Repeat:\n controller = new PageControllers.RepeatPageController(model, pageDef)\n break\n }\n\n if (typeof controller === 'undefined') {\n if (model.controllers?.[pageDef.controller]) {\n const Ctrl = model.controllers[pageDef.controller]\n controller = new Ctrl(model, pageDef) as unknown as PageControllerClass // type assertion needed because TS can't verify custom controller structure\n }\n }\n\n if (typeof controller === 'undefined') {\n throw new UnknownPageControllerError(pageDef.controller)\n }\n\n return controller\n}\n"],"mappings":"AAAA,SACEA,cAAc,EACdC,sBAAsB,QAEjB,oBAAoB;AAE3B,SAASC,0BAA0B;AAEnC,OAAO,KAAKC,eAAe;AAM3B;AACA;AACA;AACA,OAAO,SAASC,UAAUA,CAACC,KAAgB,EAAEC,OAAa,EAAE;EAC1D,MAAMC,cAAc,GAAGN,sBAAsB,CAACK,OAAO,CAACE,UAAU,CAAC;EAEjE,IAAI,CAACF,OAAO,CAACE,UAAU,EAAE;IACvB,OAAO,IAAIL,eAAe,CAACM,sBAAsB,CAACJ,KAAK,EAAEC,OAAO,CAAC;EACnE;;EAEA;EACA,IAAIC,cAAc,IAAID,OAAO,CAACE,UAAU,KAAKD,cAAc,EAAE;IAC3DD,OAAO,CAACE,UAAU,GAAGD,cAAc;EACrC;EAEA,IAAIC,UAA2C;EAE/C,QAAQF,OAAO,CAACE,UAAU;IACxB,KAAKR,cAAc,CAACU,KAAK;MACvBF,UAAU,GAAG,IAAIL,eAAe,CAACQ,mBAAmB,CAACN,KAAK,EAAEC,OAAO,CAAC;MACpE;IAEF,KAAKN,cAAc,CAACY,IAAI;MACtBJ,UAAU,GAAG,IAAIL,eAAe,CAACM,sBAAsB,CAACJ,KAAK,EAAEC,OAAO,CAAC;MACvE;IAEF,KAAKN,cAAc,CAACa,QAAQ;MAC1BL,UAAU,GAAG,IAAIL,eAAe,CAACW,sBAAsB,CAACT,KAAK,EAAEC,OAAO,CAAC;MACvE;IAEF,KAAKN,cAAc,CAACe,OAAO;MACzBP,UAAU,GAAG,IAAIL,eAAe,CAACa,qBAAqB,CAACX,KAAK,EAAEC,OAAO,CAAC;MACtE;IAEF,KAAKN,cAAc,CAACiB,MAAM;MACxBT,UAAU,GAAG,IAAIL,eAAe,CAACe,oBAAoB,CAACb,KAAK,EAAEC,OAAO,CAAC;MACrE;IAEF,KAAKN,cAAc,CAACmB,UAAU;MAC5BX,UAAU,GAAG,IAAIL,eAAe,CAACiB,wBAAwB,CAACf,KAAK,EAAEC,OAAO,CAAC;MACzE;IAEF,KAAKN,cAAc,CAACqB,MAAM;MACxBb,UAAU,GAAG,IAAIL,eAAe,CAACmB,oBAAoB,CAACjB,KAAK,EAAEC,OAAO,CAAC;MACrE;EACJ;EAEA,IAAI,OAAOE,UAAU,KAAK,WAAW,EAAE;IACrC,IAAIH,KAAK,CAACkB,WAAW,GAAGjB,OAAO,CAACE,UAAU,CAAC,EAAE;MAC3C,MAAMgB,IAAI,GAAGnB,KAAK,CAACkB,WAAW,CAACjB,OAAO,CAACE,UAAU,CAAC;MAClDA,UAAU,GAAG,IAAIgB,IAAI,CAACnB,KAAK,EAAEC,OAAO,CAAmC,EAAC;IAC1E;EACF;EAEA,IAAI,OAAOE,UAAU,KAAK,WAAW,EAAE;IACrC,MAAM,IAAIN,0BAA0B,CAACI,OAAO,CAACE,UAAU,CAAC;EAC1D;EAEA,OAAOA,UAAU;AACnB","ignoreList":[]}
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
<div id="{{component.model.name}}" class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
|
|
74
74
|
data-locationtype="{{component.type | lower}}"
|
|
75
75
|
data-country="{{component.model.country}}"
|
|
76
|
+
data-lang="{{component.model.lang}}"
|
|
76
77
|
data-maplayers="{{component.model.mapLayers}}">
|
|
77
78
|
{{ govukFieldset({
|
|
78
79
|
legend: {
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
{% macro OsGridRefField(component) %}
|
|
5
5
|
{% set hasErrors = component.model.errorMessage %}
|
|
6
|
-
<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
|
|
6
|
+
<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
|
|
7
|
+
data-locationtype="{{component.type | lower}}"
|
|
8
|
+
data-lang="{{component.model.lang}}">
|
|
7
9
|
<div class="app-location-field-inputs">
|
|
8
10
|
{{ TextField(component) }}
|
|
9
11
|
</div>
|
package/package.json
CHANGED
|
@@ -4,6 +4,11 @@ import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
|
|
|
4
4
|
import createDrawPlugin from '@defra/interactive-map/plugins/draw-ml'
|
|
5
5
|
import { bbox } from '@turf/bbox'
|
|
6
6
|
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_LANG,
|
|
9
|
+
ENGLISH_LANG,
|
|
10
|
+
WELSH_LANG
|
|
11
|
+
} from './map-constants.js'
|
|
7
12
|
import {
|
|
8
13
|
EVENTS,
|
|
9
14
|
createMap,
|
|
@@ -15,11 +20,31 @@ import {
|
|
|
15
20
|
} from './map.js'
|
|
16
21
|
import sssiDataset from './sssi-dataset.js'
|
|
17
22
|
import { formatDelimtedList } from './utils.js'
|
|
23
|
+
import cy from '../../server/plugins/engine/i18n/translations/cy.json' with { type: 'json' }
|
|
24
|
+
import enGB from '../../server/plugins/engine/i18n/translations/en-GB.json' with { type: 'json' }
|
|
25
|
+
|
|
26
|
+
const englishTranslations = enGB.components.geospatialField.map
|
|
27
|
+
const welshTranslations = cy.components.geospatialField.map
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @type {Record<LanguageCode, GeospatialLanguageTexts>}
|
|
31
|
+
*/
|
|
32
|
+
export const languageTexts = {
|
|
33
|
+
[ENGLISH_LANG]: englishTranslations,
|
|
34
|
+
[WELSH_LANG]: welshTranslations
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get the map texts for the given language code
|
|
39
|
+
* @param {LanguageCode} lang - the lanugae code
|
|
40
|
+
*/
|
|
41
|
+
export function getTexts(lang = DEFAULT_LANG) {
|
|
42
|
+
return languageTexts[lang]
|
|
43
|
+
}
|
|
18
44
|
|
|
19
45
|
const helpPanelConfig = {
|
|
20
46
|
focus: false,
|
|
21
47
|
showLabel: true,
|
|
22
|
-
label: 'How to use this map',
|
|
23
48
|
mobile: {
|
|
24
49
|
slot: 'drawer',
|
|
25
50
|
open: true,
|
|
@@ -41,59 +66,79 @@ const helpPanelConfig = {
|
|
|
41
66
|
}
|
|
42
67
|
|
|
43
68
|
/**
|
|
69
|
+
* @param {GeospatialPanelTexts} texts
|
|
44
70
|
* @param {boolean} allowLine
|
|
45
71
|
* @param {boolean} allowShape
|
|
46
72
|
*/
|
|
47
|
-
function getLineOrShapeText(allowLine, allowShape) {
|
|
73
|
+
function getLineOrShapeText(texts, allowLine, allowShape) {
|
|
48
74
|
if (allowLine && allowShape) {
|
|
49
|
-
return
|
|
75
|
+
return texts.lineOrShapeText
|
|
50
76
|
}
|
|
51
77
|
if (allowLine) {
|
|
52
|
-
return
|
|
78
|
+
return texts.lineText
|
|
53
79
|
}
|
|
54
80
|
if (allowShape) {
|
|
55
|
-
return
|
|
81
|
+
return texts.shapeText
|
|
56
82
|
}
|
|
57
83
|
return ''
|
|
58
84
|
}
|
|
59
85
|
|
|
60
86
|
/**
|
|
87
|
+
* @param {GeospatialPanelTexts} texts
|
|
61
88
|
* @param {boolean} allowPoint
|
|
62
89
|
* @param {boolean} allowLine
|
|
63
90
|
* @param {boolean} allowShape
|
|
64
91
|
*/
|
|
65
|
-
function getAllowedTypesPhrase(allowPoint, allowLine, allowShape) {
|
|
92
|
+
function getAllowedTypesPhrase(texts, allowPoint, allowLine, allowShape) {
|
|
66
93
|
const items = []
|
|
67
94
|
|
|
68
95
|
if (allowPoint) {
|
|
69
|
-
items.push(
|
|
96
|
+
items.push(texts.typesPhrasePoint)
|
|
70
97
|
}
|
|
71
98
|
if (allowLine) {
|
|
72
|
-
items.push(
|
|
99
|
+
items.push(texts.typesPhraseLine)
|
|
73
100
|
}
|
|
74
101
|
if (allowShape) {
|
|
75
|
-
items.push(
|
|
102
|
+
items.push(texts.typesPhraseShape)
|
|
76
103
|
}
|
|
77
104
|
|
|
78
|
-
return formatDelimtedList(items, ',',
|
|
105
|
+
return formatDelimtedList(items, ',', texts.typesPhraseOr)
|
|
79
106
|
}
|
|
80
107
|
|
|
81
108
|
/**
|
|
109
|
+
* Gets the type description for a given feature
|
|
110
|
+
* @param {Feature} feature - the geojson feature
|
|
111
|
+
* @param {GeometryTexts} typeDescriptions
|
|
112
|
+
*/
|
|
113
|
+
function getTypeDescription(feature, typeDescriptions) {
|
|
114
|
+
switch (feature.geometry.type) {
|
|
115
|
+
case 'Point':
|
|
116
|
+
return typeDescriptions.point
|
|
117
|
+
case 'LineString':
|
|
118
|
+
return typeDescriptions.line
|
|
119
|
+
case 'Polygon':
|
|
120
|
+
return typeDescriptions.polygon
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @param {GeospatialPanelTexts} texts
|
|
82
126
|
* @param {boolean} allowPoint
|
|
83
127
|
* @param {boolean} allowLine
|
|
84
128
|
* @param {boolean} allowShape
|
|
85
129
|
*/
|
|
86
|
-
export function getHelpPanelHtml(allowPoint, allowLine, allowShape) {
|
|
87
|
-
const lineOrShapeText = getLineOrShapeText(allowLine, allowShape)
|
|
88
|
-
const
|
|
89
|
-
? `<li
|
|
130
|
+
export function getHelpPanelHtml(texts, allowPoint, allowLine, allowShape) {
|
|
131
|
+
const lineOrShapeText = getLineOrShapeText(texts, allowLine, allowShape)
|
|
132
|
+
const point3 = lineOrShapeText
|
|
133
|
+
? `<li>${texts.point3} ${lineOrShapeText}</li>`
|
|
90
134
|
: ''
|
|
91
135
|
const allowedTypesText = getAllowedTypesPhrase(
|
|
136
|
+
texts,
|
|
92
137
|
allowPoint,
|
|
93
138
|
allowLine,
|
|
94
139
|
allowShape
|
|
95
140
|
)
|
|
96
|
-
return `<p class="govuk-body-s govuk-!-margin-bottom-2"
|
|
141
|
+
return `<p class="govuk-body-s govuk-!-margin-bottom-2">${texts.ledeIntro} ${allowedTypesText} ${texts.ledeOutro}</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>${texts.point1}</li><li>${texts.point2}</li>${point3}<li>${texts.point4}</li></ul>`
|
|
97
142
|
}
|
|
98
143
|
|
|
99
144
|
const lineFeatureProperties = {
|
|
@@ -108,15 +153,6 @@ const polygonFeatureProperties = {
|
|
|
108
153
|
strokeWidth: 2
|
|
109
154
|
}
|
|
110
155
|
|
|
111
|
-
/**
|
|
112
|
-
* @type {Record<'Point' | 'LineString' | 'Polygon', string>}
|
|
113
|
-
*/
|
|
114
|
-
const typeDescriptions = {
|
|
115
|
-
Point: 'Point',
|
|
116
|
-
LineString: 'Line',
|
|
117
|
-
Polygon: 'Shape'
|
|
118
|
-
}
|
|
119
|
-
|
|
120
156
|
const POINT_SVG =
|
|
121
157
|
'<path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" /><circle cx="12" cy="10" r="3" />'
|
|
122
158
|
const POLYGON_SVG =
|
|
@@ -199,19 +235,30 @@ export function processGeospatial(config, geospatial, index) {
|
|
|
199
235
|
const options = {
|
|
200
236
|
geometryTypes
|
|
201
237
|
}
|
|
238
|
+
const lang = /** @type {LanguageCode} */ (
|
|
239
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
240
|
+
geospatial.dataset.lang || DEFAULT_LANG
|
|
241
|
+
)
|
|
202
242
|
const uiManager = getUIManager(
|
|
203
243
|
geojson,
|
|
204
244
|
map,
|
|
205
245
|
mapId,
|
|
206
246
|
listEl,
|
|
207
247
|
geospatialInput,
|
|
208
|
-
options
|
|
248
|
+
options,
|
|
249
|
+
lang
|
|
209
250
|
)
|
|
210
251
|
|
|
252
|
+
const languageManager = {
|
|
253
|
+
lang,
|
|
254
|
+
texts: getTexts(lang)
|
|
255
|
+
}
|
|
256
|
+
|
|
211
257
|
/**
|
|
212
258
|
* @type {Context}
|
|
213
259
|
*/
|
|
214
260
|
const context = {
|
|
261
|
+
languageManager,
|
|
215
262
|
map,
|
|
216
263
|
featuresManager,
|
|
217
264
|
activeFeatureManager,
|
|
@@ -251,15 +298,17 @@ export function addFeatureToMap(feature, drawPlugin, map) {
|
|
|
251
298
|
* @param {string} mapId - the ID of the map
|
|
252
299
|
* @param {boolean} [disabled] - render the list with disabled links
|
|
253
300
|
* @param {boolean} [readonly] - render the list in readonly mode
|
|
301
|
+
* @param {LanguageCode} [lang] - the language for the feature details
|
|
254
302
|
*/
|
|
255
303
|
export function createFeaturesHTML(
|
|
256
304
|
features,
|
|
257
305
|
mapId,
|
|
258
306
|
disabled = false,
|
|
259
|
-
readonly = false
|
|
307
|
+
readonly = false,
|
|
308
|
+
lang = DEFAULT_LANG
|
|
260
309
|
) {
|
|
261
310
|
return `<dl class="govuk-summary-list">
|
|
262
|
-
${features.map((feature, index) => createFeatureHTML(feature, index, mapId, disabled, readonly)).join('\n')}
|
|
311
|
+
${features.map((feature, index) => createFeatureHTML(feature, index, mapId, disabled, readonly, lang)).join('\n')}
|
|
263
312
|
</dl>`
|
|
264
313
|
}
|
|
265
314
|
|
|
@@ -279,14 +328,17 @@ export function focusFeature(feature, mapProvider) {
|
|
|
279
328
|
* @param {string} mapId - the ID of the map
|
|
280
329
|
* @param {boolean} [disabled] - render the list with disabled links
|
|
281
330
|
* @param {boolean} [readonly] - render the list item in readonly mode
|
|
331
|
+
* @param {LanguageCode} [lang] - the language for the feature details
|
|
282
332
|
*/
|
|
283
333
|
export function createFeatureHTML(
|
|
284
334
|
feature,
|
|
285
335
|
index,
|
|
286
336
|
mapId,
|
|
287
337
|
disabled = false,
|
|
288
|
-
readonly = false
|
|
338
|
+
readonly = false,
|
|
339
|
+
lang = DEFAULT_LANG
|
|
289
340
|
) {
|
|
341
|
+
const texts = getTexts(lang)
|
|
290
342
|
const flattened = feature.geometry.coordinates.flat(2)
|
|
291
343
|
|
|
292
344
|
const points = []
|
|
@@ -302,28 +354,28 @@ export function createFeatureHTML(
|
|
|
302
354
|
// Change action link
|
|
303
355
|
const changeAction = () => `<li class="govuk-summary-list__actions-list-item">
|
|
304
356
|
<a class="govuk-link govuk-link--no-visited-state ${disabled ? 'govuk-link--disabled' : ''}" href="#${mapId}" data-action="edit" data-id="${feature.id}"
|
|
305
|
-
data-type="${feature.geometry.type}"
|
|
357
|
+
data-type="${feature.geometry.type}">${texts.itemUpdateLink}<span class="govuk-visually-hidden"> ${texts.itemVisuallyHidden}</span></a>
|
|
306
358
|
</li>`
|
|
307
359
|
|
|
308
360
|
// Delete action link
|
|
309
361
|
const deleteAction = () => `<li class="govuk-summary-list__actions-list-item">
|
|
310
362
|
<a class="govuk-link govuk-link--no-visited-state ${disabled ? 'govuk-link--disabled' : ''}" href="#" data-action="delete" data-id="${feature.id}"
|
|
311
|
-
data-type="${feature.geometry.type}"
|
|
363
|
+
data-type="${feature.geometry.type}">${texts.itemDeleteLink}<span class="govuk-visually-hidden"> ${texts.itemVisuallyHidden}</span></a>
|
|
312
364
|
</li>`
|
|
313
365
|
|
|
314
366
|
// Focus action link
|
|
315
367
|
const focusAction = () => `<li class="govuk-summary-list__actions-list-item">
|
|
316
|
-
<a class="govuk-link govuk-link--no-visited-state" href="#${mapId}" data-action="focus" data-id="${feature.id}"
|
|
368
|
+
<a class="govuk-link govuk-link--no-visited-state" href="#${mapId}" data-action="focus" data-id="${feature.id}">${texts.itemFocusLink}<span class="govuk-visually-hidden"> ${texts.itemVisuallyHidden}</span></a>
|
|
317
369
|
</li>`
|
|
318
370
|
|
|
319
371
|
const links = readonly ? focusAction() : `${changeAction()}${deleteAction()}`
|
|
320
|
-
|
|
321
372
|
const actions = `<ul class="govuk-summary-list__actions-list">${links}</ul>`
|
|
373
|
+
const typeDescription = getTypeDescription(feature, texts.typeDescriptions)
|
|
322
374
|
|
|
323
375
|
return `<div class="govuk-summary-list__row govuk-summary-list__row--no-border">
|
|
324
376
|
<dt class="govuk-summary-list__key">
|
|
325
377
|
<div class="govuk-form-group">
|
|
326
|
-
<label class="govuk-label govuk-label--s" ${readonly ? '' : `for="description_${index}"`}
|
|
378
|
+
<label class="govuk-label govuk-label--s" ${readonly ? '' : `for="description_${index}"`}>${texts.itemLabel1} ${index + 1} ${texts.itemLabel2}</label>
|
|
327
379
|
${description}
|
|
328
380
|
</div>
|
|
329
381
|
</dt>
|
|
@@ -334,24 +386,24 @@ export function createFeatureHTML(
|
|
|
334
386
|
<div class="govuk-summary-list__row">
|
|
335
387
|
<details class="govuk-details govuk-!-margin-bottom-2">
|
|
336
388
|
<summary class="govuk-details__summary">
|
|
337
|
-
<span class="govuk-details__summary-text"
|
|
389
|
+
<span class="govuk-details__summary-text">${texts.details.summary}</span>
|
|
338
390
|
</summary>
|
|
339
391
|
<div class="govuk-details__text">
|
|
340
392
|
<dl class="govuk-summary-list">
|
|
341
393
|
<div class="govuk-summary-list__row">
|
|
342
|
-
<dt class="govuk-summary-list__key"
|
|
343
|
-
<dd class="govuk-summary-list__value">${
|
|
394
|
+
<dt class="govuk-summary-list__key">${texts.details.type}</dt>
|
|
395
|
+
<dd class="govuk-summary-list__value">${typeDescription}</dd>
|
|
344
396
|
</div>
|
|
345
397
|
<div class="govuk-summary-list__row">
|
|
346
|
-
<dt class="govuk-summary-list__key"
|
|
398
|
+
<dt class="govuk-summary-list__key">${texts.details.centroidGridReference}</dt>
|
|
347
399
|
<dd class="govuk-summary-list__value">${feature.properties.centroidGridReference}</dd>
|
|
348
400
|
</div>
|
|
349
401
|
<div class="govuk-summary-list__row">
|
|
350
|
-
<dt class="govuk-summary-list__key"
|
|
402
|
+
<dt class="govuk-summary-list__key">${texts.details.firstPointGridReference}</dt>
|
|
351
403
|
<dd class="govuk-summary-list__value">${feature.properties.coordinateGridReference}</dd>
|
|
352
404
|
</div>
|
|
353
405
|
<div class="govuk-summary-list__row">
|
|
354
|
-
<dt class="govuk-summary-list__key"
|
|
406
|
+
<dt class="govuk-summary-list__key">${texts.details.detailedCoordinates}</dt>
|
|
355
407
|
<dd class="govuk-summary-list__value">
|
|
356
408
|
<ol class="govuk-list govuk-list--number">${coordinates}</ol>
|
|
357
409
|
</dd>
|
|
@@ -510,11 +562,24 @@ function getFeaturesManager(geojson) {
|
|
|
510
562
|
* @param {string} mapId - the ID of the map
|
|
511
563
|
* @param {HTMLDivElement} listEl - where to render the feature list
|
|
512
564
|
* @param {Function} renderValue - function that renders the features JSON into the hidden textarea
|
|
565
|
+
* @param {LanguageCode} [lang] - the language for the feature details
|
|
513
566
|
* @returns {RenderList}
|
|
514
567
|
*/
|
|
515
|
-
function getListRenderer(
|
|
568
|
+
function getListRenderer(
|
|
569
|
+
geojson,
|
|
570
|
+
mapId,
|
|
571
|
+
listEl,
|
|
572
|
+
renderValue,
|
|
573
|
+
lang = DEFAULT_LANG
|
|
574
|
+
) {
|
|
516
575
|
return function renderList(disabled = false) {
|
|
517
|
-
const html = createFeaturesHTML(
|
|
576
|
+
const html = createFeaturesHTML(
|
|
577
|
+
geojson.features,
|
|
578
|
+
mapId,
|
|
579
|
+
disabled,
|
|
580
|
+
false,
|
|
581
|
+
lang
|
|
582
|
+
)
|
|
518
583
|
|
|
519
584
|
listEl.innerHTML = html
|
|
520
585
|
|
|
@@ -542,6 +607,7 @@ function getValueRenderer(geojson, geospatialInput) {
|
|
|
542
607
|
* @param {HTMLDivElement} listEl - where to render the feature list
|
|
543
608
|
* @param {HTMLTextAreaElement} geospatialInput - the geospatial textarea
|
|
544
609
|
* @param { UIManagerOptions | undefined } options - extra options such as allowable geometry types
|
|
610
|
+
* @param {LanguageCode} [lang] - the language for the feature details
|
|
545
611
|
*/
|
|
546
612
|
export function getUIManager(
|
|
547
613
|
geojson,
|
|
@@ -549,7 +615,8 @@ export function getUIManager(
|
|
|
549
615
|
mapId,
|
|
550
616
|
listEl,
|
|
551
617
|
geospatialInput,
|
|
552
|
-
options
|
|
618
|
+
options,
|
|
619
|
+
lang = DEFAULT_LANG
|
|
553
620
|
) {
|
|
554
621
|
/**
|
|
555
622
|
* Get a CSV list of geometry types the user can create
|
|
@@ -594,7 +661,7 @@ export function getUIManager(
|
|
|
594
661
|
}
|
|
595
662
|
|
|
596
663
|
const renderValue = getValueRenderer(geojson, geospatialInput)
|
|
597
|
-
const renderList = getListRenderer(geojson, mapId, listEl, renderValue)
|
|
664
|
+
const renderList = getListRenderer(geojson, mapId, listEl, renderValue, lang)
|
|
598
665
|
|
|
599
666
|
/** @type {UIManager} */
|
|
600
667
|
return {
|
|
@@ -661,17 +728,19 @@ function onMapReadyFactory(context) {
|
|
|
661
728
|
const allowPoint = types.includes('point')
|
|
662
729
|
const allowLine = types.includes('line')
|
|
663
730
|
const allowShape = types.includes('shape')
|
|
731
|
+
const { texts } = context.languageManager
|
|
664
732
|
|
|
665
733
|
// Add info panel
|
|
666
734
|
map.addPanel('info', {
|
|
667
735
|
...helpPanelConfig,
|
|
668
|
-
|
|
736
|
+
label: texts.helpPanel.label,
|
|
737
|
+
html: getHelpPanelHtml(texts.helpPanel, allowPoint, allowLine, allowShape)
|
|
669
738
|
})
|
|
670
739
|
|
|
671
740
|
if (allowPoint) {
|
|
672
741
|
map.addButton('btnAddPoint', {
|
|
673
742
|
variant: 'tertiary',
|
|
674
|
-
label:
|
|
743
|
+
label: texts.buttons.point,
|
|
675
744
|
iconSvgContent: POINT_SVG,
|
|
676
745
|
onClick: () => {
|
|
677
746
|
resetActiveFeature()
|
|
@@ -688,7 +757,7 @@ function onMapReadyFactory(context) {
|
|
|
688
757
|
if (allowShape) {
|
|
689
758
|
map.addButton('btnAddPolygon', {
|
|
690
759
|
variant: 'tertiary',
|
|
691
|
-
label:
|
|
760
|
+
label: texts.buttons.polygon,
|
|
692
761
|
iconSvgContent: POLYGON_SVG,
|
|
693
762
|
onClick: () => {
|
|
694
763
|
resetActiveFeature()
|
|
@@ -705,7 +774,7 @@ function onMapReadyFactory(context) {
|
|
|
705
774
|
if (allowLine) {
|
|
706
775
|
map.addButton('btnAddLine', {
|
|
707
776
|
variant: 'tertiary',
|
|
708
|
-
label:
|
|
777
|
+
label: texts.buttons.line,
|
|
709
778
|
iconSvgContent: LINE_SVG,
|
|
710
779
|
onClick: () => {
|
|
711
780
|
resetActiveFeature()
|
|
@@ -1129,6 +1198,7 @@ function onListElKeydownFactory() {
|
|
|
1129
1198
|
* Renders the features into the list
|
|
1130
1199
|
* @callback RenderList
|
|
1131
1200
|
* @param {boolean} [disabled] - whether to render the list with disabled links
|
|
1201
|
+
* @param {LanguageCode} [lang] - the language for the feature details
|
|
1132
1202
|
* @returns {void}
|
|
1133
1203
|
*/
|
|
1134
1204
|
|
|
@@ -1183,8 +1253,59 @@ function onListElKeydownFactory() {
|
|
|
1183
1253
|
* @property {GetAllowableGeometryTypes} getAllowableGeometryTypes - function that returns the array of geometry types a user can create
|
|
1184
1254
|
*/
|
|
1185
1255
|
|
|
1256
|
+
/**
|
|
1257
|
+
* @typedef {object} GeometryTexts
|
|
1258
|
+
* @property {string} point - the label for a point feature in the list
|
|
1259
|
+
* @property {string} line - the label for a line string feature in the list
|
|
1260
|
+
* @property {string} polygon - the label for a polygon feature in the list
|
|
1261
|
+
*/
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* @typedef {object} GeospatialPanelTexts
|
|
1265
|
+
* @property {string} label - the label for the info panel
|
|
1266
|
+
* @property {string} ledeIntro - the lede intro text for the info panel
|
|
1267
|
+
* @property {string} ledeOutro - the lede outro text for the info panel
|
|
1268
|
+
* @property {string} lineText - the label for the info panel line text
|
|
1269
|
+
* @property {string} shapeText - the label for the info panel shape text
|
|
1270
|
+
* @property {string} point1 - the text for bullet point 1 in the info panel
|
|
1271
|
+
* @property {string} point2 - the text for bullet point 2 in the info panel
|
|
1272
|
+
* @property {string} point3 - the text for bullet point 3 in the info panel
|
|
1273
|
+
* @property {string} point4 - the text for bullet point 4 in the info panel
|
|
1274
|
+
* @property {string} lineOrShapeText - the label for the info panel line or shape text
|
|
1275
|
+
* @property {string} typesPhrasePoint - the label for the info panel types phrase point
|
|
1276
|
+
* @property {string} typesPhraseLine - the label for the info panel types phrase line
|
|
1277
|
+
* @property {string} typesPhraseShape - the label for the info panel types phrase shape
|
|
1278
|
+
* @property {string} typesPhraseOr - the label for the info panel types phrase "or"
|
|
1279
|
+
*/
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* @typedef {object} GeospatialLanguageTexts
|
|
1283
|
+
* @property {GeometryTexts} typeDescriptions - the descriptions of the geometry types
|
|
1284
|
+
* @property {GeospatialPanelTexts} helpPanel - texts for the info panel
|
|
1285
|
+
* @property {GeometryTexts} buttons - the labels for the action buttons
|
|
1286
|
+
* @property {string} itemLabel1 - the first part of the label for a feature in the list
|
|
1287
|
+
* @property {string} itemLabel2 - the second part of the label for a feature in the list
|
|
1288
|
+
* @property {string} itemUpdateLink - the label for the "update" link for a feature in the list
|
|
1289
|
+
* @property {string} itemDeleteLink - the label for the "delete" link for a feature in the list
|
|
1290
|
+
* @property {string} itemFocusLink - the label for the "focus" link for a feature in the list
|
|
1291
|
+
* @property {string} itemVisuallyHidden - visually hidden text to add context to action links
|
|
1292
|
+
* @property {object} details - labels for the details section of a feature in the list
|
|
1293
|
+
* @property {string} details.summary - label for the summary of a feature in the list
|
|
1294
|
+
* @property {string} details.type - label for the type of a feature in the list
|
|
1295
|
+
* @property {string} details.centroidGridReference - label for the centroid grid reference of a feature in the list
|
|
1296
|
+
* @property {string} details.firstPointGridReference - label for the first point grid reference of a feature in the list
|
|
1297
|
+
* @property {string} details.detailedCoordinates - label for the detailed coordinates of a feature in the list
|
|
1298
|
+
*/
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* @typedef {object} LanguageManager
|
|
1302
|
+
* @property {LanguageCode} lang - the language for the interactive map
|
|
1303
|
+
* @property {GeospatialLanguageTexts} texts - the descriptions of the geometry types
|
|
1304
|
+
*/
|
|
1305
|
+
|
|
1186
1306
|
/**
|
|
1187
1307
|
* @typedef {object} Context
|
|
1308
|
+
* @property {LanguageManager} languageManager - the language manager for the interactive map
|
|
1188
1309
|
* @property {InteractiveMap} map - the interactive map
|
|
1189
1310
|
* @property {MapLibreMap} [mapProvider] - the interactive map provider
|
|
1190
1311
|
* @property {FeaturesManager} featuresManager - the features manager
|
|
@@ -1195,5 +1316,6 @@ function onListElKeydownFactory() {
|
|
|
1195
1316
|
*/
|
|
1196
1317
|
|
|
1197
1318
|
/**
|
|
1319
|
+
* @import { LanguageCode } from './map.js'
|
|
1198
1320
|
* @import { MapLibreMap, UIManagerOptions } from './map.js'
|
|
1199
1321
|
*/
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// @ts-expect-error - no types
|
|
2
2
|
import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
|
|
3
3
|
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_LANG,
|
|
6
|
+
ENGLISH_LANG,
|
|
7
|
+
WELSH_LANG
|
|
8
|
+
} from './map-constants.js'
|
|
4
9
|
import {
|
|
5
10
|
EVENTS,
|
|
6
11
|
centerMap,
|
|
@@ -14,9 +19,30 @@ import {
|
|
|
14
19
|
osGridRefToLatLong
|
|
15
20
|
} from './map.js'
|
|
16
21
|
import sssiDataset from './sssi-dataset.js'
|
|
22
|
+
import cy from '../../server/plugins/engine/i18n/translations/cy.json' with { type: 'json' }
|
|
23
|
+
import enGB from '../../server/plugins/engine/i18n/translations/en-GB.json' with { type: 'json' }
|
|
24
|
+
|
|
25
|
+
const englishTranslations = enGB.components.locationFieldBase.map
|
|
26
|
+
const welshTranslations = cy.components.locationFieldBase.map
|
|
17
27
|
|
|
18
28
|
const LOCATION_FIELD_SELECTOR = 'input.govuk-input'
|
|
19
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @type {Record<LanguageCode, LocationLanguageTexts>}
|
|
32
|
+
*/
|
|
33
|
+
export const languageTexts = {
|
|
34
|
+
[ENGLISH_LANG]: englishTranslations,
|
|
35
|
+
[WELSH_LANG]: welshTranslations
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the map texts for the given language code
|
|
40
|
+
* @param {LanguageCode} lang - the lanugae code
|
|
41
|
+
*/
|
|
42
|
+
export function getTexts(lang = DEFAULT_LANG) {
|
|
43
|
+
return languageTexts[lang]
|
|
44
|
+
}
|
|
45
|
+
|
|
20
46
|
/**
|
|
21
47
|
* Gets initial map config for a location field
|
|
22
48
|
* @param {HTMLDivElement} locationField - the location field element
|
|
@@ -437,6 +463,11 @@ export function processLocation(config, location, index) {
|
|
|
437
463
|
initConfig.plugins = [createDatasetsPlugin({ datasets })]
|
|
438
464
|
}
|
|
439
465
|
|
|
466
|
+
const lang = /** @type {LanguageCode} */ (
|
|
467
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
468
|
+
location.dataset.lang || DEFAULT_LANG
|
|
469
|
+
)
|
|
470
|
+
|
|
440
471
|
const { map, interactPlugin } = createMap(mapId, initConfig, config)
|
|
441
472
|
|
|
442
473
|
map.on(
|
|
@@ -461,11 +492,13 @@ export function processLocation(config, location, index) {
|
|
|
461
492
|
throw new Error('Not implemented')
|
|
462
493
|
}
|
|
463
494
|
|
|
495
|
+
const texts = getTexts(lang)
|
|
496
|
+
|
|
464
497
|
// Add info panel
|
|
465
498
|
map.addPanel('info', {
|
|
466
499
|
focus: false,
|
|
467
500
|
showLabel: true,
|
|
468
|
-
label:
|
|
501
|
+
label: texts.helpPanel.label,
|
|
469
502
|
mobile: {
|
|
470
503
|
slot: 'drawer',
|
|
471
504
|
open: true,
|
|
@@ -484,7 +517,7 @@ export function processLocation(config, location, index) {
|
|
|
484
517
|
dismissible: true,
|
|
485
518
|
modal: false
|
|
486
519
|
},
|
|
487
|
-
html:
|
|
520
|
+
html: `<ul><li>${texts.helpPanel.point1}</li><li>${texts.helpPanel.point2}</li><li>${texts.helpPanel.point3}</li><li>${texts.helpPanel.point4}</li></ul>`
|
|
488
521
|
})
|
|
489
522
|
|
|
490
523
|
// Enable the interact plugin
|
|
@@ -494,5 +527,20 @@ export function processLocation(config, location, index) {
|
|
|
494
527
|
}
|
|
495
528
|
|
|
496
529
|
/**
|
|
530
|
+
* @typedef {object} LocationPanelTexts
|
|
531
|
+
* @property {string} label - the label for the info panel
|
|
532
|
+
* @property {string} point1 - the text for bullet point 1 in the info panel
|
|
533
|
+
* @property {string} point2 - the text for bullet point 2 in the info panel
|
|
534
|
+
* @property {string} point3 - the text for bullet point 3 in the info panel
|
|
535
|
+
* @property {string} point4 - the text for bullet point 4 in the info panel
|
|
536
|
+
*/
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* @typedef {object} LocationLanguageTexts
|
|
540
|
+
* @property {LocationPanelTexts} helpPanel - texts for the info panel
|
|
541
|
+
*/
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* @import { LanguageCode } from './map.js'
|
|
497
545
|
* @import { InteractiveMap, InteractiveMapInitConfig, MapCenter, MapLibreMap, MapsEnvironmentConfig } from './map.js'
|
|
498
546
|
*/
|