Compare commits

10 Commits
vue ... master

Author SHA1 Message Date
789838dd07 Fix SNT track color 2025-07-18 00:28:37 +02:00
a5fe6ebf75 Update DNT GPX file 2025-07-18 00:25:07 +02:00
d0dbb85e28 Add manual message upload 2025-05-11 13:19:59 +02:00
6a42494099 Fix SNT track color 2025-04-23 11:12:49 +02:00
1d90b11aef Add function to rebuild GeoJSON 2025-04-23 11:06:43 +02:00
bc75cbc17d Add Build GeoJSON Catch 2025-04-23 11:02:16 +02:00
2e8372d923 Update geo/snt.gpx 2025-04-22 13:40:51 +02:00
383890a9be Add SNT gpx 2025-04-22 13:40:25 +02:00
ae8a27fa64 Fix lightbox addToAlbum external reference 2023-10-19 21:43:02 +02:00
af05650443 Bump lightbox to 2.11.4 2023-10-19 21:33:59 +02:00
7 changed files with 69427 additions and 115 deletions

69304
geo/snt.gpx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -168,6 +168,31 @@ class Feed extends PhpObject {
return $bNewMsg; return $bNewMsg;
} }
public function addManualPosition($sLat, $sLng, $iTimestamp) {
$sTimeZone = date_default_timezone_get();
$oDateTime = new \DateTime('@'.$iTimestamp);
$oDateTime->setTimezone(new \DateTimeZone($sTimeZone));
$asWeather = $this->getWeather(array($sLat, $sLng), $iTimestamp);
$asMsg = [
'ref_msg_id' => $iTimestamp.'/man',
'id_feed' => $this->getFeedId(),
'type' => 'OK',
'latitude' => $sLat,
'longitude' => $sLng,
'iso_time' => $oDateTime->format("Y-m-d\TH:i:sO"), //Incorrect ISO 8601 format, but compliant with Spot data
'site_time' => $oDateTime->format(Db::TIMESTAMP_FORMAT),
'timezone' => $sTimeZone,
'unix_time' => $iTimestamp,
'content' => '',
'battery_state' => '',
'posted_on' => date(Db::TIMESTAMP_FORMAT),
];
$iMessageId = $this->oDb->insertRow(self::MSG_TABLE, array_merge($asMsg, $asWeather));
return $iMessageId;
}
private function updateFeed() { private function updateFeed() {
$bNewMsg = false; $bNewMsg = false;
$asData = $this->retrieveFeed(); $asData = $this->retrieveFeed();

View File

@@ -630,6 +630,13 @@ class Spot extends Main
return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']); return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']);
} }
public function addPosition($sLat, $sLng, $iTimestamp) {
$oFeed = new Feed($this->oDb, $this->oProject->getFeedIds()[0]);
$bResult = ($oFeed->addManualPosition($sLat, $sLng, $iTimestamp) > 0);
return self::getJsonResult($bResult, $bResult?'':$this->oDb->getLastError());
}
public function getAdminSettings($sType='') { public function getAdminSettings($sType='') {
$oFeed = new Feed($this->oDb); $oFeed = new Feed($this->oDb);
$asData = array( $asData = array(
@@ -744,6 +751,10 @@ class Spot extends Main
)); ));
} }
public function buildGeoJSON($sCodeName) {
return Converter::convertToGeoJson($sCodeName);
}
public static function decToDms($dValue, $sType) { public static function decToDms($dValue, $sType) {
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S'; //Latitude if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S'; //Latitude
else $sDirection = ($dValue >= 0)?'E':'W'; //Longitude else $sDirection = ($dValue >= 0)?'E':'W'; //Longitude

View File

@@ -25,6 +25,9 @@ $oValue = $_REQUEST['value'] ?? '';
$iId = $_REQUEST['id'] ?? 0 ; $iId = $_REQUEST['id'] ?? 0 ;
$sType = $_REQUEST['type'] ?? ''; $sType = $_REQUEST['type'] ?? '';
$sEmail = $_REQUEST['email'] ?? ''; $sEmail = $_REQUEST['email'] ?? '';
$sLat = $_REQUEST['latitude'] ?? '';
$sLng = $_REQUEST['longitude'] ?? '';
$iTimestamp = $_REQUEST['timestamp'] ?? 0;
//Initiate class //Initiate class
$oSpot = new Spot(__FILE__, $sTimezone); $oSpot = new Spot(__FILE__, $sTimezone);
@@ -70,6 +73,9 @@ if($sAction!='')
case 'add_comment': case 'add_comment':
$sResult = $oSpot->addComment($iId, $sContent); $sResult = $oSpot->addComment($iId, $sContent);
break; break;
case 'add_position':
$sResult = $oSpot->addPosition($sLat, $sLng, $iTimestamp);
break;
case 'admin_new': case 'admin_new':
$sResult = $oSpot->createProject(); $sResult = $oSpot->createProject();
break; break;
@@ -88,6 +94,9 @@ if($sAction!='')
case 'sql': case 'sql':
$sResult = $oSpot->getDbBuildScript(); $sResult = $oSpot->getDbBuildScript();
break; break;
case 'build_geojson':
$sResult = $oSpot->buildGeoJSON($sName);
break;
default: default:
$sResult = Main::getJsonResult(false, Main::NOT_FOUND); $sResult = Main::getJsonResult(false, Main::NOT_FOUND);
} }

