diff --git a/loko/assets/static/assets/asset_generic_map.js b/loko/assets/static/assets/asset_generic_map.js index a7ced9a..36c7815 100644 --- a/loko/assets/static/assets/asset_generic_map.js +++ b/loko/assets/static/assets/asset_generic_map.js @@ -94,6 +94,9 @@ addIntersectionAssetsLayer(container); addConnectionLinesLayer(); } + + // Ensure asset layers are stacked above basemaps + bringAssetLayersToTop(); }); } @@ -224,6 +227,8 @@ addLineLayer(); addPointLayer(); } + + bringAssetLayersToTop(); } function addPointLayer() { @@ -651,9 +656,29 @@ 'current-asset-icon', ]; + function getBasemapBeforeLayer(m) { + if (!m || !m.getStyle) return undefined; + const styleLayers = (m.getStyle() && m.getStyle().layers) || []; + const drawLayer = styleLayers.find(l => l.id && (l.id.startsWith('gl-draw-') || l.id.startsWith('custom-draw-'))); + if (drawLayer) return drawLayer.id; + + // Return first existing asset layer so basemap is placed below it + for (const id of ASSET_LAYER_ORDER) { + if (m.getLayer(id)) return id; + } + return undefined; + } + function bringAssetLayersToTop() { + if (!map || typeof map.isStyleLoaded !== 'function' || !map.isStyleLoaded()) return; ASSET_LAYER_ORDER.forEach(id => { - if (map.getLayer(id)) map.moveLayer(id); + if (map.getLayer(id)) { + try { + map.moveLayer(id); + } catch (e) { + // ignore if layer cannot be moved + } + } }); } @@ -661,16 +686,25 @@ if (typeof LayerSwitcherControl === 'undefined') return; const layerSwitcher = new LayerSwitcherControl({ + onBasemapChange: function() { + bringAssetLayersToTop(); + }, layers: [ { id: 'ortho', name: 'Orthophotos', icon: 'satellite', group: 'ortho', + beforeLayer: getBasemapBeforeLayer, + onLayerAdded: () => bringAssetLayersToTop(), + onVisibilityChange: (layerId, isVisible) => { + if (isVisible) bringAssetLayersToTop(); + }, layer: { type: 'raster', paint: { 'raster-opacity': 1 } }, + basemaps: (window.MAP_BACKGROUNDS && window.MAP_BACKGROUNDS.length > 0) ? window.MAP_BACKGROUNDS : undefined, sublayers: [ { id: 'urbis', @@ -700,6 +734,12 @@ map.addControl(layerSwitcher, 'top-left'); + // Listen for layer switcher events on map to keep asset layers on top + map.on('layerswitcher:layerAdded', bringAssetLayersToTop); + map.on('layerswitcher:visibilityChange', (e) => { + if (e && e.visible) bringAssetLayersToTop(); + }); + // The LayerSwitcherControl appends sublayer selectors to document.body with // position:fixed and hardcoded coordinates designed for fullscreen maps. // We move each selector into #asset-map (position:relative) and switch to @@ -723,8 +763,9 @@ // After any ortho interaction, put asset layers back on top map.getContainer().addEventListener('click', (e) => { - if (e.target.closest('.layer-switcher-btn') || e.target.closest('.layer-switcher-sublayer-btn')) { - setTimeout(bringAssetLayersToTop, 150); + if (e.target.closest('.layer-switcher-btn') || e.target.closest('.layer-switcher-sublayer-btn') || e.target.closest('.layer-switcher-item')) { + setTimeout(bringAssetLayersToTop, 50); + setTimeout(bringAssetLayersToTop, 200); } }, true); } @@ -761,6 +802,10 @@ }); } } + + bringAssetLayersToTop(); }; + window.bringAssetLayersToTop = bringAssetLayersToTop; + })(); diff --git a/loko/assets/static/assets/asset_geometry_edit.js b/loko/assets/static/assets/asset_geometry_edit.js index 46f97d7..986b747 100644 --- a/loko/assets/static/assets/asset_geometry_edit.js +++ b/loko/assets/static/assets/asset_geometry_edit.js @@ -278,6 +278,10 @@ } }); + if (typeof window.bringAssetLayersToTop === 'function') { + window.bringAssetLayersToTop(); + } + // Remove draw control and listeners if (drawInstance && drawControlAdded) { mapInstance.off('draw.create', handleDrawCreate); diff --git a/loko/assets/templates/assets/detail_generic.html b/loko/assets/templates/assets/detail_generic.html index 9cb723e..2378e61 100644 --- a/loko/assets/templates/assets/detail_generic.html +++ b/loko/assets/templates/assets/detail_generic.html @@ -1852,11 +1852,11 @@ {% block script %} - + - + @@ -1865,11 +1865,11 @@ {% block extra_scripts %} - + - + diff --git a/loko/assets/tests.py b/loko/assets/tests.py index 2867f86..53588b2 100644 --- a/loko/assets/tests.py +++ b/loko/assets/tests.py @@ -26,7 +26,7 @@ class NatureLocationsGeoJSONTest(TestCase): # Create a user self.user = User.objects.create_user(username="testuser", password="password123") - self.config = UserConfig.objects.create(user=self.user) + self.config = UserConfig.objects.create(user=self.user, is_intern=True, limit_assets_to_contracts=False) # Give thematic access to user UserThematics.objects.create( @@ -5720,6 +5720,8 @@ class NatureLocationDetailViewTest(TestCase): self.assertTemplateNotUsed(response, 'assets/naturegreensurface_detail.html') self.assertContains(response, "GS-001") self.assertContains(response, 'id="asset-map"') + self.assertContains(response, 'asset_generic_map.js?v=20261010_order') + self.assertContains(response, 'layer-switcher-control.js?v=20261010_order') diff --git a/loko/common/static/common/layer-switcher-control.js b/loko/common/static/common/layer-switcher-control.js index 495b05f..ceaba9f 100644 --- a/loko/common/static/common/layer-switcher-control.js +++ b/loko/common/static/common/layer-switcher-control.js @@ -748,6 +748,9 @@ if (mainLayer.onVisibilityChange && typeof mainLayer.onVisibilityChange === 'function') { mainLayer.onVisibilityChange(layerId, false, this.map); } + if (typeof this.options.onVisibilityChange === 'function') { + this.options.onVisibilityChange(layerId, false, this.map); + } if (typeof this.map.fire === 'function') { this.map.fire('layerswitcher:visibilityChange', { layerId, visible: false }); } @@ -776,7 +779,7 @@ const mainLayer = this.layers[0] || {}; let beforeLayer = typeof mainLayer.beforeLayer === 'function' ? mainLayer.beforeLayer(this.map) - : mainLayer.beforeLayer; + : (mainLayer.beforeLayer || (typeof this.options.beforeLayer === 'function' ? this.options.beforeLayer(this.map) : this.options.beforeLayer)); if (this.map.getLayer('territory-mask')) { beforeLayer = 'territory-mask'; @@ -788,7 +791,15 @@ beforeLayer = undefined; const layers = (this.map.getStyle() && this.map.getStyle().layers) || []; for (const l of layers) { - if (l.id.startsWith('gl-draw-') || l.id.startsWith('custom-draw-') || l.id.startsWith('polygon-')) { + if ( + l.id.startsWith('gl-draw-') || + l.id.startsWith('custom-draw-') || + l.id.startsWith('polygon-') || + l.id.startsWith('asset-') || + l.id.startsWith('nature-') || + l.id.startsWith('layer-') || + l.id.startsWith('intersection-') + ) { beforeLayer = l.id; break; } @@ -827,9 +838,15 @@ if (mainLayer.onLayerAdded && typeof mainLayer.onLayerAdded === 'function') { mainLayer.onLayerAdded(layerId, this.map); } + if (typeof this.options.onLayerAdded === 'function') { + this.options.onLayerAdded(layerId, this.map); + } if (mainLayer.onVisibilityChange && typeof mainLayer.onVisibilityChange === 'function') { mainLayer.onVisibilityChange(layerId, true, this.map); } + if (typeof this.options.onVisibilityChange === 'function') { + this.options.onVisibilityChange(layerId, true, this.map); + } if (typeof this.map.fire === 'function') { this.map.fire('layerswitcher:layerAdded', { layerId, config: bg }); this.map.fire('layerswitcher:visibilityChange', { layerId, visible: true });