Compare commits
7 Commits
6b7c6b72e6
...
7800885e0b
| Author | SHA1 | Date | |
|---|---|---|---|
| 7800885e0b | |||
| f00e0b738f | |||
| 9119fcca74 | |||
| 10095b412f | |||
| 062dced9bc | |||
| 0300d8b577 | |||
| 33d5a927c1 |
2
files/db/update_v14_to_v15.sql
Normal file
2
files/db/update_v14_to_v15.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE messages ADD posted_on TIMESTAMP DEFAULT 0 AFTER battery_state;
|
||||||
|
UPDATE messages SET posted_on = led, led = led;
|
||||||
@@ -44,23 +44,23 @@ class Email extends PhpObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function send() {
|
public function send() {
|
||||||
|
$oPHPMailer = new PHPMailer(true);
|
||||||
|
|
||||||
|
//Server settings
|
||||||
|
if(Settings::DEBUG) $oPHPMailer->SMTPDebug = SMTP::DEBUG_SERVER;//Enable verbose debug output
|
||||||
|
$oPHPMailer->isSMTP(); //Send using SMTP
|
||||||
|
$oPHPMailer->CharSet = Settings::TEXT_ENC; //Mail Character Set
|
||||||
|
$oPHPMailer->Encoding = 'base64'; //Base 64 Character Encoding
|
||||||
|
$oPHPMailer->Host = Settings::MAIL_SERVER; //Set the SMTP server to send through
|
||||||
|
$oPHPMailer->SMTPAuth = true; //Enable SMTP authentication
|
||||||
|
$oPHPMailer->Username = Settings::MAIL_USER; //SMTP username
|
||||||
|
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
|
||||||
|
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
||||||
|
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
||||||
|
$oPHPMailer->setFrom(Settings::MAIL_FROM, 'Spotty');
|
||||||
|
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, 'Spotty');
|
||||||
|
|
||||||
foreach($this->asDests as $asDest) {
|
foreach($this->asDests as $asDest) {
|
||||||
$oPHPMailer = new PHPMailer(true);
|
|
||||||
|
|
||||||
//Server settings
|
|
||||||
if(Settings::DEBUG) $oPHPMailer->SMTPDebug = SMTP::DEBUG_SERVER;//Enable verbose debug output
|
|
||||||
$oPHPMailer->isSMTP(); //Send using SMTP
|
|
||||||
$oPHPMailer->CharSet = Settings::TEXT_ENC; //Mail Character Set
|
|
||||||
$oPHPMailer->Encoding = 'base64'; //Base 64 Character Encoding
|
|
||||||
$oPHPMailer->Host = Settings::MAIL_SERVER; //Set the SMTP server to send through
|
|
||||||
$oPHPMailer->SMTPAuth = true; //Enable SMTP authentication
|
|
||||||
$oPHPMailer->Username = Settings::MAIL_USER; //SMTP username
|
|
||||||
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
|
|
||||||
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
|
||||||
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
|
||||||
$oPHPMailer->setFrom(Settings::MAIL_FROM, 'Spotty');
|
|
||||||
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, 'Spotty');
|
|
||||||
|
|
||||||
//Message
|
//Message
|
||||||
$this->oTemplate->setLanguage($asDest['language'], Spot::DEFAULT_LANG);
|
$this->oTemplate->setLanguage($asDest['language'], Spot::DEFAULT_LANG);
|
||||||
$this->oTemplate->setTimezone($asDest['timezone']);
|
$this->oTemplate->setTimezone($asDest['timezone']);
|
||||||
@@ -77,7 +77,12 @@ class Email extends PhpObject {
|
|||||||
$sPlainMessage = strip_tags(str_replace('<br />', "\n", $sHtmlMessage));
|
$sPlainMessage = strip_tags(str_replace('<br />', "\n", $sHtmlMessage));
|
||||||
|
|
||||||
//Recipients
|
//Recipients
|
||||||
$oPHPMailer->addAddress($asDest['email'], $asDest['name']);
|
try {
|
||||||
|
$oPHPMailer->addAddress($asDest['email'], $asDest['name']);
|
||||||
|
} catch (Exception $oError) {
|
||||||
|
$this->addError('Invalid address skipped: '.$asDest['email'].' ('.$asDest['name'].')');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//Content
|
//Content
|
||||||
$oPHPMailer->isHTML(true);
|
$oPHPMailer->isHTML(true);
|
||||||
@@ -85,13 +90,18 @@ class Email extends PhpObject {
|
|||||||
$oPHPMailer->Body = $sHtmlMessage;
|
$oPHPMailer->Body = $sHtmlMessage;
|
||||||
$oPHPMailer->AltBody = $sPlainMessage;
|
$oPHPMailer->AltBody = $sPlainMessage;
|
||||||
|
|
||||||
|
$bSuccess = true;
|
||||||
try {
|
try {
|
||||||
$oPHPMailer->send();
|
$bSuccess = $bSuccess && $oPHPMailer->send();
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $oError) {
|
||||||
$this->addError('Message could not be sent to "'.$asDest['email'].'". Mailer Error: '.$oPHPMailer->ErrorInfo);
|
$this->addError('Message could not be sent to "'.$asDest['email'].'". Mailer Error: '.$oPHPMailer->ErrorInfo);
|
||||||
|
$oPHPMailer->getSMTPInstance()->reset();
|
||||||
}
|
}
|
||||||
|
$oPHPMailer->clearAddresses();
|
||||||
|
$oPHPMailer->clearCustomHeaders();
|
||||||
}
|
}
|
||||||
|
return $bSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getTimeZoneCity($sTimeZone) {
|
private static function getTimeZoneCity($sTimeZone) {
|
||||||
|
|||||||
27
inc/Feed.php
27
inc/Feed.php
@@ -93,23 +93,27 @@ class Feed extends PhpObject {
|
|||||||
return array_shift($asFeeds);
|
return array_shift($asFeeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMessages($asActivePeriod = array()) {
|
public function getMessages($asConstraints=array()) {
|
||||||
$asInfo = array(
|
$asInfo = array(
|
||||||
'select' => array('id_message', 'ref_msg_id', 'type', 'latitude', 'longitude', 'site_time', 'timezone', 'unix_time'),
|
'select' => array(Db::getId(self::MSG_TABLE), 'ref_msg_id', 'type', 'latitude', 'longitude', 'site_time', 'timezone', 'unix_time'),
|
||||||
'from' => self::MSG_TABLE,
|
'from' => self::MSG_TABLE,
|
||||||
'constraint'=> array(Db::getId(self::FEED_TABLE) => $this->getFeedId()),
|
'join' => array(self::FEED_TABLE => Db::getId(self::FEED_TABLE)),
|
||||||
'constOpe' => array(Db::getId(self::FEED_TABLE) => "="),
|
'constraint'=> array(Db::getId(self::FEED_TABLE, true) => $this->getFeedId()),
|
||||||
|
'constOpe' => array(Db::getId(self::FEED_TABLE, true) => "="),
|
||||||
'orderBy' => array('site_time'=>'ASC')
|
'orderBy' => array('site_time'=>'ASC')
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!empty($asActivePeriod)) {
|
if(!empty($asConstraints)) $asInfo = array_merge($asInfo, $asConstraints);
|
||||||
$asInfo['constraint']['site_time'] = $asActivePeriod;
|
|
||||||
$asInfo['constOpe']['site_time'] = "BETWEEN";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->oDb->selectRows($asInfo);
|
return $this->oDb->selectRows($asInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLastMessageId($asConstraints=array()) {
|
||||||
|
|
||||||
|
$asMessages = $this->getMessages($asConstraints);
|
||||||
|
return end($asMessages)[Db::getId(self::MSG_TABLE)];
|
||||||
|
}
|
||||||
|
|
||||||
public function checkUpdateFeed($sProjectMode) {
|
public function checkUpdateFeed($sProjectMode) {
|
||||||
$bNewMsg = false;
|
$bNewMsg = false;
|
||||||
|
|
||||||
@@ -128,7 +132,7 @@ class Feed extends PhpObject {
|
|||||||
private function updateFeed() {
|
private function updateFeed() {
|
||||||
$bNewMsg = false;
|
$bNewMsg = false;
|
||||||
$asData = $this->retrieveFeed();
|
$asData = $this->retrieveFeed();
|
||||||
$sLastUpdate = date(Db::TIMESTAMP_FORMAT);
|
$sNow = date(Db::TIMESTAMP_FORMAT);
|
||||||
if(!isset($asData['response']['errors']) || empty($asData['response']['errors'])) {
|
if(!isset($asData['response']['errors']) || empty($asData['response']['errors'])) {
|
||||||
$asMsgs = $asData['response']['feedMessageResponse']['messages'];
|
$asMsgs = $asData['response']['feedMessageResponse']['messages'];
|
||||||
$asFeed = $asData['response']['feedMessageResponse']['feed'];
|
$asFeed = $asData['response']['feedMessageResponse']['feed'];
|
||||||
@@ -155,7 +159,7 @@ class Feed extends PhpObject {
|
|||||||
'name' => $asFeed['name'],
|
'name' => $asFeed['name'],
|
||||||
'description' => $asFeed['description'],
|
'description' => $asFeed['description'],
|
||||||
'status' => $asFeed['status'],
|
'status' => $asFeed['status'],
|
||||||
'last_update' => $sLastUpdate
|
'last_update' => $sNow
|
||||||
);
|
);
|
||||||
$iFeedId = $this->oDb->insertUpdateRow(self::FEED_TABLE, $asFeedInfo, array('ref_feed_id'));
|
$iFeedId = $this->oDb->insertUpdateRow(self::FEED_TABLE, $asFeedInfo, array('ref_feed_id'));
|
||||||
|
|
||||||
@@ -177,6 +181,7 @@ class Feed extends PhpObject {
|
|||||||
|
|
||||||
$iMsgId = $this->oDb->selectId(self::MSG_TABLE, array('ref_msg_id'=>$asMsg['ref_msg_id']));
|
$iMsgId = $this->oDb->selectId(self::MSG_TABLE, array('ref_msg_id'=>$asMsg['ref_msg_id']));
|
||||||
if(!$iMsgId) {
|
if(!$iMsgId) {
|
||||||
|
$asMsg['posted_on'] = $sNow;
|
||||||
$this->oDb->insertRow(self::MSG_TABLE, $asMsg);
|
$this->oDb->insertRow(self::MSG_TABLE, $asMsg);
|
||||||
$bNewMsg = true;
|
$bNewMsg = true;
|
||||||
}
|
}
|
||||||
@@ -184,7 +189,7 @@ class Feed extends PhpObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else $this->oDb->updateRow(self::FEED_TABLE, $this->getFeedId(), array('last_update'=>$sLastUpdate));
|
else $this->oDb->updateRow(self::FEED_TABLE, $this->getFeedId(), array('last_update'=>$sNow));
|
||||||
|
|
||||||
return $bNewMsg;
|
return $bNewMsg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,16 +69,19 @@ class Media extends PhpObject {
|
|||||||
return Spot::getResult(($sError==''), $sError, $asData);
|
return Spot::getResult(($sError==''), $sError, $asData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMediasInfo($iMediaId=0) {
|
public function getMediasInfo($oMediaIds=null) {
|
||||||
$bOwnMedia = ($iMediaId > 0);
|
$bOwnMedia = is_numeric($oMediaIds); //1 value
|
||||||
if($bOwnMedia && empty($this->asMedia) || !$bOwnMedia && empty($this->asMedias)) {
|
$bConstraintArray = is_array($oMediaIds); //Custom Constraints
|
||||||
|
|
||||||
|
if($bOwnMedia && empty($this->asMedia) || !$bOwnMedia && empty($this->asMedias) || $bConstraintArray) {
|
||||||
if($this->oProject->getProjectId()) {
|
if($this->oProject->getProjectId()) {
|
||||||
$asParams = array(
|
$asParams = array(
|
||||||
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'timezone', '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,
|
'from' => self::MEDIA_TABLE,
|
||||||
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
|
||||||
);
|
);
|
||||||
if($bOwnMedia) $asParams['constraint'][Db::getId(self::MEDIA_TABLE)] = $iMediaId;
|
if($bOwnMedia) $asParams['constraint'][Db::getId(self::MEDIA_TABLE)] = $oMediaIds;
|
||||||
|
if($bConstraintArray) $asParams = array_merge($asParams, $oMediaIds);
|
||||||
|
|
||||||
$asMedias = $this->oDb->selectRows($asParams);
|
$asMedias = $this->oDb->selectRows($asParams);
|
||||||
foreach($asMedias as &$asMedia) {
|
foreach($asMedias as &$asMedia) {
|
||||||
@@ -86,13 +89,13 @@ class Media extends PhpObject {
|
|||||||
$asMedia['thumb_path'] = $this->getMediaThumbnail($asMedia['filename']);
|
$asMedia['thumb_path'] = $this->getMediaThumbnail($asMedia['filename']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($asMedias)) {
|
if(!empty($asMedias) && !$bConstraintArray) {
|
||||||
if($bOwnMedia) $this->asMedia = array_shift($asMedias);
|
if($bOwnMedia) $this->asMedia = array_shift($asMedias);
|
||||||
else $this->asMedias = $asMedias;
|
else $this->asMedias = $asMedias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $bOwnMedia?$this->asMedia:$this->asMedias;
|
return $bOwnMedia?$this->asMedia:$asMedias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInfo() {
|
public function getInfo() {
|
||||||
|
|||||||
@@ -164,6 +164,17 @@ class Project extends PhpObject {
|
|||||||
return $iLastUpdate;
|
return $iLastUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLastMessageId($asConstraints=array()): int {
|
||||||
|
$iLastMsg = 0;
|
||||||
|
|
||||||
|
$asFeedIds = $this->getFeedIds();
|
||||||
|
foreach($asFeedIds as $iFeedId) {
|
||||||
|
$iLastMsg = max($iLastMsg, (new Feed($this->oDb, $iFeedId))->getLastMessageId($asConstraints));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $iLastMsg;
|
||||||
|
}
|
||||||
|
|
||||||
public function getMaps() {
|
public function getMaps() {
|
||||||
$sQuery =
|
$sQuery =
|
||||||
"SELECT codename, geo_name, min_zoom, max_zoom, attribution ".
|
"SELECT codename, geo_name, min_zoom, max_zoom, attribution ".
|
||||||
|
|||||||
287
inc/Spot.php
287
inc/Spot.php
@@ -88,7 +88,7 @@ class Spot extends Main
|
|||||||
(
|
(
|
||||||
'tables' => array
|
'tables' => array
|
||||||
(
|
(
|
||||||
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::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'timezone', 'unix_time', 'content', 'battery_state', 'posted_on'),
|
||||||
Feed::FEED_TABLE => array('ref_feed_id', Db::getId(Feed::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
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'),
|
Feed::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
||||||
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to'),
|
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to'),
|
||||||
@@ -146,7 +146,10 @@ class Spot extends Main
|
|||||||
),
|
),
|
||||||
'cascading_delete' => array
|
'cascading_delete' => array
|
||||||
(
|
(
|
||||||
Feed::SPOT_TABLE => array(Feed::MSG_TABLE)
|
Feed::SPOT_TABLE => array(Feed::FEED_TABLE),
|
||||||
|
Feed::FEED_TABLE => array(Feed::MSG_TABLE),
|
||||||
|
Project::PROJ_TABLE => array(Feed::FEED_TABLE, Media::MEDIA_TABLE, self::POST_TABLE),
|
||||||
|
self::MAP_TABLE => array(self::MAPPING_TABLE)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -217,14 +220,13 @@ class Spot extends Main
|
|||||||
$oEmail->setDestInfo($this->oUser->getActiveUsersInfo());
|
$oEmail->setDestInfo($this->oUser->getActiveUsersInfo());
|
||||||
|
|
||||||
//Add Position
|
//Add Position
|
||||||
$asMessages = $this->getSpotMessages();
|
$asLastMessage = array_shift($this->getSpotMessages(array($this->oProject->getLastMessageId($this->getFeedConstraints(Feed::MSG_TABLE)))));
|
||||||
$asLastMessage = end($asMessages);
|
|
||||||
$asLastMessage['token'] = Settings::GEO_SERVER_TOKEN;
|
$asLastMessage['token'] = Settings::GEO_SERVER_TOKEN;
|
||||||
$oEmail->oTemplate->setTags($asLastMessage);
|
$oEmail->oTemplate->setTags($asLastMessage);
|
||||||
$oEmail->oTemplate->setTag('date_time', 'time:'.$asLastMessage['unix_time'], 'd/m/Y, H:i');
|
$oEmail->oTemplate->setTag('date_time', 'time:'.$asLastMessage['unix_time'], 'd/m/Y, H:i');
|
||||||
|
|
||||||
//Add latest news feed
|
//Add latest news feed
|
||||||
$asNews = $this->getNewsFeed(0, 0, true);
|
$asNews = $this->getNextFeed(0, true);
|
||||||
$iPostCount = 0;
|
$iPostCount = 0;
|
||||||
foreach($asNews as $asPost) {
|
foreach($asNews as $asPost) {
|
||||||
if($asPost['type'] != 'message') {
|
if($asPost['type'] != 'message') {
|
||||||
@@ -262,13 +264,15 @@ class Spot extends Main
|
|||||||
return self::getJsonResult($bSuccess, '');
|
return self::getJsonResult($bSuccess, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMarkers()
|
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
|
||||||
{
|
{
|
||||||
$asMessages = $this->getSpotMessages();
|
$asMessages = $this->getSpotMessages($asMessageIds);
|
||||||
|
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||||
|
|
||||||
//Add medias
|
//Add medias
|
||||||
if(!empty($asMessages)) {
|
if(!empty($asMessages)) {
|
||||||
$asMedias = $this->getMedias('taken_on');
|
$asMedias = $this->getMedias('taken_on', $asMediaIds);
|
||||||
|
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||||
|
|
||||||
//Assign medias to closest message
|
//Assign medias to closest message
|
||||||
$iIndex = 0;
|
$iIndex = 0;
|
||||||
@@ -277,7 +281,9 @@ class Spot extends Main
|
|||||||
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) {
|
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) {
|
||||||
$iIndex++;
|
$iIndex++;
|
||||||
}
|
}
|
||||||
if($iIndex == 0) $iMsgIndex = $iIndex;
|
|
||||||
|
//All medias before first message or after last message are assigned to first/last message respectively
|
||||||
|
if($iIndex == 0) $iMsgIndex = $iIndex;
|
||||||
elseif($iIndex > $iMaxIndex) $iMsgIndex = $iMaxIndex;
|
elseif($iIndex > $iMaxIndex) $iMsgIndex = $iMaxIndex;
|
||||||
else {
|
else {
|
||||||
$iHalfWayPoint = ($asMessages[$iIndex - 1]['unix_time'] + $asMessages[$iIndex]['unix_time'])/2;
|
$iHalfWayPoint = ($asMessages[$iIndex - 1]['unix_time'] + $asMessages[$iIndex]['unix_time'])/2;
|
||||||
@@ -288,15 +294,17 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add Project Last Update
|
//Spot Last Update
|
||||||
$asLastUpdate = array();
|
$asLastUpdate = array();
|
||||||
$this->addTimeStamp($asLastUpdate, $this->oProject->getLastUpdate());
|
$this->addTimeStamp($asLastUpdate, $this->oProject->getLastUpdate());
|
||||||
|
|
||||||
return self::getJsonResult(true, '', array(
|
$asResult = array(
|
||||||
'messages' => $asMessages,
|
'messages' => $asMessages,
|
||||||
'maps' => $this->oProject->getMaps(),
|
'maps' => $this->oProject->getMaps(),
|
||||||
'last_update' => $asLastUpdate
|
'last_update' => $asLastUpdate
|
||||||
));
|
);
|
||||||
|
|
||||||
|
return $bInternal?$asResult:self::getJsonResult(true, '', $asResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function subscribe($sEmail) {
|
public function subscribe($sEmail) {
|
||||||
@@ -327,82 +335,81 @@ class Spot extends Main
|
|||||||
return $this->oLang->getTranslation($sDesc);
|
return $this->oLang->getTranslation($sDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSpotMessages()
|
private function getSpotMessages($asMsgIds=array())
|
||||||
{
|
{
|
||||||
$asMessages = array();
|
$asConstraints = $this->getFeedConstraints(Feed::MSG_TABLE);
|
||||||
|
if(!empty($asMsgIds)) {
|
||||||
|
$asConstraints['constraint'][Db::getId(Feed::MSG_TABLE)] = $asMsgIds;
|
||||||
|
$asConstraints['constOpe'][Db::getId(Feed::MSG_TABLE)] = 'IN';
|
||||||
|
}
|
||||||
|
|
||||||
|
$asCombinedMessages = array();
|
||||||
|
|
||||||
//Get messages from all feeds belonging to the project
|
//Get messages from all feeds belonging to the project
|
||||||
$asFeeds = $this->oProject->getFeedIds();
|
$asFeeds = $this->oProject->getFeedIds();
|
||||||
foreach($asFeeds as $iFeedId) {
|
foreach($asFeeds as $iFeedId) {
|
||||||
$oFeed = new Feed($this->oDb, $iFeedId);
|
$oFeed = new Feed($this->oDb, $iFeedId);
|
||||||
$asMessages = $oFeed->getMessages($this->oProject->getActivePeriod());
|
$asMessages = $oFeed->getMessages($asConstraints);
|
||||||
foreach($asMessages as &$asMessage)
|
foreach($asMessages as $asMessage)
|
||||||
{
|
{
|
||||||
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
||||||
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
||||||
$asMessage['lat_dms'] = self::decToDms($asMessage['latitude'], 'lat');
|
$asMessage['lat_dms'] = self::decToDms($asMessage['latitude'], 'lat');
|
||||||
$asMessage['lon_dms'] = self::decToDms($asMessage['longitude'], 'lon');
|
$asMessage['lon_dms'] = self::decToDms($asMessage['longitude'], 'lon');
|
||||||
|
$asMessage['displayed_id'] = $asMessage[Db::getId(Feed::MSG_TABLE)];
|
||||||
|
|
||||||
$this->addTimeStamp($asMessage, $asMessage['unix_time'], $asMessage['timezone']);
|
$this->addTimeStamp($asMessage, $asMessage['unix_time'], $asMessage['timezone']);
|
||||||
|
$asCombinedMessages[] = $asMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sort chronologically
|
return $asCombinedMessages;
|
||||||
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
|
||||||
|
|
||||||
//Add Display ID
|
|
||||||
$asSortedMessages = array_values($asMessages);
|
|
||||||
foreach($asSortedMessages as $iIndex=>&$asSortedMessage) $asSortedMessage['displayed_id'] = $iIndex + 1;
|
|
||||||
|
|
||||||
return $asSortedMessages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get valid medias based on $sTimeRefField:
|
* Get valid medias based on $sTimeRefField:
|
||||||
* - taken_on: Date/time on which the media was taken
|
* - taken_on: Date/time on which the media was taken
|
||||||
* - posted_on: Date/time on which the media was uploaded
|
* - posted_on: Date/time on which the media was uploaded
|
||||||
* @param String $sTimeRefField Field to calculate relative times
|
* @param String $sTimeRefField Field to calculate relative times: 'taken_on' or 'posted_on'
|
||||||
* @return Array Medias info
|
* @return Array Medias info
|
||||||
*/
|
*/
|
||||||
private function getMedias($sTimeRefField)
|
private function getMedias($sTimeRefField, $asMediaIds=array())
|
||||||
{
|
{
|
||||||
$asMedias = $this->oMedia->getMediasInfo();
|
//Constraints
|
||||||
$asValidMedias = array();
|
$asConstraints = $this->getFeedConstraints(Media::MEDIA_TABLE, $sTimeRefField);
|
||||||
foreach($asMedias as $asMedia) {
|
if(!empty($asMediaIds)) {
|
||||||
$sTimeRef = $asMedia[$sTimeRefField];
|
$asConstraints['constraint'][Db::getId(Media::MEDIA_TABLE)] = $asMediaIds;
|
||||||
if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) {
|
$asConstraints['constOpe'][Db::getId(Media::MEDIA_TABLE)] = 'IN';
|
||||||
$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), $asMedia['timezone']);
|
|
||||||
$asValidMedias[] = $asMedia;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usort($asValidMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
$asMedias = $this->oMedia->getMediasInfo($asConstraints);
|
||||||
|
foreach($asMedias as &$asMedia) {
|
||||||
|
$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']);
|
||||||
|
$asMedia['displayed_id'] = $asMedia[Db::getId(Media::MEDIA_TABLE)];
|
||||||
|
|
||||||
$asSortedMedias = array_values($asValidMedias);
|
$this->addTimeStamp($asMedia, strtotime($asMedia[$sTimeRefField]), $asMedia['timezone']);
|
||||||
foreach($asSortedMedias as $iIndex=>&$asSortedMedia) $asSortedMedia['displayed_id'] = $iIndex + 1;
|
}
|
||||||
|
|
||||||
return $asSortedMedias;
|
return $asMedias;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPosts()
|
private function getPosts($asPostIds=array())
|
||||||
{
|
{
|
||||||
$asInfo = array(
|
$asInfo = array(
|
||||||
'select' => array(Db::getFullColumnName(self::POST_TABLE, '*'), 'gravatar'),
|
'select' => array(Db::getFullColumnName(self::POST_TABLE, '*'), 'gravatar'),
|
||||||
'from' => self::POST_TABLE,
|
'from' => self::POST_TABLE,
|
||||||
'join' => array(User::USER_TABLE => Db::getId(User::USER_TABLE)),
|
'join' => array(User::USER_TABLE => Db::getId(User::USER_TABLE))
|
||||||
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()),
|
|
||||||
'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=")
|
|
||||||
);
|
);
|
||||||
if($this->oProject->getMode()==Project::MODE_HISTO) {
|
$asInfo = array_merge($asInfo, $this->getFeedConstraints(self::POST_TABLE));
|
||||||
$asInfo['constraint']['site_time'] = $this->oProject->getActivePeriod('to');
|
|
||||||
$asInfo['constOpe']['site_time'] = "<=";
|
if(!empty($asPostIds)) {
|
||||||
|
$asInfo['constraint'][Db::getId(self::POST_TABLE)] = $asPostIds;
|
||||||
|
$asInfo['constOpe'][Db::getId(self::POST_TABLE)] = 'IN';
|
||||||
}
|
}
|
||||||
$asPosts = $this->oDb->selectRows($asInfo);
|
$asPosts = $this->oDb->selectRows($asInfo);
|
||||||
|
|
||||||
@@ -413,7 +420,6 @@ class Spot extends Main
|
|||||||
|
|
||||||
$this->addTimeStamp($asPost, $iUnixTimeStamp, $asPost['timezone']);
|
$this->addTimeStamp($asPost, $iUnixTimeStamp, $asPost['timezone']);
|
||||||
}
|
}
|
||||||
usort($asPosts, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
|
||||||
|
|
||||||
return $asPosts;
|
return $asPosts;
|
||||||
}
|
}
|
||||||
@@ -425,54 +431,145 @@ class Spot extends Main
|
|||||||
if($sTimeZone != '') $asData['formatted_time_local'] = $this->getTimeFormat($iTime, $sTimeZone);
|
if($sTimeZone != '') $asData['formatted_time_local'] = $this->getTimeFormat($iTime, $sTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNewsFeed($iChunk=0, $iRefTimePoint=0, $bInternal=false)
|
private function getFeedConstraints($sType, $sTimeField='site_time', $sReturnFormat='array') {
|
||||||
{
|
$asConsArray = array();
|
||||||
$bHistoMode = ($this->oProject->getMode() == Project::MODE_HISTO);
|
$sConsSql = "";
|
||||||
$asFeeds = array();
|
$asActPeriod = $this->oProject->getActivePeriod();
|
||||||
$asFeedTypes = array(
|
|
||||||
'message' => array(
|
//Filter on Project ID
|
||||||
'table' => Feed::MSG_TABLE,
|
$sConsSql = "WHERE ".Db::getId(Project::PROJ_TABLE)." = ".$this->oProject->getProjectId();
|
||||||
'feed' => $this->getSpotMessages(),
|
$asConsArray = array(
|
||||||
'priority' => 0
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()),
|
||||||
),
|
'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=")
|
||||||
'media' => array(
|
|
||||||
'table' => Media::MEDIA_TABLE,
|
|
||||||
'feed' => $this->getMedias('posted_on'),
|
|
||||||
'priority' => 1
|
|
||||||
),
|
|
||||||
'post' => array(
|
|
||||||
'table' => self::POST_TABLE,
|
|
||||||
'feed' => $this->getPosts(),
|
|
||||||
'priority' => 2
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
foreach($asFeedTypes as $sFeedType=>$asFeedTypeInfo) {
|
|
||||||
foreach($asFeedTypeInfo['feed'] as $asFeed) {
|
|
||||||
$iTableId = $asFeed[Db::getId($asFeedTypeInfo['table'])];
|
|
||||||
|
|
||||||
//Build unique sorting ID
|
//Time Filter
|
||||||
$iSort = $asFeed['unix_time'].'.'.$asFeedTypeInfo['priority'].$iTableId;
|
switch($sType) {
|
||||||
|
case Feed::MSG_TABLE:
|
||||||
//Build feed (not including new feeds added in between chunk by concurrent access)
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod;
|
||||||
if($iChunk == 0 || $iSort <= $iRefTimePoint) {
|
$asConsArray['constOpe'][$sTimeField] = "BETWEEN";
|
||||||
$asFeeds[$iSort] = $asFeed;
|
$sConsSql .= " AND ".$sTimeField." BETWEEN '".$asActPeriod['from']."' AND '".$asActPeriod['to']."'";
|
||||||
$asFeeds[$iSort]['type'] = $sFeedType;
|
break;
|
||||||
$asFeeds[$iSort]['id'] = $iTableId;
|
case Media::MEDIA_TABLE:
|
||||||
}
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
||||||
|
$asConsArray['constOpe'][$sTimeField] = "<=";
|
||||||
//Build Reference Time Point (latest item extracted by first chunk)
|
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
||||||
if($iChunk == 0 && $iSort > $iRefTimePoint) $iRefTimePoint = $iSort;
|
break;
|
||||||
}
|
case self::POST_TABLE:
|
||||||
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
||||||
|
$asConsArray['constOpe'][$sTimeField] = "<=";
|
||||||
|
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sort by key
|
return ($sReturnFormat=='array')?$asConsArray:$sConsSql;
|
||||||
if($bHistoMode) ksort($asFeeds); //Old first
|
}
|
||||||
else krsort($asFeeds); //New first
|
|
||||||
|
|
||||||
//Split chunks
|
public function getNewFeed($iRefIdFirst) {
|
||||||
$asFeeds = array_slice($asFeeds, $iChunk * self::FEED_CHUNK_SIZE, self::FEED_CHUNK_SIZE);
|
$asResult = array();
|
||||||
|
|
||||||
return $bInternal?$asFeeds:self::getJsonResult(true, '', array('ref_id'=>$iRefTimePoint, 'feed' => $asFeeds));
|
if($this->oProject->getMode() != Project::MODE_HISTO) {
|
||||||
|
$asMessageIds = $asMediaIds = array();
|
||||||
|
|
||||||
|
//New Feed Items
|
||||||
|
$asResult = $this->getFeed($iRefIdFirst, ">", "DESC");
|
||||||
|
foreach($asResult['feed'] as $asItem) {
|
||||||
|
switch($asItem['type']) {
|
||||||
|
case 'message':
|
||||||
|
$asMessageIds[] = $asItem['id'];
|
||||||
|
break;
|
||||||
|
case 'media':
|
||||||
|
$asMediaIds[] = $asItem['id'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//New Markers
|
||||||
|
$asMarkers = $this->getMarkers(
|
||||||
|
empty($asMessageIds)?array(0):$asMessageIds,
|
||||||
|
empty($asMediaIds)?array(0):$asMediaIds,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$asResult = array_merge($asResult, $asMarkers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::getJsonResult(true, '', $asResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNextFeed($iRefIdLast=0, $bInternal=false) {
|
||||||
|
if($this->oProject->getMode() == Project::MODE_HISTO) {
|
||||||
|
$sDirection = ">";
|
||||||
|
$sSort = "ASC";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$sDirection = "<";
|
||||||
|
$sSort = "DESC";
|
||||||
|
}
|
||||||
|
$asResult = $this->getFeed($iRefIdLast, $sDirection, $sSort);
|
||||||
|
return $bInternal?$asResult['feed']:self::getJsonResult(true, '', $asResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFeed($iRefId=0, $sDirection, $sSort) {
|
||||||
|
$this->oDb->cleanSql($iRefId);
|
||||||
|
$this->oDb->cleanSql($sDirection);
|
||||||
|
$this->oDb->cleanSql($sSort);
|
||||||
|
|
||||||
|
$sMediaRefField = 'posted_on';
|
||||||
|
$sQuery = implode(" ", array(
|
||||||
|
"SELECT type, id, ref",
|
||||||
|
"FROM (",
|
||||||
|
"SELECT id_project, id_message AS id, 'message' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.0', id_message) AS ref",
|
||||||
|
"FROM ".Feed::MSG_TABLE,
|
||||||
|
"INNER JOIN feeds USING(id_feed)",
|
||||||
|
$this->getFeedConstraints(Feed::MSG_TABLE, 'site_time', 'sql'),
|
||||||
|
"UNION",
|
||||||
|
"SELECT id_project, id_media AS id, 'media' AS type, CONCAT(UNIX_TIMESTAMP(".$sMediaRefField."), '.1', id_media) AS ref",
|
||||||
|
"FROM ".Media::MEDIA_TABLE,
|
||||||
|
$this->getFeedConstraints(Media::MEDIA_TABLE, $sMediaRefField, 'sql'),
|
||||||
|
"UNION",
|
||||||
|
"SELECT id_project, id_post AS id, 'post' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.2', id_post) AS ref",
|
||||||
|
"FROM ".self::POST_TABLE,
|
||||||
|
$this->getFeedConstraints(self::POST_TABLE, 'site_time', 'sql'),
|
||||||
|
") AS items",
|
||||||
|
($iRefId > 0)?("WHERE ref ".$sDirection." ".$iRefId):"",
|
||||||
|
"ORDER BY ref ".$sSort,
|
||||||
|
"LIMIT ".self::FEED_CHUNK_SIZE
|
||||||
|
));
|
||||||
|
|
||||||
|
//Get new chunk
|
||||||
|
$asItems = $this->oDb->getArrayQuery($sQuery, true);
|
||||||
|
|
||||||
|
//Update Reference Point with latest/earliest value
|
||||||
|
$iRefIdFirst = $iRefIdLast = 0;
|
||||||
|
if(!empty($asItems)) {
|
||||||
|
$iRefIdLast = end($asItems)['ref'];
|
||||||
|
$iRefIdFirst = reset($asItems)['ref'];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sort Table IDs by type & Get attributes
|
||||||
|
foreach($asItems as $asItem) {
|
||||||
|
$asFeedIds[$asItem['type']][$asItem['id']] = $asItem;
|
||||||
|
}
|
||||||
|
$asFeedAttrs = array(
|
||||||
|
'message' => $this->getSpotMessages(array_keys($asFeedIds['message'])),
|
||||||
|
'media' => $this->getMedias($sMediaRefField, array_keys($asFeedIds['media'])),
|
||||||
|
'post' => $this->getPosts(array_keys($asFeedIds['post']))
|
||||||
|
);
|
||||||
|
|
||||||
|
//Replace Array Key with Item ID
|
||||||
|
foreach($asFeedAttrs as $sType=>$asFeedAttr) {
|
||||||
|
foreach($asFeedAttr as $asFeed) {
|
||||||
|
$asFeeds[$sType][$asFeed['id_'.$sType]] = $asFeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign
|
||||||
|
foreach($asItems as &$asItem) {
|
||||||
|
$asItem = array_merge($asFeeds[$asItem['type']][$asItem['id']], $asItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('ref_id_last'=>$iRefIdLast, 'ref_id_first'=>$iRefIdFirst, 'sort'=>$sSort, 'feed'=>$asItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function syncMedias() {
|
public function syncMedias() {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ $sAction = isset($_REQUEST['a'])?$_REQUEST['a']:'';
|
|||||||
$sTimezone = $_REQUEST['t'] ?? '';
|
$sTimezone = $_REQUEST['t'] ?? '';
|
||||||
$sName = isset($_GET['name'])?$_GET['name']:'';
|
$sName = isset($_GET['name'])?$_GET['name']:'';
|
||||||
$sContent = isset($_GET['content'])?$_GET['content']:'';
|
$sContent = isset($_GET['content'])?$_GET['content']:'';
|
||||||
$iChunk = isset($_GET['chunk'])?$_GET['chunk']:0;
|
|
||||||
$iProjectId = $_REQUEST['id_project'] ?? 0;
|
$iProjectId = $_REQUEST['id_project'] ?? 0;
|
||||||
$sField = isset($_REQUEST['field'])?$_REQUEST['field']:'';
|
$sField = isset($_REQUEST['field'])?$_REQUEST['field']:'';
|
||||||
$oValue = isset($_REQUEST['value'])?$_REQUEST['value']:'';
|
$oValue = isset($_REQUEST['value'])?$_REQUEST['value']:'';
|
||||||
@@ -44,8 +43,11 @@ if($sAction!='')
|
|||||||
case 'markers':
|
case 'markers':
|
||||||
$sResult = $oSpot->getMarkers();
|
$sResult = $oSpot->getMarkers();
|
||||||
break;
|
break;
|
||||||
case 'feed':
|
case 'next_feed':
|
||||||
$sResult = $oSpot->getNewsFeed($iChunk, $iId);
|
$sResult = $oSpot->getNextFeed($iId);
|
||||||
|
break;
|
||||||
|
case 'new_feed':
|
||||||
|
$sResult = $oSpot->getNewFeed($iId);
|
||||||
break;
|
break;
|
||||||
case 'add_post':
|
case 'add_post':
|
||||||
$sResult = $oSpot->addPost($sName, $sContent);
|
$sResult = $oSpot->addPost($sName, $sContent);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<div id="projects">
|
<div id="projects">
|
||||||
|
<div id="background"></div>
|
||||||
<div id="submap">
|
<div id="submap">
|
||||||
<div class="loader fa fa-fw fa-map flicker" id="map_loading"></div>
|
<div class="loader fa fa-fw fa-map flicker" id="map_loading"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,15 +32,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="feed">
|
<div id="feed">
|
||||||
<div id="posts">
|
<div id="feed-panel">
|
||||||
<div id="poster"></div>
|
<div id="poster"></div>
|
||||||
<div id="posts_list"></div>
|
<div id="posts_list"></div>
|
||||||
<div id="loading"></div>
|
<div id="loading"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="elems">
|
<div id="elems">
|
||||||
<div id="settings-button" class="spot-control"><i class="fa fa-menu fa-fw"></i></div>
|
<div id="settings-button" class="spot-control"><i class="fa fa-menu"></i></div>
|
||||||
<div id="post-button" class="spot-control"><i class="fa fa-fw"></i></div>
|
<div id="post-button" class="spot-control"><i class="fa"></i></div>
|
||||||
<div id="legend" class="leaflet-control-layers leaflet-control leaflet-control-layers-expanded">
|
<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>
|
<div class="track"><span class="line main"></span><span class="desc">[#]lang:track_main[#]</span></div>
|
||||||
<div class="track"><span class="line off-track"></span><span class="desc">[#]lang:track_off-track[#]</span></div>
|
<div class="track"><span class="line off-track"></span><span class="desc">[#]lang:track_off-track[#]</span></div>
|
||||||
@@ -56,7 +57,7 @@ oSpot.onSamePageMove = function(asHash) {
|
|||||||
self.tmp('$Map').empty();
|
self.tmp('$Map').empty();
|
||||||
self.tmp('map', null);
|
self.tmp('map', null);
|
||||||
self.tmp('$PostList').empty();
|
self.tmp('$PostList').empty();
|
||||||
setFeedUpdateTimer(false);
|
setFeedUpdateTimer(-1);
|
||||||
initProject(asHash.items[0]);
|
initProject(asHash.items[0]);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -82,14 +83,18 @@ oSpot.onResize = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
oSpot.onQuitPage = function() {
|
oSpot.onQuitPage = function() {
|
||||||
setFeedUpdateTimer(false);
|
setFeedUpdateTimer(-1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
oSpot.onKeydown = function(oEvent) {
|
oSpot.onKeydown = function(oEvent) {
|
||||||
switch(oEvent.which) {
|
switch(oEvent.which) {
|
||||||
case 27:
|
case 27:
|
||||||
if(!$('#lightboxOverlay').is(':visible')) toggleFeedPanel(false);
|
$bFeedPanelOpen = isFeedPanelOpen();
|
||||||
|
$bSettingsPanelOpen = isSettingsPanelOpen();
|
||||||
|
$bAnimation = ($bFeedPanelOpen && $bSettingsPanelOpen)?'none':null;
|
||||||
|
if($bFeedPanelOpen) toggleFeedPanel(false, $bAnimation);
|
||||||
|
if($bSettingsPanelOpen) toggleSettingsPanel(false, $bAnimation);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,12 +117,17 @@ function isFeedPanelOpen() {
|
|||||||
return self.tmp('$Projects').hasClass('with-feed');
|
return self.tmp('$Projects').hasClass('with-feed');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSettingsPanel(bShow) {
|
function toggleSettingsPanel(bShow, sMapAction) {
|
||||||
self.tmp('$Projects').toggleClass('with-settings', (typeof bShow === 'undefined')?null:bShow);
|
self.tmp('$Projects').toggleClass('with-settings', (typeof bShow === 'undefined')?null:bShow);
|
||||||
oSpot.onResize();
|
oSpot.onResize();
|
||||||
if(isMobile()) $('#post-button').toggle(!isSettingsPanelOpen());
|
if(isMobile()) $('#post-button').toggle(!isSettingsPanelOpen());
|
||||||
|
|
||||||
oSpot.tmp('map').panBy([(isSettingsPanelOpen()?-1:1)*self.tmp('$Settings').outerWidth(true)/2, 0], {duration: 0.5});
|
sMapAction = sMapAction || 'panTo';
|
||||||
|
switch(sMapAction) {
|
||||||
|
case 'none': break;
|
||||||
|
case 'panTo': oSpot.tmp('map').panBy([(isSettingsPanelOpen()?-1:1)*self.tmp('$Settings').outerWidth(true)/2, 0], {duration: 0.5}); break;
|
||||||
|
case 'panToInstant': oSpot.tmp('map').panBy([(isSettingsPanelOpen()?-1:1)*self.tmp('$Settings').outerWidth(true)/2, 0]); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSettingsPanelOpen() {
|
function isSettingsPanelOpen() {
|
||||||
@@ -174,16 +184,18 @@ function initPage(asHash) {
|
|||||||
|
|
||||||
//Post Panel one-off init (see initPosts for project related init)
|
//Post Panel one-off init (see initPosts for project related init)
|
||||||
//Scrollbar
|
//Scrollbar
|
||||||
self.tmp('simple-bar', new SimpleBar($('#posts')[0]));
|
self.tmp('simple-bar', new SimpleBar($('#feed-panel')[0]));
|
||||||
self.tmp('simple-bar').getScrollElement().addEventListener('scroll', onFeedScroll);
|
self.tmp('simple-bar').getScrollElement().addEventListener('scroll', onFeedScroll);
|
||||||
|
|
||||||
//Add "Loading" Post
|
//Add "Loading" Post
|
||||||
getPost({type: 'loading', headerless: true, formatted_time: '', relative_time: ''}).appendTo($('#loading'));
|
getPost({type: 'loading', headerless: true, formatted_time: '', relative_time: ''}).appendTo($('#loading'));
|
||||||
|
|
||||||
|
/*
|
||||||
//Mobile events
|
//Mobile events
|
||||||
$("#feed").onSwipe(function(aiDelta){
|
$("#feed").onSwipe(function(aiDelta){
|
||||||
if(aiDelta.x > self.tmp('$Feed').outerWidth(true)/3 && aiDelta.x > Math.abs(aiDelta.y)) toggleFeedPanel(false);
|
if(aiDelta.x > self.tmp('$Feed').outerWidth(true)/3 && aiDelta.x > Math.abs(aiDelta.y)) toggleFeedPanel(false);
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
//Feed Panel
|
//Feed Panel
|
||||||
initPosts();
|
initPosts();
|
||||||
@@ -257,7 +269,7 @@ function initPosts() {
|
|||||||
function()
|
function()
|
||||||
{
|
{
|
||||||
$('#post').val('');
|
$('#post').val('');
|
||||||
updateFeed(true);
|
onAutoUpdate();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id_project: self.vars(['project', 'id']),
|
id_project: self.vars(['project', 'id']),
|
||||||
@@ -331,11 +343,6 @@ function setUserInterface() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAutoUpdate(bStart) {
|
|
||||||
if(!bStart && self.tmp('simple-bar').getScrollElement().scrollTop == 0) updateFeed(true, true);
|
|
||||||
setFeedUpdateTimer(60, onAutoUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getElevWidth() {
|
function getElevWidth() {
|
||||||
var
|
var
|
||||||
iPageWidth = self.tmp('$Projects').width(),
|
iPageWidth = self.tmp('$Projects').width(),
|
||||||
@@ -518,28 +525,18 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Conversion of hours into natural language
|
//Conversion of hours into natural language
|
||||||
var iTimeMinutes = 0, iTimeHours = 0, iTimeDays = Math.floor(iTime/8); //8 hours a day
|
var sDuration = oSpot.getNaturalDuration(iTime);
|
||||||
if(iTimeDays > 1) iTimeDays = Math.round(iTimeDays * 2) / 2; //Round down to the closest half day
|
|
||||||
else {
|
|
||||||
iTimeDays = 0;
|
|
||||||
iTimeHours = Math.floor(iTime);
|
|
||||||
iTime -= iTimeHours;
|
|
||||||
|
|
||||||
iTimeMinutes = Math.floor(iTime * 4) * 15; //Round down to the closest 15 minutes
|
|
||||||
}
|
|
||||||
var sDuration = '~ '
|
|
||||||
+(iTimeDays>0?(iTimeDays+(iTimeDays%2==0?'':'½')+' '+oSpot.lang(iTimeDays>1?'unit_days':'unit_day')):'')//Days
|
|
||||||
+((iTimeHours>0 || iTimeDays==0)?iTimeHours+oSpot.lang('unit_hour'):'') //Hours
|
|
||||||
+((iTimeDays>0 || iTimeMinutes==0)?'':iTimeMinutes) //Minutes
|
|
||||||
|
|
||||||
//Tooltip details info
|
//Tooltip details info
|
||||||
$TooltipBody.append($('<div>', {'class':'separator'}));
|
$TooltipBody
|
||||||
var $TooltipDetails = $('<div>', {'class':'details'}).appendTo($TooltipBody);
|
.append($('<div>', {'class':'separator'}))
|
||||||
$('<p>', {'class':'detail'}).addIcon('fa-distance fa-fw', true).append(Math.round(iDistance/1000)+'km').appendTo($TooltipDetails);
|
.append($('<div>', {'class':'details'})
|
||||||
$('<p>', {'class':'detail'}).addIcon('fa-time fa-fw', true).append(sDuration).appendTo($TooltipDetails);
|
.append($('<p>', {'class':'detail'}).addIcon('fa-distance fa-fw', true).append(Math.round(iDistance/1000)+'km'))
|
||||||
$('<p>', {'class':'detail'}).addIcon('fa-elev-gain fa-fw', true).append(iElevGain+'m').appendTo($TooltipDetails);
|
.append($('<p>', {'class':'detail'}).addIcon('fa-time fa-fw', true).append(sDuration))
|
||||||
$('<p>', {'class':'detail'}).addIcon('fa-elev-drop fa-fw', true).append(iElevDrop+'m').appendTo($TooltipDetails);
|
.append($('<p>', {'class':'detail'}).addIcon('fa-elev-gain fa-fw', true).append(iElevGain+'m'))
|
||||||
|
.append($('<p>', {'class':'detail'}).addIcon('fa-elev-drop fa-fw', true).append(iElevDrop+'m'))
|
||||||
|
);
|
||||||
|
|
||||||
//Trail Start/End
|
//Trail Start/End
|
||||||
self.tmp(['trail-markers', asProperties.name], {
|
self.tmp(['trail-markers', asProperties.name], {
|
||||||
'start' : L.marker(new L.latLng(aiCoords[0][1], aiCoords[0][0]), {icon: getDivIcon('track-start')}),
|
'start' : L.marker(new L.latLng(aiCoords[0][1], aiCoords[0][0]), {icon: getDivIcon('track-start')}),
|
||||||
@@ -558,22 +555,43 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
}
|
}
|
||||||
}).addTo(oMap));
|
}).addTo(oMap));
|
||||||
|
|
||||||
|
//Last message
|
||||||
|
var oLastMsg = (aoMessages.length > 0)?aoMessages[aoMessages.length-1]:{};
|
||||||
|
|
||||||
//Centering map
|
//Centering map
|
||||||
var iPanelWidth = isMobile()?0:parseInt(self.tmp('$Feed').outerWidth(true));
|
var iPanelWidth = isMobile()?0:parseInt(self.tmp('$Feed').outerWidth(true));
|
||||||
if(
|
if(
|
||||||
self.vars(['project', 'mode']) == self.consts.modes.blog &&
|
self.vars(['project', 'mode']) == self.consts.modes.blog &&
|
||||||
aoMessages.length > 0 &&
|
!$.isEmptyObject(oLastMsg) &&
|
||||||
self.getHash()[2] != 'message'
|
self.getHash()[2] != 'message'
|
||||||
) {
|
) {
|
||||||
//Zoom on last message
|
//Zoom on last message
|
||||||
var oLastMsg = aoMessages[aoMessages.length-1];
|
|
||||||
oMap.setView(L.latLng(oLastMsg.latitude, oLastMsg.longitude), 15);
|
oMap.setView(L.latLng(oLastMsg.latitude, oLastMsg.longitude), 15);
|
||||||
oMap.panBy([iPanelWidth/2, 0]);
|
oMap.panBy([iPanelWidth/2, 0]);
|
||||||
}
|
}
|
||||||
else oMap.fitBounds(self.tmp('track').getBounds(), {paddingTopLeft: L.point(5, self.tmp('marker_size').height + 5), paddingBottomRight: L.point(5 + iPanelWidth, 5)});
|
else oMap.fitBounds(self.tmp('track').getBounds(), {paddingTopLeft: L.point(5, self.tmp('marker_size').height + 5), paddingBottomRight: L.point(5 + iPanelWidth, 5)});
|
||||||
|
|
||||||
|
//Add Spot messages
|
||||||
|
addSpotMessages(aoMessages);
|
||||||
|
|
||||||
|
//Open tooltip on latest message in mobile mode
|
||||||
|
if(
|
||||||
|
!$.isEmptyObject(oLastMsg) &&
|
||||||
|
self.vars(['project', 'mode']) == self.consts.modes.blog &&
|
||||||
|
(!oLastMsg.medias || oLastMsg.medias.length < 3) &&
|
||||||
|
isMobile()
|
||||||
|
) oSpot.tmp(['markers', oLastMsg.id_message]).openPopup();
|
||||||
|
|
||||||
|
/*
|
||||||
|
oSpot.tmp('tracks', aoTracks);
|
||||||
|
next(24, 0, 0, 5);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSpotMessages(aoMessages) {
|
||||||
|
|
||||||
//Spot Messages
|
//Spot Messages
|
||||||
var iWorkSpaceMinWidth = self.tmp('$Projects').width() - self.tmp('$Feed').outerWidth(true) - self.tmp('$Settings').outerWidth(true);
|
var iWorkSpaceMinWidth = isMobile()?self.tmp('$Projects').width():(self.tmp('$Projects').width() - self.tmp('$Feed').outerWidth(true) - self.tmp('$Settings').outerWidth(true));
|
||||||
$.each(aoMessages, function(iKey, oMsg){
|
$.each(aoMessages, function(iKey, oMsg){
|
||||||
|
|
||||||
//Marker
|
//Marker
|
||||||
@@ -581,7 +599,7 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
id: oMsg.id_message,
|
id: oMsg.id_message,
|
||||||
riseOnHover: true,
|
riseOnHover: true,
|
||||||
icon: getDivIcon('message-in fa-rotate-270')
|
icon: getDivIcon('message-in fa-rotate-270')
|
||||||
}).addTo(oMap);
|
}).addTo(self.tmp('map'));
|
||||||
|
|
||||||
//Tooltip
|
//Tooltip
|
||||||
$Tooltip = $('<div>', {'class':'info-window'})
|
$Tooltip = $('<div>', {'class':'info-window'})
|
||||||
@@ -621,21 +639,8 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
offset: new L.Point(0, -30)
|
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) &&
|
|
||||||
isMobile()
|
|
||||||
) oMarker.openPopup();
|
|
||||||
|
|
||||||
oSpot.tmp(['markers', oMsg.id_message], oMarker);
|
oSpot.tmp(['markers', oMsg.id_message], oMarker);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
oSpot.tmp('tracks', aoTracks);
|
|
||||||
next(24, 0, 0, 5);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSoftPopup(e, sMode) {
|
function toggleSoftPopup(e, sMode) {
|
||||||
@@ -662,44 +667,6 @@ function toggleSoftPopup(e, sMode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
function next(iCurrTrack, iCurrIndex, iCurrOffset, iCurrZoom) {
|
|
||||||
var aoTracks = oSpot.tmp('tracks');
|
|
||||||
var aoOffset = {0:[0,0], 1:[-1,0], 2:[-1,1], 3:[0,1], 4:[1,1], 5:[1,0], 6:[1,-1], 7:[0,-1], 8:[-1,-1]};
|
|
||||||
|
|
||||||
console.log('Getting Track '+iCurrTrack+'/'+(aoTracks.features.length - 1)+', '+
|
|
||||||
'Point '+iCurrIndex+'/'+(aoTracks.features[iCurrTrack].geometry.coordinates.length - 1)+', '+
|
|
||||||
'Zoom '+iCurrZoom+'/14, '+
|
|
||||||
'Offset ['+aoOffset[iCurrOffset][0]+','+aoOffset[iCurrOffset][1]+']');
|
|
||||||
|
|
||||||
//Position map
|
|
||||||
var iLat = aoTracks.features[iCurrTrack].geometry.coordinates[iCurrIndex][1] + aoOffset[iCurrOffset][1] * 0.0347910214271;
|
|
||||||
var iLng = aoTracks.features[iCurrTrack].geometry.coordinates[iCurrIndex][0] + aoOffset[iCurrOffset][0] * 0.1016235351560;
|
|
||||||
oSpot.tmp('map').setView(L.latLng(iLat, iLng), iCurrZoom);
|
|
||||||
|
|
||||||
//Go to next
|
|
||||||
iCurrOffset++;
|
|
||||||
if(iCurrZoom < 13 || iCurrOffset > 8) {
|
|
||||||
iCurrOffset = 0;
|
|
||||||
iCurrZoom++;
|
|
||||||
if(iCurrZoom > 14) {
|
|
||||||
iCurrZoom = 5;
|
|
||||||
iCurrIndex += 100;
|
|
||||||
if(!(iCurrIndex in aoTracks.features[iCurrTrack].geometry.coordinates)) {
|
|
||||||
iCurrIndex = 0;
|
|
||||||
iCurrTrack++;
|
|
||||||
if(!(iCurrTrack in aoTracks.features)) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timer = setTimeout(function(){next(iCurrTrack, iCurrIndex, iCurrOffset, iCurrZoom);}, 1000);
|
|
||||||
}
|
|
||||||
function stop() {
|
|
||||||
clearTimeout(timer);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getDivIcon(sIcon) {
|
function getDivIcon(sIcon) {
|
||||||
return L.divIcon({
|
return L.divIcon({
|
||||||
className: '',
|
className: '',
|
||||||
@@ -715,12 +682,50 @@ function onFeedScroll() {
|
|||||||
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) updateFeed();
|
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) updateFeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onAutoUpdate(bStart) {
|
||||||
|
bStart = bStart || false;
|
||||||
|
if(!bStart) checkNewFeed();
|
||||||
|
setFeedUpdateTimer(60, onAutoUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNewFeed() {
|
||||||
|
self.get(
|
||||||
|
'new_feed',
|
||||||
|
function(asData) {
|
||||||
|
var iItemCount = Object.keys(asData.feed).length;
|
||||||
|
if(iItemCount > 0) self.tmp('ref_id_first', asData.ref_id_first);
|
||||||
|
|
||||||
|
//Feed
|
||||||
|
var $Posts = $('<div>');
|
||||||
|
$.each(asData.feed, function(iKey, asPost) {
|
||||||
|
$Posts.append(getPost(asPost));
|
||||||
|
});
|
||||||
|
self.tmp('$PostList').prepend($Posts.children());
|
||||||
|
|
||||||
|
//Markers
|
||||||
|
addSpotMessages(asData.messages);
|
||||||
|
|
||||||
|
//Message Last Update
|
||||||
|
updateSettingsPanel(asData.last_update);
|
||||||
|
}, {
|
||||||
|
id_project: self.vars(['project', 'id']),
|
||||||
|
id: self.tmp('ref_id_first')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFeedUpdateTimer(iSeconds, fCallback) {
|
||||||
|
if(typeof self.tmp('update_timer') != 'undefined') clearTimeout(self.tmp('update_timer'));
|
||||||
|
if(iSeconds >= 0) self.tmp('update_timer', setTimeout(fCallback, iSeconds * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
function updateFeed(bFirstChunk, bDiscrete, fCallback) {
|
function updateFeed(bFirstChunk, bDiscrete, fCallback) {
|
||||||
bFirstChunk = bFirstChunk || false;
|
bFirstChunk = bFirstChunk || false;
|
||||||
bDiscrete = bDiscrete || false;
|
bDiscrete = bDiscrete || false;
|
||||||
fCallback = fCallback || function(){};
|
fCallback = fCallback || function(){};
|
||||||
|
|
||||||
if(bFirstChunk) self.tmp('ref_id', 0);
|
//First/Last Item displayed on the feed
|
||||||
|
if(bFirstChunk) self.tmp('ref_id_last', 0);
|
||||||
|
|
||||||
if(self.tmp('updatable')) {
|
if(self.tmp('updatable')) {
|
||||||
if(!self.tmp('out-of-data') || bFirstChunk) {
|
if(!self.tmp('out-of-data') || bFirstChunk) {
|
||||||
@@ -729,39 +734,36 @@ function updateFeed(bFirstChunk, bDiscrete, fCallback) {
|
|||||||
|
|
||||||
var $Posts = $('<div>');
|
var $Posts = $('<div>');
|
||||||
|
|
||||||
if(bFirstChunk===true) {
|
|
||||||
self.tmp('news_chunk', 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.get(
|
self.get(
|
||||||
'feed',
|
'next_feed',
|
||||||
function(asData) {
|
function(asData) {
|
||||||
$('#loading').hide();
|
$('#loading').hide();
|
||||||
|
var iItemCount = Object.keys(asData.feed).length;
|
||||||
|
|
||||||
|
//Update pointers
|
||||||
|
self.tmp('out-of-data', iItemCount < self.vars('chunk_size'));
|
||||||
|
if(iItemCount > 0) {
|
||||||
|
self.tmp('ref_id_last', asData.ref_id_last);
|
||||||
|
if(bFirstChunk === true) self.tmp('ref_id_first', asData.ref_id_first);
|
||||||
|
}
|
||||||
|
|
||||||
self.tmp('ref_id', asData.ref_id);
|
//Add posts
|
||||||
|
if(bFirstChunk === true) self.tmp('$PostList').empty();
|
||||||
$.each(asData.feed, function(iKey, asPost){
|
$.each(asData.feed, function(iKey, asPost){
|
||||||
$Posts.append(getPost(asPost));
|
$Posts.append(getPost(asPost));
|
||||||
});
|
});
|
||||||
|
|
||||||
self.tmp('news_chunk', self.tmp('news_chunk') + 1);
|
|
||||||
self.tmp('out-of-data', Object.keys(asData.feed).length != self.vars('chunk_size'));
|
|
||||||
|
|
||||||
if(bFirstChunk===true) self.tmp('$PostList').empty();
|
|
||||||
self.tmp('$PostList').append($Posts.children());
|
self.tmp('$PostList').append($Posts.children());
|
||||||
|
|
||||||
self.tmp('$PostList').find('img').waitForImages(true).done(fCallback);
|
self.tmp('$PostList').find('img').waitForImages(true).done(fCallback);
|
||||||
|
|
||||||
self.tmp('updatable', true);
|
self.tmp('updatable', true);
|
||||||
}, {
|
}, {
|
||||||
id_project: self.vars(['project', 'id']),
|
id_project: self.vars(['project', 'id']),
|
||||||
chunk: self.tmp('news_chunk'),
|
id: self.tmp('ref_id_last')
|
||||||
id: self.tmp('ref_id')
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(bFirstChunk) setFeedUpdateTimer(0.2);
|
else if(bFirstChunk) setFeedUpdateTimer(0.2, function(){updateFeed(bFirstChunk, bDiscrete, fCallback);});
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusOnPost(oFocusPost) {
|
function focusOnPost(oFocusPost) {
|
||||||
@@ -780,16 +782,10 @@ function focusOnPost(oFocusPost) {
|
|||||||
else console.log('Missing element ID '+sElemId);
|
else console.log('Missing element ID '+sElemId);
|
||||||
|
|
||||||
//Reset Hash
|
//Reset Hash
|
||||||
flushHash(['post', 'message']);
|
oSpot.flushHash(['post', 'message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFeedUpdateTimer(iSeconds, fCallback) {
|
|
||||||
fCallback = fCallback || function(){updateFeed(true);};
|
|
||||||
if(typeof self.tmp('update_timer') != 'undefined') clearTimeout(self.tmp('update_timer'));
|
|
||||||
if(iSeconds > 0) self.tmp('update_timer', setTimeout(fCallback, iSeconds * 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPost(asPost) {
|
function getPost(asPost) {
|
||||||
asPost.headerless = asPost.headerless || false;
|
asPost.headerless = asPost.headerless || false;
|
||||||
var bLink = false;
|
var bLink = false;
|
||||||
@@ -946,17 +942,41 @@ function getGoogleMapsLink(asInfo) {
|
|||||||
}).text(asInfo.lat_dms+' '+asInfo.lon_dms);
|
}).text(asInfo.lat_dms+' '+asInfo.lon_dms);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHash(sType, iId) {
|
/*
|
||||||
sType = sType || '';
|
function next(iCurrTrack, iCurrIndex, iCurrOffset, iCurrZoom) {
|
||||||
iId = iId || 0;
|
var aoTracks = oSpot.tmp('tracks');
|
||||||
|
var aoOffset = {0:[0,0], 1:[-1,0], 2:[-1,1], 3:[0,1], 4:[1,1], 5:[1,0], 6:[1,-1], 7:[0,-1], 8:[-1,-1]};
|
||||||
|
|
||||||
var asHash = self.getHash();
|
console.log('Getting Track '+iCurrTrack+'/'+(aoTracks.features.length - 1)+', '+
|
||||||
if(iId) self.setHash(asHash.page, [asHash.items[0], sType, iId]);
|
'Point '+iCurrIndex+'/'+(aoTracks.features[iCurrTrack].geometry.coordinates.length - 1)+', '+
|
||||||
}
|
'Zoom '+iCurrZoom+'/14, '+
|
||||||
|
'Offset ['+aoOffset[iCurrOffset][0]+','+aoOffset[iCurrOffset][1]+']');
|
||||||
|
|
||||||
function flushHash(asTypes) {
|
//Position map
|
||||||
asTypes = asTypes || [];
|
var iLat = aoTracks.features[iCurrTrack].geometry.coordinates[iCurrIndex][1] + aoOffset[iCurrOffset][1] * 0.0347910214271;
|
||||||
var asHash = self.getHash();
|
var iLng = aoTracks.features[iCurrTrack].geometry.coordinates[iCurrIndex][0] + aoOffset[iCurrOffset][0] * 0.1016235351560;
|
||||||
if(asHash.items.length > 1 && (asTypes.length == 0 || asTypes.indexOf(asHash.items[1]) != -1)) self.setHash(asHash.page, [asHash.items[0]]);
|
oSpot.tmp('map').setView(L.latLng(iLat, iLng), iCurrZoom);
|
||||||
|
|
||||||
|
//Go to next
|
||||||
|
iCurrOffset++;
|
||||||
|
if(iCurrZoom < 13 || iCurrOffset > 8) {
|
||||||
|
iCurrOffset = 0;
|
||||||
|
iCurrZoom++;
|
||||||
|
if(iCurrZoom > 14) {
|
||||||
|
iCurrZoom = 5;
|
||||||
|
iCurrIndex += 100;
|
||||||
|
if(!(iCurrIndex in aoTracks.features[iCurrTrack].geometry.coordinates)) {
|
||||||
|
iCurrIndex = 0;
|
||||||
|
iCurrTrack++;
|
||||||
|
if(!(iCurrTrack in aoTracks.features)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timer = setTimeout(function(){next(iCurrTrack, iCurrIndex, iCurrOffset, iCurrZoom);}, 1000);
|
||||||
}
|
}
|
||||||
</script>
|
function stop() {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
@@ -25,3 +25,5 @@
|
|||||||
* Add mail frequency slider
|
* Add mail frequency slider
|
||||||
* Use WMTS servers directly when not using Geo Caching Server
|
* Use WMTS servers directly when not using Geo Caching Server
|
||||||
* Allow HEIF picture format
|
* Allow HEIF picture format
|
||||||
|
* Meteo on message
|
||||||
|
* pbf map format (https://www.arcgis.com/home/item.html?id=7dc6cea0b1764a1f9af2e679f642f0f5)
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
return {maxWidth: iMaxMediaWidth, maxHeight: iMaxMediaHeight, direction: sDirection};
|
return {maxWidth: iMaxMediaWidth, maxHeight: iMaxMediaHeight, direction: sDirection};
|
||||||
};
|
};
|
||||||
|
|
||||||
updateHash('media', self.album[imageNumber].id);
|
oSpot.updateHash('media', self.album[imageNumber].id);
|
||||||
|
|
||||||
if(self.options.hasVideo) {
|
if(self.options.hasVideo) {
|
||||||
var $lbContainer = this.$lightbox.find('.lb-container');
|
var $lbContainer = this.$lightbox.find('.lb-container');
|
||||||
@@ -585,7 +585,10 @@
|
|||||||
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.
|
||||||
self.$overlay.focus();
|
//ADDED-START
|
||||||
|
//self.$overlay.focus();
|
||||||
|
self.$overlay.trigger( 'focus' );
|
||||||
|
//ADDED-END
|
||||||
|
|
||||||
self.showImage();
|
self.showImage();
|
||||||
}
|
}
|
||||||
@@ -704,6 +707,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Lightbox.prototype.enableKeyboardNav = function() {
|
Lightbox.prototype.enableKeyboardNav = function() {
|
||||||
|
//ADDED-START
|
||||||
|
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));
|
||||||
};
|
};
|
||||||
@@ -750,7 +756,7 @@
|
|||||||
|
|
||||||
if($hasVideoNav) $lbContainer.removeClass('lb-video-nav');
|
if($hasVideoNav) $lbContainer.removeClass('lb-video-nav');
|
||||||
}
|
}
|
||||||
flushHash();
|
oSpot.flushHash();
|
||||||
//ADDED-END
|
//ADDED-END
|
||||||
|
|
||||||
$(window).off('resize', this.sizeOverlay);
|
$(window).off('resize', this.sizeOverlay);
|
||||||
|
|||||||
@@ -149,6 +149,20 @@ function Spot(asGlobals)
|
|||||||
if(bReboot) location.reload();
|
if(bReboot) location.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.updateHash = function(sType, iId) {
|
||||||
|
sType = sType || '';
|
||||||
|
iId = iId || 0;
|
||||||
|
|
||||||
|
var asHash = self.getHash();
|
||||||
|
if(iId) self.setHash(asHash.page, [asHash.items[0], sType, iId]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.flushHash = function(asTypes) {
|
||||||
|
asTypes = asTypes || [];
|
||||||
|
var asHash = self.getHash();
|
||||||
|
if(asHash.items.length > 1 && (asTypes.length == 0 || asTypes.indexOf(asHash.items[1]) != -1)) self.setHash(asHash.page, [asHash.items[0]]);
|
||||||
|
};
|
||||||
|
|
||||||
/* Page Switch - DOM Replacement */
|
/* Page Switch - DOM Replacement */
|
||||||
|
|
||||||
this.getActionLink = function(sAction, oVars)
|
this.getActionLink = function(sAction, oVars)
|
||||||
@@ -227,6 +241,23 @@ function Spot(asGlobals)
|
|||||||
var $FadeInElem = bFirstPage?self.elem.container:self.elem.main;
|
var $FadeInElem = bFirstPage?self.elem.container:self.elem.main;
|
||||||
$FadeInElem.hide().fadeTo('slow', 1);
|
$FadeInElem.hide().fadeTo('slow', 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getNaturalDuration = function(iHours) {
|
||||||
|
var iTimeMinutes = 0, iTimeHours = 0, iTimeDays = Math.floor(iHours/8); //8 hours a day
|
||||||
|
if(iTimeDays > 1) iTimeDays = Math.round(iTimeDays * 2) / 2; //Round down to the closest half day
|
||||||
|
else {
|
||||||
|
iTimeDays = 0;
|
||||||
|
iTimeHours = Math.floor(iHours);
|
||||||
|
iHours -= iTimeHours;
|
||||||
|
|
||||||
|
iTimeMinutes = Math.floor(iHours * 4) * 15; //Round down to the closest 15 minutes
|
||||||
|
}
|
||||||
|
return '~ '
|
||||||
|
+(iTimeDays>0?(iTimeDays+(iTimeDays%2==0?'':'½')+' '+oSpot.lang(iTimeDays>1?'unit_days':'unit_day')):'')//Days
|
||||||
|
+((iTimeHours>0 || iTimeDays==0)?iTimeHours+oSpot.lang('unit_hour'):'') //Hours
|
||||||
|
+((iTimeDays>0 || iTimeMinutes==0)?'':iTimeMinutes) //Minutes
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common Functions */
|
/* Common Functions */
|
||||||
|
|||||||
@@ -62,6 +62,10 @@
|
|||||||
|
|
||||||
/* Common objects */
|
/* Common objects */
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
body, textarea, input, button {
|
body, textarea, input, button {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Ubuntu', sans-serif;
|
font-family: 'Ubuntu', sans-serif;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ $stroke-width-axis : 2;
|
|||||||
.fa, .heightgraph-toggle-icon {
|
.fa, .heightgraph-toggle-icon {
|
||||||
@extend .control-icon;
|
@extend .control-icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Leaflet Heightgraph fixes */
|
/* Leaflet Heightgraph fixes */
|
||||||
|
|||||||
@@ -27,33 +27,29 @@ $legend-color: $post-color;
|
|||||||
|
|
||||||
#projects {
|
#projects {
|
||||||
|
|
||||||
|
/* Panels movements */
|
||||||
&.with-feed {
|
&.with-feed {
|
||||||
#submap {
|
#submap {
|
||||||
width: calc(100% - #{$panel-width});
|
width: calc(100% - #{$panel-width});
|
||||||
min-width: calc(100% - #{$panel-width-max});
|
min-width: calc(100% - #{$panel-width-max});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#feed {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.leaflet-right {
|
.leaflet-right {
|
||||||
width: $panel-width;
|
width: $panel-width;
|
||||||
max-width: calc(#{$panel-width-max});
|
max-width: calc(#{$panel-width-max});
|
||||||
}
|
}
|
||||||
|
|
||||||
#feed {
|
|
||||||
z-index: 999;
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#post-button {
|
#post-button {
|
||||||
.fa {
|
.fa {
|
||||||
@extend .fa-next;
|
@extend .fa-next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:not(.with-feed) {
|
|
||||||
#feed #posts {
|
|
||||||
right: -100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.with-settings {
|
&.with-settings {
|
||||||
#submap {
|
#submap {
|
||||||
width: calc(100% - #{$panel-width});
|
width: calc(100% - #{$panel-width});
|
||||||
@@ -66,8 +62,7 @@ $legend-color: $post-color;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#settings {
|
#settings {
|
||||||
z-index: 999;
|
left: 0;
|
||||||
transition: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#settings-button {
|
#settings-button {
|
||||||
@@ -76,11 +71,7 @@ $legend-color: $post-color;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:not(.with-settings) {
|
|
||||||
#settings #settings-panel {
|
|
||||||
left: -100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.with-feed.with-settings {
|
&.with-feed.with-settings {
|
||||||
#submap {
|
#submap {
|
||||||
width: calc(100% - #{$panel-width} * 2);
|
width: calc(100% - #{$panel-width} * 2);
|
||||||
@@ -88,6 +79,15 @@ $legend-color: $post-color;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#background {
|
||||||
|
background: #666;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#submap {
|
#submap {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -239,7 +239,7 @@ $legend-color: $post-color;
|
|||||||
|
|
||||||
/* Pull right/left controls by $panel-width */
|
/* Pull right/left controls by $panel-width */
|
||||||
.leaflet-right, .leaflet-left {
|
.leaflet-right, .leaflet-left {
|
||||||
transition: all 0.5s;
|
transition: width 0.5s, max-width 0.5s, left 0.5s, right 0.5s;
|
||||||
width: 0;
|
width: 0;
|
||||||
max-width: 0;
|
max-width: 0;
|
||||||
}
|
}
|
||||||
@@ -340,11 +340,8 @@ $legend-color: $post-color;
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: -1;
|
|
||||||
transition-property: z-index;
|
|
||||||
transition-duration: 0.1s;
|
|
||||||
transition-delay: 0.5s;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
input, textarea {
|
input, textarea {
|
||||||
background-color: $post-input-bg;
|
background-color: $post-input-bg;
|
||||||
@@ -360,20 +357,23 @@ $legend-color: $post-color;
|
|||||||
color: $post-color;
|
color: $post-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#feed-panel, #settings-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#feed {
|
#feed {
|
||||||
right: 0;
|
right: calc(min(#{$panel-width}, #{$panel-width-max}) * -1);
|
||||||
|
transition: right 0.5s;
|
||||||
width: #{$panel-width};
|
width: #{$panel-width};
|
||||||
max-width: calc(#{$panel-width-max});
|
max-width: calc(#{$panel-width-max});
|
||||||
|
|
||||||
#posts {
|
#feed-panel {
|
||||||
position: absolute;
|
|
||||||
transition: all 0.5s;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
#posts_list {
|
#posts_list {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -589,7 +589,7 @@ $legend-color: $post-color;
|
|||||||
text-align: justify;
|
text-align: justify;
|
||||||
background: rgba(255, 255, 255, 0.6);
|
background: rgba(255, 255, 255, 0.6);
|
||||||
border-radius: 0 0 3px 3px;
|
border-radius: 0 0 3px 3px;
|
||||||
transition: all 0.3s;
|
transition: opacity 0.3s;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,7 +611,8 @@ $legend-color: $post-color;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#settings {
|
#settings {
|
||||||
left: 0;
|
left: calc(min(#{$panel-width} + 3px, #{$panel-width-max} + 3px) * -1);
|
||||||
|
transition: left 0.5s;
|
||||||
width: calc(#{$panel-width} + 3px); //Add box-shadow
|
width: calc(#{$panel-width} + 3px); //Add box-shadow
|
||||||
max-width: calc(#{$panel-width-max} + 3px); //Add box-shadow
|
max-width: calc(#{$panel-width-max} + 3px); //Add box-shadow
|
||||||
|
|
||||||
@@ -620,11 +621,6 @@ $legend-color: $post-color;
|
|||||||
margin: $block-spacing;
|
margin: $block-spacing;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, .5);
|
box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, .5);
|
||||||
position: absolute;
|
|
||||||
transition: all 0.5s;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
color: $post-color;
|
color: $post-color;
|
||||||
background: rgba(255, 255, 255, 0.8);
|
background: rgba(255, 255, 255, 0.8);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -29,6 +29,14 @@
|
|||||||
#feed, #settings {
|
#feed, #settings {
|
||||||
width: calc(100% - 44px - 2 * #{$block-spacing});
|
width: calc(100% - 44px - 2 * #{$block-spacing});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#feed {
|
||||||
|
right: calc((100% - 44px - 2 * #{$block-spacing}) * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#settings {
|
||||||
|
left: calc((100% - 44px - 2 * #{$block-spacing}) * -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user