Fix media marker popup
This commit is contained in:
51
lib/Spot.php
51
lib/Spot.php
@@ -275,33 +275,38 @@ class Spot extends Main
|
|||||||
|
|
||||||
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
|
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
|
||||||
{
|
{
|
||||||
|
//Get messages
|
||||||
$asMessages = $this->getSpotMessages($asMessageIds);
|
$asMessages = $this->getSpotMessages($asMessageIds);
|
||||||
$asGeoMedias = array();
|
|
||||||
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
|
||||||
$bHasMsg = !empty($asMessages);
|
|
||||||
|
|
||||||
foreach($asMessages as &$asMessage) {
|
foreach($asMessages as &$asMessage) {
|
||||||
$asMessage['id'] = $asMessage[Db::getId(Feed::MSG_TABLE)];
|
$asMessage['id'] = $asMessage[Db::getId(Feed::MSG_TABLE)];
|
||||||
$asMessage['type'] = 'message';
|
$asMessage['type'] = 'message';
|
||||||
$asMessage['subtype'] = 'message';
|
$asMessage['subtype'] = 'message';
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add medias
|
//Get Geo-positioned Medias
|
||||||
$asMedias = $this->getMedias('taken_on', $asMediaIds);
|
$asMedias = $this->getMedias('taken_on', $asMediaIds);
|
||||||
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
$asGeoMedias = $this->getMedias('posted_on', $asMediaIds, true);
|
||||||
|
foreach($asGeoMedias as &$asGeoMedia) {
|
||||||
|
$iId = $asGeoMedia[Db::getId(Media::MEDIA_TABLE)];
|
||||||
|
unset($asGeoMedia[Db::getId(Media::MEDIA_TABLE)]);
|
||||||
|
|
||||||
|
$asGeoMedia['id'] = $iId;
|
||||||
|
$asGeoMedia['type'] = 'media';
|
||||||
|
$asGeoMedia['lat_dms'] = self::decToDms($asGeoMedia['latitude'], 'lat');
|
||||||
|
$asGeoMedia['lon_dms'] = self::decToDms($asGeoMedia['longitude'], 'lon');
|
||||||
|
$asGeoMedia['medias'] = array_values(array_filter($asMedias, function($asMedia) use ($iId) {
|
||||||
|
return $asMedia['id_media'] == $iId;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
//Assign medias to closest message
|
//Assign medias to closest message
|
||||||
|
if(!empty($asMessages)) {
|
||||||
|
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||||
|
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||||
|
|
||||||
$iIndex = 0;
|
$iIndex = 0;
|
||||||
$iMaxIndex = count($asMessages) - 1;
|
$iMaxIndex = count($asMessages) - 1;
|
||||||
foreach($asMedias as $asMedia) {
|
foreach($asMedias as $asMedia) {
|
||||||
if($asMedia['latitude']!='' && $asMedia['longitude']!='') {
|
|
||||||
$asMedia['id'] = $asMedia[Db::getId(Media::MEDIA_TABLE)];
|
|
||||||
$asMedia['type'] = 'media';
|
|
||||||
$asMedia['lat_dms'] = self::decToDms($asMedia['latitude'], 'lat');
|
|
||||||
$asMedia['lon_dms'] = self::decToDms($asMedia['longitude'], 'lon');
|
|
||||||
$asGeoMedias[] = $asMedia;
|
|
||||||
}
|
|
||||||
if($bHasMsg) {
|
|
||||||
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) $iIndex++;
|
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) $iIndex++;
|
||||||
|
|
||||||
//All medias before first message or after last message are assigned to first/last message respectively
|
//All medias before first message or after last message are assigned to first/last message respectively
|
||||||
@@ -316,6 +321,7 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Combine markers
|
||||||
$asMarkers = [...$asMessages, ...$asGeoMedias];
|
$asMarkers = [...$asMessages, ...$asGeoMedias];
|
||||||
usort($asMarkers, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
usort($asMarkers, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||||
|
|
||||||
@@ -400,13 +406,19 @@ class Spot extends Main
|
|||||||
* @param String $sTimeRefField Field to calculate relative times: 'taken_on' or 'posted_on'
|
* @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, $asMediaIds=array())
|
private function getMedias($sTimeRefField, $asMediaIds=array(), $bOnlyGeoMedia=false)
|
||||||
{
|
{
|
||||||
//Constraints
|
//Constraints
|
||||||
$asConstraints = $this->getFeedConstraints(Media::MEDIA_TABLE, $sTimeRefField);
|
$asConstraints = $this->getFeedConstraints(Media::MEDIA_TABLE, $sTimeRefField);
|
||||||
if(!empty($asMediaIds)) {
|
if(!empty($asMediaIds)) {
|
||||||
$asConstraints['constraint'][Db::getId(Media::MEDIA_TABLE)] = $asMediaIds;
|
|
||||||
$asConstraints['constOpe'][Db::getId(Media::MEDIA_TABLE)] = 'IN';
|
$asConstraints['constOpe'][Db::getId(Media::MEDIA_TABLE)] = 'IN';
|
||||||
|
$asConstraints['constraint'][Db::getId(Media::MEDIA_TABLE)] = $asMediaIds;
|
||||||
|
}
|
||||||
|
if($bOnlyGeoMedia) {
|
||||||
|
$asConstraints['constOpe']['latitude'] = ' IS NOT ';
|
||||||
|
$asConstraints['constraint']['latitude'] = 'NULL';
|
||||||
|
$asConstraints['constOpe']['longitude'] = ' IS NOT ';
|
||||||
|
$asConstraints['constraint']['longitude'] = 'NULL';
|
||||||
}
|
}
|
||||||
|
|
||||||
$asMedias = $this->oMedia->getMediasInfo($asConstraints);
|
$asMedias = $this->oMedia->getMediasInfo($asConstraints);
|
||||||
@@ -550,7 +562,6 @@ class Spot extends Main
|
|||||||
$this->oDb->cleanSql($sDirection);
|
$this->oDb->cleanSql($sDirection);
|
||||||
$this->oDb->cleanSql($sSort);
|
$this->oDb->cleanSql($sSort);
|
||||||
|
|
||||||
$sMediaRefField = 'posted_on';
|
|
||||||
$sProjectIdField = Db::getId(Project::PROJ_TABLE);
|
$sProjectIdField = Db::getId(Project::PROJ_TABLE);
|
||||||
$sMsgIdField = Db::getId(Feed::MSG_TABLE);
|
$sMsgIdField = Db::getId(Feed::MSG_TABLE);
|
||||||
$sMediaIdField = Db::getId(Media::MEDIA_TABLE);
|
$sMediaIdField = Db::getId(Media::MEDIA_TABLE);
|
||||||
@@ -564,9 +575,9 @@ class Spot extends Main
|
|||||||
"INNER JOIN ".Feed::FEED_TABLE." USING({$sFeedIdField})",
|
"INNER JOIN ".Feed::FEED_TABLE." USING({$sFeedIdField})",
|
||||||
$this->getFeedConstraints(Feed::MSG_TABLE, 'site_time', 'sql'),
|
$this->getFeedConstraints(Feed::MSG_TABLE, 'site_time', 'sql'),
|
||||||
"UNION",
|
"UNION",
|
||||||
"SELECT {$sProjectIdField}, {$sMediaIdField} AS id, 'media' AS type, CONCAT(UNIX_TIMESTAMP({$sMediaRefField}), '.1', {$sMediaIdField}) AS ref",
|
"SELECT {$sProjectIdField}, {$sMediaIdField} AS id, 'media' AS type, CONCAT(UNIX_TIMESTAMP(posted_on), '.1', {$sMediaIdField}) AS ref",
|
||||||
"FROM ".Media::MEDIA_TABLE,
|
"FROM ".Media::MEDIA_TABLE,
|
||||||
$this->getFeedConstraints(Media::MEDIA_TABLE, $sMediaRefField, 'sql'),
|
$this->getFeedConstraints(Media::MEDIA_TABLE, 'posted_on', 'sql'),
|
||||||
"UNION",
|
"UNION",
|
||||||
"SELECT {$sProjectIdField}, {$sPostIdField} AS id, 'post' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.2', {$sPostIdField}) AS ref",
|
"SELECT {$sProjectIdField}, {$sPostIdField} AS id, 'post' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.2', {$sPostIdField}) AS ref",
|
||||||
"FROM ".self::POST_TABLE,
|
"FROM ".self::POST_TABLE,
|
||||||
@@ -594,7 +605,7 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
$asFeedAttrs = array(
|
$asFeedAttrs = array(
|
||||||
'message' => empty($asFeedIds['message'])?array():$this->getSpotMessages(array_keys($asFeedIds['message'])),
|
'message' => empty($asFeedIds['message'])?array():$this->getSpotMessages(array_keys($asFeedIds['message'])),
|
||||||
'media' => empty($asFeedIds['media'])?array():$this->getMedias($sMediaRefField, array_keys($asFeedIds['media'])),
|
'media' => empty($asFeedIds['media'])?array():$this->getMedias('posted_on', array_keys($asFeedIds['media'])),
|
||||||
'post' => empty($asFeedIds['post'])?array():$this->getPosts(array_keys($asFeedIds['post']))
|
'post' => empty($asFeedIds['post'])?array():$this->getPosts(array_keys($asFeedIds['post']))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export default {
|
|||||||
settingsPanelOpen: false,
|
settingsPanelOpen: false,
|
||||||
track: null,
|
track: null,
|
||||||
markers: [],
|
markers: [],
|
||||||
markerSize: {width: 32, height: 32},
|
|
||||||
markerProps: {
|
markerProps: {
|
||||||
image: {mainClasses: 'media', iconMain: 'marker', iconSub: 'image'},
|
image: {mainClasses: 'media', iconMain: 'marker', iconSub: 'image'},
|
||||||
video: {mainClasses: 'media', iconMain: 'marker', iconSub: 'video'},
|
video: {mainClasses: 'media', iconMain: 'marker', iconSub: 'video'},
|
||||||
@@ -304,12 +303,12 @@ export default {
|
|||||||
this.closePopup();
|
this.closePopup();
|
||||||
let oMarker = this.markers.find((oCandidate) => oCandidate.id == iMarkerId && oCandidate.type == sMarkerType);
|
let oMarker = this.markers.find((oCandidate) => oCandidate.id == iMarkerId && oCandidate.type == sMarkerType);
|
||||||
this.openPopup({
|
this.openPopup({
|
||||||
offset: [0, this.markerSize.height * -1], //FIXME
|
|
||||||
lnglat: [oMarker.longitude, oMarker.latitude],
|
lnglat: [oMarker.longitude, oMarker.latitude],
|
||||||
options: oMarker
|
options: oMarker,
|
||||||
|
offset: [0, -32] //FIXME
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
openPopup({offset=[0, 0], lnglat, options={}} = {}) {
|
openPopup({lnglat, options={}, offset=[0, 0]} = {}) {
|
||||||
const $Popup = document.createElement('div');
|
const $Popup = document.createElement('div');
|
||||||
this.popup.element = new Popup({
|
this.popup.element = new Popup({
|
||||||
anchor: 'bottom',
|
anchor: 'bottom',
|
||||||
|
|||||||
@@ -17,11 +17,27 @@ export default {
|
|||||||
},
|
},
|
||||||
inject: ['lang', 'consts'],
|
inject: ['lang', 'consts'],
|
||||||
computed: {
|
computed: {
|
||||||
timeIcon() {
|
timeinfo() {
|
||||||
return (this.options.type == 'media')?'image-shot':'time';
|
return (this.options.type == 'media')?
|
||||||
|
{
|
||||||
|
icon: 'image-shot',
|
||||||
|
local_time: this.options.taken_on_formatted_time_local,
|
||||||
|
site_time: this.options.taken_on_formatted_time,
|
||||||
|
offset: this.options.taken_on_day_offset,
|
||||||
|
relative_time: this.options.taken_on_relative_time
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
icon: 'time',
|
||||||
|
local_time: this.options.formatted_time_local,
|
||||||
|
site_time: this.options.formatted_time,
|
||||||
|
offset: this.options.day_offset,
|
||||||
|
relative_time: this.options.relative_time
|
||||||
|
};
|
||||||
},
|
},
|
||||||
medias() {
|
localTime() {
|
||||||
return (this.options.type == 'media')?[this.options]:this.options?.medias;
|
return this.timeinfo.local_time +
|
||||||
|
((this.project.mode == this.consts.modes.blog)?' (' + this.timeinfo.relative_time + ')':'')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,16 +69,15 @@ export default {
|
|||||||
<spotIcon :icon="'altitude'" width="fixed" size="lg" :text="options.altitude+'m'" />
|
<spotIcon :icon="'altitude'" width="fixed" size="lg" :text="options.altitude+'m'" />
|
||||||
</div>
|
</div>
|
||||||
<div class="section time">
|
<div class="section time">
|
||||||
<projectRelTime :icon="timeIcon" :localTime="options.formatted_time_local" :siteTime="options.formatted_time" :offset="options.day_offset" />
|
<projectRelTime :icon="timeinfo.icon" :localTime="localTime" :siteTime="timeinfo.site_time" :offset="timeinfo.offset" />
|
||||||
<span v-if="project.mode==consts.modes.blog"> ({{ options.relative_time }})</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="section weather" v-if="options.weather_icon && options.weather_icon!='unknown'" :title="options.weather_cond==''?'':lang.get('weather.'+options.weather_icon)">
|
<div class="section weather" v-if="options.weather_icon && options.weather_icon!='unknown'" :title="options.weather_cond==''?'':lang.get('weather.'+options.weather_icon)">
|
||||||
<spotIcon :icon="options.weather_icon" width="fixed" size="lg" :text="options.weather_temp+'°C'" />
|
<spotIcon :icon="options.weather_icon" width="fixed" size="lg" :text="options.weather_temp+'°C'" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="medias" class="section medias">
|
<div v-if="options.medias" class="section medias">
|
||||||
<spotIcon v-if="options.type=='message'" icon="media" width="fixed" size="lg" :text="lang.get('media.nearby')" />
|
<spotIcon v-if="options.type=='message'" icon="media" width="fixed" size="lg" :text="lang.get('media.nearby')" />
|
||||||
<div class="medias-list">
|
<div class="medias-list">
|
||||||
<projectMediaLink v-for="media in medias" :options="media" :type="'marker'" />
|
<projectMediaLink v-for="media in options?.medias" :options="media" :type="'marker'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
transform: String
|
transform: String
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
classNames() {
|
iconClassNames() {
|
||||||
return [
|
return [
|
||||||
'spot-icon',
|
'spot-icon',
|
||||||
this.icon,
|
this.icon,
|
||||||
@@ -49,23 +49,37 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span :title="title" v-if="title || hasText" class="spot-icon-box">
|
<span :title="title" :class="hasText?'spot-icon-with-text':null">
|
||||||
<FontAwesomeIcon :icon="iconDefinition" :class="classNames" :fixed-width="resolvedFixedWidth" :width-auto="resolvedAutoWidth" :size="resolvedSize" :transform="resolvedTransform" />
|
<span class="spot-icon-symbol">
|
||||||
<span v-if="hasText" :class="textClasses">{{ text }}</span>
|
<FontAwesomeIcon
|
||||||
|
:icon="iconDefinition"
|
||||||
|
:class="['spot-icon', this.icon, this.classes, this.margin?'margin-'+this.margin:null]"
|
||||||
|
:fixed-width="resolvedFixedWidth"
|
||||||
|
:width-auto="resolvedAutoWidth"
|
||||||
|
:size="resolvedSize"
|
||||||
|
:transform="resolvedTransform"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span v-if="hasText" :class="['spot-icon-text', textClasses]">{{ text }}</span>
|
||||||
</span>
|
</span>
|
||||||
<FontAwesomeIcon v-else :icon="iconDefinition" :class="classNames" :fixed-width="resolvedFixedWidth" :width-auto="resolvedAutoWidth" :size="resolvedSize" :transform="resolvedTransform" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
@use "@styles/var";
|
@use "@styles/var";
|
||||||
|
|
||||||
.spot-icon-box {
|
.spot-icon-with-text {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
|
align-items: flex-start;
|
||||||
gap: var.$elem-spacing;
|
gap: var.$elem-spacing;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
.spot-icon-symbol {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spot-icon-text {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,6 +178,9 @@
|
|||||||
top: var.$block-spacing;
|
top: var.$block-spacing;
|
||||||
right: var.$block-spacing;
|
right: var.$block-spacing;
|
||||||
|
|
||||||
|
.spot-icon-with-text {
|
||||||
|
gap: 0;
|
||||||
|
|
||||||
.spot-icon {
|
.spot-icon {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@@ -186,7 +189,6 @@
|
|||||||
color: color.$message-bg;
|
color: color.$message-bg;
|
||||||
border-radius: var.$block-radius 0 0 var.$block-radius;
|
border-radius: var.$block-radius 0 0 var.$block-radius;
|
||||||
padding: var.$elem-spacing;
|
padding: var.$elem-spacing;
|
||||||
margin-right: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.temperature {
|
.temperature {
|
||||||
@@ -199,6 +201,7 @@
|
|||||||
border-radius: 0 var.$block-radius var.$block-radius 0;
|
border-radius: 0 var.$block-radius var.$block-radius 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.staticmap {
|
.staticmap {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ $thumbnail-max-size: 60px;
|
|||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.maplibregl-popup-tip {
|
||||||
|
border-top-color: color.$default-bg-light;
|
||||||
|
}
|
||||||
|
|
||||||
.maplibregl-popup-content {
|
.maplibregl-popup-content {
|
||||||
padding: var.$block-spacing;
|
padding: var.$block-spacing;
|
||||||
background-color: color.$default-bg-light;
|
background-color: color.$default-bg-light;
|
||||||
|
|||||||
Reference in New Issue
Block a user