New settings panel & &subscription

This commit is contained in:
2020-04-05 18:56:42 +02:00
parent 7a03fa94ab
commit 13a9155634
20 changed files with 887 additions and 241 deletions

View File

@@ -3,6 +3,24 @@
<div class="loader fa fa-fw fa-map flicker" id="map_loading"></div>
</div>
<div id="map"></div>
<div id="settings">
<div id="settings-sections">
<div class="settings-section">
<h1><i class="fa fa-fw push fa-map"></i>[#]lang:maps[#]</h1>
<div id="layers"></div>
</div>
<div class="settings-section newsletter">
<h1><i class="fa fa-fw push fa-newsletter"></i>[#]lang:newsletter[#]</h1>
<input type="email" name="email" id="email" placeholder="[#]lang:nl_email_placeholder[#]" /><button id="nl_btn"><span><i class="fa"></i></span></button>
<div id="settings-feedback" class="feedback"></div>
<div id="nl_desc"></div>
</div>
<div class="settings-section">
<h1><i class="fa fa-fw push fa-project"></i>[#]lang:projects[#]</h1>
<div id="settings-projects"></div>
</div>
</div>
</div>
<div id="feed">
<div id="posts">
<div id="poster"></div>
@@ -11,6 +29,7 @@
</div>
</div>
<div id="elems">
<div id="settings-button"><i class="fa fa-menu fa-fw"></i></div>
<div id="post-button"><i class="fa fa-fw"></i></div>
<div id="legend" class="leaflet-control-layers leaflet-control leaflet-control-layers-expanded">
<div class="track"><span class="line main"></span><span class="desc">[#]lang:track_main[#]</span></div>
@@ -40,7 +59,6 @@ oSpot.pageInit = function(asHash) {
};
oSpot.onResize = function() {
self.tmp('mobile', $('#mobile').is(':visible'));
self.tmp('feed_width', self.tmp('with_feed')?$('#feed').outerWidth(true):0);
self.tmp('map_offset', -1 * self.tmp('feed_width') / $('body').outerWidth(true));
@@ -64,7 +82,7 @@ oSpot.onKeydown = function(oEvent) {
}
}
function toggleFeedPanel(bShow, bAutoPan) {
function toggleFeedPanel(bShow, sMapAction) {
var $Container = $('#projects');
if(typeof bShow === 'undefined') $Container.toggleClass('with-feed');
else $Container.toggleClass('with-feed', bShow);
@@ -72,17 +90,36 @@ function toggleFeedPanel(bShow, bAutoPan) {
oSpot.tmp('with_feed', $Container.hasClass('with-feed'));
oSpot.onResize();
if(typeof bAutoPan === 'undefined') bAutoPan = true;
if(bAutoPan && typeof oSpot.tmp('map') != 'undefined') {
oSpot.tmp('map').panBy([(oSpot.tmp('with_feed')?1:-1)*$('#feed').outerWidth(true)/2, 0], {
duration: 0.5
});
if(isMobile()) $('#settings-button').toggle(!oSpot.tmp('with_feed'));
sMapAction = sMapAction || 'panTo';
switch(sMapAction) {
case 'none': break;
case 'panTo': oSpot.tmp('map').panBy([(oSpot.tmp('with_feed')?1:-1)*$('#feed').outerWidth(true)/2, 0], {duration: 0.5}); break;
case 'panToInstant': oSpot.tmp('map').panBy([(oSpot.tmp('with_feed')?1:-1)*$('#feed').outerWidth(true)/2, 0]); break;
case 'fitBounds': oSpot.tmp('map').fitBounds(self.tmp('track').getBounds(), {paddingTopLeft: L.point(5, self.tmp('marker_size').height + 5), paddingBottomRight: L.point(self.tmp('feed_width') + 5, 5)}); break;
}
}
function toggleSettingsPanel(bShow) {
var $Container = $('#projects');
if(typeof bShow === 'undefined') $Container.toggleClass('with-settings');
else $Container.toggleClass('with-settings', bShow);
var bWithSettings = isSettingsPanelOpen();
oSpot.onResize();
if(isMobile()) $('#post-button').toggle(!bWithSettings);
oSpot.tmp('map').panBy([(bWithSettings?-1:1)*$('#settings').outerWidth(true)/2, 0], {duration: 0.5});
}
function isSettingsPanelOpen() {
return $('#projects').hasClass('with-settings');
}
function isMobile() {
self.tmp('mobile', $('#mobile').is(':visible'));
return self.tmp('mobile');
return $('#mobile').is(':visible');
}
function initPage(asHash) {
@@ -97,8 +134,7 @@ function initPage(asHash) {
self.tmp('trail-markers', 'object');
self.tmp('marker_size', {width: 32, height: 32});
toggleFeedPanel(!isMobile(), false);
oSpot.onResize();
toggleFeedPanel(false, 'none');
//Lightbox options
lightbox.option({
@@ -119,6 +155,7 @@ function initPage(asHash) {
self.tmp(['track-type-styles', sTrackType], {weight: parseInt($Legend.css('height')), color: $Legend.css('background-color'), opacity: 1});
});
//Post Panel one-off init (see initPosts for project related init)
//Scrollbar
self.tmp('simple-bar', new SimpleBar($('#posts')[0]));
self.tmp('simple-bar').getScrollElement().addEventListener('scroll', onFeedScroll);
@@ -130,6 +167,12 @@ function initPage(asHash) {
$("#feed").onSwipe(function(aiDelta){
if(aiDelta.x > self.tmp('feed_width')/3 && aiDelta.x > Math.abs(aiDelta.y)) toggleFeedPanel(false);
});
//Feed Panel
initPosts();
//Settings Panel
initSettings();
//project Bootstrap
initProject(asHash.items[0]);
@@ -163,53 +206,116 @@ function initProject(sProjectCodeName){
mimeType: 'application/json'
})
).done(function(aoMessages, aoTracks) {
initSpotMessages(aoMessages[0]['data'] || [], aoTracks[0]);
initSpotMessages(aoMessages[0]['data'] || [], aoTracks[0], aoMessages[0]['desc']=='No Data');
});
//Posts
initPosts();
}
function initPosts() {
var $Poster = $('#poster').empty();
if(self.vars(['project', 'mode'])==self.consts.modes.histo) $Poster.hide();
else {
var asPoster = {
type: 'poster',
formatted_time: '',
relative_time: oSpot.lang('post_new_message')
};
getPost(asPoster).appendTo($Poster.show());
autosize($('#post'));
$('#submit').click(function(){
if($Poster.checkForm())
{
self.get(
'add_post',
function()
{
$('#name').val('');
$('#post').val('');
updateFeed(true);
},
{
project_id: self.vars(['project', 'id']),
name: $('#name').val(),
content: $('#post').val()
}
);
}
});
}
//Show/Hide Poster Panel
var bHistoMode = (self.vars(['project', 'mode']) == self.consts.modes.histo);
$('#poster').toggle(!bHistoMode);
//Feed auto-update
self.tmp('simple-bar').getScrollElement().scrollTop = 0;
if(self.vars(['project', 'mode']) != self.consts.modes.histo) onAutoUpdate(true);
if(!bHistoMode) onAutoUpdate(true);
else updateFeed(true);
}
function initPosts() {
var asPoster = {
type: 'poster',
formatted_time: '',
relative_time: oSpot.lang('post_new_message')
};
getPost(asPoster).appendTo($('#poster'));
autosize($('#post'));
$('#submit').click(function(){
if($('#poster').checkForm())
{
self.get(
'add_post',
function()
{
$('#post').val('');
updateFeed(true);
},
{
project_id: self.vars(['project', 'id']),
name: $('#name').val(),
content: $('#post').val()
}
);
}
});
}
function initSettings(){
//Scrollbar
new SimpleBar($('#settings-sections')[0]);
//Feedback display function
var settingsFeedback = function(sType, sMsg){
$('<p>', {'class': sType})
.append($('<i>', {'class':'fa push fa-'+sType}))
.append(sMsg)
.appendTo($('#settings-feedback'))
.slideDown('fast')
.delay(5000)
.slideUp('fast', function(){$(this).remove();});
};
//Newsletter Subscription
$('#nl_btn').click(function(){
var sAction = $(this).prop('name');
var sEmail = $('#email').val();
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(sEmail)) settingsFeedback('error', 'this is not an email');
else {
oSpot.get(
sAction,
function(asData) {
settingsFeedback('success', oSpot.lang('nl_'+sAction+'d'));
oSpot.vars('user', asData);
setUserInterface();
},
{'email': sEmail},
function(sDesc) {settingsFeedback('error', sDesc);},
function(sState) {
var bLoading = (sState=='start');
$('#nl_btn')
.prop('disabled', bLoading)
.toggleClass('loading', bLoading);
}
);
}
});
//Twink interface with user data
setUserInterface();
}
function setUserInterface() {
var asUserInfo = oSpot.vars('user');
if(asUserInfo.id_user) { //Subscribed User
$('#email').val(asUserInfo.email).prop('disabled', true);
$('#nl_btn').attr({name: 'unsubscribe', title: oSpot.lang('nl_unsubscribe'), 'class':'unsubscribe'});
$('#nl_desc').text(oSpot.lang('nl_subscribed_desc'));
//Populate nickname
if(asUserInfo.name) $('#name').val(asUserInfo.name);
}
else { //Unsubscribed User
//Switch to subcribe mode
$('#email').val('').prop('disabled', false);
$('#nl_btn').attr({name: 'subscribe', title: oSpot.lang('nl_subscribe'), 'class':'subscribe'});
$('#nl_desc').text(oSpot.lang('nl_unsubscribed_desc'));
//Reset nickname
$('#name').val('');
}
}
function onAutoUpdate(bFirstExec) {
bFirstExec = bFirstExec || false;
if(bFirstExec) updateFeed(true);
@@ -218,11 +324,17 @@ function onAutoUpdate(bFirstExec) {
}
function getElevWidth() {
// Page widthFeed Panel Legend width (bottom left) Elevation right margin (from page side)
return $('#projects').width() - oSpot.tmp('feed_width') - $('.leaflet-bottom.leaflet-left > .leaflet-control-layers').outerWidth(true) - parseInt($('.leaflet-bottom.leaflet-right > .leaflet-control-scale').css('margin-right').slice(0, -2));
var
iPageWidth = $('#projects').width(),
iFeedPanelWidth = oSpot.tmp('feed_width'),
iSettingsPanelWidth = isSettingsPanelOpen()?$('#settings').outerWidth(true):0,
iLegendWidth = $('.leaflet-bottom.leaflet-left > .leaflet-control-layers').outerWidth(true),
oElevRightMarging = parseInt($('.leaflet-bottom.leaflet-right > .leaflet-control-scale').css('margin-right').slice(0, -2));
return iPageWidth - iFeedPanelWidth - iSettingsPanelWidth - iLegendWidth - oElevRightMarging;
}
function initSpotMessages(aoMessages, aoTracks) {
function initSpotMessages(aoMessages, aoTracks, bNoFeed) {
//Tile layers
aoLayers = {};
@@ -241,6 +353,13 @@ function initSpotMessages(aoMessages, aoTracks) {
});
self.tmp('map', oMap);
//Controls: Settings Panel
var oSettingsPanel = L.control({position: 'topleft'});
var $SettingsButton = $('#settings-button').clone();
$SettingsButton.click(toggleSettingsPanel);
oSettingsPanel.onAdd = function(oMap) {return $SettingsButton[0];};
oSettingsPanel.addTo(oMap);
//Controls: Feed Panel
var oFeedPanel = L.control({position: 'topright'});
var $PostButton = $('#post-button').clone();
@@ -254,28 +373,24 @@ function initSpotMessages(aoMessages, aoTracks) {
oLegend.addTo(oMap);
//Controls: Projects
var oProjects = L.control({position: 'bottomleft'});
oProjects.onAdd = function(oMap) {
var $Labels = $('<div>', {'class': 'leaflet-control-layers-base'});
$.each(self.vars('projects'), function(sCodeName, asProject){
var asRadioAttrs = {'type': 'radio', 'class': 'leaflet-control-layers-selector', 'name':'project', 'value': sCodeName};
if(asProject.id == self.vars(['project', 'id'])) asRadioAttrs.checked = 'checked';
var $Radio =$('<input>', asRadioAttrs).change(function(){
self.setHash(self.vars('page'), [$(this).val()]);
});
var $Label = $('<label>').append($('<div>')
.append($Radio)
.append($('<span>').text(' '+asProject.name))
.append($('<a>', {'class':'fa fa-download push-left', href:asProject.gpxfilepath}).click(function(e){e.stopPropagation();}))
);
$Labels.append($Label);
var $Labels = $('<div>', {'class': 'leaflet-control-layers-base'});
$.each(self.vars('projects'), function(sCodeName, asProject){
var asRadioAttrs = {'type': 'radio', 'class': 'leaflet-control-layers-selector', 'name':'project', 'value': sCodeName};
if(asProject.id == self.vars(['project', 'id'])) asRadioAttrs.checked = 'checked';
var $Radio =$('<input>', asRadioAttrs).change(function(){
toggleSettingsPanel(false);
self.setHash(self.vars('page'), [$(this).val()]);
});
return $('<div>', {'class':'leaflet-control-layers leaflet-control leaflet-control-layers-expanded'}).append($('<section>').append($Labels))[0];
};
oProjects.addTo(oMap);
var $Label = $('<label>').append($('<div>')
.append($Radio)
.append($('<span>').text(' '+asProject.name))
.append($('<a>', {'class':'fa fa-download push-left', href:asProject.gpxfilepath, title:oSpot.lang('track_download')}).click(function(e){e.stopPropagation();}))
);
$Labels.append($Label);
});
$('#settings-projects').empty().append($Labels);
//Controls: Scale
oScale = L.control.scale({imperial: false, 'position':'bottomright'}).addTo(oMap);
@@ -295,8 +410,9 @@ function initSpotMessages(aoMessages, aoTracks) {
}).addTo(oMap);
self.tmp('elev', oElev);
//Controls: Tiles (layers)
//Controls: Tiles (layers): Add & Move to Settings Panel
L.control.layers(aoLayers, null, {position: 'topleft'}).addTo(oMap);
$('#layers').empty().append($('.leaflet-control-layers-list .leaflet-control-layers-base'));
//Tracks, colors & popup
var oActualTracks = L.geoJson(aoTracks, {
@@ -305,7 +421,7 @@ function initSpotMessages(aoMessages, aoTracks) {
}
}).addTo(oMap);
var oTracks = L.geoJson(aoTracks, {
self.tmp('track', L.geoJson(aoTracks, {
style: {weight: 20, opacity: 0},
onEachFeature: function(feature, oLayer) {
var asProperties = feature.properties;
@@ -392,19 +508,18 @@ function initSpotMessages(aoMessages, aoTracks) {
(oElev.addData.bind(oElev))(feature, oLayer);
}
}
}).addTo(oMap);
}).addTo(oMap));
//Centering map
var bWithFeedPanel = (!bNoFeed && !isMobile());
if(self.vars(['project', 'mode'])==self.consts.modes.blog && aoMessages.length > 0)
{
//Zoom on last message
var oLastMsg = aoMessages[aoMessages.length-1];
oMap.setView(L.latLng(oLastMsg.latitude, oLastMsg.longitude), 15);
//Recenter map to be at the center of 70% (map_offset) of the page, 30% being used by posts
oMap.setOffsetView(self.tmp('map_offset'));
oMap.panBy([(bWithFeedPanel?1:0)*$('#feed').outerWidth(true)/2, 0]);
}
else oMap.fitBounds(oTracks.getBounds(), {paddingTopLeft: L.point(5, self.tmp('marker_size').height + 5), paddingBottomRight: L.point(self.tmp('feed_width') + 5, 5)});
else oMap.fitBounds(self.tmp('track').getBounds(), {paddingTopLeft: L.point(5, self.tmp('marker_size').height + 5), paddingBottomRight: L.point(5 + parseInt(bWithFeedPanel?$('#feed').outerWidth(true):0), 5)});
//Spot Messages
$.each(aoMessages, function(iKey, oMsg){
@@ -426,7 +541,7 @@ function initSpotMessages(aoMessages, aoTracks) {
.append(oMsg.formatted_time+(self.vars(['project', 'mode'])==self.consts.modes.blog?' ('+oMsg.relative_time+')':'')+self.tmp('site_tz_notice')))
.append($('<p>', {'class':'coordinates'})
.addIcon('fa-coords fa-fw fa-lg', false)
.append('Lat : '+oMsg.latitude+', Lng : '+oMsg.longitude));
.append(getGoogleMapsLink(oMsg)));
//Tooltip medias
if(oMsg.medias) {
@@ -440,14 +555,14 @@ function initSpotMessages(aoMessages, aoTracks) {
}
oMarker.bindPopup($Tooltip[0], {
maxWidth: 1000,
maxWidth: $('#projects').width(),
autoPan: false,
closeOnClick: true,
offset: new L.Point(0, -30)
});
//Open tooltip on latest message in mobile mode
if(iKey === (aoMessages.length - 1) && self.vars(['project', 'mode']) == self.consts.modes.blog && (!oMsg.medias || oMsg.medias.length < 3) && self.tmp('mobile')) oMarker.openPopup();
if(iKey === (aoMessages.length - 1) && self.vars(['project', 'mode']) == self.consts.modes.blog && (!oMsg.medias || oMsg.medias.length < 3) && isMobile()) oMarker.openPopup();
oSpot.tmp(['markers', oMsg.id_message], oMarker);
});
@@ -498,7 +613,7 @@ function updateFeed(bFirstChunk, bDiscrete) {
self.tmp('updatable', true);
if(bFirstChunk && !self.tmp('mobile') && !$.isEmptyObject(asData)) toggleFeedPanel(true, false);
if(bFirstChunk && !isMobile() && !$.isEmptyObject(asData)) toggleFeedPanel(true, 'none');
}, {
'project_id': self.vars(['project', 'id']),
'chunk': self.tmp('news_chunk')
@@ -517,7 +632,7 @@ function setFeedUpdateTimer(iSeconds, fCallback) {
function getPost(asPost) {
asPost.headerless = asPost.headerless || false;
var $Post = $('<div>', {'class':'post '+asPost.type+(asPost.headerless?' headerless':'')});
var sRelTime = (asPost.relative_time!='')?((self.vars(['project', 'mode'])==self.consts.modes.histo)?asPost.formatted_time.substr(0, 10):asPost.relative_time):'';
var sRelTime = (asPost.relative_time!='')?((self.vars('project') && self.vars(['project', 'mode'])==self.consts.modes.histo)?asPost.formatted_time.substr(0, 10):asPost.relative_time):'';
var sAbsTime = asPost.formatted_time;
var sType = asPost.subtype || asPost.type;
var $Body = {};
@@ -526,7 +641,7 @@ function getPost(asPost) {
case 'message':
$Body = $('<div>')
.data('id', asPost.id_message)
.append($('<p>').addIcon('fa-coords', true).append(asPost.lat_dms+' '+asPost.lon_dms))
.append($('<p>').addIcon('fa-coords', true).append(getGoogleMapsLink(asPost)))
.append($('<p>').addIcon('fa-time', true).append(sAbsTime+self.tmp('site_tz_notice')))
.append($('<a>', {'class':'drill'})
.append($('<img>', {'class':'staticmap', title: oSpot.lang('click_zoom'), src: getWmtsApiUrl('static', asPost.latitude, asPost.longitude, 13)}))
@@ -536,9 +651,17 @@ function getPost(asPost) {
)
.click(function(){
var oMarker = oSpot.tmp(['markers', $(this).parent().data('id')]);
self.tmp('map').setOffsetView(self.tmp('map_offset'), oMarker.getLatLng(), 13);
if(isMobile()) {
toggleFeedPanel(false, 'panToInstant');
self.tmp('map').setView(oMarker.getLatLng(), 15);
}
else {
var iOffset = $('#feed').outerWidth(true)/2 - ($('#projects').hasClass('with-settings')?1:-1)*$('#settings').outerWidth(true)/2;
var iRatio = -1 * iOffset / $('body').outerWidth(true);
self.tmp('map').setOffsetView(iRatio, oMarker.getLatLng(), 15);
}
if(!oMarker.isPopupOpen()) oMarker.openPopup();
if(self.tmp('mobile')) toggleFeedPanel(false);
})
)
.hover(
@@ -615,4 +738,13 @@ function getMediaLink(asData, sType) {
return $Link;
}
function getGoogleMapsLink(asInfo) {
return $('<a>', {
href:'https://www.google.com/maps/place/'+asInfo.lat_dms+'+'+asInfo.lon_dms+'/@'+asInfo.latitude+','+asInfo.longitude+',10z',
title: oSpot.lang('see_on_google'),
target: '_blank',
rel: 'noreferrer'
}).text(asInfo.lat_dms+' '+asInfo.lon_dms);
}
</script>