@@ -257,15 +257,15 @@ function getFeaturesManager(geojson) {
257257 * Factory to render features into the list and hidden textarea
258258 * @param {GeoJSON } geojson - the geojson of features
259259 * @param {string } mapId - the ID of the map
260- * @param {HTMLDivElement } listContainer - where to render the feature list
260+ * @param {HTMLDivElement } listEl - where to render the feature list
261261 * @param {Function } renderValue - function that renders the features JSON into the hidden textarea
262262 * @returns {RenderList }
263263 */
264- function getListRenderer ( geojson , mapId , listContainer , renderValue ) {
264+ function getListRenderer ( geojson , mapId , listEl , renderValue ) {
265265 return function renderList ( ) {
266266 const html = createFeaturesHTML ( geojson . features , mapId )
267267
268- listContainer . innerHTML = html
268+ listEl . innerHTML = html
269269
270270 renderValue ( )
271271 }
@@ -284,41 +284,14 @@ function getValueRenderer(geojson, geospatialInput) {
284284}
285285
286286/**
287- * Processes a geospatial field to add map capability
288- * @param {MapsEnvironmentConfig } config - the geospatial field element
289- * @param {Element } geospatial - the geospatial field element
290- * @param {number } index - the 0-based index
287+ * Factory closure to manage the UI
288+ * @param {GeoJSON } geojson - the features
289+ * @param {InteractiveMap } map - the map
290+ * @param {string } mapId - the ID of the map
291+ * @param {HTMLDivElement } listEl - where to render the feature list
292+ * @param {HTMLTextAreaElement } geospatialInput - the geospatial textarea
291293 */
292- export function processGeospatial ( config , geospatial , index ) {
293- // @ts -expect-error - Defra namespace currently comes from UMD support files
294- const defra = window . defra
295-
296- if ( ! ( geospatial instanceof HTMLDivElement ) ) {
297- return
298- }
299-
300- const geospatialInput = geospatial . querySelector ( '.govuk-textarea' )
301- if ( ! ( geospatialInput instanceof HTMLTextAreaElement ) ) {
302- return
303- }
304-
305- const { listContainer, mapId } = createContainers ( geospatialInput , index )
306- const geojson = getGeoJSON ( geospatialInput )
307- const bounds = geojson . features . length ? bbox ( geojson ) : undefined
308- const drawPlugin = defra . drawMLPlugin ( )
309-
310- const initConfig = {
311- ...defaultConfig ,
312- bounds,
313- plugins : [ drawPlugin ]
314- }
315-
316- const { map, interactPlugin } = createMap ( mapId , initConfig , config )
317- const featuresManager = getFeaturesManager ( geojson )
318- const activeFeatureManager = getActiveFeatureManager ( )
319- const renderValue = getValueRenderer ( geojson , geospatialInput )
320- const renderList = getListRenderer ( geojson , mapId , listContainer , renderValue )
321-
294+ function getUIManager ( geojson , map , mapId , listEl , geospatialInput ) {
322295 /**
323296 * Toggle the hidden state of the action buttons
324297 * @type {ToggleActionButtons }
@@ -334,7 +307,7 @@ export function processGeospatial(config, geospatial, index) {
334307 * @type {FocusDescriptionInput }
335308 */
336309 function focusDescriptionInput ( ) {
337- const inputs = listContainer . querySelectorAll ( 'input' )
310+ const inputs = listEl . querySelectorAll ( 'input' )
338311 if ( inputs . length ) {
339312 const lastInput = /** @type {HTMLInputElement } */ inputs . item (
340313 inputs . length - 1
@@ -344,14 +317,53 @@ export function processGeospatial(config, geospatial, index) {
344317 }
345318 }
346319
320+ const renderValue = getValueRenderer ( geojson , geospatialInput )
321+ const renderList = getListRenderer ( geojson , mapId , listEl , renderValue )
322+
347323 /** @type {UIManager } */
348- const uiManager = {
324+ return {
349325 renderList,
350326 renderValue,
351- listContainer ,
327+ listEl ,
352328 toggleActionButtons,
353329 focusDescriptionInput
354330 }
331+ }
332+
333+ /**
334+ * Processes a geospatial field to add map capability
335+ * @param {MapsEnvironmentConfig } config - the geospatial field element
336+ * @param {Element } geospatial - the geospatial field element
337+ * @param {number } index - the 0-based index
338+ */
339+ export function processGeospatial ( config , geospatial , index ) {
340+ // @ts -expect-error - Defra namespace currently comes from UMD support files
341+ const defra = window . defra
342+
343+ if ( ! ( geospatial instanceof HTMLDivElement ) ) {
344+ return
345+ }
346+
347+ const geospatialInput = geospatial . querySelector ( '.govuk-textarea' )
348+ if ( ! ( geospatialInput instanceof HTMLTextAreaElement ) ) {
349+ return
350+ }
351+
352+ const { listEl, mapId } = createContainers ( geospatialInput , index )
353+ const geojson = getGeoJSON ( geospatialInput )
354+ const bounds = geojson . features . length ? bbox ( geojson ) : undefined
355+ const drawPlugin = defra . drawMLPlugin ( )
356+
357+ const initConfig = {
358+ ...defaultConfig ,
359+ bounds,
360+ plugins : [ drawPlugin ]
361+ }
362+
363+ const { map, interactPlugin } = createMap ( mapId , initConfig , config )
364+ const featuresManager = getFeaturesManager ( geojson )
365+ const activeFeatureManager = getActiveFeatureManager ( )
366+ const uiManager = getUIManager ( geojson , map , mapId , listEl , geospatialInput )
355367
356368 /**
357369 * @type {Context }
@@ -374,7 +386,7 @@ export function processGeospatial(config, geospatial, index) {
374386 */
375387function addEventListeners ( context ) {
376388 const { map, uiManager } = context
377- const { listContainer } = uiManager
389+ const { listEl } = uiManager
378390
379391 map . on ( EVENTS . mapReady , onMapReadyFactory ( context ) )
380392 map . on ( EVENTS . drawReady , onDrawReadyFactory ( context ) )
@@ -383,17 +395,8 @@ function addEventListeners(context) {
383395 map . on ( EVENTS . drawCancelled , onDrawCancelledFactory ( context ) )
384396 map . on ( EVENTS . interactMarkerChange , onInteractMarkerChangedFactory ( context ) )
385397
386- listContainer . addEventListener (
387- 'click' ,
388- onListContainerClickFactory ( context ) ,
389- false
390- )
391-
392- listContainer . addEventListener (
393- 'change' ,
394- onListContainerChangeFactory ( context ) ,
395- false
396- )
398+ listEl . addEventListener ( 'click' , onListElClickFactory ( context ) , false )
399+ listEl . addEventListener ( 'change' , onListElChangeFactory ( context ) , false )
397400}
398401
399402/**
@@ -422,21 +425,21 @@ function getGeoJSON(geospatialInput) {
422425 * @param {number } index - the 0 based index
423426 */
424427function createContainers ( geospatialInput , index ) {
425- const mapContainer = document . createElement ( 'div' )
428+ const mapEl = document . createElement ( 'div' )
426429 const mapId = `geospatialmap_${ index } `
427430
428- mapContainer . setAttribute ( 'id' , mapId )
429- mapContainer . setAttribute ( 'class' , 'map-container' )
431+ mapEl . setAttribute ( 'id' , mapId )
432+ mapEl . setAttribute ( 'class' , 'map-container' )
430433
431- const listContainer = document . createElement ( 'div' )
434+ const listEl = document . createElement ( 'div' )
432435 const listId = `${ mapId } _list`
433- listContainer . setAttribute ( 'id' , listId )
436+ listEl . setAttribute ( 'id' , listId )
434437
435- geospatialInput . after ( mapContainer )
436- mapContainer . after ( listContainer )
438+ geospatialInput . after ( mapEl )
439+ mapEl . after ( listEl )
437440 geospatialInput . classList . add ( 'js-hidden' )
438441
439- return { mapContainer , listContainer , mapId }
442+ return { mapEl , listEl , mapId }
440443}
441444
442445/**
@@ -689,7 +692,7 @@ function onInteractMarkerChangedFactory(context) {
689692 * Callback factory function that fires a 'click' event is fired on the list container
690693 * @param {Context } context - the UI context
691694 */
692- function onListContainerClickFactory ( context ) {
695+ function onListElClickFactory ( context ) {
693696 const {
694697 map,
695698 featuresManager,
@@ -702,45 +705,69 @@ function onListContainerClickFactory(context) {
702705 const { getActiveFeature, setActiveFeature } = activeFeatureManager
703706 const { renderList, toggleActionButtons } = uiManager
704707
708+ /**
709+ * Delete a feature
710+ * @param {string } id - the feature id
711+ * @param {string } type - the feature type
712+ */
713+ function deleteFeature ( id , type ) {
714+ if ( type === 'Point' ) {
715+ map . removeMarker ( id )
716+ removeFeature ( id )
717+ } else {
718+ drawPlugin . deleteFeature ( id )
719+ removeFeature ( id )
720+ }
721+
722+ renderList ( )
723+ }
724+
725+ /**
726+ * Start editing feature
727+ * @param {string } id - the feature id
728+ * @param {string } type - the feature type
729+ */
730+ function editFeature ( id , type ) {
731+ setActiveFeature ( id )
732+
733+ // "Change" feature link was clicked
734+ if ( type === 'Point' ) {
735+ interactPlugin . selectFeature ( { featureId : id } )
736+ interactPlugin . enable ( )
737+ } else {
738+ drawPlugin . editFeature ( id )
739+ }
740+ toggleActionButtons ( true )
741+ }
742+
705743 /**
706744 * List container delegated 'click' events handler
707745 * @param {MouseEvent } e
708746 */
709747 return function ( e ) {
710748 const target = e . target
749+
711750 if ( ! ( target instanceof HTMLElement ) ) {
712751 return
713752 }
714753
715- if ( target . tagName === 'A' && target . dataset . action && target . dataset . id ) {
754+ if (
755+ target . tagName === 'A' &&
756+ target . dataset . action &&
757+ target . dataset . id &&
758+ target . dataset . type
759+ ) {
716760 const { action, id, type } = target . dataset
717761
718762 if ( ! getActiveFeature ( ) && action === 'edit' ) {
719- setActiveFeature ( id )
720-
721- // "Change" feature link was clicked
722- if ( type === 'Point' ) {
723- interactPlugin . selectFeature ( { featureId : id } )
724- interactPlugin . enable ( )
725- } else {
726- drawPlugin . editFeature ( id )
727- }
728- toggleActionButtons ( true )
763+ editFeature ( id , type )
729764 } else {
730765 e . preventDefault ( )
731766 e . stopPropagation ( )
732767
733768 if ( action === 'delete' ) {
734769 // "Remove" feature link was clicked
735- if ( type === 'Point' ) {
736- map . removeMarker ( id )
737- removeFeature ( id )
738- } else {
739- drawPlugin . deleteFeature ( id )
740- removeFeature ( id )
741- }
742-
743- renderList ( )
770+ deleteFeature ( id , type )
744771 }
745772 }
746773 }
@@ -751,7 +778,7 @@ function onListContainerClickFactory(context) {
751778 * Callback factory function that fires a 'change' event is fired on the list container
752779 * @param {Context } context - the UI context
753780 */
754- function onListContainerChangeFactory ( context ) {
781+ function onListElChangeFactory ( context ) {
755782 const { featuresManager, uiManager } = context
756783 const { getFeature } = featuresManager
757784 const { renderValue } = uiManager
@@ -891,7 +918,7 @@ function onListContainerChangeFactory(context) {
891918 * @typedef {object } UIManager
892919 * @property {RenderValue } renderValue - function that renders the features JSON into the hidden textarea
893920 * @property {RenderList } renderList - function that renders the features into the list
894- * @property {HTMLDivElement } listContainer - the summary list of features
921+ * @property {HTMLDivElement } listEl - the summary list of features
895922 * @property {ToggleActionButtons } toggleActionButtons - function that toggles the action buttons
896923 * @property {FocusDescriptionInput } focusDescriptionInput - function that sets focus to a description input element
897924 */
0 commit comments