Skip to content

Commit b7b835e

Browse files
Sonar fixes
1 parent fb7c3e0 commit b7b835e

1 file changed

Lines changed: 110 additions & 83 deletions

File tree

src/client/javascripts/geospatial-map.js

Lines changed: 110 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
375387
function 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
*/
424427
function 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

Comments
 (0)