Add Local Time Zone

This commit is contained in:
2021-05-24 01:05:36 +02:00
parent 6b3d637e64
commit b398480c7f
19 changed files with 1815 additions and 1679 deletions

View File

@@ -0,0 +1,50 @@
ALTER TABLE medias ADD timezone CHAR(64) AFTER posted_on;
ALTER TABLE messages ADD timezone CHAR(64) AFTER site_time;
ALTER TABLE posts ADD timezone CHAR(64) AFTER site_time;
UPDATE messages
SET iso_time = DATE_FORMAT(CONVERT_TZ(iso_time,'+00:00','+02:00'), '%Y-%m-%dT%T+0200'),
led = led
WHERE id_feed = 2;
UPDATE messages
INNER JOIN feeds ON feeds.id_feed = messages.id_feed
INNER JOIN projects ON projects.id_project = feeds.id_project
SET messages.timezone = projects.timezone,
messages.led = messages.led;
UPDATE posts
SET timezone = 'Europe/Paris',
led = led;
UPDATE posts
INNER JOIN projects ON projects.id_project = posts.id_project
SET posts.id_user = 1,
posts.timezone = projects.timezone,
posts.led = posts.led
WHERE posts.name IN ('francois', 'françois','Francois', 'François', 'franzz');
UPDATE posts
SET timezone = 'Pacific/Auckland',
led = led
WHERE name = 'nz';
UPDATE posts
SET timezone = 'Atlantic/Madeira',
led = led
WHERE id_post IN (141, 142);
UPDATE medias
INNER JOIN projects ON projects.id_project = medias.id_project
SET medias.timezone = projects.timezone,
medias.led = medias.led;
UPDATE medias
SET timezone = 'Atlantic/Madeira',
taken_on = posted_on,
led = led
WHERE id_media IN (64, 65);
ALTER TABLE projects DROP COLUMN timezone;
UPDATE maps SET attribution = 'OpenTopoMap (CC-BY-SA)' WHERE id_map = 2;

View File

