Bye bye spot.js

This commit is contained in:
2026-04-25 23:55:11 +02:00
parent 7dc2b28c44
commit b339d6d068
13 changed files with 270 additions and 470 deletions

View File

@@ -22,7 +22,7 @@ export default {
},
data() {
return {
server: this.spot.consts.server,
server: this.consts.server,
feed: {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true},
refreshRate: 60,
lastUpdate: { unix_time: 0, relative_time: '', formatted_time: ''},
@@ -63,9 +63,6 @@ export default {
},
nlAction() {
return this.subscribed?'unsubscribe':'subscribe';
},
mobile() {
return this.spot.isMobile();
}
},
watch: {
@@ -75,6 +72,12 @@ export default {
if(sNewBaseMap && this.map.getLayer(sNewBaseMap)) this.map.setLayoutProperty(sNewBaseMap, 'visibility', 'visible');
}
},
'hash.items.0'(newProjectCodename, oldProjectCodename) {
if(newProjectCodename && newProjectCodename != oldProjectCodename) {
this.hash.items = [newProjectCodename];
this.init();
}
}
},
provide() {
return {
@@ -87,42 +90,28 @@ export default {
project: this
};
},
inject: ['spot', 'lang', 'hash', 'projects', 'user'],
inject: ['api', 'lang', 'hash', 'projects', 'user', 'consts', 'isMobile'],
beforeMount() {
if(this.hash.items.length == 0) this.hash.items[0] = this.spot.vars('default_project_codename');
if(this.hash.items.length == 0) this.hash.items[0] = this.projects.getDefaultCodeName();
},
mounted() {
this.spot.addPage('project', {
onResize: () => {
//this.spot.tmp('map_offset', -1 * (this.feedPanelOpen?getOuterWidth(this.$refs.feed):0) / getOuterWidth(window));
/* TODO
if(typeof this.spot.tmp('elev') != 'undefined' && this.spot.tmp('elev')._showState) {
this.spot.tmp('elev').resize({width:this.getElevWidth()});
}
*/
},
onSamePageMove: (asNewHash, asOldHash) => {
//this.toggleSettingsPanel(false);
//this.quit();
//Check for project change
if(asNewHash.items[0] != asOldHash.items[0]) {
this.hash.items = [asNewHash.items[0]];
this.init();
}
},
onQuitPage: () => {
this.quit();
}
});
window.addEventListener('resize', this.handleResize);
this.init();
},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize);
this.quit();
},
methods: {
handleResize() {
//this.spot.tmp('map_offset', -1 * (this.feedPanelOpen?getOuterWidth(this.$refs.feed):0) / getOuterWidth(window));
/* TODO
if(typeof this.spot.tmp('elev') != 'undefined' && this.spot.tmp('elev')._showState) {
this.spot.tmp('elev').resize({width:this.getElevWidth()});
}
*/
},
async init() {
let bFirstLoad = (typeof this.currProject.codename == 'undefined');
this.initProject();
@@ -142,9 +131,25 @@ export default {
this.setFeedUpdateTimer(-1);
this.map.remove();
},
getNaturalDuration(iHours) {
var iTimeMinutes = 0, iTimeHours = 0, iTimeDays = Math.floor(iHours/8); //8 hours a day
if(iTimeDays > 1) iTimeDays = Math.round(iTimeDays * 2) / 2; //Round down to the closest half day
else {
iTimeDays = 0;
iTimeHours = Math.floor(iHours);
iHours -= iTimeHours;
iTimeMinutes = Math.floor(iHours * 4) * 15; //Round down to the closest 15 minutes
}
return '~ '
+(iTimeDays>0?(iTimeDays+(iTimeDays%2==0?'':'½')+' '+this.lang.get(iTimeDays>1?'unit_days':'unit_day')):'') //Days
+((iTimeHours>0 || iTimeDays==0)?iTimeHours+this.lang.get('unit_hour'):'') //Hours
+((iTimeDays>0 || iTimeMinutes==0)?'':iTimeMinutes); //Minutes
},
initProject() {
this.currProject = this.projects[this.hash.items[0]];
this.modeHisto = (this.currProject.mode == this.spot.consts.modes.histo);
this.modeHisto = (this.currProject.mode == this.consts.modes.histo);
this.feed = {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true};
this.posts = [];
//this.baseMap = null;
@@ -185,8 +190,8 @@ export default {
},
async initMap() {
//Start async calls
const oMarkersPromise = this.spot.get2('markers', {id_project: this.currProject.id});
const oTrackPromise = this.spot.get2('geojson', {id_project: this.currProject.id});
const oMarkersPromise = this.api.get('markers', {id_project: this.currProject.id});
const oTrackPromise = this.api.get('geojson', {id_project: this.currProject.id});
//Build Map
if(this.map) this.map.remove();
@@ -324,11 +329,11 @@ export default {
});
},
async positionMap(oTrack) {
let bOpenFeedPanel = !this.mobile;
let bOpenFeedPanel = !this.isMobile();
let oBounds = new LngLatBounds();
if( //Blog Mode: Fit to last message
this.currProject.mode == this.spot.consts.modes.blog &&
this.currProject.mode == this.consts.modes.blog &&
this.markers.messages.length > 0 &&
this.hash.items[2] != 'message'
) {
@@ -399,7 +404,11 @@ export default {
medias: [oMedia],
project: this.currProject
});
this.popup.content.provide('spot', this.spot).provide('lang', this.lang).mount($Popup);
this.popup.content
.provide('spot', this.spot)
.provide('lang', this.lang)
.provide('consts', this.consts)
.mount($Popup);
},
openMarkerPopup(oFeature) {
this.closeMarkerPopup();
@@ -434,7 +443,11 @@ export default {
medias: JSON.parse(oFeature.properties.medias || '[]'),
project: this.currProject
});
this.popup.content.provide('spot', this.spot).provide('lang', this.lang).mount($Popup);
this.popup.content
.provide('spot', this.spot)
.provide('lang', this.lang)
.provide('consts', this.consts)
.mount($Popup);
},
closeMarkerPopup() {
if(this.popup.content) {
@@ -450,11 +463,11 @@ export default {
if(!this.feed.outOfData && !this.feed.loading) {
//Get next chunk
this.feed.loading = true;
let aoData = await this.spot.get2('next_feed', {id_project: this.currProject.id, id: this.feed.refIdLast});
let aoData = await this.api.get('next_feed', {id_project: this.currProject.id, id: this.feed.refIdLast});
let iPostCount = Object.keys(aoData.feed).length;
//Update pointers
this.feed.outOfData = (iPostCount < this.spot.consts.chunk_size);
this.feed.outOfData = (iPostCount < this.consts.chunk_size);
if(iPostCount > 0) {
this.feed.refIdLast = aoData.ref_id_last;
if(this.feed.firstChunk) this.feed.refIdFirst = aoData.ref_id_first;
@@ -480,7 +493,7 @@ export default {
if(iSeconds >= 0) this.feedTimer = setTimeout(this.checkNewFeed, iSeconds * 1000);
},
async checkNewFeed() {
let aoData = await this.spot.get2('new_feed', {id_project: this.currProject.id, id: this.feed.refIdFirst});
let aoData = await this.api.get('new_feed', {id_project: this.currProject.id, id: this.feed.refIdFirst});
if(Object.keys(aoData.feed).length > 0) {
//Update pointer
@@ -533,10 +546,10 @@ export default {
var regexEmail = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if(!regexEmail.test(this.user.email)) this.nlFeedbacks.push({type:'error', 'msg':this.lang.get('nl_invalid_email')});
else {
this.spot.get2(this.nlAction, {'email': this.user.email, 'name': this.user.name}, this.nlLoading)
this.api.get(this.nlAction, {'email': this.user.email, 'name': this.user.name})
.then((asUser, sDesc) => {
this.nlFeedbacks.push('success', sDesc);
this.user = asUser;
Object.assign(this.user, asUser);
})
.catch((sDesc) => {this.nlFeedbacks.push('error', sDesc);});
}
@@ -545,8 +558,8 @@ export default {
let bOldValue = this.feedPanelOpen;
this.feedPanelOpen = (typeof bShow === 'object' || typeof bShow === 'undefined')?(!this.feedPanelOpen):bShow;
if(bOldValue != this.feedPanelOpen && !this.mobile) {
this.spot.onResize();
if(bOldValue != this.feedPanelOpen && !this.isMobile()) {
this.handleResize();
sMapAction = sMapAction || 'panTo';
switch(sMapAction) {
@@ -579,8 +592,8 @@ export default {
let bOldValue = this.settingsPanelOpen;
this.settingsPanelOpen = (typeof bShow === 'object' || typeof bShow === 'undefined')?(!this.settingsPanelOpen):bShow;
if(bOldValue != this.settingsPanelOpen && !this.mobile) {
this.spot.onResize();
if(bOldValue != this.settingsPanelOpen && !this.isMobile()) {
this.handleResize();
sMapAction = sMapAction || 'panTo';
switch(sMapAction) {
@@ -640,7 +653,7 @@ export default {
<div id="settings-panel" class="map-panel">
<div class="settings-header">
<div class="logo"><img width="289" height="72" src="images/logo_black.png" alt="Spotty" /></div>
<div id="last_update" v-if="this.currProject.mode == this.spot.consts.modes.blog && lastUpdate.unix_time > 0">
<div id="last_update" v-if="this.currProject.mode == this.consts.modes.blog && lastUpdate.unix_time > 0">
<p><span><img src="images/spot-logo-only.svg" alt="" /></span><abbr :title="lastUpdate.formatted_time">{{ lang.get('last_update')+' '+lastUpdate.relative_time }}</abbr></p>
</div>
</div>
@@ -680,7 +693,7 @@ export default {
</div>
{{ lang.get(subscribed?'nl_subscribed_desc':'nl_unsubscribed_desc') }}
</div>
<div class="settings-section admin" v-if="spot.checkClearance(spot.consts.clearances.admin)">
<div class="settings-section admin" v-if="user.hasClearance(consts.clearances.admin)">
<h1><SpotIcon :icon="'admin fa-fw'" :text="lang.get('admin')" /></h1>
<a class="button" href="#admin"><SpotIcon :icon="'config'" :text="lang.get('admin_config')" /></a>
<a class="button" href="#upload"><SpotIcon :icon="'upload'" :text="lang.get('admin_upload')" /></a>
@@ -692,16 +705,16 @@ export default {
<SpotIcon :icon="'credits'" :text="lang.get('credits_project')" />
</a> {{ lang.get('credits_license') }}</div>
</div>
<div :class="'map-control map-control-icon settings-control map-control-'+(mobile?'bottom':'top')" @click="toggleSettingsPanel">
<div :class="'map-control map-control-icon settings-control map-control-'+(isMobile()?'bottom':'top')" @click="toggleSettingsPanel">
<SpotIcon :icon="settingsPanelOpen?'prev':'menu'" />
</div>
<div v-if="!mobile" id="legend" class="map-control settings-control map-control-bottom">
<div v-if="!isMobile()" id="legend" class="map-control settings-control map-control-bottom">
<div v-for="(color, hikeType) in hikes.colors" class="track">
<span class="line" :style="'background-color:'+color+'; height:'+hikes.width+'px;'"></span>
<span class="desc">{{ lang.get('track_'+hikeType) }}</span>
</div>
</div>
<div id="title" :class="'map-control settings-control map-control-'+(mobile?'bottom':'top')">
<div id="title" :class="'map-control settings-control map-control-'+(isMobile()?'bottom':'top')">
<span>{{ currProject.name }}</span>
</div>
</div>
@@ -718,7 +731,7 @@ export default {
<ProjectPost :options="{type: 'loading', headerless: true}" />
</div>
</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-'+(isMobile()?'bottom':'top')" @click="toggleFeedPanel">
<SpotIcon :icon="feedPanelOpen?'next':'post'" />
</div>
</div>