@defra/forms-engine-plugin 4.13.0 → 4.14.1
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 +32 -0
- package/.server/client/javascripts/geospatial-map.js +161 -70
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/map.d.ts +6 -0
- package/.server/client/javascripts/map.js +5 -0
- package/.server/client/javascripts/map.js.map +1 -1
- package/.server/client/javascripts/utils.d.ts +7 -0
- package/.server/client/javascripts/utils.js +21 -0
- package/.server/client/javascripts/utils.js.map +1 -0
- package/.server/server/forms/simple-form.yaml +9 -0
- package/.server/server/plugins/engine/components/GeospatialField.d.ts +1 -0
- package/.server/server/plugins/engine/components/GeospatialField.js +9 -5
- package/.server/server/plugins/engine/components/GeospatialField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +2 -2
- package/.server/server/plugins/engine/components/helpers/geospatial.js +32 -5
- package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/geospatial.test.js +37 -6
- package/.server/server/plugins/engine/components/helpers/geospatial.test.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +4 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/views/components/geospatialfield.html +1 -1
- package/package.json +2 -2
- package/src/client/javascripts/geospatial-map.js +168 -53
- package/src/client/javascripts/map.js +5 -0
- package/src/client/javascripts/utils.js +23 -0
- package/src/server/forms/simple-form.yaml +9 -0
- package/src/server/plugins/engine/components/GeospatialField.ts +11 -7
- package/src/server/plugins/engine/components/helpers/geospatial.ts +49 -11
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +4 -1
- package/src/server/plugins/engine/views/components/geospatialfield.html +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {boolean} allowPoint
|
|
3
|
+
* @param {boolean} allowLine
|
|
4
|
+
* @param {boolean} allowShape
|
|
5
|
+
*/
|
|
6
|
+
export function getHelpPanelHtml(allowPoint: boolean, allowLine: boolean, allowShape: boolean): string;
|
|
1
7
|
/**
|
|
2
8
|
* Extract and parses the GeoJSON from the textarea
|
|
3
9
|
* @param {HTMLTextAreaElement} geospatialInput - the textarea containing the geojson
|
|
@@ -45,6 +51,23 @@ export function focusFeature(feature: Feature, mapProvider: MapLibreMap): void;
|
|
|
45
51
|
* @param {boolean} [readonly] - render the list item in readonly mode
|
|
46
52
|
*/
|
|
47
53
|
export function createFeatureHTML(feature: Feature, index: number, mapId: string, disabled?: boolean, readonly?: boolean): string;
|
|
54
|
+
/**
|
|
55
|
+
* Factory closure to manage the UI
|
|
56
|
+
* @param {GeoJSON} geojson - the features
|
|
57
|
+
* @param {InteractiveMap} map - the map
|
|
58
|
+
* @param {string} mapId - the ID of the map
|
|
59
|
+
* @param {HTMLDivElement} listEl - where to render the feature list
|
|
60
|
+
* @param {HTMLTextAreaElement} geospatialInput - the geospatial textarea
|
|
61
|
+
* @param { UIManagerOptions | undefined } options - extra options such as allowable geometry types
|
|
62
|
+
*/
|
|
63
|
+
export function getUIManager(geojson: GeoJSON, map: InteractiveMap, mapId: string, listEl: HTMLDivElement, geospatialInput: HTMLTextAreaElement, options: UIManagerOptions | undefined): {
|
|
64
|
+
renderList: RenderList;
|
|
65
|
+
renderValue: RenderValue;
|
|
66
|
+
listEl: HTMLDivElement;
|
|
67
|
+
toggleActionButtons: (hidden: boolean) => void;
|
|
68
|
+
focusDescriptionInput: () => void;
|
|
69
|
+
getAllowableGeometryTypes: () => string[];
|
|
70
|
+
};
|
|
48
71
|
export type GeoJSON = {
|
|
49
72
|
/**
|
|
50
73
|
* - the GeoJSON type string
|
|
@@ -99,6 +122,10 @@ export type RenderValue = () => void;
|
|
|
99
122
|
* Toggles the action button hidden state
|
|
100
123
|
*/
|
|
101
124
|
export type ToggleActionButtons = (hidden: boolean) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Returns the list of geometry types a user can create
|
|
127
|
+
*/
|
|
128
|
+
export type GetAllowableGeometryTypes = () => string[];
|
|
102
129
|
/**
|
|
103
130
|
* Set focus to the last description input
|
|
104
131
|
*/
|
|
@@ -160,6 +187,10 @@ export type UIManager = {
|
|
|
160
187
|
* - function that sets focus to a description input element
|
|
161
188
|
*/
|
|
162
189
|
focusDescriptionInput: FocusDescriptionInput;
|
|
190
|
+
/**
|
|
191
|
+
* - function that returns the array of geometry types a user can create
|
|
192
|
+
*/
|
|
193
|
+
getAllowableGeometryTypes: GetAllowableGeometryTypes;
|
|
163
194
|
};
|
|
164
195
|
export type Context = {
|
|
165
196
|
/**
|
|
@@ -196,4 +227,5 @@ import type { Feature } from '../../server/plugins/engine/types.js';
|
|
|
196
227
|
import type { InteractiveMap } from '../../client/javascripts/map.js';
|
|
197
228
|
import type { FeatureCollection } from '../../server/plugins/engine/types.js';
|
|
198
229
|
import type { MapLibreMap } from '../../client/javascripts/map.js';
|
|
230
|
+
import type { UIManagerOptions } from '../../client/javascripts/map.js';
|
|
199
231
|
import type { Geometry } from '../../server/plugins/engine/types.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bbox } from '@turf/bbox';
|
|
2
2
|
import { EVENTS, createMap, defaultConfig, getCentroidGridRef, getCoordinateGridRef } from "./map.js";
|
|
3
|
+
import { formatDelimtedList } from "./utils.js";
|
|
3
4
|
const helpPanelConfig = {
|
|
4
5
|
showLabel: true,
|
|
5
6
|
label: 'How to use this map',
|
|
@@ -20,9 +21,56 @@ const helpPanelConfig = {
|
|
|
20
21
|
open: true,
|
|
21
22
|
dismissible: true,
|
|
22
23
|
modal: false
|
|
23
|
-
}
|
|
24
|
-
html: '<p class="govuk-body-s govuk-!-margin-bottom-2">You can add points, shapes or lines to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li><li>Double‑click, or select \'Done\', when you have finished drawing a line or shape</li><li>Give the location a name</li></ul>'
|
|
24
|
+
}
|
|
25
25
|
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {boolean} allowLine
|
|
29
|
+
* @param {boolean} allowShape
|
|
30
|
+
*/
|
|
31
|
+
function getLineOrShapeText(allowLine, allowShape) {
|
|
32
|
+
if (allowLine && allowShape) {
|
|
33
|
+
return 'a line or shape';
|
|
34
|
+
}
|
|
35
|
+
if (allowLine) {
|
|
36
|
+
return 'a line';
|
|
37
|
+
}
|
|
38
|
+
if (allowShape) {
|
|
39
|
+
return 'a shape';
|
|
40
|
+
}
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {boolean} allowPoint
|
|
46
|
+
* @param {boolean} allowLine
|
|
47
|
+
* @param {boolean} allowShape
|
|
48
|
+
*/
|
|
49
|
+
function getAllowedTypesPhrase(allowPoint, allowLine, allowShape) {
|
|
50
|
+
const items = [];
|
|
51
|
+
if (allowPoint) {
|
|
52
|
+
items.push('points');
|
|
53
|
+
}
|
|
54
|
+
if (allowLine) {
|
|
55
|
+
items.push('lines');
|
|
56
|
+
}
|
|
57
|
+
if (allowShape) {
|
|
58
|
+
items.push('shapes');
|
|
59
|
+
}
|
|
60
|
+
return formatDelimtedList(items, ',', 'or');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {boolean} allowPoint
|
|
65
|
+
* @param {boolean} allowLine
|
|
66
|
+
* @param {boolean} allowShape
|
|
67
|
+
*/
|
|
68
|
+
export function getHelpPanelHtml(allowPoint, allowLine, allowShape) {
|
|
69
|
+
const lineOrShapeText = getLineOrShapeText(allowLine, allowShape);
|
|
70
|
+
const doneExtra = lineOrShapeText ? `<li>Double‑click, or select 'Done', when you have finished drawing ${lineOrShapeText}</li>` : '';
|
|
71
|
+
const allowedTypesText = getAllowedTypesPhrase(allowPoint, allowLine, allowShape);
|
|
72
|
+
return `<p class="govuk-body-s govuk-!-margin-bottom-2">You can add ${allowedTypesText} to the map.</p><ul class="govuk-list govuk-list--number govuk-body-s"><li>Search for a county, place or postcode</li><li>Use the + and - icons to zoom in and out</li>${doneExtra}<li>Give the location a name</li></ul>`;
|
|
73
|
+
}
|
|
26
74
|
const lineFeatureProperties = {
|
|
27
75
|
stroke: 'rgba(0, 11, 112, 1)',
|
|
28
76
|
fill: 'rgba(0, 11, 112, 0.2)',
|
|
@@ -138,7 +186,11 @@ export function processGeospatial(config, geospatial, index) {
|
|
|
138
186
|
} = createMap(mapId, initConfig, config);
|
|
139
187
|
const featuresManager = getFeaturesManager(geojson);
|
|
140
188
|
const activeFeatureManager = getActiveFeatureManager();
|
|
141
|
-
const
|
|
189
|
+
const geometryTypes = geospatial.dataset.geometrytypes;
|
|
190
|
+
const options = {
|
|
191
|
+
geometryTypes
|
|
192
|
+
};
|
|
193
|
+
const uiManager = getUIManager(geojson, map, mapId, listEl, geospatialInput, options);
|
|
142
194
|
|
|
143
195
|
/**
|
|
144
196
|
* @type {Context}
|
|
@@ -454,16 +506,32 @@ function getValueRenderer(geojson, geospatialInput) {
|
|
|
454
506
|
* @param {string} mapId - the ID of the map
|
|
455
507
|
* @param {HTMLDivElement} listEl - where to render the feature list
|
|
456
508
|
* @param {HTMLTextAreaElement} geospatialInput - the geospatial textarea
|
|
509
|
+
* @param { UIManagerOptions | undefined } options - extra options such as allowable geometry types
|
|
457
510
|
*/
|
|
458
|
-
function getUIManager(geojson, map, mapId, listEl, geospatialInput) {
|
|
511
|
+
export function getUIManager(geojson, map, mapId, listEl, geospatialInput, options) {
|
|
512
|
+
/**
|
|
513
|
+
* Get a CSV list of geometry types the user can create
|
|
514
|
+
* @returns {string[]}
|
|
515
|
+
*/
|
|
516
|
+
function getAllowableGeometryTypes() {
|
|
517
|
+
return options?.geometryTypes ? options.geometryTypes.split(',') : ['point', 'line', 'shape'];
|
|
518
|
+
}
|
|
519
|
+
|
|
459
520
|
/**
|
|
460
521
|
* Toggle the hidden state of the action buttons
|
|
461
522
|
* @type {ToggleActionButtons}
|
|
462
523
|
*/
|
|
463
524
|
function toggleActionButtons(hidden) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
525
|
+
const types = getAllowableGeometryTypes();
|
|
526
|
+
if (types.includes('point')) {
|
|
527
|
+
map.toggleButtonState('btnAddPoint', 'hidden', hidden);
|
|
528
|
+
}
|
|
529
|
+
if (types.includes('shape')) {
|
|
530
|
+
map.toggleButtonState('btnAddPolygon', 'hidden', hidden);
|
|
531
|
+
}
|
|
532
|
+
if (types.includes('line')) {
|
|
533
|
+
map.toggleButtonState('btnAddLine', 'hidden', hidden);
|
|
534
|
+
}
|
|
467
535
|
}
|
|
468
536
|
|
|
469
537
|
/**
|
|
@@ -487,7 +555,8 @@ function getUIManager(geojson, map, mapId, listEl, geospatialInput) {
|
|
|
487
555
|
renderValue,
|
|
488
556
|
listEl,
|
|
489
557
|
toggleActionButtons,
|
|
490
|
-
focusDescriptionInput
|
|
558
|
+
focusDescriptionInput,
|
|
559
|
+
getAllowableGeometryTypes
|
|
491
560
|
};
|
|
492
561
|
}
|
|
493
562
|
|
|
@@ -539,7 +608,8 @@ function onMapReadyFactory(context) {
|
|
|
539
608
|
} = context;
|
|
540
609
|
const {
|
|
541
610
|
toggleActionButtons,
|
|
542
|
-
renderList
|
|
611
|
+
renderList,
|
|
612
|
+
getAllowableGeometryTypes
|
|
543
613
|
} = uiManager;
|
|
544
614
|
const {
|
|
545
615
|
resetActiveFeature
|
|
@@ -551,68 +621,82 @@ function onMapReadyFactory(context) {
|
|
|
551
621
|
* @param {MapLibreMap} e.map - the map provider instance
|
|
552
622
|
*/
|
|
553
623
|
return function onMapReady(e) {
|
|
624
|
+
const types = getAllowableGeometryTypes();
|
|
625
|
+
const allowPoint = types.includes('point');
|
|
626
|
+
const allowLine = types.includes('line');
|
|
627
|
+
const allowShape = types.includes('shape');
|
|
628
|
+
|
|
554
629
|
// Add info panel
|
|
555
|
-
map.addPanel('info',
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
label: 'Add point',
|
|
559
|
-
iconSvgContent: POINT_SVG,
|
|
560
|
-
onClick: () => {
|
|
561
|
-
resetActiveFeature();
|
|
562
|
-
toggleActionButtons(true);
|
|
563
|
-
renderList(true);
|
|
564
|
-
interactPlugin.enable();
|
|
565
|
-
},
|
|
566
|
-
mobile: {
|
|
567
|
-
slot: 'actions'
|
|
568
|
-
},
|
|
569
|
-
tablet: {
|
|
570
|
-
slot: 'actions'
|
|
571
|
-
},
|
|
572
|
-
desktop: {
|
|
573
|
-
slot: 'actions'
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
map.addButton('btnAddPolygon', {
|
|
577
|
-
variant: 'tertiary',
|
|
578
|
-
label: 'Add shape',
|
|
579
|
-
iconSvgContent: POLYGON_SVG,
|
|
580
|
-
onClick: () => {
|
|
581
|
-
resetActiveFeature();
|
|
582
|
-
toggleActionButtons(true);
|
|
583
|
-
renderList(true);
|
|
584
|
-
drawPlugin.newPolygon(generateID(), polygonFeatureProperties);
|
|
585
|
-
},
|
|
586
|
-
mobile: {
|
|
587
|
-
slot: 'actions'
|
|
588
|
-
},
|
|
589
|
-
tablet: {
|
|
590
|
-
slot: 'actions'
|
|
591
|
-
},
|
|
592
|
-
desktop: {
|
|
593
|
-
slot: 'actions'
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
map.addButton('btnAddLine', {
|
|
597
|
-
variant: 'tertiary',
|
|
598
|
-
label: 'Add line',
|
|
599
|
-
iconSvgContent: LINE_SVG,
|
|
600
|
-
onClick: () => {
|
|
601
|
-
resetActiveFeature();
|
|
602
|
-
toggleActionButtons(true);
|
|
603
|
-
renderList(true);
|
|
604
|
-
drawPlugin.newLine(generateID(), lineFeatureProperties);
|
|
605
|
-
},
|
|
606
|
-
mobile: {
|
|
607
|
-
slot: 'actions'
|
|
608
|
-
},
|
|
609
|
-
tablet: {
|
|
610
|
-
slot: 'actions'
|
|
611
|
-
},
|
|
612
|
-
desktop: {
|
|
613
|
-
slot: 'actions'
|
|
614
|
-
}
|
|
630
|
+
map.addPanel('info', {
|
|
631
|
+
...helpPanelConfig,
|
|
632
|
+
html: getHelpPanelHtml(allowPoint, allowLine, allowShape)
|
|
615
633
|
});
|
|
634
|
+
if (allowPoint) {
|
|
635
|
+
map.addButton('btnAddPoint', {
|
|
636
|
+
variant: 'tertiary',
|
|
637
|
+
label: 'Add point',
|
|
638
|
+
iconSvgContent: POINT_SVG,
|
|
639
|
+
onClick: () => {
|
|
640
|
+
resetActiveFeature();
|
|
641
|
+
toggleActionButtons(true);
|
|
642
|
+
renderList(true);
|
|
643
|
+
interactPlugin.enable();
|
|
644
|
+
},
|
|
645
|
+
mobile: {
|
|
646
|
+
slot: 'actions'
|
|
647
|
+
},
|
|
648
|
+
tablet: {
|
|
649
|
+
slot: 'actions'
|
|
650
|
+
},
|
|
651
|
+
desktop: {
|
|
652
|
+
slot: 'actions'
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
if (allowShape) {
|
|
657
|
+
map.addButton('btnAddPolygon', {
|
|
658
|
+
variant: 'tertiary',
|
|
659
|
+
label: 'Add shape',
|
|
660
|
+
iconSvgContent: POLYGON_SVG,
|
|
661
|
+
onClick: () => {
|
|
662
|
+
resetActiveFeature();
|
|
663
|
+
toggleActionButtons(true);
|
|
664
|
+
renderList(true);
|
|
665
|
+
drawPlugin.newPolygon(generateID(), polygonFeatureProperties);
|
|
666
|
+
},
|
|
667
|
+
mobile: {
|
|
668
|
+
slot: 'actions'
|
|
669
|
+
},
|
|
670
|
+
tablet: {
|
|
671
|
+
slot: 'actions'
|
|
672
|
+
},
|
|
673
|
+
desktop: {
|
|
674
|
+
slot: 'actions'
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
if (allowLine) {
|
|
679
|
+
map.addButton('btnAddLine', {
|
|
680
|
+
variant: 'tertiary',
|
|
681
|
+
label: 'Add line',
|
|
682
|
+
iconSvgContent: LINE_SVG,
|
|
683
|
+
onClick: () => {
|
|
684
|
+
resetActiveFeature();
|
|
685
|
+
toggleActionButtons(true);
|
|
686
|
+
renderList(true);
|
|
687
|
+
drawPlugin.newLine(generateID(), lineFeatureProperties);
|
|
688
|
+
},
|
|
689
|
+
mobile: {
|
|
690
|
+
slot: 'actions'
|
|
691
|
+
},
|
|
692
|
+
tablet: {
|
|
693
|
+
slot: 'actions'
|
|
694
|
+
},
|
|
695
|
+
desktop: {
|
|
696
|
+
slot: 'actions'
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
}
|
|
616
700
|
|
|
617
701
|
// Set the map provider on the context
|
|
618
702
|
context.mapProvider = e.map;
|
|
@@ -1083,6 +1167,12 @@ function onListElKeydownFactory() {
|
|
|
1083
1167
|
* @returns {void}
|
|
1084
1168
|
*/
|
|
1085
1169
|
|
|
1170
|
+
/**
|
|
1171
|
+
* Returns the list of geometry types a user can create
|
|
1172
|
+
* @callback GetAllowableGeometryTypes
|
|
1173
|
+
* @returns {string[]}
|
|
1174
|
+
*/
|
|
1175
|
+
|
|
1086
1176
|
/**
|
|
1087
1177
|
* Set focus to the last description input
|
|
1088
1178
|
* @callback FocusDescriptionInput
|
|
@@ -1112,6 +1202,7 @@ function onListElKeydownFactory() {
|
|
|
1112
1202
|
* @property {HTMLDivElement} listEl - the summary list of features
|
|
1113
1203
|
* @property {ToggleActionButtons} toggleActionButtons - function that toggles the action buttons
|
|
1114
1204
|
* @property {FocusDescriptionInput} focusDescriptionInput - function that sets focus to a description input element
|
|
1205
|
+
* @property {GetAllowableGeometryTypes} getAllowableGeometryTypes - function that returns the array of geometry types a user can create
|
|
1115
1206
|
*/
|
|
1116
1207
|
|
|
1117
1208
|
/**
|
|
@@ -1126,6 +1217,6 @@ function onListElKeydownFactory() {
|
|
|
1126
1217
|
*/
|
|
1127
1218
|
|
|
1128
1219
|
/**
|
|
1129
|
-
* @import { MapLibreMap } from '../../client/javascripts/map.js'
|
|
1220
|
+
* @import { MapLibreMap, UIManagerOptions } from '../../client/javascripts/map.js'
|
|
1130
1221
|
*/
|
|
1131
1222
|
//# sourceMappingURL=geospatial-map.js.map
|