Compare commits

...

13 Commits

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
b3cd217e28 Add altitude on image 2023-10-15 18:33:36 +02:00
5f597647b4 Support geo located images & videos 2023-08-12 23:35:40 +02:00
199e3a1269 Bump leaflet to 1.9.4 2023-08-09 23:10:04 +02:00
15 changed files with 69596 additions and 147 deletions

View File

@@ -0,0 +1,3 @@
ALTER TABLE medias ADD latitude DECIMAL(7,5) AFTER timezone;
ALTER TABLE medias ADD longitude DECIMAL(8,5) AFTER latitude;
ALTER TABLE medias ADD altitude SMALLINT AFTER longitude;

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;
}
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() {
$bNewMsg = false;
$asData = $this->retrieveFeed();

View File

@@ -76,7 +76,7 @@ class Media extends PhpObject {
if($bOwnMedia && empty($this->asMedia) || !$bOwnMedia && empty($this->asMedias) || $bConstraintArray) {
if($this->oProject->getProjectId()) {
$asParams = array(
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'timezone', 'width', 'height', 'rotate', 'type AS subtype', 'comment'),
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'timezone', 'latitude', 'longitude', 'altitude', 'width', 'height', 'rotate', 'type AS subtype', 'comment'),
'from' => self::MEDIA_TABLE,
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
);
@@ -128,6 +128,9 @@ class Media extends PhpObject {
'taken_on' => date(Db::TIMESTAMP_FORMAT, ($asMediaInfo['taken_ts'] > 0)?$asMediaInfo['taken_ts']:$asMediaInfo['file_ts']),
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asMediaInfo['file_ts']),
'timezone' => $asMediaInfo['timezone'],
'latitude' => is_null($asMediaInfo['latitude'])?'NULL':$asMediaInfo['latitude'],
'longitude' => is_null($asMediaInfo['longitude'])?'NULL':$asMediaInfo['longitude'],
'altitude' => is_null($asMediaInfo['altitude'])?'NULL':$asMediaInfo['altitude'],
'width' => $asMediaInfo['width'],
'height' => $asMediaInfo['height'],
'rotate' => $asMediaInfo['rotate'],
@@ -151,21 +154,23 @@ class Media extends PhpObject {
{
$sMediaPath = self::getMediaPath($sMediaName);
$sType = self::getMediaType($sMediaName);
$iPostedOn = filemtime($sMediaPath);
$sTimeZone = date_default_timezone_get();
$iWidth = 0;
$iHeight = 0;
$sRotate = '0';
$sTakenOn = '';
$fLat = null;
$fLng = null;
$iAlt = null;
switch($sType) {
case 'video':
$asResult = array();
$sParams = implode(' ', array(
'-loglevel error', //Remove comments
'-select_streams v:0', //First video channel
'-show_entries '. //filter tags : Width, Height, Creation Time & Rotation
'format_tags=creation_time,com.apple.quicktime.creationdate:'.
'-show_entries '. //filter tags : Width, Height, Creation Time, Location & Rotation
'format_tags=creation_time,com.apple.quicktime.creationdate,com.apple.quicktime.location.ISO6709:'.
'stream_tags=rotate,creation_time:'.
'stream=width,height',
'-print_format json', //output format: json
@@ -181,6 +186,11 @@ class Media extends PhpObject {
}
else $sTakenOn = $asExif['format']['tags']['creation_time'] ?? $asExif['streams'][0]['tags']['creation_time'];
//Location
if(isset($asExif['format']['tags']['com.apple.quicktime.location.ISO6709'])) {
list($fLat, $fLng, $iAlt) = self::getLatLngAltFromISO6709($asExif['format']['tags']['com.apple.quicktime.location.ISO6709']);
}
//Width & Height
$iWidth = $asExif['streams'][0]['width'];
$iHeight = $asExif['streams'][0]['height'];
@@ -209,6 +219,14 @@ class Media extends PhpObject {
$sTimeZone = $asExif['EXIF']['OffsetTimeOriginal'] ?? $asExif['EXIF']['UndefinedTag:0x9011'] ?? Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
}
//Location
if(array_key_exists('GPS', $asExif)) {
$asGps = $asExif['GPS'];
$fLat = self::getLatLngFromExif($asGps['GPSLatitudeRef'] ?? $asGps['UndefinedTag:0x0001'], $asGps['GPSLatitude'] ?? $asGps['UndefinedTag:0x0002']);
$fLng = self::getLatLngFromExif($asGps['GPSLongitudeRef'] ?? $asGps['UndefinedTag:0x0003'], $asGps['GPSLongitude'] ?? $$asGps['UndefinedTag:0x0004']);
$iAlt = (($asGps['GPSAltitudeRef'] ?? $asGps['UndefinedTag:0x0005'] ?? '0') == '1'?-1:1) * ($asGps['GPSAltitude'] ?? $asGps['UndefinedTag:0x0006'] ?? 0);
}
//Orientation
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
switch($asExif['IFD0']['Orientation'])
@@ -232,6 +250,9 @@ class Media extends PhpObject {
return array(
'timezone' => $sTimeZone,
'latitude' => $fLat,
'longitude' => $fLng,
'altitude' => $iAlt,
'taken_ts' => $iTakenOn,
'file_ts' => $iPostedOn,
'width' => $iWidth,
@@ -290,4 +311,29 @@ class Media extends PhpObject {
return $sType;
}
}
private static function getLatLngFromExif($sDirection, $asCoords) {
$fCoord = 0;
foreach($asCoords as $iIndex=>$sCoord) {
$fValue = 0;
$asCoordParts = explode('/', $sCoord);
switch(count($asCoordParts)) {
case 1:
$fValue = $asCoordParts[0];
break;
case 2:
$fValue = floatval($asCoordParts[0]) / floatval($asCoordParts[1]);
break;
}
$fCoord += $fValue / pow(60, $iIndex);
}
return $fCoord * (($sDirection == 'W' || $sDirection == 'S')?-1:1);
}
private static function getLatLngAltFromISO6709($sIso6709) {
preg_match('/^(?P<lat>[\+\-][0,1]?\d{2}\.\d+)(?P<lng>[\+\-][0,1]?\d{2}\.\d+)(?P<alt>[\+\-]\d+)?/', $sIso6709, $asMatches);
return array(floatval($asMatches['lat']), floatval($asMatches['lng']), floatval($asMatches['alt'] ?? 0));
}
}

View File

@@ -87,7 +87,7 @@ class Spot extends Main
Feed::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to'),
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), Db::getId(User::USER_TABLE), 'name', 'content', 'site_time', 'timezone'),
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'timezone', 'width', 'height', 'rotate', 'comment'),
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'timezone', 'latitude', 'longitude', 'altitude', 'width', 'height', 'rotate', 'comment'),
User::USER_TABLE => array('name', 'email', 'gravatar', 'language', 'timezone', 'active', 'clearance'),
Map::MAP_TABLE => array('codename', 'pattern', 'token', 'tile_size', 'min_zoom', 'max_zoom', 'attribution'),
Map::MAPPING_TABLE => array(Db::getId(Map::MAP_TABLE) , Db::getId(Project::PROJ_TABLE))
@@ -110,6 +110,7 @@ class Spot extends Main
'last_update' => "TIMESTAMP DEFAULT 0",
'latitude' => "DECIMAL(7,5)",
'longitude' => "DECIMAL(8,5)",
'altitude' => "SMALLINT",
'model' => "VARCHAR(20)",
'name' => "VARCHAR(100)",
'pattern' => "VARCHAR(200) NOT NULL",
@@ -121,7 +122,7 @@ class Spot extends Main
'site_time' => "TIMESTAMP DEFAULT 0", //DEFAULT 0 removes auto-set to current time
'status' => "VARCHAR(10)",
'taken_on' => "TIMESTAMP DEFAULT 0",
'timezone' => "CHAR(64) NOT NULL", //see mysql.time_zone_name
'timezone' => "CHAR(64) NOT NULL", //see mysql.time_zone_name
'token' => "VARCHAR(4096)",
'type' => "VARCHAR(20)",
'unix_time' => "INT",
@@ -269,23 +270,24 @@ class Spot extends Main
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
{
$asMessages = $this->getSpotMessages($asMessageIds);
$asGeoMedias = array();
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
$bHasMsg = !empty($asMessages);
//Add medias
if(!empty($asMessages)) {
$asMedias = $this->getMedias('taken_on', $asMediaIds);
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
$asMedias = $this->getMedias('taken_on', $asMediaIds);
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
//Assign medias to closest message
$iIndex = 0;
$iMaxIndex = count($asMessages) - 1;
foreach($asMedias as $asMedia) {
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) {
$iIndex++;
}
//Assign medias to closest message
$iIndex = 0;
$iMaxIndex = count($asMessages) - 1;
foreach($asMedias as $asMedia) {
if($asMedia['latitude']!='' && $asMedia['longitude']!='') $asGeoMedias[] = $asMedia;
elseif($bHasMsg) {
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) $iIndex++;
//All medias before first message or after last message are assigned to first/last message respectively
if($iIndex == 0) $iMsgIndex = $iIndex;
if($iIndex == 0) $iMsgIndex = $iIndex;
elseif($iIndex > $iMaxIndex) $iMsgIndex = $iMaxIndex;
else {
$iHalfWayPoint = ($asMessages[$iIndex - 1]['unix_time'] + $asMessages[$iIndex]['unix_time'])/2;
@@ -302,6 +304,7 @@ class Spot extends Main
$asResult = array(
'messages' => $asMessages,
'medias' => $asGeoMedias,
'maps' => $this->oMap->getProjectMaps($this->oProject->getProjectId()),
'last_update' => $asLastUpdate
);
@@ -627,6 +630,13 @@ class Spot extends Main
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='') {
$oFeed = new Feed($this->oDb);
$asData = array(
@@ -741,6 +751,10 @@ class Spot extends Main
));
}
public function buildGeoJSON($sCodeName) {
return Converter::convertToGeoJson($sCodeName);
}
public static function decToDms($dValue, $sType) {
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S'; //Latitude
else $sDirection = ($dValue >= 0)?'E':'W'; //Longitude

View File

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

View File

@@ -282,7 +282,7 @@ function initProject(sProjectCodeName, oFocusPost){
).done(function(aoMessages, aoTracks) {
var asData = aoMessages[0]['data'];
setMapLayers(asData['maps']);
initSpotMessages(asData['messages'], aoTracks[0]);
initSpotMessages(asData['messages'], aoTracks[0], asData['medias']);
updateSettingsPanel(asData['last_update']);
});
@@ -420,7 +420,7 @@ function setMapLayers(asLayers) {
});
}
function initSpotMessages(aoMessages, aoTracks) {
function initSpotMessages(aoMessages, aoTracks, aoMedias) {
var bIsMobile = isMobile();
//Map
@@ -656,7 +656,10 @@ function initSpotMessages(aoMessages, aoTracks) {
}
//Add Spot messages
addSpotMessages(aoMessages);
addSpotMarkers(aoMessages);
//Add Medias
addMediaMarkers(aoMedias)
//Open tooltip on latest message in mobile mode
if(
@@ -672,7 +675,7 @@ function initSpotMessages(aoMessages, aoTracks) {
*/
}
function addSpotMessages(aoMessages) {
function addSpotMarkers(aoMessages) {
//Spot Messages
var iWorkSpaceMinWidth = isMobile()?self.tmp('$Projects').width():(self.tmp('$Projects').width() - self.tmp('$Feed').outerWidth(true) - self.tmp('$Settings').outerWidth(true));
@@ -689,7 +692,7 @@ function addSpotMessages(aoMessages) {
$Tooltip = $('<div>', {'class':'info-window'})
.append($('<h1>')
.addIcon('fa-message fa-lg', true)
.append($('<span>').text('Message '+oSpot.lang('counter', oMsg.displayed_id)))
.append($('<span>').text(oSpot.lang('post_message')+' '+oSpot.lang('counter', oMsg.displayed_id)))
.append($('<span>', {'class':'message-type'}).text('('+oMsg.type+')'))
)
.append($('<div>', {'class':'separator'}))
@@ -746,6 +749,74 @@ function addSpotMessages(aoMessages) {
});
}
function addMediaMarkers(aoMedias) {
var iWorkSpaceMinWidth = isMobile()?self.tmp('$Projects').width():(self.tmp('$Projects').width() - self.tmp('$Feed').outerWidth(true) - self.tmp('$Settings').outerWidth(true));
$.each(aoMedias, function(iKey, oMedia){
var oMarker = L.marker(L.latLng(oMedia.latitude, oMedia.longitude), {
id: oMedia.id_media,
riseOnHover: true,
icon: getDivIcon(oMedia.subtype)
}).addTo(self.tmp('map'));
//Tooltip
$Tooltip = $('<div>', {'class':'info-window'})
.append($('<h1>')
.addIcon('fa-'+oMedia.subtype+' fa-lg', true)
.append($('<span>').text(oSpot.lang(oMedia.subtype)+' '+oSpot.lang('counter', oMedia.displayed_id || oMedia.id_media)))
)
.append($('<div>', {'class':'separator'}))
.append($('<p>', {'class':'time'})
.addIcon('fa-time fa-fw fa-lg', true)
.append(oMedia.formatted_time+(self.vars(['project', 'mode'])==self.consts.modes.blog?' ('+oMedia.relative_time+')':'')));
//Tooltip: Time Zone
if(oMedia.formatted_time_local != oMedia.formatted_time) {
$Tooltip.append($('<p>', {'class':'timezone'})
.addIcon('fa-timezone fa-fw fa-lg', true)
.append(oSpot.lang('local_time', getRelativeTime(oMedia.formatted_time_local, oMedia.day_offset))));
}
//Tooltip: Altitude
if(oMedia.altitude) {
$Tooltip.append($('<p>', {'class':'altitude'})
.addIcon('fa-altitude fa-fw fa-lg', true)
.append(oMedia.altitude+'m'));
}
$Tooltip.data('medias', [oMedia]);
oSpot.tmp(['marker-media-tooltips', oMedia.id_media], $Tooltip);
oMarker.bindPopup(
function(e) {
let $Tooltip = oSpot.tmp(['marker-media-tooltips', e.options.id]);
$Tooltip.on('mouseout', function(){e.closePopup();});
//Tooltip: Medias: Set on the fly to avoid resource load
let oMedias = $Tooltip.data('medias');
let $Medias = $Tooltip.find('.medias');
if(oMedias && $Medias.length == 0) {
$Medias = $('<div>', {'class':'medias'});
$.each(oMedias, function(iKey, asMedia) {
$Medias.append(getMediaLink(asMedia, 'marker'));
});
$Tooltip.append($Medias);
}
return $Tooltip[0];
},
{
maxWidth: iWorkSpaceMinWidth,
autoPan: false,
closeOnClick: true,
offset: new L.Point(0, -30)
}
);
oMarker.on('mouseover', function(e) {this.openPopup();});
});
}
function toggleSoftPopup(e, sMode) {
switch(sMode) {
case 'open':
@@ -806,7 +877,7 @@ function checkNewFeed() {
self.tmp('$PostList').prepend($Posts.children());
//Markers
addSpotMessages(asData.messages);
addSpotMarkers(asData.messages);
//Message Last Update
updateSettingsPanel(asData.last_update);

View File

@@ -6,6 +6,9 @@
<div class="bar" style="width: 0%;"></div>
</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>
<script type="text/javascript">
@@ -35,6 +38,27 @@ oSpot.pageInit = function(asHash) {
$('#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);
};

View File

@@ -3,6 +3,7 @@
## Dependencies
* php-mbstring
* php-imagick
* php-gd
* php-mysql
* php-exif
* ffprobe & ffmpeg
@@ -21,10 +22,11 @@
4. Copy settings-sample.php to settings.php and populate
5. Go to #admin and create a new project, feed & maps
6. Add a GPX file named <project_codename>.gpx to /geo/
7. Run composer install
## To Do List
* ECMA import/export
* Add mail frequency slider
* Use WMTS servers directly when not using Geo Caching Server
* Allow HEIF picture format
* Vector tiles support (https://www.arcgis.com/home/item.html?id=7dc6cea0b1764a1f9af2e679f642f0f5) + Use of GL library. Use Mapbox GL JS / Maplibre GL JS / ESRI-Leaflet-vector?
* Fix .MOV playback on firefox
* Fix .MOV playback on windows firefox

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -88,6 +88,7 @@ $fa-css-prefix: fa;
.#{$fa-css-prefix}-message-in:before { content: fa-content($fa-var-shoe-prints); }
.#{$fa-css-prefix}-time:before { content: fa-content($fa-var-clock); }
.#{$fa-css-prefix}-coords:before { content: fa-content($fa-var-compass); }
.#{$fa-css-prefix}-altitude:before { content: fa-content($fa-var-mountain); }
.#{$fa-css-prefix}-drill-video:before { content: fa-content($fa-var-play-circle); }
.#{$fa-css-prefix}-drill-image:before { content: fa-content($fa-var-search); }
.#{$fa-css-prefix}-drill-message:before { content: fa-content($fa-var-search-location); }

View File

@@ -60,6 +60,11 @@
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
@@ -646,7 +651,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long