View File

@@ -6,6 +6,9 @@
<div class="bar" style="width: 0%;"></div> <div class="bar" style="width: 0%;"></div>
</div> </div>
<div id="comments"></div> <div id="comments"></div>
<div id="location">
<button id="add_loc"><i class="fa fa-message push"></i>New Position</button>
</div>
<div id="status"></div> <div id="status"></div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
@@ -35,6 +38,27 @@ oSpot.pageInit = function(asHash) {
$('#progress .bar').css('width', progress+'%'); $('#progress .bar').css('width', progress+'%');
} }
}); });
$('#add_loc').click(() => {
if(navigator.geolocation) {
addStatus('Determining position...');
navigator.geolocation.getCurrentPosition(
(position) => {
addStatus('Sending position...');
oSpot.get(
'add_position',
function(asData){addStatus('Position sent');},
{'latitude':position.coords.latitude, 'longitude':position.coords.longitude, 'timestamp':Math.round(position.timestamp / 1000)},
function(sMsgId){addStatus(self.lang(sMsgId));},
);
},
(error) => {
addStatus(error.message);
}
);
}
else addStatus('This browser does not support geolocation');
});
} }
else addStatus(self.lang('upload_mode_archived', [asProject.name]), true); else addStatus(self.lang('upload_mode_archived', [asProject.name]), true);
}; };

View File

@@ -22,6 +22,7 @@
4. Copy settings-sample.php to settings.php and populate 4. Copy settings-sample.php to settings.php and populate
5. Go to #admin and create a new project, feed & maps 5. Go to #admin and create a new project, feed & maps
6. Add a GPX file named <project_codename>.gpx to /geo/ 6. Add a GPX file named <project_codename>.gpx to /geo/
7. Run composer install
## To Do List ## To Do List
* ECMA import/export * ECMA import/export
* Add mail frequency slider * Add mail frequency slider

View File

