Refresh lightbox album when getting new feed

This commit is contained in:
2026-05-09 12:18:45 +02:00
parent 3c8cdbaad6
commit 1852f6640e
3 changed files with 139 additions and 150 deletions

View File

@@ -129,9 +129,16 @@ export default {
positionFromTop: 0, positionFromTop: 0,
resizeDuration: 400, resizeDuration: 400,
hasVideo: true, hasVideo: true,
onMediaChange: (oMedia) => { onMediaChange: async (oMedia) => {
this.hash.items = [this.currProject.codename, 'media', oMedia.id]; this.hash.items = [this.currProject.codename, 'media', oMedia.id];
if(oMedia.set == 'post-medias') this.goToPost('media', oMedia.id)?.panMapToMarker(); if(oMedia.set == 'post-medias') {
this.goToPost('media', oMedia.id)?.panMapToMarker();
if(!this.lightbox.hasMediaAfterCurrent()) {
await this.getNextFeed();
await this.$nextTick();
this.lightbox.refreshAlbum();
}
}
}, },
onClosing: () => {this.hash.items = [this.hash.items[0]];} onClosing: () => {this.hash.items = [this.hash.items[0]];}
}); });
@@ -464,6 +471,10 @@ export default {
const iXOffset = (this.settingsPanelOpen?getOuterWidth(this.$refs.settings):0) - (this.feedPanelOpen?getOuterWidth(this.$refs.feed):0); const iXOffset = (this.settingsPanelOpen?getOuterWidth(this.$refs.settings):0) - (this.feedPanelOpen?getOuterWidth(this.$refs.feed):0);
return new Promise((resolve) => { return new Promise((resolve) => {
if(!this.map) {
resolve();
return;
}
this.map.once('moveend', resolve); this.map.once('moveend', resolve);
this.map.easeTo({ this.map.easeTo({
center: oLngLat, center: oLngLat,
@@ -474,7 +485,7 @@ export default {
}); });
}, },
isMarkerVisible(oLngLat){ isMarkerVisible(oLngLat){
return this.map.getBounds().contains(oLngLat); return !!this.map && this.map.getBounds().contains(oLngLat);
}, },
getGoogleMapsLink(asInfo) { getGoogleMapsLink(asInfo) {
return $('<a>', { return $('<a>', {

View File

@@ -55,51 +55,51 @@ export default class Lightbox {
} }
onBodyClick(event) { onBodyClick(event) {
const link = event.target.closest('a[rel^="lightbox"], area[rel^="lightbox"], a[data-lightbox], area[data-lightbox]'); const link = event.target.closest('a[data-lightbox], area[data-lightbox]');
if (!link) return; if (!link) return;
event.preventDefault(); event.preventDefault();
this.start(link); this.start(link);
} }
renderIcon(name) { renderIcon(name, sClass=null) {
return icon(getIcon(name), {classes: ['spot-icon', name]}).html; return icon(getIcon(name), {classes: ['spot-icon', name, sClass]}).html;
} }
build() { build() {
if (!document.getElementById('lightbox')) { if (!document.getElementById('lightbox')) {
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
wrapper.innerHTML = ` wrapper.innerHTML = `
<div id="lightboxOverlay" tabindex="-1" class="lightboxOverlay"></div> <div id="lightboxOverlay" tabindex="-1" class="lightboxOverlay"></div>
<div id="lightbox" tabindex="-1" class="lightbox"> <div id="lightbox" tabindex="-1" class="lightbox">
<div class="lb-outerContainer"> <div class="lb-outerContainer">
<div class="lb-container"> <div class="lb-container">
<img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" alt="" /> <img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" alt="" />
<video class="lb-video" controls autoplay></video> <video class="lb-video" controls autoplay></video>
<div class="lb-nav"> <div class="lb-nav">
<div class="lb-prev-area"> <div class="lb-prev-area">
<a class="lb-prev" aria-label="Previous image" href="" role="button">${this.renderIcon('prev')}</a> <a class="lb-prev" aria-label="Previous image" href="" role="button">${this.renderIcon('prev')}</a>
</div>
<div class="lb-next-area">
<a class="lb-next" aria-label="Next image" href="" role="button">${this.renderIcon('next')}</a>
</div>
</div> </div>
<div class="lb-next-area"> <div class="lb-loader">
<a class="lb-next" aria-label="Next image" href="" role="button">${this.renderIcon('next')}</a> <a class="lb-cancel" href="#">${this.renderIcon('cancel')}</a>
</div> </div>
</div> </div>
<div class="lb-loader"> <div class="lb-dataContainer desktop">
<a class="lb-cancel" href="#">${this.renderIcon('cancel')}</a> <div class="lb-data">
<div class="lb-details">
<span class="lb-caption"></span>
</div>
<div class="lb-closeContainer">
<a class="lb-close" href="#" role="button">${this.renderIcon('close', 'fa-lg')}</a>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="lb-dataContainer desktop"> `;
<div class="lb-data">
<div class="lb-details">
<span class="lb-caption"></span>
</div>
<div class="lb-closeContainer">
<a class="lb-close" href="#" role="button">${this.renderIcon('close')}</a>
</div>
</div>
</div>
</div>
`;
document.body.append(...wrapper.children); document.body.append(...wrapper.children);
} }
@@ -179,22 +179,11 @@ export default class Lightbox {
let imageNumber = 0; let imageNumber = 0;
const setName = link.getAttribute('data-lightbox'); const setName = link.getAttribute('data-lightbox');
if (setName) { const links = [...document.querySelectorAll(`${link.tagName}[data-lightbox="${CSS.escape(setName)}"]`)];
const links = [...document.querySelectorAll(`${link.tagName}[data-lightbox="${CSS.escape(setName)}"]`)]; links.forEach((item, index) => {
links.forEach((item, index) => { this.addToAlbum(item);
this.addToAlbum(item); if (item === link) imageNumber = index;
if (item === link) imageNumber = index; });
});
} else if (link.getAttribute('rel') === 'lightbox') {
this.addToAlbum(link);
} else {
const rel = link.getAttribute('rel');
const links = [...document.querySelectorAll(`${link.tagName}[rel="${CSS.escape(rel)}"]`)];
links.forEach((item, index) => {
this.addToAlbum(item);
if (item === link) imageNumber = index;
});
}
this.fade(this.overlay, true, this.options.fadeDuration); this.fade(this.overlay, true, this.options.fadeDuration);
this.fade(this.lightbox, true, this.options.fadeDuration); this.fade(this.lightbox, true, this.options.fadeDuration);
@@ -216,34 +205,64 @@ export default class Lightbox {
id: link.getAttribute('data-id'), id: link.getAttribute('data-id'),
width: parseInt(img?.getAttribute('width') || '0', 10), width: parseInt(img?.getAttribute('width') || '0', 10),
height: parseInt(img?.getAttribute('height') || '0', 10), height: parseInt(img?.getAttribute('height') || '0', 10),
set: link.getAttribute('data-lightbox') || link.getAttribute('rel') || '' set: link.getAttribute('data-lightbox') || ''
}); });
} }
hasMediaAfterCurrent() {
return this.currentImageIndex < this.album.length - 1;
}
refreshAlbum() {
const current = this.album[this.currentImageIndex];
if (!current?.set) return;
const links = [...document.querySelectorAll(`a[data-lightbox="${CSS.escape(current.set)}"], area[data-lightbox="${CSS.escape(current.set)}"]`)];
if (!links.length) return;
const existingKeys = new Set(this.album.map((media) => this.getMediaKey(media)));
links.forEach((link) => {
const key = this.getLinkMediaKey(link);
if (existingKeys.has(key)) return;
this.addToAlbum(link);
existingKeys.add(key);
});
this.updateNav();
}
getMediaKey(media) {
return `${media.set}:${media.id}`;
}
getLinkMediaKey(link) {
return `${link.getAttribute('data-lightbox') || ''}:${link.getAttribute('data-id')}`;
}
getMaxSizes(mediaWidth, mediaHeight, mediaType) { getMaxSizes(mediaWidth, mediaHeight, mediaType) {
let maxWidth = window.innerWidth - this.containerPadding.left - this.containerPadding.right; let maxWidth = window.innerWidth - this.containerPadding.left - this.containerPadding.right;
let maxHeight = window.innerHeight - this.containerPadding.top - this.containerPadding.bottom - this.options.positionFromTop; let maxHeight = window.innerHeight - this.containerPadding.top - this.containerPadding.bottom - this.options.positionFromTop;
const border = mediaType === 'image' ? this.imageBorderWidth : this.videoBorderWidth; const border = mediaType === 'image' ? this.imageBorderWidth : this.videoBorderWidth;
maxWidth -= border.left + border.right; maxWidth -= border.left + border.right;
maxHeight -= border.top + border.bottom; maxHeight -= border.top + border.bottom;
maxHeight -= this.getDataContainerHeight(maxWidth + this.containerPadding.left + this.containerPadding.right + border.left + border.right);
const dataMaxWidth = this.dataContainer.offsetWidth || 0; return {
const dataMaxHeight = this.dataContainer.offsetHeight || 0; maxWidth: Math.max(maxWidth, 1),
const ratio = mediaWidth / mediaHeight; maxHeight: Math.max(maxHeight, 1)
};
}
const heightH = Math.min(maxHeight, mediaHeight); getDataContainerHeight(width = null) {
const widthH = Math.min(heightH * ratio, maxWidth - dataMaxWidth); if (!this.dataContainer) return 0;
const surfaceH = Math.min(heightH, widthH / ratio) * widthH;
const widthV = Math.min(maxWidth, mediaWidth); const currentWidth = this.dataContainer.style.width;
const heightV = Math.min(widthV / ratio, maxHeight - dataMaxHeight); if (width !== null) this.dataContainer.style.width = `${width}px`;
const surfaceV = Math.min(widthV, heightV * ratio) * heightV; const height = Math.ceil(this.dataContainer.getBoundingClientRect().height || this.dataContainer.offsetHeight || 0);
this.dataContainer.style.width = currentWidth;
const direction = surfaceV > surfaceH ? 'vertical' : 'horizontal'; return height;
if (direction === 'vertical') maxHeight -= dataMaxHeight;
else maxWidth -= dataMaxWidth;
return { maxWidth, maxHeight, direction };
} }
updateSize(index) { updateSize(index) {
@@ -252,9 +271,6 @@ export default class Lightbox {
let maxWidth = maxSizes.maxWidth; let maxWidth = maxSizes.maxWidth;
let maxHeight = maxSizes.maxHeight; let maxHeight = maxSizes.maxHeight;
this.lightbox.classList.remove('vertical', 'horizontal');
this.lightbox.classList.add(maxSizes.direction);
if (this.options.fitImagesInViewport) { if (this.options.fitImagesInViewport) {
if (this.options.maxWidth && this.options.maxWidth < maxWidth) maxWidth = this.options.maxWidth; if (this.options.maxWidth && this.options.maxWidth < maxWidth) maxWidth = this.options.maxWidth;
if (this.options.maxHeight && this.options.maxHeight < maxHeight) maxHeight = this.options.maxHeight; if (this.options.maxHeight && this.options.maxHeight < maxHeight) maxHeight = this.options.maxHeight;
@@ -288,15 +304,16 @@ export default class Lightbox {
const media = this.album[index]; const media = this.album[index];
if (!media) return; if (!media) return;
this.updateDetails(media, false);
this.hideElements([this.dataContainer]);
this.disableKeyboardNav(); this.disableKeyboardNav();
this.fade(this.overlay, true, this.options.fadeDuration); this.fade(this.overlay, true, this.options.fadeDuration);
this.fade(this.loader, true, 200); this.fade(this.loader, true, 200);
this.hideElements([this.image, this.video, this.nav, this.prev, this.next, this.caption, this.closeButton]); this.hideElements([this.image, this.video, this.nav, this.prev, this.next]);
this.resetImageTransform(); this.resetImageTransform();
this.dataContainer.style.width = '200px';
this.dataContainer.style.height = '35px';
this.outerContainer.classList.add('animating'); this.outerContainer.classList.add('animating');
this.container.classList.remove('moveable', 'moving', 'lb-video-nav'); this.container.classList.remove('moveable', 'moving', 'lb-video-nav');
this.currentImageIndex = index;
this.options.onMediaChange(media); this.options.onMediaChange(media);
@@ -329,8 +346,6 @@ export default class Lightbox {
}; };
this.image.src = media.link; this.image.src = media.link;
} }
this.currentImageIndex = index;
} }
sizeOverlay() { sizeOverlay() {
@@ -349,15 +364,14 @@ export default class Lightbox {
const border = mediaType === 'image' ? this.imageBorderWidth : this.videoBorderWidth; const border = mediaType === 'image' ? this.imageBorderWidth : this.videoBorderWidth;
const newWidth = width + this.containerPadding.left + this.containerPadding.right + border.left + border.right; const newWidth = width + this.containerPadding.left + this.containerPadding.right + border.left + border.right;
const newHeight = height + this.containerPadding.top + this.containerPadding.bottom + border.top + border.bottom; const newHeight = height + this.containerPadding.top + this.containerPadding.bottom + border.top + border.bottom;
const dataHeight = this.getDataContainerHeight(newWidth);
this.outerContainer.style.transition = `width ${this.options.resizeDuration}ms, height ${this.options.resizeDuration}ms`; this.outerContainer.style.transition = `width ${this.options.resizeDuration}ms, height ${this.options.resizeDuration}ms`;
this.outerContainer.style.width = `${newWidth}px`; this.outerContainer.style.width = `${newWidth}px`;
this.outerContainer.style.height = `${newHeight}px`; this.outerContainer.style.height = `${newHeight + dataHeight}px`;
this.container.style.height = `${newHeight}px`;
window.setTimeout(() => { window.setTimeout(() => {
if (this.lightbox.classList.contains('vertical')) this.dataContainer.style.width = `${newWidth}px`;
else this.dataContainer.style.height = `${newHeight}px`;
this.overlay.focus(); this.overlay.focus();
this.showImage(); this.showImage();
this.outerContainer.style.transition = ''; this.outerContainer.style.transition = '';
@@ -400,22 +414,29 @@ export default class Lightbox {
} }
} }
updateDetails() { updateDetails(media = this.album[this.currentImageIndex], show = true) {
const media = this.album[this.currentImageIndex];
if (!media) return; if (!media) return;
if (media.title) { if (media.title) {
if (this.options.sanitizeTitle) this.caption.textContent = media.title; if (this.options.sanitizeTitle) this.caption.textContent = media.title;
else this.caption.innerHTML = media.title; else this.caption.innerHTML = media.title;
this.fade(this.caption, true, 200); if (show) this.fade(this.caption, true, 200);
else this.setVisible(this.caption, true);
} else { } else {
this.caption.textContent = ''; this.caption.textContent = '';
this.setVisible(this.caption, false); this.setVisible(this.caption, false);
} }
this.fade(this.closeButton, true, 200); if (show) {
this.outerContainer.classList.remove('animating'); this.fade(this.closeButton, true, 200);
this.fade(this.dataContainer, true, this.options.resizeDuration); this.outerContainer.classList.remove('animating');
this.fade(this.dataContainer, true, this.options.resizeDuration);
} else {
this.setVisible(this.closeButton, true);
this.setVisible(this.dataContainer, false);
this.dataContainer.style.transition = '';
this.dataContainer.style.opacity = '0';
}
} }
preloadNeighboringImages() { preloadNeighboringImages() {

View File

@@ -33,91 +33,52 @@ body.lb-disable-scrolling {
/* Data Container (comments, close) */ /* Data Container (comments, close) */
.lb-dataContainer { .lb-dataContainer {
position: relative;
margin: 0;
padding: 0;
width: 100%;
flex: 0 0 auto;
overflow: hidden; overflow: hidden;
background-color: color.$media-bg-light;
.lb-data { .lb-data {
display: flex; display: flex;
align-items: center;
margin: var.$elem-spacing; margin: var.$elem-spacing;
gap: var.$block-spacing; gap: var.$block-spacing;
color: color.$default-inv; color: color.$media;
.lb-details {
display: contents;
}
.lb-caption { .lb-caption {
display: flex; display: contents;
gap: var.$block-spacing;
.lb-caption-line { .lb-caption-line {
flex: 0 0 auto; flex: 0 0 auto;
line-height: 1.33333333333em; //icon height line-height: 1.33333333333em; //icon height
} }
}
.lb-closeContainer .lb-close { .lb-caption-line.comment {
@extend .clickable;
font-size: 1.3333333333em;
line-height: 1em;
color: color.$default-inv;
&:hover {
color: color.$default-inv-hover;
}
}
}
}
&.vertical {
flex-direction: column;
.lb-dataContainer {
.lb-data {
flex-direction: row;
.lb-details {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
width: 100%;
.lb-caption-line.comment {
flex: 1 1 auto;
min-width: 0;
@include common.no-text-overflow();
}
}
.lb-closeContainer {
.lb-close {
text-align: right;
}
} }
} }
}
}
&.horizontal {
flex-direction: row;
.lb-dataContainer {
height: 100%;
.lb-data {
flex-direction: column;
.lb-caption {
flex-direction: column;
}
.lb-closeContainer .lb-close { .lb-closeContainer {
margin-top: calc(1em/1.33333333); flex: 0 0 auto;
margin-left: auto;
.lb-close {
@extend .clickable;
color: color.$media;
&:hover {
color: color.$media-hover;
}
} }
} }
} }
} }
/* Picture Container */ /* Picture Container */
.lb-outerContainer { .lb-outerContainer {
position: relative; position: relative;
width: 250px; width: 250px;
@@ -127,7 +88,7 @@ body.lb-disable-scrolling {
.lb-container { .lb-container {
overflow: hidden; overflow: hidden;
height: 100%; position: relative;
&.moveable { &.moveable {
cursor: grab; cursor: grab;
@@ -138,7 +99,6 @@ body.lb-disable-scrolling {
} }
.lb-image { .lb-image {
height: auto;
max-width: inherit; max-width: inherit;
max-height: none; max-height: none;
border-radius: 0; border-radius: 0;
@@ -228,13 +188,10 @@ body.lb-disable-scrolling {
} }
.lb-loader { .lb-loader {
position: absolute; position: fixed;
top: 50%; top: 50%;
transform: translateY(-50%); left: 50%;
left: 0; transform: translate(-50%, -50%);
width: 100%;
text-align: center;
line-height: 0;
.lb-cancel { .lb-cancel {
@extend .flicker; @extend .flicker;