diff --git a/src/components/Dropdown.vue b/src/components/Dropdown.vue index 9c37eefcf222732d5af1d9ea81b93b065e23bc2e..29c52e5214b95550c8ff4a63429ed1d5ad789cf6 100644 --- a/src/components/Dropdown.vue +++ b/src/components/Dropdown.vue @@ -10,16 +10,16 @@ > <input v-if="search" + v-model="input" + v-on:keyup.enter="select(0)" + @input="handelInput" class="search" autocomplete="off" tabindex="0" - @input="handelInput" - v-on:keyup.enter="select(0)" - v-model="input" - :placeholder="placeholder" + :placeholder="placehold" /> <!-- {{placeholder}} --> - <div class="default text">{{ selected || placeholder }}</div> + <div v-if="!input" class="default text">{{ selected || placeholder }}</div> <i :class="['dropdown icon', { clear: search && selected }]" @click="clear" @@ -57,6 +57,10 @@ export default { } return options.length > 0 ? options : null; }, + + placehold() { + return this.input ? "" : this.placeholder; + }, }, data() { @@ -70,6 +74,7 @@ export default { toggleDropdown() { this.isOpen = !this.isOpen; }, + select(index) { setTimeout(() => { this.isOpen = false; // * quick & dirty, car toggle dropdown est rappelé plusieurs fois aileurs, à creuser... @@ -77,24 +82,29 @@ export default { this.$emit("update:selection", this.options[index]); this.input = ""; }, + searchOptions(options) { return options.filter((el) => el.toLowerCase().includes(this.input.toLowerCase()) ); }, + clear() { if (this.search) { this.input = ""; this.clearSelected(); } }, + clearSelected() { this.$emit("update:selection", ""); }, + handelInput() { this.isOpen = true; this.clearSelected(); }, + clickOutsideDropdown(e) { if (!e.target.closest(`#custom-dropdown${this.identifier}`)) this.isOpen = false; @@ -102,11 +112,7 @@ export default { }, created() { - let randomnum = - Math.floor( - Math.random() * 10000 - ); - this.identifier = randomnum; + this.identifier = Math.floor(Math.random() * 10000); window.addEventListener("mousedown", this.clickOutsideDropdown); }, diff --git a/src/components/map-layers/SidebarLayers.vue b/src/components/map-layers/SidebarLayers.vue index c67abca84ad04a8c5520d5960285dc4cef572985..8ee1575b5b5e6790735d6d1dca07218175aaf406 100644 --- a/src/components/map-layers/SidebarLayers.vue +++ b/src/components/map-layers/SidebarLayers.vue @@ -47,7 +47,6 @@ <div v-for="basemap in baseMaps" - :key="`list-${basemap.id}`" class="basemaps-items ui accordion styled" > @@ -58,15 +57,17 @@ > {{ basemap.title }} </div> - <div :id="`queryable-layers-selector-${basemap.id}`" v-if="isQueryable(basemap)"> + <div + :id="`queryable-layers-selector-${basemap.id}`" + v-if="isQueryable(basemap)" + > <b>Couche requêtable</b> - <Dropdown + <Dropdown @update:selection="onQueryLayerChange($event)" :options="getQueryableLayers(basemap)" :selected="selectedQueryLayer" :search="true" /> - </div> <div :class="{ active: isActive(basemap) }" @@ -77,7 +78,8 @@ <div v-for="(layer, index) in basemap.layers" :key="basemap.id + '-' + layer.id + '-' + index" - class="layer-item transition visible item list-group-item" :data-id="layer.id" + class="layer-item transition visible item list-group-item" + :data-id="layer.id" > <p class="layer-handle-sort"> <i class="th icon"></i>{{ layer.title }} @@ -104,168 +106,201 @@ </template> <script> -import { mapUtil } from "@/assets/js/map-util.js"; +import { mapState } from "vuex"; +import Sortable from "sortablejs"; import Dropdown from "@/components/Dropdown.vue"; -import Sortable from 'sortablejs'; +import { mapUtil } from "@/assets/js/map-util.js"; export default { name: "SidebarLayers", + components: { Dropdown, }, + data() { return { - selectedQueryLayer:null, - activeBasemap:null, + selectedQueryLayer: null, + activeBasemap: null, baseMaps: [], - layers: [], expanded: false, }; }, + + computed: { + ...mapState("map", ["availableLayers"]), + }, + methods: { isActive(basemap) { return basemap.active !== undefined && basemap.active; }, + activateGroup(basemap) { this.baseMaps.forEach((basemap) => (basemap.active = false)); basemap.active = true; - this.activeBasemap=basemap; + this.activeBasemap = basemap; basemap.title += " "; //weird!! Force refresh this.addLayers(basemap); - let mapOptions = localStorage.getItem('geocontrib-map-options') || {}; - mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {}; - let project=this.$route.params.slug; - mapOptions[project] = { - ...mapOptions[project], - 'current-basemap-index': basemap.id - }; - localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions)); - - + let mapOptions = localStorage.getItem("geocontrib-map-options") || {}; + mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {}; + let project = this.$route.params.slug; + mapOptions[project] = { + ...mapOptions[project], + "current-basemap-index": basemap.id, + }; + localStorage.setItem( + "geocontrib-map-options", + JSON.stringify(mapOptions) + ); }, + updateOpacity(event, layer) { console.log(event.target.value, layer); mapUtil.updateOpacity(layer.id, event.target.value); layer.opacity = event.target.value; }, + getOpacity(opacity) { return Math.round(parseFloat(opacity) * 100); }, - onQueryLayerChange(layer){ + + onQueryLayerChange(layer) { console.log(layer); - this.selectedQueryLayer=layer.name; + this.selectedQueryLayer = layer.name; }, - isQueryable(baseMap){ - let queryableLayer=baseMap.layers.filter(l => l.queryable === true); - return queryableLayer.length>0; + + isQueryable(baseMap) { + let queryableLayer = baseMap.layers.filter((l) => l.queryable === true); + return queryableLayer.length > 0; }, - onlayerMove(event){ - console.log(event) - // Get the names of the current layers in order. - const currentLayersNamesInOrder = Array.from(document.getElementsByClassName('layer-item transition visible')).map(el => el.children[0].innerText); + onlayerMove(event) { + console.log(event); + // Get the names of the current layers in order. + const currentLayersNamesInOrder = Array.from( + document.getElementsByClassName("layer-item transition visible") + ).map((el) => el.children[0].innerText); // Create an array to put the layers in order. let movedLayers = []; - + for (const layerName of currentLayersNamesInOrder) { - movedLayers.push(this.activeBasemap.layers.filter(el => el.title === layerName)[0]); + movedLayers.push( + this.activeBasemap.layers.filter((el) => el.title === layerName)[0] + ); } - // Remove existing layers undefined - movedLayers = movedLayers.filter(function(x) { + movedLayers = movedLayers.filter(function (x) { return x !== undefined; }); - const eventOrder = new CustomEvent('change-layers-order', { + const eventOrder = new CustomEvent("change-layers-order", { detail: { - layers: movedLayers - } - }) + layers: movedLayers, + }, + }); document.dispatchEvent(eventOrder); // Save the basemaps options into the localstorage - console.log(this.baseMaps) - this.setLocalstorageMapOptions(this.baseMaps) + console.log(this.baseMaps); + this.setLocalstorageMapOptions(this.baseMaps); }, + setLocalstorageMapOptions(basemaps) { - let mapOptions = localStorage.getItem('geocontrib-map-options') || {}; + let mapOptions = localStorage.getItem("geocontrib-map-options") || {}; mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {}; - let project=this.$route.params.slug; + let project = this.$route.params.slug; mapOptions[project] = { ...mapOptions[project], - 'basemaps': basemaps + basemaps: basemaps, }; - localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions)); + localStorage.setItem( + "geocontrib-map-options", + JSON.stringify(mapOptions) + ); }, - initSortable(){ + initSortable() { this.baseMaps.forEach((basemap) => { - new Sortable(document.getElementById(`list-${basemap.id}`), { - animation: 150, - handle: '.layer-handle-sort', // The element that is active to drag - ghostClass: 'blue-background-class', - dragClass: 'white-opacity-background-class', - onEnd: this.onlayerMove.bind(this) - }); + new Sortable(document.getElementById(`list-${basemap.id}`), { + animation: 150, + handle: ".layer-handle-sort", // The element that is active to drag + ghostClass: "blue-background-class", + dragClass: "white-opacity-background-class", + onEnd: this.onlayerMove.bind(this), + }); }); }, - // Check if there are changes in the basemaps settings. Changes are detected if: - // - one basemap has been added or deleted - // - one layer has been added or deleted to a basemap - areChangesInBasemaps(basemapFromServer, basemapFromLocalstorage={}) { - let isSameBasemaps = false; - let isSameLayers = true; - let isSameTitles = true; - - // Compare the length and the id values of the basemaps - const idBasemapsServer = basemapFromServer.map(b => b.id).sort(); - const idBasemapsLocalstorage = basemapFromLocalstorage.length ? basemapFromLocalstorage.map(b => b.id).sort() : {}; - isSameBasemaps = (idBasemapsServer.length === idBasemapsLocalstorage.length - && idBasemapsServer.every((value, index) => value === idBasemapsLocalstorage[index])) - - // For each basemap, compare the length and id values of the layers - outer_block: { - for(let basemapServer of basemapFromServer) { - let idLayersServer = basemapServer.layers.map(b => b.id).sort(); - if (basemapFromLocalstorage.length){ - for (let basemapLocalstorage of basemapFromLocalstorage) { - if (basemapServer.id === basemapLocalstorage.id) { - let idLayersLocalstorage = basemapLocalstorage.layers.map(b => b.id).sort(); - isSameLayers = (idLayersServer.length === idLayersLocalstorage.length - && idLayersServer.every((value, index) => value === idLayersLocalstorage[index])); - if (!isSameLayers) { - break outer_block; + // - one basemap has been added or deleted + // - one layer has been added or deleted to a basemap + areChangesInBasemaps(basemapFromServer, basemapFromLocalstorage = {}) { + let isSameBasemaps = false; + let isSameLayers = true; + let isSameTitles = true; + // Compare the length and the id values of the basemaps + const idBasemapsServer = basemapFromServer.map((b) => b.id).sort(); + const idBasemapsLocalstorage = basemapFromLocalstorage.length + ? basemapFromLocalstorage.map((b) => b.id).sort() + : {}; + isSameBasemaps = + idBasemapsServer.length === idBasemapsLocalstorage.length && + idBasemapsServer.every( + (value, index) => value === idBasemapsLocalstorage[index] + ); + // For each basemap, compare the length and id values of the layers + outer_block: { + for (let basemapServer of basemapFromServer) { + let idLayersServer = basemapServer.layers.map((b) => b.id).sort(); + if (basemapFromLocalstorage.length) { + for (let basemapLocalstorage of basemapFromLocalstorage) { + if (basemapServer.id === basemapLocalstorage.id) { + let idLayersLocalstorage = basemapLocalstorage.layers + .map((b) => b.id) + .sort(); + isSameLayers = + idLayersServer.length === idLayersLocalstorage.length && + idLayersServer.every( + (value, index) => value === idLayersLocalstorage[index] + ); + if (!isSameLayers) { + break outer_block; + } } } } } - } - - // Compare basemaps titles - const titlesBasemapsServer = basemapFromServer.map(b => b.title).sort(); - const titlesBasemapsLocalstorage = basemapFromLocalstorage.length ? basemapFromLocalstorage.map(b => b.title).sort() : {}; + // Compare basemaps titles + const titlesBasemapsServer = basemapFromServer + .map((b) => b.title) + .sort(); + const titlesBasemapsLocalstorage = basemapFromLocalstorage.length + ? basemapFromLocalstorage.map((b) => b.title).sort() + : {}; - isSameTitles = titlesBasemapsServer.every((title, index) => title === titlesBasemapsLocalstorage[index]); + isSameTitles = titlesBasemapsServer.every( + (title, index) => title === titlesBasemapsLocalstorage[index] + ); - if (!isSameTitles) { - break outer_block; + if (!isSameTitles) { + break outer_block; + } } - } - return !(isSameBasemaps && isSameLayers && isSameTitles); - }, - getQueryableLayers(baseMap){ - let queryableLayer=baseMap.layers.filter(l => l.queryable === true); - return queryableLayer.map(x=>{ + return !(isSameBasemaps && isSameLayers && isSameTitles); + }, + + getQueryableLayers(baseMap) { + let queryableLayer = baseMap.layers.filter((l) => l.queryable === true); + return queryableLayer.map((x) => { return { - name:x.title, - value:x - } + name: x.title, + value: x, + }; }); }, + addLayers(baseMap) { - baseMap.layers.forEach((layer) => { - var layerOptions = this.layers.find((l) => l.id === layer.id); + var layerOptions = this.availableLayers.find((l) => l.id === layer.id); console.log(layerOptions); layer = Object.assign(layer, layerOptions); layer.options.basemapId = baseMap.id; @@ -276,35 +311,39 @@ export default { mapUtil.addLayers(baseMap.layers.slice().reverse(), null, null); }, }, + mounted() { this.baseMaps = this.$store.state.map.basemaps; - let project=this.$route.params.slug; - const mapOptions = JSON.parse(localStorage.getItem('geocontrib-map-options')) || {}; - if (mapOptions - && mapOptions[project]) { - - // If already in the storage, we need to check if the admin did some + let project = this.$route.params.slug; + const mapOptions = + JSON.parse(localStorage.getItem("geocontrib-map-options")) || {}; + if (mapOptions && mapOptions[project]) { + // If already in the storage, we need to check if the admin did some // modification in the basemaps on the server side. The rule is: if one layer has been added // or deleted in the server, then we reset the localstorage. - const baseMapsFromLocalstorage = mapOptions[project]['basemaps']; - const areChanges = this.areChangesInBasemaps(this.baseMaps, baseMapsFromLocalstorage); + const baseMapsFromLocalstorage = mapOptions[project]["basemaps"]; + const areChanges = this.areChangesInBasemaps( + this.baseMaps, + baseMapsFromLocalstorage + ); if (areChanges) { mapOptions[project] = { - 'map-options': this.baseMaps, - 'current-basemap-index': 0, + "map-options": this.baseMaps, + "current-basemap-index": 0, }; - localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions)); + localStorage.setItem( + "geocontrib-map-options", + JSON.stringify(mapOptions) + ); } else { this.baseMaps = baseMapsFromLocalstorage; } } - - this.layers = this.$store.state.map.layers; if (this.baseMaps.length > 0) { this.baseMaps[0].active = true; - this.activeBasemap=this.baseMaps[0]; + this.activeBasemap = this.baseMaps[0]; this.addLayers(this.baseMaps[0]); } else { mapUtil.addLayers( @@ -313,11 +352,7 @@ export default { this.$store.state.configuration.DEFAULT_BASE_MAP.OPTIONS ); } - setTimeout(this.initSortable.bind(this),1000) - - - - + setTimeout(this.initSortable.bind(this), 1000); }, }; </script> diff --git a/src/components/project/ProjectMappingContextLayer.vue b/src/components/project/ProjectMappingContextLayer.vue index a5cf259de873064ea77c5be8bee7cf70027c6faf..9b732a334589c3b263cb0067bd770bfbc8093730 100644 --- a/src/components/project/ProjectMappingContextLayer.vue +++ b/src/components/project/ProjectMappingContextLayer.vue @@ -11,7 +11,7 @@ <!-- {{ form.layer }} --> <!-- {% else %} --> <Dropdown - :options="availableLayers" + :options="availableLayerOptions" :selected="selectedLayer.name" :selection.sync="selectedLayer" :search="true" @@ -70,18 +70,11 @@ export default { }, computed: { - ...mapState("map", ["layers"]), + ...mapState("map", ["availableLayers"]), selectedLayer: { get() { - const matchingLayer = this.retrieveLayer(this.layer.title); - if (matchingLayer !== undefined) { - return { - name: matchingLayer !== undefined ? matchingLayer.service : "", - value: this.layer ? this.layer.title : "", - }; - } - return []; + return this.retrieveLayer(this.layer.title) || []; }, set(newValue) { @@ -109,8 +102,8 @@ export default { }, }, - availableLayers: function () { - return this.layers.map((el) => { + availableLayerOptions: function () { + return this.availableLayers.map((el) => { return { id: el.id, name: `${el.title} - ${el.service}`, @@ -122,14 +115,14 @@ export default { placeholder: function () { return this.selectedLayer && this.selectedLayer.name - ? this.selectedLayer.name + ? "" : "Choisissez une couche"; }, }, methods: { retrieveLayer(title) { - return this.layers.find((el) => el.title === title); + return this.availableLayerOptions.find((el) => el.title === title); }, removeLayer() { diff --git a/src/main.js b/src/main.js index 22fdd2b3b48d5fa8a340a744abf90bded82bf99a..724a17140dc042cedd811c9027eb374e807a067d 100644 --- a/src/main.js +++ b/src/main.js @@ -20,7 +20,7 @@ axios.get("/config/config.json") store.dispatch("GET_ALL_PROJECTS"), store.dispatch("GET_STATIC_PAGES"), store.dispatch("GET_USER_LEVEL_PROJECTS"), - store.dispatch("map/GET_LAYERS"), + store.dispatch("map/GET_AVAILABLE_LAYERS"), store.dispatch("GET_USER_LEVEL_PERMISSIONS"), ]).then(axios.spread(function () { new Vue({ diff --git a/src/store/modules/map.js b/src/store/modules/map.js index 24a4501cdee8f6294e85ea7e5e0ca4eea5f65b78..d47afc9ef721f6a3201ff1db473b051c92552a1e 100644 --- a/src/store/modules/map.js +++ b/src/store/modules/map.js @@ -15,11 +15,11 @@ const map = { basemapsToDelete: [], features: [], geojsonFeatures: null, - layers: null, + availableLayers: null, }, mutations: { - SET_LAYERS(state, layers) { - state.layers = layers; + SET_LAYERS(state, availableLayers) { + state.availableLayers = availableLayers; }, SET_GEOJSON_FEATURES(state, geojsonFeatures) { state.geojsonFeatures = geojsonFeatures; @@ -87,7 +87,7 @@ const map = { }, actions: { - GET_LAYERS({ commit }) { + GET_AVAILABLE_LAYERS({ commit }) { return axios .get(`${this.state.configuration.VUE_APP_DJANGO_API_BASE}layers/`) .then((response) => (commit("SET_LAYERS", response.data))) @@ -138,7 +138,7 @@ const map = { : 0; layersToLoad = state.baseMaps[basemapIndex].layers; layersToLoad.forEach((layerToLoad) => { - state.layers.forEach((layer) => { + state.availableLayers.forEach((layer) => { if (layer.id === layerToLoad.id) { layerToLoad = Object.assign(layerToLoad, layer); } diff --git a/src/views/feature/Feature_detail.vue b/src/views/feature/Feature_detail.vue index c1a5260d995a927fe087fbad2379afa4a0fb723d..edd4147bd47ce9ef9548875020e1e9c1d79f16fc 100644 --- a/src/views/feature/Feature_detail.vue +++ b/src/views/feature/Feature_detail.vue @@ -563,7 +563,7 @@ export default { // - if not, load the default map and service options let layersToLoad = null; var baseMaps = this.$store.state.map.basemaps; - var layers = this.$store.state.map.layers; + var layers = this.$store.state.map.availableLayers; if (baseMaps && baseMaps.length > 0) { const basemapIndex = 0; layersToLoad = baseMaps[basemapIndex].layers;