@@ -1,5 +1,5 @@
/*! /*!
* Lightbox v2.11.3 * Lightbox v2.11.4
* by Lokesh Dhakar * by Lokesh Dhakar
* *
* More info: * More info:
@@ -46,8 +46,6 @@
fadeDuration: 600, fadeDuration: 600,
fitImagesInViewport: true, fitImagesInViewport: true,
imageFadeDuration: 600, imageFadeDuration: 600,
// maxWidth: 800,
// maxHeight: 600,
positionFromTop: 50, positionFromTop: 50,
resizeDuration: 700, resizeDuration: 700,
showImageNumberLabel: true, showImageNumberLabel: true,
@@ -62,10 +60,8 @@
to prevent xss and other injection attacks. to prevent xss and other injection attacks.
*/ */
sanitizeTitle: false sanitizeTitle: false
//ADDED-START , hasVideo: true
, hasVideo: true
, onMediaChange: (oMedia) => {} , onMediaChange: (oMedia) => {}
//ADDED-END
}; };
Lightbox.prototype.option = function(options) { Lightbox.prototype.option = function(options) {
@@ -147,7 +143,6 @@
</div>\ </div>\
').appendTo($('body')); ').appendTo($('body'));
// Cache jQuery objects // Cache jQuery objects
this.$lightbox = $('#lightbox'); this.$lightbox = $('#lightbox');
this.$overlay = $('#lightboxOverlay'); this.$overlay = $('#lightboxOverlay');
@@ -155,8 +150,7 @@
this.$container = this.$lightbox.find('.lb-container'); this.$container = this.$lightbox.find('.lb-container');
this.$image = this.$lightbox.find('.lb-image'); this.$image = this.$lightbox.find('.lb-image');
this.$nav = this.$lightbox.find('.lb-nav'); this.$nav = this.$lightbox.find('.lb-nav');
//ADDED-START
if(self.options.hasVideo) { if(self.options.hasVideo) {
this.$video = $('<video class="lb-video" controls autoplay></video>'); this.$video = $('<video class="lb-video" controls autoplay></video>');
this.$image.after(this.$video); this.$image.after(this.$video);
@@ -166,8 +160,7 @@
bottom: parseInt(this.$video.css('border-bottom-width'), 10), bottom: parseInt(this.$video.css('border-bottom-width'), 10),
left: parseInt(this.$video.css('border-left-width'), 10) left: parseInt(this.$video.css('border-left-width'), 10)
}; };
} }
//ADDED-END
// Store css values for future lookup // Store css values for future lookup
this.containerPadding = { this.containerPadding = {
@@ -185,11 +178,8 @@
}; };
// Attach event handlers to the newly minted DOM elements // Attach event handlers to the newly minted DOM elements
//ADDED-START this.$overlay.hide().add(this.$lightbox.find('.lb-dataContainer')).on('click', function() {
//this.$overlay.hide().on('click', function() { self.end();
this.$overlay.hide().add(this.$lightbox.find('.lb-dataContainer')).on('click', function() {
//ADDED-END
self.end();
return false; return false;
}); });
@@ -250,9 +240,13 @@
}); });
this.$lightbox.find('.lb-loader, .lb-close').on('click', function() { this.$lightbox.find('.lb-loader, .lb-close').on('click keyup', function(e) {
self.end(); // If mouse click OR 'enter' or 'space' keypress, close LB
return false; if (
e.type === 'click' || (e.type === 'keyup' && (e.which === 13 || e.which === 32))) {
self.end();
return false;
}
}); });
}; };
@@ -265,7 +259,6 @@
this.sizeOverlay(); this.sizeOverlay();
//ADDED-START
//Manage Zoom Event //Manage Zoom Event
this.$nav.mousewheel((e) => { this.$nav.mousewheel((e) => {
var asImg = self.album[this.currentImageIndex]; var asImg = self.album[this.currentImageIndex];
@@ -324,7 +317,6 @@
self.$image.css('--translate-x', fTransX + 'px'); self.$image.css('--translate-x', fTransX + 'px');
self.$image.css('--translate-y', fTransY + 'px'); self.$image.css('--translate-y', fTransY + 'px');
} }
//ADDED-END
this.album = []; this.album = [];
var imageNumber = 0; var imageNumber = 0;
@@ -349,7 +341,7 @@
// If image is part of a set // If image is part of a set
$links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]'); $links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]');
for (var j = 0; j < $links.length; j = ++j) { for (var j = 0; j < $links.length; j = ++j) {
this.addToAlbum($($links[j])); this.addToAlbum($($links[j]));
if ($links[j] === $link[0]) { if ($links[j] === $link[0]) {
imageNumber = j; imageNumber = j;
} }
@@ -358,14 +350,7 @@
} }
// Position Lightbox // Position Lightbox
//ADDED-START this.$lightbox.fadeIn(this.options.fadeDuration);
//var top = $window.scrollTop() + this.options.positionFromTop;
//var left = $window.scrollLeft();
this.$lightbox/*.css({
top: top + 'px',
left: left + 'px'
})*/.fadeIn(this.options.fadeDuration);
//ADDED-END
// Disable scrolling of the page while open // Disable scrolling of the page while open
if (this.options.disableScrolling) { if (this.options.disableScrolling) {
@@ -379,20 +364,18 @@
this.album.push({ this.album.push({
alt: $link.attr('data-alt'), alt: $link.attr('data-alt'),
link: $link.attr('href'), link: $link.attr('href'),
title: $link.attr('data-title') || $link.attr('title') title: $link.attr('data-title') || $link.attr('title'),
//ADDED-START
, orientation: $link.attr('data-orientation') orientation: $link.attr('data-orientation'),
, type: $link.attr('data-type') type: $link.attr('data-type'),
, id: $link.attr('data-id') id: $link.attr('data-id'),
, $Media: $link.attr('data-type')=='video'?this.$video:this.$image $Media: $link.attr('data-type')=='video'?this.$video:this.$image,
, width: $link.find('img').attr('width') width: $link.find('img').attr('width'),
, height: $link.find('img').attr('height') height: $link.find('img').attr('height'),
, set: $link.attr('data-lightbox') || $link.attr('rel') set: $link.attr('data-lightbox') || $link.attr('rel')
//ADDED-END
}); });
} }
//ADDED-START
Lightbox.prototype.getMaxSizes = function(iMediaWidth, iMediaHeight, sMediaType) { Lightbox.prototype.getMaxSizes = function(iMediaWidth, iMediaHeight, sMediaType) {
var iWindowWidth = $(window).width(); var iWindowWidth = $(window).width();
var iWindowHeight = $(window).height(); var iWindowHeight = $(window).height();
@@ -473,20 +456,20 @@
// Hide most UI elements in preparation for the animated resizing of the lightbox. // Hide most UI elements in preparation for the animated resizing of the lightbox.
Lightbox.prototype.changeImage = function(imageNumber) { Lightbox.prototype.changeImage = function(imageNumber) {
var self = this; var self = this;
var filename = this.album[imageNumber].link; var filename = this.album[imageNumber].link;
// Disable keyboard nav during transitions
this.disableKeyboardNav();
// Show loading state // Disable keyboard nav during transitions
this.$overlay.fadeIn(this.options.fadeDuration); this.disableKeyboardNav();
$('.lb-loader').fadeIn('slow');
this.$lightbox.find('.lb-image, .lb-video, .lb-nav, .lb-prev, .lb-next, .lb-number, .lb-caption, .lb-close').hide(); // Show loading state
this.$overlay.fadeIn(this.options.fadeDuration);
$('.lb-loader').fadeIn('slow');
this.$lightbox.find('.lb-image, .lb-video, .lb-nav, .lb-prev, .lb-next, .lb-number, .lb-caption, .lb-close').hide();
this.$image.css({'--scale': '1', '--translate-x': '0', '--translate-y': '0'}); this.$image.css({'--scale': '1', '--translate-x': '0', '--translate-y': '0'});
self.$lightbox.find('.lb-dataContainer').css({width:'200px', height:'30px'}); self.$lightbox.find('.lb-dataContainer').css({width:'200px', height:'30px'});
this.$outerContainer.addClass('animating'); this.$outerContainer.addClass('animating');
this.$container.removeClass('moveable moving'); this.$container.removeClass('moveable moving');
this.options.onMediaChange(self.album[imageNumber]); this.options.onMediaChange(self.album[imageNumber]);
@@ -534,31 +517,19 @@
break; break;
} }
this.currentImageIndex = imageNumber; this.currentImageIndex = imageNumber;
}; };
//ADDED-END
// Stretch overlay to fit the viewport // Stretch overlay to fit the viewport
Lightbox.prototype.sizeOverlay = function(e) { Lightbox.prototype.sizeOverlay = function(e) {
//var self = this; /*
/*
We use a setTimeout 0 to pause JS execution and let the rendering catch-up. We use a setTimeout 0 to pause JS execution and let the rendering catch-up.
Why do this? If the `disableScrolling` option is set to true, a class is added to the body Why do this? If the `disableScrolling` option is set to true, a class is added to the body
tag that disables scrolling and hides the scrollbar. We want to make sure the scrollbar is tag that disables scrolling and hides the scrollbar. We want to make sure the scrollbar is
hidden before we measure the document width, as the presence of the scrollbar will affect the hidden before we measure the document width, as the presence of the scrollbar will affect the
number. number.
*/ */
//ADDED-START if(e) {
/*
setTimeout(function() {
self.$overlay
.width($(document).width())
.height($(document).height());
}, 0);
*/
if(e) {
if(typeof oResizeTimer != 'undefined') clearTimeout(oResizeTimer); if(typeof oResizeTimer != 'undefined') clearTimeout(oResizeTimer);
oResizeTimer = setTimeout( oResizeTimer = setTimeout(
() => { () => {
@@ -573,17 +544,16 @@
}, },
200 200
); );
} }
//ADDED-END
}; };
// Animate the size of the lightbox to fit the image we are showing // Animate the size of the lightbox to fit the image we are showing
// This method also shows the the image. // This method also shows the the image.
//ADDED-START //ADDED-START
//Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) { //Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) {
Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight, media) { Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight, media) {
media = media || 'image'; media = media || 'image';
//ADDED-END //ADDED-END
var self = this; var self = this;
var oldWidth = this.$outerContainer.outerWidth(); var oldWidth = this.$outerContainer.outerWidth();
@@ -597,19 +567,13 @@
//ADDED-END //ADDED-END
function postResize() { function postResize() {
//ADDED-START
//self.$lightbox.find('.lb-dataContainer').width(newWidth);
if(self.$lightbox.hasClass('vertical')) self.$lightbox.find('.lb-dataContainer').width(newWidth); if(self.$lightbox.hasClass('vertical')) self.$lightbox.find('.lb-dataContainer').width(newWidth);
else self.$lightbox.find('.lb-dataContainer').height(newHeight); else self.$lightbox.find('.lb-dataContainer').height(newHeight);
//ADDED-END
self.$lightbox.find('.lb-prevLink').height(newHeight); self.$lightbox.find('.lb-prevLink').height(newHeight);
self.$lightbox.find('.lb-nextLink').height(newHeight); self.$lightbox.find('.lb-nextLink').height(newHeight);
// Set focus on one of the two root nodes so keyboard events are captured. // Set focus on one of the two root nodes so keyboard events are captured.
//ADDED-START self.$overlay.trigger('focus');
//self.$overlay.focus();
self.$overlay.trigger( 'focus' );
//ADDED-END
self.showImage(); self.showImage();
} }
@@ -630,11 +594,8 @@
Lightbox.prototype.showImage = function() { Lightbox.prototype.showImage = function() {
this.$lightbox.find('.lb-loader').stop(true).hide(); this.$lightbox.find('.lb-loader').stop(true).hide();
//ADDED-START
//this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration);
if(this.options.hasVideo && this.album[this.currentImageIndex].type == 'video') this.$lightbox.find('.lb-video').fadeIn(this.options.imageFadeDuration); if(this.options.hasVideo && this.album[this.currentImageIndex].type == 'video') this.$lightbox.find('.lb-video').fadeIn(this.options.imageFadeDuration);
else this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration); else this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration);
//ADDED-END
this.updateNav(); this.updateNav();
this.updateDetails(); this.updateDetails();
@@ -691,29 +652,10 @@
$caption.text(this.album[this.currentImageIndex].title); $caption.text(this.album[this.currentImageIndex].title);
} else { } else {
$caption.html(this.album[this.currentImageIndex].title); $caption.html(this.album[this.currentImageIndex].title);
} }
//ADDED-START
//$caption.fadeIn('fast');
$caption.add(this.$lightbox.find('.lb-close')).fadeIn('fast'); $caption.add(this.$lightbox.find('.lb-close')).fadeIn('fast');
//ADDED-END
} }
//ADDED-START
/*
//ADDED-END
if (this.album.length > 1 && this.options.showImageNumberLabel) {
var labelText = this.imageCountLabel(this.currentImageIndex + 1, this.album.length);
//ADDED-START
//this.$lightbox.find('.lb-number').text(labelText).fadeIn('fast');
this.$lightbox.find('.lb-number').empty().append(labelText).fadeIn('fast');
//ADDED-END
} else {
this.$lightbox.find('.lb-number').hide();
}
//ADDED-START
*/
//ADDED-END
this.$outerContainer.removeClass('animating'); this.$outerContainer.removeClass('animating');
this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() { this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() {
@@ -734,9 +676,7 @@
}; };
Lightbox.prototype.enableKeyboardNav = function() { Lightbox.prototype.enableKeyboardNav = function() {
//ADDED-START this.disableKeyboardNav();
this.disableKeyboardNav();
//ADDED-END
this.$lightbox.on('keyup.keyboard', $.proxy(this.keyboardAction, this)); this.$lightbox.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
this.$overlay.on('keyup.keyboard', $.proxy(this.keyboardAction, this)); this.$overlay.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
}; };
@@ -775,19 +715,17 @@
Lightbox.prototype.end = function() { Lightbox.prototype.end = function() {
this.disableKeyboardNav(); this.disableKeyboardNav();
//ADDED-START if(this.options.hasVideo) {
if(this.options.hasVideo) { var $lbContainer = this.$lightbox.find('.lb-container');
var $lbContainer = this.$lightbox.find('.lb-container'); var $hasVideoNav = $lbContainer.hasClass('lb-video-nav');
var $hasVideoNav = $lbContainer.hasClass('lb-video-nav'); this.$video.attr('src', '');
this.$video.attr('src', '');
if($hasVideoNav) $lbContainer.removeClass('lb-video-nav'); if($hasVideoNav) $lbContainer.removeClass('lb-video-nav');
} }
oSpot.flushHash(); oSpot.flushHash();
//ADDED-END
$(window).off('resize', this.sizeOverlay); $(window).off('resize', this.sizeOverlay);
this.$nav.off('mousewheel'); this.$nav.off('mousewheel');
this.$lightbox.fadeOut(this.options.fadeDuration); this.$lightbox.fadeOut(this.options.fadeDuration);
this.$overlay.fadeOut(this.options.fadeDuration); this.$overlay.fadeOut(this.options.fadeDuration);