Fix page routing

This commit is contained in:
2026-04-12 00:06:08 +02:00
parent f81fbd454e
commit cb505d9092
4 changed files with 90 additions and 65 deletions

View File

@@ -12,73 +12,85 @@ const aoRoutes = {
export default { export default {
data() { data() {
return { return {
hash: {}, hash: {page: '', items: []},
consts: this.spot.consts, consts: this.spot.consts,
user: this.spot.vars('user') user: this.spot.vars('user'),
routes: aoRoutes
}; };
}, },
provide() { provide() {
return { return {
hash: this.hash,
projects: this.spot.vars('projects'), projects: this.spot.vars('projects'),
consts: this.consts, consts: this.consts,
user: this.user user: this.user
}; };
}, },
inject: ['spot'],
computed: { computed: {
page() { route() {
this.spot.vars('page', this.hash.page); return this.routes[this.hash.page];
return aoRoutes[this.hash.page]; },
hashSnapshot() {
return JSON.stringify(this.hash);
} }
}, },
inject: ['spot'],
created() { created() {
//User //User
this.user.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || this.consts.default_timezone; this.user.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || this.consts.default_timezone;
//Set initial page
let asInitHash = this.getHash();
if(!asInitHash.page) this.hash.page = this.spot.consts.default_page;
else this.hash = asInitHash;
}, },
mounted() { mounted() {
window.addEventListener('hashchange', () => {this.onHashChange();}); //Catch browser hash change
var oEvent = new Event('hashchange'); window.addEventListener('hashchange', this.onHashChange);
window.dispatchEvent(oEvent);
}, },
methods: { watch: {
_hash(hash, bReboot) { hashSnapshot(jNewHash, jOldHash) {
bReboot = bReboot || false; const asNewHash = JSON.parse(jNewHash);
if(!hash) return window.location.hash.slice(1); const asOldHash = JSON.parse(jOldHash);
else window.location.hash = '#'+hash; this.spot.vars('page', this.hash.page); //FIXME remove
if(bReboot) location.reload(); //Sync variable -> #hash
}, if(asNewHash != this.getHash()) {
onHashChange() { this.setHash(asNewHash.page, asNewHash.items);
let asHash = this.getHash();
if(asHash.hash !='' && asHash.page != '') {
if(asHash.page == this.hash.page) this.spot.onSamePageMove(asHash);
this.hash = asHash;
} }
else if(!this.hash.page) this.setHash(this.spot.consts.default_page);
},
getHash() {
let sHash = this._hash();
let asHash = sHash.split(this.spot.consts.hash_sep);
let sPage = asHash.shift() || '';
return {hash:sHash, page:sPage, items:asHash};
},
setHash(sPage, asItems, bReboot) {
bReboot = bReboot || false;
sPage = sPage || '';
asItems = asItems || [];
if(typeof asItems == 'string') asItems = [asItems];
if(sPage != '') { //Same Page change
let sItems = (asItems.length > 0)?this.spot.consts.hash_sep+asItems.join(this.spot.consts.hash_sep):''; if(asNewHash != asOldHash && asNewHash.page == asOldHash.page) {
this._hash(sPage+sItems, bReboot); this.spot.onSamePageMove(asNewHash, asOldHash);
} }
} }
},
methods: {
onHashChange() { //Sync #hash -> variable
let asHash = this.getHash();
if(asHash != this.hash) this.hash = asHash;
this.spot.vars('page', this.hash.page); //FIXME remove
},
getHash() {
let sHash = window.location.hash.slice(1);
let asHash = sHash.split(this.spot.consts.hash_sep);
let sPage = asHash.shift() || '';
return {page: sPage, items: asHash};
},
setHash(sPage = '', asItems = []) {
if(typeof asItems == 'string') asItems = [asItems];
const sItems = (asItems.length > 0)?(this.spot.consts.hash_sep + asItems.join(this.spot.consts.hash_sep)):'';
window.location.hash = '#' + sPage + sItems;
}
},
beforeUnmount() {
window.removeEventListener('hashchange', this.onHashChange)
} }
} }
</script> </script>
<template> <template>
<div id="main"> <div id="main">
<component :is="page" /> <component :is="route" />
</div> </div>
<div id="mobile"></div> <div id="mobile"></div>
</template> </template>

View File

@@ -2,15 +2,13 @@
import 'maplibre-gl/dist/maplibre-gl.css'; import 'maplibre-gl/dist/maplibre-gl.css';
import { Map, NavigationControl, Marker, LngLatBounds, LngLat, Popup } from 'maplibre-gl'; import { Map, NavigationControl, Marker, LngLatBounds, LngLat, Popup } from 'maplibre-gl';
import { createApp, defineComponent, nextTick, ref, defineCustomElement, provide, inject } from 'vue'; import { createApp, defineComponent, nextTick, ref, defineCustomElement, provide, inject } from 'vue';
import simplebar from 'simplebar-vue'; import Simplebar from 'simplebar-vue';
import autosize from 'autosize'; import autosize from 'autosize';
import mousewheel from 'jquery-mousewheel'; import mousewheel from 'jquery-mousewheel';
import waitforimages from 'jquery.waitforimages'; import waitforimages from 'jquery.waitforimages';
import lightbox from '../scripts/lightbox.js'; import lightbox from '../scripts/lightbox.js';
//import SimpleBar from 'simplebar';
import SpotIcon from './spotIcon.vue'; import SpotIcon from './spotIcon.vue';
import SpotButton from './spotButton.vue'; import SpotButton from './spotButton.vue';
import ProjectPost from './projectPost.vue'; import ProjectPost from './projectPost.vue';
@@ -22,7 +20,7 @@ export default {
SpotButton, SpotButton,
ProjectPost, ProjectPost,
ProjectPopup, ProjectPopup,
simplebar Simplebar
}, },
data() { data() {
return { return {
@@ -35,7 +33,6 @@ export default {
settingsPanelOpen: false, settingsPanelOpen: false,
markerSize: {width: 32, height: 32}, markerSize: {width: 32, height: 32},
currProject: {}, currProject: {},
currProjectCodeName: null,
modeHisto: false, modeHisto: false,
posts: [], posts: [],
nlFeedbacks: [], nlFeedbacks: [],
@@ -76,14 +73,11 @@ export default {
}, },
watch: { watch: {
baseMap(sNewBaseMap, sOldBaseMap) { baseMap(sNewBaseMap, sOldBaseMap) {
if(sOldBaseMap) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none'); if(this.map.isStyleLoaded()) {
if(sNewBaseMap) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible'); if(sOldBaseMap) this.map.setLayoutProperty(sOldBaseMap, 'visibility', 'none');
if(sNewBaseMap) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible');
}
}, },
currProjectCodeName(sNewCodeName, sOldCodeName) {
//this.toggleSettingsPanel(false);
if(this.$parent.hash.items.length==0) this.$parent.setHash(this.$parent.hash.page, [sNewCodeName]);
this.init();
}
}, },
provide() { provide() {
return { return {
@@ -96,7 +90,10 @@ export default {
project: this project: this
}; };
}, },
inject: ['spot', 'projects', 'user'], inject: ['spot', 'hash', 'projects', 'user'],
beforeMount() {
if(this.$parent.hash.items.length == 0) this.$parent.hash.items[0] = this.spot.vars('default_project_codename');
},
mounted() { mounted() {
this.spot.addPage('project', { this.spot.addPage('project', {
onResize: () => { onResize: () => {
@@ -108,15 +105,25 @@ export default {
} }
*/ */
}, },
onSamePageMove: (asNewHash, asOldHash) => {
//this.toggleSettingsPanel(false);
//this.quit();
//Check for project change
if(asNewHash.items[0] != asOldHash.items[0]) {
console.log('Project change: '+(asOldHash.items[0])+' ->', asNewHash.items[0]);
this.init();
}
},
onQuitPage: () => { onQuitPage: () => {
this.setFeedUpdateTimer(-1); this.quit();
} }
}); });
this.currProjectCodeName = (this.$parent.hash.items.length==0)?this.spot.vars('default_project_codename'):this.$parent.hash.items[0]; this.init();
}, },
beforeUnmount() { beforeUnmount() {
this.setFeedUpdateTimer(-1); this.quit();
}, },
methods: { methods: {
init() { init() {
@@ -126,8 +133,14 @@ export default {
this.initFeed(); this.initFeed();
this.initMap(); this.initMap();
}, },
quit() {
lightbox.end();
this.$refs.feedSimpleBar.scrollElement.removeEventListener('scroll', (oEvent) => {this.onFeedScroll(oEvent);});
this.setFeedUpdateTimer(-1);
this.map.remove();
},
initProject() { initProject() {
this.currProject = this.projects[this.currProjectCodeName]; this.currProject = this.projects[this.$parent.hash.items[0]];
this.modeHisto = (this.currProject.mode == this.spot.consts.modes.histo); this.modeHisto = (this.currProject.mode == this.spot.consts.modes.histo);
this.feed = {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true}; this.feed = {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true};
this.posts = []; this.posts = [];
@@ -178,7 +191,7 @@ export default {
this.messages = aoMarkers.messages; this.messages = aoMarkers.messages;
this.lastUpdate = aoMarkers.last_update; this.lastUpdate = aoMarkers.last_update;
console.log(this.baseMaps); //console.log(this.baseMaps);
//Base maps (raster tiles) //Base maps (raster tiles)
let asSources = {}; let asSources = {};
@@ -574,12 +587,12 @@ export default {
</div> </div>
</div> </div>
<div class="settings-sections"> <div class="settings-sections">
<simplebar id="settings-sections-scrollbox"> <Simplebar id="settings-sections-scrollbox">
<div class="settings-section"> <div class="settings-section">
<h1><SpotIcon :icon="'project'" :classes="'fa-fw'" :text="spot.lang('hikes')" /></h1> <h1><SpotIcon :icon="'project'" :classes="'fa-fw'" :text="spot.lang('hikes')" /></h1>
<div class="settings-section-body"> <div class="settings-section-body">
<div class="radio" v-for="project in projects"> <div class="radio" v-for="project in projects">
<input type="radio" :id="project.id" :value="project.codename" v-model="currProjectCodeName" /> <input type="radio" :id="project.id" :value="project.codename" v-model="$parent.hash.items[0]" />
<label :for="project.id"> <label :for="project.id">
<span>{{ project.name }}</span> <span>{{ project.name }}</span>
<a class="download" :href="project.gpxfilepath" :title="spot.lang('track_download')" @click.stop="()=>{}"> <a class="download" :href="project.gpxfilepath" :title="spot.lang('track_download')" @click.stop="()=>{}">
@@ -614,7 +627,7 @@ export default {
<a class="button" href="#admin"><SpotIcon :icon="'config'" :text="spot.lang('admin_config')" /></a> <a class="button" href="#admin"><SpotIcon :icon="'config'" :text="spot.lang('admin_config')" /></a>
<a class="button" href="#upload"><SpotIcon :icon="'upload'" :text="spot.lang('admin_upload')" /></a> <a class="button" href="#upload"><SpotIcon :icon="'upload'" :text="spot.lang('admin_upload')" /></a>
</div> </div>
</simplebar> </Simplebar>
</div> </div>
<div class="settings-footer"> <div class="settings-footer">
<a href="https://git.lutran.fr/franzz/spot" :title="spot.lang('credits_git')" target="_blank" rel="noopener"> <a href="https://git.lutran.fr/franzz/spot" :title="spot.lang('credits_git')" target="_blank" rel="noopener">
@@ -635,7 +648,7 @@ export default {
</div> </div>
</div> </div>
<div id="feed" class="map-container map-container-right" ref="feed"> <div id="feed" class="map-container map-container-right" ref="feed">
<simplebar id="feed-panel" class="map-panel" ref="feedSimpleBar"> <Simplebar id="feed-panel" class="map-panel" ref="feedSimpleBar">
<div id="feed-header"> <div id="feed-header">
<ProjectPost v-if="modeHisto" :options="{type: 'archived', headerless: true}" /> <ProjectPost v-if="modeHisto" :options="{type: 'archived', headerless: true}" />
<ProjectPost v-else :options="{type: 'poster', relative_time: spot.lang('post_new_message')}" /> <ProjectPost v-else :options="{type: 'poster', relative_time: spot.lang('post_new_message')}" />
@@ -646,7 +659,7 @@ export default {
<div id="feed-footer" v-if="feed.loading"> <div id="feed-footer" v-if="feed.loading">
<ProjectPost :options="{type: 'loading', headerless: true}" /> <ProjectPost :options="{type: 'loading', headerless: true}" />
</div> </div>
</simplebar> </Simplebar>
<div :class="'map-control map-control-icon feed-control map-control-'+(mobile?'bottom':'top')" @click="toggleFeedPanel"> <div :class="'map-control map-control-icon feed-control map-control-'+(mobile?'bottom':'top')" @click="toggleFeedPanel">
<SpotIcon :icon="feedPanelOpen?'next':'post'" /> <SpotIcon :icon="feedPanelOpen?'next':'post'" />
</div> </div>

View File

@@ -58,7 +58,7 @@ export default {
(position) => { (position) => {
this.logs.push('Sending position...'); this.logs.push('Sending position...');
this.spot.get2('add_position', {'latitude':position.coords.latitude, 'longitude':position.coords.longitude, 'timestamp':Math.round(position.timestamp / 1000)}) this.spot.get2('add_position', {'latitude':position.coords.latitude, 'longitude':position.coords.longitude, 'timestamp':Math.round(position.timestamp / 1000)})
.then((asData) => {this.logs.push('Position sent');}) .then((asData) => {this.logs.push(self.lang(sMsgId));})
.catch((sMsgId) => {this.logs.push(self.lang(sMsgId));}); .catch((sMsgId) => {this.logs.push(self.lang(sMsgId));});
}, },
(error) => { (error) => {

View File

@@ -195,9 +195,9 @@ export default class Spot {
else console.log('no init for the page: '+asHash.page); else console.log('no init for the page: '+asHash.page);
} }
onSamePageMove(asHash) { onSamePageMove(asNewHash, asOldHash) {
let sPage = this.vars('page'); let sPage = this.vars('page');
return (this.pages[sPage] && this.pages[sPage].onSamePageMove)?this.pages[sPage].onSamePageMove(asHash):false; return (this.pages[sPage] && this.pages[sPage].onSamePageMove)?this.pages[sPage].onSamePageMove(asNewHash, asOldHash):false;
} }
onQuitPage() { onQuitPage() {