Add auto-update

This commit is contained in:
2026-01-17 20:19:01 +01:00
parent 4f3be3342c
commit 28f95162aa

View File

@@ -28,6 +28,8 @@ export default {
return { return {
server: this.spot.consts.server, server: this.spot.consts.server,
feed: {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true}, feed: {loading:false, updatable:true, outOfData:false, refIdFirst:0, refIdLast:0, firstChunk:true},
refreshRate: 60,
lastUpdate: { unix_time: 0, relative_time: '', formatted_time: ''},
feedPanelOpen: false, feedPanelOpen: false,
feedSimpleBar: null, feedSimpleBar: null,
settingsPanelOpen: false, settingsPanelOpen: false,
@@ -108,11 +110,17 @@ export default {
this.spot.tmp('elev').resize({width:this.getElevWidth()}); this.spot.tmp('elev').resize({width:this.getElevWidth()});
} }
*/ */
},
onQuitPage: () => {
this.setFeedUpdateTimer(-1);
} }
}); });
this.currProjectCodeName = (this.$parent.hash.items.length==0)?this.spot.vars('default_project_codename'):this.$parent.hash.items[0]; this.currProjectCodeName = (this.$parent.hash.items.length==0)?this.spot.vars('default_project_codename'):this.$parent.hash.items[0];
}, },
beforeUnmount() {
this.setFeedUpdateTimer(-1);
},
methods: { methods: {
init() { init() {
let bFirstLoad = (typeof this.currProject.codename == 'undefined'); let bFirstLoad = (typeof this.currProject.codename == 'undefined');
@@ -155,10 +163,15 @@ export default {
//Add post Event handling //Add post Event handling
//TODO //TODO
//Get first posts batch
await this.getNextFeed(); await this.getNextFeed();
this.$refs.feedSimpleBar.scrollElement.scrollTop = 0;
//Scroll to post //Scroll to post
if(this.$parent.hash.items.length == 3) this.findPost({type: this.$parent.hash.items[1], id: this.$parent.hash.items[2]}); if(this.$parent.hash.items.length == 3) this.findPost({type: this.$parent.hash.items[1], id: this.$parent.hash.items[2]});
//Start auto-update
if(!this.modeHisto) this.setFeedUpdateTimer(this.refreshRate);
}, },
async initMap() { async initMap() {
//Get Map Info //Get Map Info
@@ -166,6 +179,7 @@ export default {
this.baseMap = null; this.baseMap = null;
this.baseMaps = aoMarkers.maps; this.baseMaps = aoMarkers.maps;
this.messages = aoMarkers.messages; this.messages = aoMarkers.messages;
this.lastUpdate = aoMarkers.last_update;
//Base maps (raster tiles) //Base maps (raster tiles)
let asSources = {}; let asSources = {};
@@ -233,34 +247,20 @@ export default {
}); });
//Markers //Markers
let aoMarkerSource = {type:'geojson', data:{type: 'FeatureCollection', features:[]}}; this.map.addImage('markerIcon', (await this.map.loadImage('images/footprint_mapbox.png')).data);
for(const oMsg of this.messages) { this.map.addSource('markers', {
aoMarkerSource.data.features.push({ type:'geojson',
'type': 'Feature', data: {
'properties': { type: 'FeatureCollection',
...oMsg, features: this.convertMsgToFeatures(this.messages)
...{'description': ''}
},
'geometry': {
'type': 'Point',
'coordinates': [oMsg.longitude, oMsg.latitude]
} }
}); });
}
this.map.addSource('markers', aoMarkerSource);
const image = await this.map.loadImage('images/footprint_mapbox.png');
this.map.addImage('markerIcon', image.data);
this.map.addLayer({ this.map.addLayer({
'id': 'markers', 'id': 'markers',
'type': 'symbol', 'type': 'symbol',
'source': 'markers', 'source': 'markers',
'layout': { 'layout': {'icon-image': 'markerIcon'}
//'icon-anchor': 'bottom',
'icon-image': 'markerIcon'
//'icon-overlap': 'always'
}
}); });
this.map.on('click', 'markers', (e) => { this.map.on('click', 'markers', (e) => {
this.openMarkerPopup(e.features[0]); this.openMarkerPopup(e.features[0]);
}); });
@@ -311,6 +311,78 @@ export default {
//Legend //Legend
}, },
convertMsgToFeatures(oMsg) {
return oMsg.map(oMsg => ({
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [oMsg.longitude, oMsg.latitude]
},
'properties': {
...oMsg,
...{'description': ''}
}
}));
},
async getNextFeed() {
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 iPostCount = Object.keys(aoData.feed).length;
//Update pointers
this.feed.outOfData = (iPostCount < this.spot.consts.chunk_size);
if(iPostCount > 0) {
this.feed.refIdLast = aoData.ref_id_last;
if(this.feed.firstChunk) this.feed.refIdFirst = aoData.ref_id_first;
}
//Add posts
this.posts.push(...aoData.feed);
this.feed.loading = false;
this.feed.firstChunk = false;
}
return true;
},
onFeedScroll(oEvent) {
//FIXME remove jquery dependency
var $Box = $(oEvent.currentTarget);
var $BoxContent = $Box.find('.simplebar-content');
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) this.getNextFeed();
},
setFeedUpdateTimer(iSeconds) {
if(typeof this.feedTimer != 'undefined') clearTimeout(this.feedTimer);
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});
if(Object.keys(aoData.feed).length > 0) {
//Update pointer
this.feed.refIdFirst = aoData.ref_id_first;
//Add new posts
this.posts.unshift(...aoData.feed);
}
//Add new Markers
if(Object.keys(aoData.messages).length > 0) {
const oMarkerSource = this.map.getSource('markers');
oMarkerSource.setData({
type: 'FeatureCollection',
features: [...oMarkerSource._data.features, ...this.convertMsgToFeatures(aoData.messages)]
});
}
//Message Last Update
this.lastUpdate = aoData.last_update;
//Reschedule
this.setFeedUpdateTimer(this.refreshRate);
},
openMarkerPopup(oFeature) { openMarkerPopup(oFeature) {
this.closeMarkerPopup(); this.closeMarkerPopup();
@@ -389,34 +461,6 @@ export default {
rel: 'noreferrer noopener' rel: 'noreferrer noopener'
}).text(asInfo.lat_dms+' '+asInfo.lon_dms); }).text(asInfo.lat_dms+' '+asInfo.lon_dms);
}, },
async getNextFeed() {
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 iPostCount = Object.keys(aoData.feed).length;
this.feed.loading = false;
this.feed.firstChunk = false;
//Update pointers
this.feed.outOfData = (iPostCount < this.spot.consts.chunk_size);
if(iPostCount > 0) {
this.feed.refIdLast = aoData.ref_id_last;
if(this.feed.firstChunk) this.feed.refIdFirst = aoData.ref_id_first;
}
//Add posts
this.posts.push(...aoData.feed);
}
return true;
},
onFeedScroll(oEvent) {
//FIXME remove jquery dependency
var $Box = $(oEvent.currentTarget);
var $BoxContent = $Box.find('.simplebar-content');
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) this.getNextFeed();
},
async manageSubs() { async manageSubs() {
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,}))$/; 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.spot.lang('nl_invalid_email')}); if(!regexEmail.test(this.user.email)) this.nlFeedbacks.push({type:'error', 'msg':this.spot.lang('nl_invalid_email')});
@@ -526,7 +570,9 @@ export default {
<div id="settings-panel" class="map-panel"> <div id="settings-panel" class="map-panel">
<div class="settings-header"> <div class="settings-header">
<div class="logo"><img width="289" height="72" src="images/logo_black.png" alt="Spotty" /></div> <div class="logo"><img width="289" height="72" src="images/logo_black.png" alt="Spotty" /></div>
<div id="last_update"><p><span><img src="images/spot-logo-only.svg" alt="" /></span><abbr></abbr></p></div> <div id="last_update" v-if="this.currProject.mode == this.spot.consts.modes.blog && lastUpdate.unix_time > 0">
<p><span><img src="images/spot-logo-only.svg" alt="" /></span><abbr :title="lastUpdate.formatted_time">{{ spot.lang('last_update')+' '+lastUpdate.relative_time }}</abbr></p>
</div>
</div> </div>
<div class="settings-sections"> <div class="settings-sections">
<simplebar id="settings-sections-scrollbox"> <simplebar id="settings-sections-scrollbox">