@@ -35,7 +35,7 @@ class Email extends PhpObject {
/**
* Set Target User Info
* @param array $asDests Contains: id_user, name, email, language, active
* @param array $asDests Contains: id_user, name, email, language, timezone, active
*/
public function setDestInfo($asDests) {
if(array_key_exists('email', $asDests)) $asDests = array($asDests);

View File

@@ -90,7 +90,7 @@ class Feed extends PhpObject {
public function getMessages($asActivePeriod = array()) {
$asInfo = array(
'select' => array('id_message', 'ref_msg_id', 'type', 'latitude', 'longitude', 'site_time', 'unix_time'),
'select' => array('id_message', 'ref_msg_id', 'type', 'latitude', 'longitude', 'site_time', 'timezone', 'unix_time'),
'from' => self::MSG_TABLE,
'constraint'=> array(Db::getId(self::FEED_TABLE) => $this->getFeedId()),
'constOpe' => array(Db::getId(self::FEED_TABLE) => "="),
@@ -163,7 +163,8 @@ class Feed extends PhpObject {
'latitude' => $asMsg['latitude'],
'longitude' => $asMsg['longitude'],
'iso_time' => $asMsg['dateTime'], //ISO 8601 time (backup)
'site_time' => date(Db::TIMESTAMP_FORMAT, $asMsg['unixTime']), //Conversion to Site Time (default timezone, see Settings::TIMEZONE)
'site_time' => date(Db::TIMESTAMP_FORMAT, $asMsg['unixTime']), //Conversion to Site Time
'timezone' => Spot::getTimeZoneFromDate($asMsg['dateTime']), //Local Time Zone
'unix_time' => $asMsg['unixTime'], //UNIX Time (backup)
'content' => $asMsg['messageContent'],
'battery_state' => $asMsg['batteryState']
@@ -200,13 +201,16 @@ class Feed extends PhpObject {
}
public function delete() {
$sDesc = '';
$asResult = array();
if($this->getFeedId() > 0) {
$bSuccess = $this->oDb->deleteRow(self::FEED_TABLE, $this->getFeedId());
if(!$bSuccess) $sDesc = $this->oDb->getLastError();
$asResult = array(
'id' => $this->getFeedId(),
'del' => $this->oDb->deleteRow(self::FEED_TABLE, $this->getFeedId()),
'desc' => $this->oDb->getLastError()
);
}
else $sDesc = 'Error while setting project: no Feed ID';
else $asResult = array('del'=>false, 'desc'=>'Error while setting project: no Feed ID');
return $sDesc;
return $asResult;
}
}

View File

@@ -68,7 +68,7 @@ class Media extends PhpObject {
if($bOwnMedia && empty($this->asMedia) || !$bOwnMedia && empty($this->asMedias)) {
if($this->oProject->getProjectId()) {
$asParams = array(
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'rotate', 'type AS subtype', 'comment'),
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'timezone', 'rotate', 'type AS subtype', 'comment'),
'from' => self::MEDIA_TABLE,
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
);
@@ -109,13 +109,15 @@ class Media extends PhpObject {
$asParams[] = $sMediaName;
}
else {
//Add media to DB
$asMediaInfo = $this->getMediaInfoFromFile($sMediaName);
//Converting times to DB Time Zone, by using date()
$asDbInfo = array(
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
'filename' => $sMediaName,
'taken_on' => ($asMediaInfo['taken_ts'] > 0)?date(Db::TIMESTAMP_FORMAT, $asMediaInfo['taken_ts']):0, //Site Time
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asMediaInfo['file_ts']), //Site Time
'taken_on' => ($asMediaInfo['taken_ts'] > 0)?date(Db::TIMESTAMP_FORMAT, $asMediaInfo['taken_ts']):0,
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asMediaInfo['file_ts']),
'timezone' => $asMediaInfo['timezone'],
'rotate' => $asMediaInfo['rotate'],
'type' => $asMediaInfo['type']
);
@@ -152,7 +154,9 @@ class Media extends PhpObject {
$sMediaPath = self::getMediaPath($sMediaName);
$sType = self::getMediaType($sMediaName);
$iTimeStamp = $iTakenOn = $iPostedOn = 0;
$iTimeStamp = $iTakenOn = 0;
$iPostedOn = filemtime($sMediaPath);
$sTimeZone = date_default_timezone_get();
$sRotate = '0';
$sTakenOn = '';
switch($sType) {
@@ -161,28 +165,44 @@ class Media extends PhpObject {
$sParams = implode(' ', array(
'-loglevel error', //Remove comments
'-select_streams v:0', //First video channel
'-show_entries stream_tags=rotate,creation_time', //filter tags :rotation & creation time only
'-show_entries '. //filter tags : Creation Time & Rotation
'format_tags=creation_time,com.apple.quicktime.creationdate'.':'.
'stream_tags=rotate,creation_time',
'-print_format json', //output format: json
'-i' //input file
));
exec('ffprobe '.$sParams.' "'.$sMediaPath.'"', $asResult);
$asResult = json_decode(implode('', $asResult), true);
$asExif = json_decode(implode('', $asResult), true);
//Timestamps
$sTakenOn = date(Db::TIMESTAMP_FORMAT, strtotime($asResult['streams'][0]['tags']['creation_time']));
$iPostedOn = filemtime($sMediaPath);
//Taken On
if(isset($asExif['format']['tags']['com.apple.quicktime.creationdate'])) {
$sTakenOn = $asExif['format']['tags']['com.apple.quicktime.creationdate']; //contains Time Zone
$sTimeZone = Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
}
else $sTakenOn = $asExif['format']['tags']['creation_time'] ?? $asExif['streams'][0]['tags']['creation_time'];
//Orientation
if(isset($asResult['streams'][0]['tags']['rotate'])) $sRotate = $asResult['streams'][0]['tags']['rotate'];
if(isset($asExif['streams'][0]['tags']['rotate'])) $sRotate = $asExif['streams'][0]['tags']['rotate'];
break;
case 'image':
$asExif = @exif_read_data($sMediaPath, 0, true);
if(!$asExif) $asExif['FILE']['FileDateTime'] = filemtime($sMediaPath);
//Timestamps
if(array_key_exists('EXIF', $asExif) && array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $sTakenOn = $asExif['EXIF']['DateTimeOriginal'];
//Posted On
if(array_key_exists('FILE', $asExif) && array_key_exists('FileDateTime', $asExif['FILE'])) $iPostedOn = $asExif['FILE']['FileDateTime'];
//Taken On & Timezone
if(array_key_exists('EXIF', $asExif)) {
if(array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $sTakenOn = $asExif['EXIF']['DateTimeOriginal'];
/* Priorities:
* 1. OffsetTimeOriginal: timezone for DateTimeOriginal (exif version >= 2.31)
* 2. 0x9011: same as above, but unidentified
* 3. Timezone extracted from DateTimeOriginal
* 4. Uploader Browser Time Zone (PHP Default Time Zone)
*/
$sTimeZone = $asExif['EXIF']['OffsetTimeOriginal'] ?? $asExif['EXIF']['UndefinedTag:0x9011'] ?? Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
}
//Orientation
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
switch($asExif['IFD0']['Orientation'])
@@ -196,9 +216,10 @@ class Media extends PhpObject {
break;
}
//Media info do not have any TZ: Interpreting date time using project timezone (assuming all medias have been taken in this time zone)
//Assign the correct Time Zone to $sTakenOn if it is not already contained in it. Then get Unix Timestamp
//Time Zone (2nd parameter) will be ignored if already contained in $sTakenOn
if($sTakenOn != '') {
$oTakenOn = new DateTime($sTakenOn, new DateTimeZone($this->oProject->getTimeZone()));
$oTakenOn = new DateTime($sTakenOn, new DateTimeZone($sTimeZone));
$iTakenOn = $oTakenOn->format('U');
}
@@ -207,6 +228,7 @@ class Media extends PhpObject {
return array(
'timestamp' => $iTimeStamp,
'timezone' => $sTimeZone,
'taken_ts' => $iTakenOn,
'file_ts' => $iPostedOn,
'rotate' => $sRotate,

View File

@@ -66,7 +66,7 @@ class Project extends PhpObject {
}
public function createProjectId() {
$this->setProjectId($this->oDb->insertRow(self::PROJ_TABLE, array('timezone'=>Settings::TIMEZONE)));
$this->setProjectId($this->oDb->insertRow(self::PROJ_TABLE, array('codename'=>'')));
return $this->getProjectId();
}
@@ -104,14 +104,6 @@ class Project extends PhpObject {
}
}
public function getTimeZone() {
return $this->asGeo['timezone'];
}
public function setTimeZone($sTimeZone) {
return $this->updateField('timezone', $sTimeZone);
}
public function getFeedIds() {
return $this->oDb->selectColumn(
Feed::FEED_TABLE,
@@ -129,8 +121,7 @@ class Project extends PhpObject {
'name',
'active_from',
'active_to',
"IF(NOW() BETWEEN active_from AND active_to, 1, IF(NOW() < active_from, 0, 2)) AS mode",
'timezone'
"IF(NOW() BETWEEN active_from AND active_to, 1, IF(NOW() < active_from, 0, 2)) AS mode"
),
'from' => self::PROJ_TABLE
);
@@ -186,7 +177,7 @@ class Project extends PhpObject {
$this->asActive = array('from'=>$asProject['active_from'], 'to'=>$asProject['active_to']);
$this->sCodeName = $asProject['codename'];
$this->sName = $asProject['name'];
$this->asGeo = array('geofile'=>$asProject['geofilepath'], 'gpxfile'=>$asProject['gpxfilepath'], 'timezone'=>$asProject['timezone']);
$this->asGeo = array('geofile'=>$asProject['geofilepath'], 'gpxfile'=>$asProject['gpxfilepath']);
}
else $this->addError('Error while setting project: no project ID');
}
@@ -199,13 +190,21 @@ class Project extends PhpObject {
}
public function delete() {
$sDesc = '';
$asResult = array();
if($this->getProjectId() > 0) {
$bSuccess = $this->oDb->deleteRow(self::PROJ_TABLE, $this->getProjectId());
if(!$bSuccess) $sDesc = $this->oDb->getLastError();
$asFeedIds = $this->getFeedIds();
foreach($asFeedIds as $iFeedId) {
$asResult['feed'][] = (new Feed($this->oDb, $iFeedId))->delete();
}
else $sDesc = 'Error while setting project: no project ID';
return $sDesc;
$asResult['project'][] = array(
'id' => $this->getProjectId(),
'del' => $this->oDb->deleteRow(self::PROJ_TABLE, $this->getProjectId()),
'desc' => $this->oDb->getLastError()
);
}
else $asResult['project'][] = array('del'=>false, 'desc'=>'Error while setting project: no project ID');
return $asResult;
}
}

View File

@@ -1,17 +1,21 @@
<?php
/* Timezones
* ---------
* Site Time: Time Zone in which the User is viewing the Site (default PHP/SQL Timezone)
* Local Time: Time Zone in which the Spot Owner is
*
* - Feeds (table `feeds`):
* - last_update: timestamp in site time (see Settings::TIMEZONE)
* - last_update: timestamp in Site Time
* - Spot Messages (table `messages`):
* - unix_time: UNIX (int) in UTC
* - site_time: timestamp in site time (see Settings::TIMEZONE)
* - iso_time: raw ISO 8601 in local timezone
* - site_time: timestamp in Site Time
* - iso_time: raw ISO 8601 in Local Time
* - Medias (table `medias`):
* - posted_on: timestamp in site time (see Settings::TIMEZONE)
* - taken_on: timestamp in site time (see Settings::TIMEZONE)
* - posted_on: timestamp in Site Time
* - taken_on: timestamp in Site Time
* - Posts (table `posts`):
* - site_time: timestamp in site time (see Settings::TIMEZONE)
* - site_time: timestamp in Site Time
*/
class Spot extends Main
@@ -71,18 +75,24 @@ class Spot extends Main
$this->oDb->install();
}
public function syncPics() {
if(Settings::DEBUG) {
return (new Media($this->oDb, $this->oProject))->syncFileFolder();
}
}
protected function getSqlOptions()
{
return array
(
'tables' => array
(
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'unix_time', 'content', 'battery_state'),
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'timezone', 'unix_time', 'content', 'battery_state'),
Feed::FEED_TABLE => array('ref_feed_id', Db::getId(Feed::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
Feed::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to', 'timezone'),
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), Db::getId(User::USER_TABLE), 'name', 'content', 'site_time'),
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'rotate', 'comment'),
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', 'rotate', 'comment'),
User::USER_TABLE => array('name', 'email', 'gravatar', 'language', 'timezone', 'active'),
self::MAP_TABLE => array('codename', 'geo_name', 'min_zoom', 'max_zoom', 'attribution'),
self::MAPPING_TABLE => array(Db::getId(self::MAP_TABLE) , Db::getId(Project::PROJ_TABLE))
@@ -235,11 +245,11 @@ class Spot extends Main
public function getMarkers()
{
$asMessages = $this->getSpotMessages();
$bSuccess = !empty($this->getMedias('posted_on') + $asMessages + $this->getPosts());
$sDesc = $bSuccess?'':self::NO_DATA;
$bEmptyProject = empty($this->getMedias('posted_on') + $asMessages + $this->getPosts());
$sDesc = '';
//Add medias
if($bSuccess) {
if(!empty($asMessages)) {
$asMedias = $this->getMedias('taken_on');
//Assign medias to closest message
@@ -264,10 +274,12 @@ class Spot extends Main
$asLastUpdate = array();
$this->addTimeStamp($asLastUpdate, $this->oProject->getLastUpdate());
return self::getJsonResult($bSuccess, $sDesc, array(
return self::getJsonResult(true, $sDesc, array(
'messages' => $asMessages,
'maps' => $this->oProject->getMaps(),
'last_update' => $asLastUpdate));
'last_update' => $asLastUpdate,
'empty_project' => $bEmptyProject
));
}
public function subscribe($sEmail) {
@@ -315,7 +327,7 @@ class Spot extends Main
$asMessage['lat_dms'] = self::decToDms($asMessage['latitude'], 'lat');
$asMessage['lon_dms'] = self::decToDms($asMessage['longitude'], 'lon');
$this->addTimeStamp($asMessage, $asMessage['unix_time']);
$this->addTimeStamp($asMessage, $asMessage['unix_time'], $asMessage['timezone']);
}
}
@@ -343,10 +355,14 @@ class Spot extends Main
foreach($asMedias as $asMedia) {
$sTimeRef = $asMedia[$sTimeRefField];
if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) {
$asMedia['taken_on_formatted'] = $this->getTimeFormat(strtotime($asMedia['taken_on']));
$asMedia['posted_on_formatted'] = $this->getTimeFormat(strtotime($asMedia['posted_on']));
$iTimeStampTakenOn = strtotime($asMedia['taken_on']);
$iTimeStampPostedOn = strtotime($asMedia['posted_on']);
$asMedia['taken_on_formatted'] = $this->getTimeFormat($iTimeStampTakenOn);
$asMedia['taken_on_formatted_local'] = $this->getTimeFormat($iTimeStampTakenOn, $asMedia['timezone']);
$asMedia['posted_on_formatted'] = $this->getTimeFormat($iTimeStampPostedOn);
$asMedia['posted_on_formatted_local'] = $this->getTimeFormat($iTimeStampPostedOn, $asMedia['timezone']);
$this->addTimeStamp($asMedia, strtotime($sTimeRef));
$this->addTimeStamp($asMedia, strtotime($sTimeRef), $asMedia['timezone']);
$asValidMedias[] = $asMedia;
}
}
@@ -379,17 +395,18 @@ class Spot extends Main
$asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']);
unset($asPost[Db::getId(User::USER_TABLE)]);
$this->addTimeStamp($asPost, $iUnixTimeStamp);
$this->addTimeStamp($asPost, $iUnixTimeStamp, $asPost['timezone']);
}
usort($asPosts, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
return $asPosts;
}
private function addTimeStamp(&$asData, $iTime) {
private function addTimeStamp(&$asData, $iTime, $sTimeZone='') {
$asData['unix_time'] = (int) $iTime;
$asData['relative_time'] = Toolbox::getDateTimeDesc($iTime, $this->oLang->getLanguage());
$asData['formatted_time'] = $this->getTimeFormat($iTime);
if($sTimeZone != '') $asData['formatted_time_local'] = $this->getTimeFormat($iTime, $sTimeZone);
}
public function getNewsFeed($iChunk=0, $bInternal=false)
@@ -446,7 +463,8 @@ class Spot extends Main
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
'name' => mb_strtolower(trim($sName)),
'content' => trim($sPost),
'site_time' => date(Db::TIMESTAMP_FORMAT) //site time (Settings::TIMEZONE)
'site_time' => date(Db::TIMESTAMP_FORMAT), //Now in Site Time
'timezone' => date_default_timezone_get() //Site Time Zone
);
if($this->oUser->getUserId() > 0) $asData[Db::getId(User::USER_TABLE)] = $this->oUser->getUserId();
@@ -471,13 +489,19 @@ class Spot extends Main
return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']);
}
public function getAdminSettings() {
public function getAdminSettings($sType='') {
$oFeed = new Feed($this->oDb);
$asData = array(
'project' => $this->oProject->getProjects(),
'feed' => $oFeed->getFeeds(),
'spot' => $oFeed->getSpots()
);
foreach($asData['project'] as &$asProject) {
$asProject['active_from'] = substr($asProject['active_from'], 0, 10);
$asProject['active_to'] = substr($asProject['active_to'], 0, 10);
}
return self::getJsonResult(true, '', $asData);
}
@@ -502,30 +526,32 @@ class Spot extends Main
case 'active_to':
$bSuccess = $oProject->setActivePeriod($sValue.' 23:59:59', 'to');
break;
case 'timezone':
$bSuccess = $oProject->setTimeZone($sValue);
break;
default:
$sDesc = $this->oLang->getTranslation('unknown_field', $sField);
}
$asResult = $oProject->getProject();
$asResult['active_from'] = substr($asResult['active_from'], 0, 10);
$asResult['active_to'] = substr($asResult['active_to'], 0, 10);
break;
case 'feed':
case 'spot':
$oFeed = new Feed($this->oDb, $iId);
switch($sField) {
case 'ref_feed_id':
$bSuccess = $oFeed->setRefFeedId($sValue);
break;
case 'spot_id':
case 'id_spot':
$bSuccess = $oFeed->setSpotId($sValue);
break;
case 'project_id':
case 'id_project':
$bSuccess = $oFeed->setProjectId($sValue);
break;
default:
$sDesc = $this->oLang->getTranslation('unknown_field', $sField);
}
$asResult = $oFeed->getFeed();
break;
}
if(!$bSuccess) $sDesc = Mask::LANG_PREFIX.'error_commit_db';
if(!$bSuccess && $sDesc=='') $sDesc = Mask::LANG_PREFIX.'error_commit_db';
return self::getJsonResult($bSuccess, $sDesc, array($sType=>array($asResult)));
}
@@ -537,16 +563,18 @@ class Spot extends Main
switch($sType) {
case 'project':
$oProject = new Project($this->oDb, $iId);
$sDesc = $oProject->delete();
$asResult = $oProject->delete();
$sDesc = $asResult['project'][0]['desc'];
break;
case 'feed':
$oFeed = new Feed($this->oDb, $iId);
$sDesc = $oFeed->delete();
$asResult = array('feed'=>array($oFeed->delete()));
$sDesc = $asResult['feed'][0]['desc'];
break;
}
$bSuccess = ($sDesc=='');
return self::getJsonResult($bSuccess, $sDesc, array($sType=>array(array('id'=>$iId, 'del'=>$bSuccess))));
return self::getJsonResult($bSuccess, $sDesc, $asResult);
}
public function createProject() {
@@ -586,9 +614,30 @@ class Spot extends Main
return $iDegree.'°'.$iMinute."'".$fSecond.'"'.$sDirection;
}
public function getTimeFormat($iTime) {
$sDate = date('d/m/Y', $iTime);
$sTime = date('H:i', $iTime);
public function getTimeFormat($iTime, $sTimeZone='') {
if($sTimeZone=='') $sTimeZone = date_default_timezone_get();
$oDate = new DateTime('@'.$iTime);
$oDate->setTimezone(new DateTimeZone($sTimeZone));
$sDate = $oDate->format('d/m/Y');
$sTime = $oDate->format('H:i');
return $this->oLang->getTranslation('date_time', array($sDate, $sTime));
}
public function getTimeZoneFromDate($sDate) {
$sTimeZone = null;
preg_match('/(?<timezone>(\+|\-)\d{2}:?(\d{2}|))$/', $sDate, $asMatch);
if(array_key_exists('timezone', $asMatch)) {
$sTimeZone = $asMatch['timezone'];
//Complete short form: +12 => +1200
if(strlen($sTimeZone) == 3) $sTimeZone .= '00';
//Add colon: +1200 => +12:00
if(!strpos($sTimeZone, ':')) $sTimeZone = substr_replace($sTimeZone, ':', 3, 0);
}
return $sTimeZone;
}
}

View File

@@ -21,11 +21,11 @@ class Uploader extends UploadHandler
$this->oMedia = &$oMedia;
$this->oLang = &$oLang;
$this->sBody = '';
parent::__construct(array('image_versions'=>array(), 'accept_file_types'=>'/\.(gif|jpe?g|png|mov)$/i'));
parent::__construct(array('image_versions'=>array(), 'accept_file_types'=>'/\.(gif|jpe?g|png|mov|mp4)$/i'));
}
protected function validate($uploaded_file, $file, $error, $index) {
$bResult = parent::validate($uploaded_file, $file, $error, $index);
protected function validate($uploaded_file, $file, $error, $index, $content_range) {
$bResult = parent::validate($uploaded_file, $file, $error, $index, $content_range);
//Check project mode
if(!$this->oMedia->isProjectModeValid()) {
@@ -80,7 +80,7 @@ class UploadHandler
protected $options;
// PHP File Upload error message codes:
// http://php.net/manual/en/features.file-upload.errors.php
// https://php.net/manual/en/features.file-upload.errors.php
protected $error_messages = array(
1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
@@ -94,6 +94,7 @@ class UploadHandler
'min_file_size' => 'File is too small',
'accept_file_types' => 'Filetype not allowed',
'max_number_of_files' => 'Maximum number of files exceeded',
'invalid_file_type' => 'Invalid file type',
'max_width' => 'Image exceeds maximum width',
'min_width' => 'Image requires a minimum width',
'max_height' => 'Image exceeds maximum height',
@@ -102,9 +103,9 @@ class UploadHandler
'image_resize' => 'Failed to resize image'
);
const IMAGETYPE_GIF = 1;
const IMAGETYPE_JPEG = 2;
const IMAGETYPE_PNG = 3;
const IMAGETYPE_GIF = 'image/gif';
const IMAGETYPE_JPEG = 'image/jpeg';
const IMAGETYPE_PNG = 'image/png';
protected $image_objects = array();
protected $response = array();
@@ -388,7 +389,7 @@ class UploadHandler
protected function is_valid_file_object($file_name) {
$file_path = $this->get_upload_path($file_name);
if (is_file($file_path) && $file_name[0] !== '.') {
if (strlen($file_name) > 0 && $file_name[0] !== '.' && is_file($file_path)) {
return true;
}
return false;
@@ -457,7 +458,53 @@ class UploadHandler
return $this->fix_integer_overflow($val);
}
protected function validate($uploaded_file, $file, $error, $index) {
protected function validate_image_file($uploaded_file, $file, $error, $index) {
if ($this->imagetype($uploaded_file) !== $this->get_file_type($file->name)) {
$file->error = $this->get_error_message('invalid_file_type');
return false;
}
$max_width = @$this->options['max_width'];
$max_height = @$this->options['max_height'];
$min_width = @$this->options['min_width'];
$min_height = @$this->options['min_height'];
if ($max_width || $max_height || $min_width || $min_height) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
// If we are auto rotating the image by default, do the checks on
// the correct orientation
if (
@$this->options['image_versions']['']['auto_orient'] &&
function_exists('exif_read_data') &&
($exif = @exif_read_data($uploaded_file)) &&
(((int) @$exif['Orientation']) >= 5)
) {
$tmp = $img_width;
$img_width = $img_height;
$img_height = $tmp;
unset($tmp);
}
if (!empty($img_width) && !empty($img_height)) {
if ($max_width && $img_width > $max_width) {
$file->error = $this->get_error_message('max_width');
return false;
}
if ($max_height && $img_height > $max_height) {
$file->error = $this->get_error_message('max_height');
return false;
}
if ($min_width && $img_width < $min_width) {
$file->error = $this->get_error_message('min_width');
return false;
}
if ($min_height && $img_height < $min_height) {
$file->error = $this->get_error_message('min_height');
return false;
}
}
}
return true;
}
protected function validate($uploaded_file, $file, $error, $index, $content_range) {
if ($error) {
$file->error = $this->get_error_message($error);
return false;
@@ -498,44 +545,8 @@ class UploadHandler
$file->error = $this->get_error_message('max_number_of_files');
return false;
}
$max_width = @$this->options['max_width'];
$max_height = @$this->options['max_height'];
$min_width = @$this->options['min_width'];
$min_height = @$this->options['min_height'];
if (($max_width || $max_height || $min_width || $min_height)
&& $this->is_valid_image_file($uploaded_file)) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
// If we are auto rotating the image by default, do the checks on
// the correct orientation
if (
@$this->options['image_versions']['']['auto_orient'] &&
function_exists('exif_read_data') &&
($exif = @exif_read_data($uploaded_file)) &&
(((int) @$exif['Orientation']) >= 5)
) {
$tmp = $img_width;
$img_width = $img_height;
$img_height = $tmp;
unset($tmp);
}
}
if (!empty($img_width) && !empty($img_height)) {
if ($max_width && $img_width > $max_width) {
$file->error = $this->get_error_message('max_width');
return false;
}
if ($max_height && $img_height > $max_height) {
$file->error = $this->get_error_message('max_height');
return false;
}
if ($min_width && $img_width < $min_width) {
$file->error = $this->get_error_message('min_width');
return false;
}
if ($min_height && $img_height < $min_height) {
$file->error = $this->get_error_message('min_height');
return false;
}
if (!$content_range && $this->has_image_file_extension($file->name)) {
return $this->validate_image_file($uploaded_file, $file, $error, $index);
}
return true;
}
@@ -561,7 +572,7 @@ class UploadHandler
$name = $this->upcount_name($name);
}
// Keep an existing filename if this is part of a chunked upload:
$uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]);
$uploaded_bytes = $this->fix_integer_overflow((int)@$content_range[1]);
while (is_file($this->get_upload_path($name))) {
if ($uploaded_bytes === $this->get_file_size(
$this->get_upload_path($name))) {
@@ -572,6 +583,17 @@ class UploadHandler
return $name;
}
protected function get_valid_image_extensions($file_path) {
switch ($this->imagetype($file_path)) {
case self::IMAGETYPE_JPEG:
return array('jpg', 'jpeg');
case self::IMAGETYPE_PNG:
return array('png');
case self::IMAGETYPE_GIF:
return array('gif');
}
}
protected function fix_file_extension($file_path, $name, $size, $type, $error,
$index, $content_range) {
// Add missing file extension for known image types:
@@ -580,17 +602,7 @@ class UploadHandler
$name .= '.'.$matches[1];
}
if ($this->options['correct_image_extensions']) {
switch ($this->imagetype($file_path)) {
case self::IMAGETYPE_JPEG:
$extensions = array('jpg', 'jpeg');
break;
case self::IMAGETYPE_PNG:
$extensions = array('png');
break;
case self::IMAGETYPE_GIF:
$extensions = array('gif');
break;
}
$extensions = $this->get_valid_image_extensions($file_path);
// Adjust incorrect image file extensions:
if (!empty($extensions)) {
$parts = explode('.', $name);
@@ -1158,12 +1170,13 @@ class UploadHandler
}
protected function is_valid_image_file($file_path) {
if (!preg_match('/\.(gif|jpe?g|png)$/i', $file_path)) {
return false;
}
return !!$this->imagetype($file_path);
}
protected function has_image_file_extension($file_path) {
return !!preg_match('/\.(gif|jpe?g|png)$/i', $file_path);
}
protected function handle_image_file($file_path, $file) {
$failed_versions = array();
foreach ($this->options['image_versions'] as $version => $options) {
@@ -1182,7 +1195,7 @@ class UploadHandler
}
if (count($failed_versions)) {
$file->error = $this->get_error_message('image_resize')
.' ('.implode($failed_versions, ', ').')';
.' ('.implode(', ', $failed_versions).')';
}
// Free memory:
$this->destroy_image_object($file_path);
@@ -1195,7 +1208,7 @@ class UploadHandler
$index, $content_range);
$file->size = $this->fix_integer_overflow((int)$size);
$file->type = $type;
if ($this->validate($uploaded_file, $file, $error, $index)) {
if ($this->validate($uploaded_file, $file, $error, $index, $content_range)) {
$this->handle_form_data($file, $index);
$upload_dir = $this->get_upload_path();
if (!is_dir($upload_dir)) {
@@ -1226,9 +1239,13 @@ class UploadHandler
$file_size = $this->get_file_size($file_path, $append_file);
if ($file_size === $file->size) {
$file->url = $this->get_download_url($file->name);
if ($this->is_valid_image_file($file_path)) {
if ($this->has_image_file_extension($file->name)) {
if ($content_range && !$this->validate_image_file($file_path, $file, $error, $index)) {
unlink($file_path);
} else {
$this->handle_image_file($file_path, $file);
}
}
} else {
$file->size = $file_size;
if (!$content_range && $this->options['discard_aborted_uploads']) {
@@ -1313,11 +1330,11 @@ class UploadHandler
switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) {
case 'jpeg':
case 'jpg':
return 'image/jpeg';
return self::IMAGETYPE_JPEG;
case 'png':
return 'image/png';
return self::IMAGETYPE_PNG;
case 'gif':
return 'image/gif';
return self::IMAGETYPE_GIF;
default:
return '';
}
@@ -1458,7 +1475,7 @@ class UploadHandler
$content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE');
$content_range = $content_range_header ?
preg_split('/[^0-9]+/', $content_range_header) : null;
$size = $content_range ? $content_range[3] : null;
$size = @$content_range[3];
$files = array();
if ($upload) {
if (is_array($upload['tmp_name'])) {
@@ -1504,7 +1521,7 @@ class UploadHandler
$response = array();
foreach ($file_names as $file_name) {
$file_path = $this->get_upload_path($file_name);
$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
$success = strlen($file_name) > 0 && $file_name[0] !== '.' && is_file($file_path) && unlink($file_path);
if ($success) {
foreach ($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {

View File

@@ -13,11 +13,11 @@ ToolBox::fixGlobalVars(isset($argv)?$argv:array());
//Available variables
$sAction = isset($_REQUEST['a'])?$_REQUEST['a']:'';
$sTimezone = isset($_REQUEST['t'])?$_REQUEST['t']:'';
$sTimezone = $_REQUEST['t'] ?? '';
$sName = isset($_GET['name'])?$_GET['name']:'';
$sContent = isset($_GET['content'])?$_GET['content']:'';
$iChunk = isset($_GET['chunk'])?$_GET['chunk']:0;
$iProjectId = isset($_REQUEST['project_id'])?$_REQUEST['project_id']:0;
$iProjectId = $_REQUEST['id_project'] ?? 0;
$sField = isset($_REQUEST['field'])?$_REQUEST['field']:'';
$oValue = isset($_REQUEST['value'])?$_REQUEST['value']:'';
$iId = isset($_REQUEST['id'])?$_REQUEST['id']:0;

View File

@@ -1,6 +1,7 @@
locale = en_NZ
page_og_desc = Keep contact with François when he is off hiking
error_commit_db = Issue committing to DB
unknown_field = Field "$0" is unknown
save = Save
admin_save_success = Saved
@@ -46,17 +47,21 @@ copy_to_clipboard = Copy direct link to clipboard
link_copied = Link copied!
city_time = $0 Time
local_time = $0 Local Time
your_time = $0 Your Time
date_time = $0 at $1
time_zone = Time Zone
project_id = Project ID
id_project = Project ID
project = Project
projects = Projects
mode = Mode
code_name = Code name
start = Start
end = End
feed_id = Feed ID
id_feed = Feed ID
ref_feed_id = Ref. Feed ID
spot_id = Spot ID
id_spot = Spot ID
name = Name
status = Status
last_update = Last Spot update
@@ -64,9 +69,6 @@ ref_spot_id = Ref. Spot ID
model = Model
delete = Delete
date_time = $0 at $1
time_zone = Time zone
unit_day = day
unit_days = days
unit_hour = h

View File

@@ -1,6 +1,7 @@
locale = fr_FR
page_og_desc = Gardez le contact avec François lorsqu'il part sur les chemins
error_commit_db = Error lors de la requête SQL
unknown_field = Champ "$0" inconnu
save = Sauvegarder
admin_save_success = Sauvegardé
@@ -46,17 +47,21 @@ copy_to_clipboard = Copie le lien dans le presse-papier
link_copied = Lien copié !
city_time = heure de $0
local_time = $0 heure locale
your_time = $0 dans votre fuseau horaire
date_time = $0 à $1
time_zone = Fuseau horaire
project_id = ID projet
id_project = ID projet
project = Projet
projects = Projets
mode = Mode
code_name = Nom de code
start = Départ
end = Arrivée
feed_id = ID Feed
id_feed = ID Feed
ref_feed_id = ID Feed ref.
spot_id = ID Spot
id_spot = ID Spot
name = Description
status = Statut
last_update = Dernière maj depuis Spot
@@ -64,9 +69,6 @@ ref_spot_id = ID Spot ref.
model = Modèle
delete = Supprimer
date_time = $0 à $1
time_zone = Fuseau horaire
unit_day = jour
unit_days = jours
unit_hour = h

View File

@@ -4,13 +4,12 @@
<table>
<thead>
<tr>
<th>[#]lang:project_id[#]</th>
<th>[#]lang:id_project[#]</th>
<th>[#]lang:project[#]</th>
<th>[#]lang:mode[#]</th>
<th>[#]lang:code_name[#]</th>
<th>[#]lang:start[#]</th>
<th>[#]lang:end[#]</th>
<th>[#]lang:time_zone[#]</th>
<th>[#]lang:delete[#]</th>
</tr>
</thead>
@@ -23,10 +22,10 @@
<table>
<thead>
<tr>
<th>[#]lang:feed_id[#]</th>
<th>[#]lang:id_feed[#]</th>
<th>[#]lang:ref_feed_id[#]</th>
<th>[#]lang:spot_id[#]</th>
<th>[#]lang:project_id[#]</th>
<th>[#]lang:id_spot[#]</th>
<th>[#]lang:id_project[#]</th>
<th>[#]lang:name[#]</th>
<th>[#]lang:status[#]</th>
<th>[#]lang:last_update[#]</th>
@@ -41,7 +40,7 @@
<table>
<thead>
<tr>
<th>[#]lang:spot_id[#]</th>
<th>[#]lang:id_spot[#]</th>
<th>[#]lang:ref_spot_id[#]</th>
<th>[#]lang:name[#]</th>
<th>[#]lang:model[#]</th>
@@ -71,35 +70,41 @@ oSpot.onFeedback = function(sType, sMsg, asContext) {
function setProjects(asElemTypes) {
var aoEvents = [{on:'change', callback:commit}, {on:'keyup', callback:waitAndCommit}];
var aoChangeEvent = [aoEvents[0]];
$.each(asElemTypes, function(sElemType, aoElems) {
$.each(aoElems, function(iKey, oElem) {
var sElemId = sElemType+'_'+oElem.id;
var bNew = ($('#'+sElemId).length == 0);
var $Elem = (bNew?$('<tr>', {'id': sElemId}):$('#'+sElemId).empty())
var $Elem = (bNew?$('<tr>', {'id': sElemId}):$('#'+sElemId))
.data('type', sElemType)
.data('id', oElem.id)
.append($('<td>').text(oElem.id || ''));
.data('id', oElem.id);
if(oElem.del) $Elem.remove();
else if(!bNew) {
$Elem.find('input').each(function(iKey, oInput){
var $Input = $(oInput);
if($Input.attr('name') in oElem && $Input.attr('type')!='date') $Input.val(oElem[$Input.attr('name')]);
});
}
else {
$Elem.append($('<td>').text(oElem.id || ''));
switch(sElemType) {
case 'project':
$Elem
.append($('<td>').addInput('text', 'name', oElem.name, aoEvents))
.append($('<td>', {'class': 'mode'}).text(oElem.mode))
.append($('<td>').addInput('text', 'codename', oElem.codename, aoEvents))
.append($('<td>').addInput('date', 'active_from', oElem.active_from.substr(0, 10), aoEvents))
.append($('<td>').addInput('date', 'active_to', oElem.active_to.substr(0, 10), aoEvents))
.append($('<td>').addInput('text', 'timezone', oElem.timezone, aoEvents))
.append($('<td>').addInput('date', 'active_from', oElem.active_from, aoChangeEvent))
.append($('<td>').addInput('date', 'active_to', oElem.active_to, aoChangeEvent))
.append($('<td>').addButton('close fa-lg', '', 'del_proj', del));
break;
case 'feed':
$Elem
.append($('<td>').addInput('text', 'ref_feed_id', oElem.ref_feed_id, aoEvents))
.append($('<td>').addInput('number', 'spot_id', oElem.id_spot, aoEvents))
.append($('<td>').addInput('number', 'project_id', oElem.id_project, aoEvents))
.append($('<td>').addInput('number', 'id_spot', oElem.id_spot, aoEvents))
.append($('<td>').addInput('number', 'id_project', oElem.id_project, aoEvents))
.append($('<td>').text(oElem.name))
.append($('<td>').text(oElem.status))
.append($('<td>').text(oElem.last_update))
@@ -113,7 +118,7 @@ function setProjects(asElemTypes) {
break;
}
if(bNew) $Elem.appendTo($('#'+sElemType+'s').find('table tbody'));
$Elem.appendTo($('#'+sElemType+'s').find('table tbody'));
}
});
});

View File

@@ -204,21 +204,13 @@ function initProject(sProjectCodeName, oFocusPost){
//Page Title
self.setPageTitle(oSpot.vars(['project', 'name']));
//Timezone difference notice
var bSameTime = (
(new Date()).toLocaleString([], {timeZone: oSpot.consts.timezone}) ==
(new Date()).toLocaleString([], {timeZone: oSpot.vars(['project', 'timezone'])})
);
self.tmp('site_tz_notice', bSameTime?'':getTimeZoneDesc(oSpot.consts.timezone));
self.tmp('proj_tz_notice', bSameTime?'':getTimeZoneDesc(self.vars(['project', 'timezone'])));
//Load Track & Markers
$.when(
//Markers: Spot Messages & Medias
self.get(
'markers',
function(){},
{project_id: self.vars(['project', 'id'])},
{id_project: self.vars(['project', 'id'])},
function(e){console.log(e);}
),
//Project Geojson: Hike track
@@ -230,7 +222,7 @@ function initProject(sProjectCodeName, oFocusPost){
).done(function(aoMessages, aoTracks) {
var asData = aoMessages[0]['data'];
setMapLayers(asData['maps']);
initSpotMessages(asData['messages'] || [], aoTracks[0], aoMessages[0]['desc']=='No Data');
initSpotMessages(asData['messages'] || [], aoTracks[0], asData['empty_project']);
updateSettingsPanel(asData['last_update']);
});
@@ -268,7 +260,7 @@ function initPosts() {
updateFeed(true);
},
{
project_id: self.vars(['project', 'id']),
id_project: self.vars(['project', 'id']),
name: $('#name').val(),
content: $('#post').val()
}
@@ -590,10 +582,10 @@ function initSpotMessages(aoMessages, aoTracks, bNoFeed) {
.append(oMsg.formatted_time+(self.vars(['project', 'mode'])==self.consts.modes.blog?' ('+oMsg.relative_time+')':'')));
//Tooltip: Time Zone
if(self.tmp('site_tz_notice')!='') {
if(oMsg.formatted_time_local != oMsg.formatted_time) {
$Tooltip.append($('<p>', {'class':'timezone'})
.addIcon('fa-timezone fa-fw fa-lg')
.append(self.tmp('site_tz_notice')));
.append(oSpot.lang('local_time', oMsg.formatted_time_local)));
}
//Tooltip: Medias
@@ -743,8 +735,8 @@ function updateFeed(bFirstChunk, bDiscrete, fCallback) {
self.tmp('updatable', true);
}, {
'project_id': self.vars(['project', 'id']),
'chunk': self.tmp('news_chunk')
id_project: self.vars(['project', 'id']),
chunk: self.tmp('news_chunk')
}
);
}
@@ -789,6 +781,8 @@ function getPost(asPost) {
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 sAbsTimeLocal = asPost.formatted_time_local;
var bTimeDiff = (sAbsTime && sAbsTimeLocal != sAbsTime);
var sType = asPost.subtype || asPost.type;
var $Body = {};
@@ -800,7 +794,7 @@ function getPost(asPost) {
.data('clicked', false)
.append($('<p>').addIcon('fa-coords', true).append(getGoogleMapsLink(asPost)))
.append($('<p>').addIcon('fa-time', true).append(sAbsTime))
.append((self.tmp('site_tz_notice')!='')?$('<p>').addIcon('fa-timezone', true).append(self.tmp('site_tz_notice')):'')
.append(bTimeDiff?$('<p>').addIcon('fa-timezone', true).append(oSpot.lang('local_time', sAbsTimeLocal)):'')
.append($('<a>', {'class':'drill'})
.append($('<img>', {'class':'staticmap', title: oSpot.lang('click_zoom'), src: getWmtsApiUrl('static', asPost.latitude, asPost.longitude, 13)}))
.append($('<span>', {'class': 'drill-icon fa-stack'})
@@ -868,7 +862,7 @@ function getPost(asPost) {
.addIcon('fa-'+sType)
.append(asPost.displayed_id?' '+oSpot.lang('counter', asPost.displayed_id):'')
)
.append($('<span>', {'class':'time'}).hoverSwap(sRelTime, sAbsTime+((self.tmp('site_tz_notice')!='')?' ('+self.tmp('site_tz_notice')+')':''))))
.append($('<span>', {'class':'time', title:bTimeDiff?oSpot.lang('local_time', sAbsTimeLocal):''}).hoverSwap(sRelTime, bTimeDiff?oSpot.lang('your_time', sAbsTime):sAbsTime)))
.append($('<div>', {'class':'body'}).append($Body));
if(bLink) {
@@ -894,22 +888,19 @@ function getWmtsApiUrl(sMapId, iLat, iLng, iZoom) {
}
function getMediaLink(asData, sType) {
var bTimeDiff = (asData.posted_on_formatted && asData.posted_on_formatted_local != asData.posted_on_formatted);
var $PostedOn =
$('<span>', {'class': 'lb-caption-line', title: oSpot.lang(asData.subtype)+' '+oSpot.lang('add_on', asData.posted_on_formatted)})
$('<span>', {'class': 'lb-caption-line', title: bTimeDiff?oSpot.lang('local_time', asData.posted_on_formatted_local):''})
.addIcon('fa-upload fa-lg fa-fw', true)
.append(asData.posted_on_formatted);
var $TakenOn = (asData.taken_on == '0000-00-00 00:00:00')?'':
$('<span>', {'class': 'lb-caption-line', title: oSpot.lang(asData.subtype)+' '+oSpot.lang(asData.subtype+'_taken', asData.taken_on_formatted)})
$('<span>', {'class': 'lb-caption-line', title: bTimeDiff?oSpot.lang('local_time', asData.taken_on_formatted_local):''})
.addIcon('fa-'+asData.subtype+'-shot fa-lg fa-fw', true)
.append(asData.taken_on_formatted);
var $Timezone = (self.tmp('site_tz_notice') == '')?'':
$('<span>', {'class': 'lb-caption-line'})
.addIcon('fa-timezone fa-lg fa-fw', true)
.append(self.tmp('site_tz_notice'));
var $Title = $('<div>').append(sType=='marker'?$TakenOn:$PostedOn).append(sType=='marker'?$PostedOn:$TakenOn).append($Timezone);
var $Title = $('<div>').append(sType=='marker'?$TakenOn:$PostedOn).append(sType=='marker'?$PostedOn:$TakenOn);
var $Link =
$('<a>', {
'class': 'drill',

View File

@@ -16,6 +16,7 @@ oSpot.pageInit = function(asHash) {
.attr('data-url', self.getActionLink('upload'))
.fileupload({
dataType: 'json',
formData: {t: self.consts.timezone},
acceptFileTypes: /(\.|\/)(gif|jpe?g|png|mov)$/i,
done: function (e, asData) {
$.each(asData.result.files, function(iKey, oFile) {

View File

@@ -14,5 +14,5 @@
* ECMA import/export
* Reset zoom on image closing (lightbox)
* Add mail frequency slider
* Replace Project Time Zone with browser Time Zone when uploading media?
* Use WMTS servers directly when not using Geo Caching Server
* Allow HEIF picture format

File diff suppressed because one or more lines are too long

View File

@@ -251,14 +251,6 @@ function setElem(aoAnchor, asPath, oValue)
}
}
function getTimeZoneDesc(sTimeZoneName) {
if(sTimeZoneName.indexOf('/')==-1) return sTimeZoneName;
else {
var sCity = sTimeZoneName.split('/')[1].replace('_', ' ') || '';
return oSpot.lang('city_time', sCity);
}
}
$.prototype.addInput = function(sType, sName, sValue, aoEvents)
{
aoEvents = aoEvents || [];

View File

@@ -563,8 +563,10 @@ $legend-color: $post-color;
}
#last_update {
position: absolute;
margin-top: -2em;
padding: 0 1rem;
width: calc(100% - 2rem);
p {
text-align: center;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long