diff --git a/loko/assets/static/assets/unified_index.js b/loko/assets/static/assets/unified_index.js
index c2b8ade..2218f18 100644
--- a/loko/assets/static/assets/unified_index.js
+++ b/loko/assets/static/assets/unified_index.js
@@ -748,6 +748,14 @@ function applyInitialPreferences() {
window._restoredMapCenter = prefs.map_center;
window._restoredMapZoom = prefs.map_zoom;
}
+
+ // Basemap preference
+ if (prefs.basemap) {
+ window._restoredBasemap = prefs.basemap;
+ try {
+ localStorage.setItem('loko_active_basemap', prefs.basemap);
+ } catch (e) {}
+ }
} else if (DEFAULT_THEMATIC_CODE && DEFAULT_THEMATIC_CODE in THEMATIC_CONFIG) {
// First visit: pre-select the user's default thematic
activeThematics = new Set([DEFAULT_THEMATIC_CODE]);
@@ -775,6 +783,9 @@ function savePreferences() {
).map(cb => cb.value);
const includeNoGeomCheckbox = document.getElementById('include-no-geom');
const includeNoGeom = includeNoGeomCheckbox ? includeNoGeomCheckbox.checked : true;
+ const activeBasemap = (window.unifiedLayerSwitcher && window.unifiedLayerSwitcher.activeBasemapId)
+ || localStorage.getItem('loko_active_basemap')
+ || 'default';
const prefs = {
thematics: Array.from(activeThematics),
categories: Array.from(activeCategories),
@@ -787,6 +798,7 @@ function savePreferences() {
include_no_geom: includeNoGeom,
map_center: (typeof map !== 'undefined' && map.getCenter) ? [map.getCenter().lng, map.getCenter().lat] : null,
map_zoom: (typeof map !== 'undefined' && map.getZoom) ? map.getZoom() : null,
+ basemap: activeBasemap,
};
fetch(SAVE_ASSETS_PREFS_URL, {
method: 'POST',
@@ -2929,7 +2941,12 @@ maploader.addEventListener('mapLoaded', () => {
// Layer switcher — Urbis & Vlaanderen orthos (top-right, topmost)
if (typeof LayerSwitcherControl !== 'undefined') {
+ const initialBasemap = window._restoredBasemap || localStorage.getItem('loko_active_basemap') || 'default';
const layerSwitcher = new LayerSwitcherControl({
+ initialBasemapId: initialBasemap,
+ onBasemapChange: function (basemapId) {
+ schedulePreferencesSave();
+ },
layers: [{
id: 'basemap',
name: 'Fonds de plan & Orthophotos',
@@ -2937,7 +2954,10 @@ maploader.addEventListener('mapLoaded', () => {
beforeLayer: (map && map.getLayer('territory-mask') ? 'territory-mask' : 'locations'),
basemaps: window.MAP_BACKGROUNDS || [],
}],
- });// Reset view — fly back to initial Brussels Region view
+ });
+ window.unifiedLayerSwitcher = layerSwitcher;
+
+ // Reset view — fly back to initial Brussels Region view
map.addControl({
onAdd(m) {
this._map = m;
diff --git a/loko/assets/templates/assets/unified_index.html b/loko/assets/templates/assets/unified_index.html
index e7dea0c..ebe2085 100644
--- a/loko/assets/templates/assets/unified_index.html
+++ b/loko/assets/templates/assets/unified_index.html
@@ -1315,7 +1315,7 @@
{% block script %}
-
+
-
+
{% endblock script %}
\ No newline at end of file
diff --git a/loko/common/locale/en/LC_MESSAGES/django.mo b/loko/common/locale/en/LC_MESSAGES/django.mo
index 7eb40fc..a64342f 100644
Binary files a/loko/common/locale/en/LC_MESSAGES/django.mo and b/loko/common/locale/en/LC_MESSAGES/django.mo differ
diff --git a/loko/common/locale/en/LC_MESSAGES/django.po b/loko/common/locale/en/LC_MESSAGES/django.po
index cdbbd5c..5c1f710 100644
--- a/loko/common/locale/en/LC_MESSAGES/django.po
+++ b/loko/common/locale/en/LC_MESSAGES/django.po
@@ -553,3 +553,8 @@ msgstr "Zoom in"
#: common/templates/common/components/document_viewer.html
msgid "Réinitialiser"
msgstr "Reset"
+
+#: common/views.py:683
+msgid "Format de fond de plan invalide"
+msgstr "Invalid basemap format"
+
diff --git a/loko/common/locale/fr/LC_MESSAGES/django.mo b/loko/common/locale/fr/LC_MESSAGES/django.mo
index 8d040b2..94e12ae 100644
Binary files a/loko/common/locale/fr/LC_MESSAGES/django.mo and b/loko/common/locale/fr/LC_MESSAGES/django.mo differ
diff --git a/loko/common/locale/fr/LC_MESSAGES/django.po b/loko/common/locale/fr/LC_MESSAGES/django.po
index 0b12f73..b125da3 100644
--- a/loko/common/locale/fr/LC_MESSAGES/django.po
+++ b/loko/common/locale/fr/LC_MESSAGES/django.po
@@ -539,3 +539,8 @@ msgstr "Zoomer"
#: common/templates/common/components/document_viewer.html
msgid "Réinitialiser"
msgstr "Réinitialiser"
+
+#: common/views.py:683
+msgid "Format de fond de plan invalide"
+msgstr "Format de fond de plan invalide"
+
diff --git a/loko/common/locale/nl/LC_MESSAGES/django.mo b/loko/common/locale/nl/LC_MESSAGES/django.mo
index e47b6d7..d8192e4 100644
Binary files a/loko/common/locale/nl/LC_MESSAGES/django.mo and b/loko/common/locale/nl/LC_MESSAGES/django.mo differ
diff --git a/loko/common/locale/nl/LC_MESSAGES/django.po b/loko/common/locale/nl/LC_MESSAGES/django.po
index dd7466b..bc848c5 100644
--- a/loko/common/locale/nl/LC_MESSAGES/django.po
+++ b/loko/common/locale/nl/LC_MESSAGES/django.po
@@ -539,3 +539,8 @@ msgstr "Inzoomen"
#: common/templates/common/components/document_viewer.html
msgid "Réinitialiser"
msgstr "Herstellen"
+
+#: common/views.py:683
+msgid "Format de fond de plan invalide"
+msgstr "Ongeldig basiskaartformaat"
+
diff --git a/loko/common/static/common/layer-switcher-control.js b/loko/common/static/common/layer-switcher-control.js
index 5e37a1d..495b05f 100644
--- a/loko/common/static/common/layer-switcher-control.js
+++ b/loko/common/static/common/layer-switcher-control.js
@@ -381,7 +381,8 @@
// Extract or build basemaps list
this.basemaps = this._resolveBasemaps();
- this.activeBasemapId = localStorage.getItem('loko_active_basemap') || 'default';
+ this.activeBasemapId = options.initialBasemapId || localStorage.getItem('loko_active_basemap') || 'default';
+ this.onBasemapChange = typeof options.onBasemapChange === 'function' ? options.onBasemapChange : null;
this._injectStyles();
this._handleOutsideClick = this._handleOutsideClick.bind(this);
@@ -442,13 +443,26 @@
this.popover = this._createPopover();
map.getContainer().appendChild(this.popover);
- // Initialize active basemap on map load
- if (map.loaded()) {
+ // Initialize active basemap on map load (checking map._loaded, isStyleLoaded, or loaded)
+ const isMapReady = Boolean(
+ map._loaded ||
+ (typeof map.isStyleLoaded === 'function' && map.isStyleLoaded()) ||
+ map.loaded()
+ );
+
+ if (isMapReady) {
this._applyInitialBasemap();
} else {
- map.on('load', () => this._applyInitialBasemap());
+ map.once('load', () => this._applyInitialBasemap());
}
+ // Re-apply if the style reloads dynamically
+ map.on('style.load', () => {
+ if (this.activeBasemapId && this.activeBasemapId !== 'default') {
+ this._applyInitialBasemap();
+ }
+ });
+
document.addEventListener('click', this._handleOutsideClick);
return this.container;
@@ -660,8 +674,11 @@
}
selectBasemap(id) {
+ const previousId = this.activeBasemapId;
this.activeBasemapId = id;
- localStorage.setItem('loko_active_basemap', id);
+ try {
+ localStorage.setItem('loko_active_basemap', id);
+ } catch (e) {}
// Update UI list items
if (this.popover) {
@@ -682,9 +699,20 @@
this._applyRasterBasemap(bgConfig);
}
}
+
+ if (this.onBasemapChange && previousId !== id) {
+ try {
+ this.onBasemapChange(id);
+ } catch (err) {
+ console.error('[LayerSwitcherControl] onBasemapChange error:', err);
+ }
+ }
}
_applyInitialBasemap() {
+ if (!this.basemaps || this.basemaps.length === 0) {
+ this.basemaps = this._resolveBasemaps();
+ }
if (this.activeBasemapId && this.activeBasemapId !== 'default') {
const bgConfig = this.basemaps.find(b => b.id === this.activeBasemapId);
if (bgConfig) {
@@ -693,13 +721,15 @@
return;
}
}
- // Check if any basemap has is_default
- const defaultBg = this.basemaps.find(b => b.is_default);
- if (defaultBg) {
- this.selectBasemap(defaultBg.id);
- } else {
- this._updateButtonState();
+ // Check if any basemap has is_default only if activeBasemapId is not set
+ if (!this.activeBasemapId) {
+ const defaultBg = this.basemaps.find(b => b.is_default);
+ if (defaultBg) {
+ this.selectBasemap(defaultBg.id);
+ return;
+ }
}
+ this._updateButtonState();
}
_removeCurrentRasterLayer() {
diff --git a/loko/common/tests.py b/loko/common/tests.py
index f0ab794..48fbb8e 100644
--- a/loko/common/tests.py
+++ b/loko/common/tests.py
@@ -324,6 +324,35 @@ class AssetsIndexPreferencesTests(TestCase):
self.assertEqual(response.status_code, 400)
self.assertIn("error", response.json())
+ def test_save_assets_index_preferences_with_basemap(self):
+ self.client.force_login(self.superuser)
+ save_url = reverse("common:save_assets_index_preferences")
+ payload = {
+ "thematics": ["sign"],
+ "basemap": "urbis_ortho",
+ }
+ response = self.client.post(save_url, json.dumps(payload), content_type="application/json")
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(response.json().get("success"))
+
+ from common.models import UserConfig
+ config = UserConfig.objects.get(user=self.superuser)
+ self.assertEqual(
+ config.assets_index_preferences.get("basemap"),
+ "urbis_ortho"
+ )
+
+ def test_save_assets_index_preferences_invalid_basemap_returns_400(self):
+ self.client.force_login(self.superuser)
+ save_url = reverse("common:save_assets_index_preferences")
+ payload = {
+ "basemap": 9999,
+ }
+ response = self.client.post(save_url, json.dumps(payload), content_type="application/json")
+ self.assertEqual(response.status_code, 400)
+ self.assertIn("error", response.json())
+
+
class UserConfigCopyTests(TestCase):
diff --git a/loko/common/views.py b/loko/common/views.py
index 1683737..c5c7cec 100644
--- a/loko/common/views.py
+++ b/loko/common/views.py
@@ -663,6 +663,7 @@ def save_assets_index_preferences(request):
include_no_geom = data.get('include_no_geom', True)
map_center = data.get('map_center')
map_zoom = data.get('map_zoom')
+ basemap = data.get('basemap')
if not isinstance(thematics, list):
return JsonResponse({'error': _('Format de thématiques invalide')}, status=400)
@@ -680,13 +681,18 @@ def save_assets_index_preferences(request):
return JsonResponse({'error': _('Format de filtres statut invalide')}, status=400)
if not isinstance(validation_status_filters, list):
return JsonResponse({'error': _('Format de filtres statut de validation invalide')}, status=400)
+ if basemap is not None and not isinstance(basemap, str):
+ return JsonResponse({'error': _('Format de fond de plan invalide')}, status=400)
try:
user_config, _created = UserConfig.objects.get_or_create(user=request.user)
existing_prefs = user_config.assets_index_preferences or {}
- existing_visible_columns = existing_prefs.get('visible_columns', []) if isinstance(existing_prefs, dict) else []
+ if not isinstance(existing_prefs, dict):
+ existing_prefs = {}
+ existing_visible_columns = existing_prefs.get('visible_columns', [])
if not isinstance(existing_visible_columns, list):
existing_visible_columns = []
+ existing_basemap = existing_prefs.get('basemap', 'default')
user_config.assets_index_preferences = {
'thematics': thematics,
@@ -700,6 +706,7 @@ def save_assets_index_preferences(request):
'include_no_geom': include_no_geom,
'map_center': map_center,
'map_zoom': map_zoom,
+ 'basemap': basemap if basemap is not None else existing_basemap,
}
user_config.save(update_fields=['assets_index_preferences'])
return JsonResponse({'success': True})