<template> <div class="ui segment secondary"> <div class="field required"> <label for="basemap-title">Titre</label> <input :value="basemap.title" type="text" name="basemap-title" required @input="updateTitle" > <ul v-if="basemap.errors && basemap.errors.length > 0" id="errorlist-title" class="errorlist" > <li> {{ basemap.errors }} </li> </ul> </div> <div class="nested"> <div :id="`list-${basemap.id}`" :class="[basemap.layers.length > 0 ? 'ui segments': '', 'layers-container', 'raised']" > <ProjectMappingContextLayer v-for="layer in basemap.layers" :key="'layer-' + layer.dataKey" :layer="layer" :basemapid="basemap.id" /> </div> <div class="ui bottom two attached buttons"> <button class="ui icon button basic positive" type="button" @click="addLayer" > <i class="ui plus icon" aria-hidden="true" /> <span> Ajouter une couche</span> </button> <button class=" ui icon button basic negative" type="button" @click="deleteBasemap" > <i class="ui trash alternate icon" aria-hidden="true" /> <span> Supprimer ce fond cartographique</span> </button> </div> </div> </div> </template> <script> import { mapMutations } from 'vuex'; import Sortable from 'sortablejs'; import ProjectMappingContextLayer from '@/components/Project/Basemaps/ProjectMappingContextLayer.vue'; export default { name: 'BasemapListItem', components: { ProjectMappingContextLayer, }, props: { basemap: { type: Object, default: null, } }, data() { return { sortable: null }; }, computed: { maxLayersCount: function () { return this.basemap.layers.reduce((acc, curr) => { if (curr.dataKey > acc) { return curr.dataKey; } else { return acc; } }, 0); }, }, created() { if (this.basemap.layers) { //* add datakeys to layers coming from api this.fillLayersWithDatakey(this.basemap.layers); } }, mounted() { this.initSortable(); }, methods: { ...mapMutations('map', [ 'UPDATE_BASEMAP', 'DELETE_BASEMAP', 'REPLACE_BASEMAP_LAYERS' ]), deleteBasemap() { this.DELETE_BASEMAP(this.basemap.id); }, addLayer(layer) { const newLayer = { dataKey: this.maxLayersCount + 1, opacity: '1.00', order: 0, queryable: false, title: 'Open street map', ...layer, }; this.UPDATE_BASEMAP({ layers: [...this.basemap.layers, newLayer], id: this.basemap.id, title: this.basemap.title, errors: this.basemap.errors, }); }, updateTitle(evt) { let errors = ''; if(evt.target.value === '') { //* delete or add error message while typing errors = 'Veuillez compléter ce champ.'; } this.UPDATE_BASEMAP({ id: this.basemap.id, title: evt.target.value, errors, }); }, removeLayer(dataKey) { this.layers = this.layers.filter((layer) => layer.dataKey !== dataKey); }, fillLayersWithDatakey(layers) { let dataKey = 0; this.REPLACE_BASEMAP_LAYERS({ basemapId: this.basemap.id, layers: layers.map((el) => { dataKey += 1; return { dataKey, ...el }; }), }); }, //* drag & drop *// onlayerMove() { //* Get the names of the current layers in order. const currentLayersNamesInOrder = Array.from( document.getElementsByClassName(`basemap-${this.basemap.id}`) ).map((el) => el.id); //* increment value 'order' in this.basemap.layers looping over layers from template ^ let order = 0; const movedLayers = []; for (const id of currentLayersNamesInOrder) { const matchingLayer = this.basemap.layers.find( (el) => el.dataKey === Number(id) ); if (matchingLayer) { matchingLayer['order'] = order; movedLayers.push(matchingLayer); order += 1; } } //* update the store this.UPDATE_BASEMAP({ layers: movedLayers, id: this.basemap.id, title: this.basemap.title, errors: this.basemap.errors, }); }, initSortable() { this.sortable = new Sortable(document.getElementById(`list-${this.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), }); }, }, }; </script>