573 lines
22 KiB
JavaScript
573 lines
22 KiB
JavaScript
const modal = document.getElementById('media-gallery-preview-modal');
|
|
const body = modal && modal.querySelector('[data-media-gallery-preview-body]');
|
|
const title = modal && modal.querySelector('#media-gallery-preview-modal-label');
|
|
const gallery = document.querySelector('.media-gallery');
|
|
const search = gallery && gallery.querySelector('[data-media-gallery-search]');
|
|
const typeFilter = gallery && gallery.querySelector('[data-media-gallery-type-filter]');
|
|
const usageFilter = gallery && gallery.querySelector('[data-media-gallery-usage-filter]');
|
|
const sort = gallery && gallery.querySelector('[data-media-gallery-sort]');
|
|
const galleryCount = gallery && gallery.querySelector('[data-media-gallery-count]');
|
|
const noResults = gallery && gallery.querySelector('[data-media-gallery-no-results]');
|
|
const loadMoreWrap = gallery && gallery.querySelector('[data-media-gallery-load-more-wrap]');
|
|
const loadMoreButton = gallery && gallery.querySelector('[data-media-gallery-load-more]');
|
|
const selectModeButton = gallery && gallery.querySelector('[data-media-gallery-select-mode]');
|
|
const deleteSelectedButton = gallery && gallery.querySelector('[data-media-gallery-delete-selected]');
|
|
const addMediaButton = gallery && gallery.querySelector('[data-media-library-add]');
|
|
let galleryItems = gallery ? Array.from(gallery.querySelectorAll('[data-media-gallery-column]')) : [];
|
|
let visibleRowLimit = 4;
|
|
let galleryOffset = gallery ? Number(gallery.dataset.mediaGalleryOffset || galleryItems.length) : 0;
|
|
let galleryHasMore = gallery ? gallery.dataset.mediaGalleryHasMore === 'true' : false;
|
|
let galleryTotal = galleryCount ? Number(galleryCount.textContent || galleryItems.length) : galleryItems.length;
|
|
let galleryRefreshSequence = 0;
|
|
let selectionMode = false;
|
|
const selectedAssetIds = new Set();
|
|
const uploadForm = document.querySelector('form[action="/media-library"]');
|
|
const uploadInput = document.querySelector('[data-media-library-upload]');
|
|
const uploadZone = document.querySelector('[data-media-library-upload-zone]');
|
|
const uploadName = document.querySelector('[data-media-library-upload-name]');
|
|
const uploadModal = document.getElementById('media-library-upload-modal');
|
|
const cropModal = document.getElementById('media-library-crop-modal');
|
|
const cropImage = cropModal && cropModal.querySelector('#media-library-crop-image');
|
|
const cropApply = cropModal && cropModal.querySelector('[data-media-library-crop-apply]');
|
|
const cropCancel = cropModal && cropModal.querySelector('[data-media-library-crop-cancel]');
|
|
const cropStatus = cropModal && cropModal.querySelector('#media-library-crop-status');
|
|
const cropFrame = cropModal && cropModal.querySelector('.slide-image-cropper-frame');
|
|
let cropper = null;
|
|
let cropObjectUrl = '';
|
|
let cropSourceFile = null;
|
|
let cropFlipX = 1;
|
|
let cropFlipY = 1;
|
|
|
|
function getColumnsPerRow() {
|
|
return window.innerWidth >= 1200 ? 6 : window.innerWidth >= 992 ? 3 : window.innerWidth >= 576 ? 2 : 1;
|
|
}
|
|
|
|
function showUploadMessage(message) {
|
|
if (typeof window.showToast === 'function') {
|
|
window.showToast(message, 'warning');
|
|
return;
|
|
}
|
|
window.alert(message);
|
|
}
|
|
|
|
function showModal(target) {
|
|
if (window.pulseModal && typeof window.pulseModal.show === 'function') {
|
|
window.pulseModal.show(target);
|
|
} else if (window.bootstrap && window.bootstrap.Modal) {
|
|
window.bootstrap.Modal.getOrCreateInstance(target).show();
|
|
}
|
|
}
|
|
|
|
function hideModal(target) {
|
|
if (window.pulseModal && typeof window.pulseModal.hide === 'function') {
|
|
window.pulseModal.hide(target);
|
|
} else if (window.bootstrap && window.bootstrap.Modal) {
|
|
window.bootstrap.Modal.getOrCreateInstance(target).hide();
|
|
}
|
|
}
|
|
|
|
if (addMediaButton && uploadModal) {
|
|
addMediaButton.addEventListener('click', function () {
|
|
showModal(uploadModal);
|
|
});
|
|
}
|
|
|
|
function clearCropper() {
|
|
if (cropper) {
|
|
cropper.destroy();
|
|
cropper = null;
|
|
}
|
|
if (cropObjectUrl) {
|
|
URL.revokeObjectURL(cropObjectUrl);
|
|
cropObjectUrl = '';
|
|
}
|
|
cropSourceFile = null;
|
|
cropFlipX = 1;
|
|
cropFlipY = 1;
|
|
if (cropStatus) cropStatus.textContent = '';
|
|
if (cropFrame) cropFrame.classList.remove('is-loading');
|
|
}
|
|
|
|
function setCropperActionState(disabled) {
|
|
if (!cropModal) return;
|
|
cropModal.querySelectorAll('[data-media-library-crop-action]').forEach(function (button) {
|
|
button.disabled = Boolean(disabled);
|
|
});
|
|
}
|
|
function appendGalleryAsset(asset) {
|
|
if (!gallery || !asset) return;
|
|
const column = document.createElement('div');
|
|
column.className = 'col-12 col-sm-6 col-lg-4 col-xl-2';
|
|
column.dataset.mediaGalleryColumn = '';
|
|
column.dataset.mediaId = String(asset.id || '');
|
|
column.dataset.mediaType = asset.media_type || '';
|
|
column.dataset.mediaUsed = asset.inUse ? 'true' : 'false';
|
|
const article = document.createElement('article');
|
|
article.className = 'media-gallery-card';
|
|
article.dataset.mediaCreatedAt = asset.created_at || '';
|
|
article.dataset.mediaFileSize = asset.file_size || '0';
|
|
const preview = document.createElement('button');
|
|
preview.type = 'button';
|
|
preview.className = 'media-gallery-preview';
|
|
preview.dataset.mediaGalleryPreview = '';
|
|
preview.dataset.mediaPath = asset.media_path || '';
|
|
preview.dataset.mediaType = asset.media_type || '';
|
|
preview.dataset.mediaName = asset.original_name || '';
|
|
preview.setAttribute('aria-label', 'Preview ' + (asset.original_name || 'media'));
|
|
const media = asset.media_type === 'video' ? document.createElement('video') : document.createElement('img');
|
|
media.src = asset.media_path || '';
|
|
if (asset.media_type === 'video') {
|
|
media.muted = true;
|
|
media.playsInline = true;
|
|
media.preload = 'metadata';
|
|
} else {
|
|
media.alt = asset.original_name || '';
|
|
media.loading = 'lazy';
|
|
}
|
|
preview.appendChild(media);
|
|
if (asset.media_type === 'video') {
|
|
const play = document.createElement('span');
|
|
play.className = 'media-gallery-play';
|
|
play.setAttribute('aria-hidden', 'true');
|
|
play.innerHTML = '<i class="bi bi-play-fill"></i>';
|
|
preview.appendChild(play);
|
|
}
|
|
const format = document.createElement('span');
|
|
format.className = 'media-gallery-type';
|
|
format.textContent = asset.mediaFormat || '';
|
|
preview.appendChild(format);
|
|
const details = document.createElement('div');
|
|
details.className = 'media-gallery-details';
|
|
const header = document.createElement('div');
|
|
header.className = 'media-gallery-header';
|
|
const name = document.createElement('h4');
|
|
name.className = 'media-gallery-name';
|
|
name.title = asset.original_name || '';
|
|
name.textContent = asset.original_name || '';
|
|
header.appendChild(name);
|
|
if (asset.canDelete) {
|
|
if (asset.inUse) {
|
|
const lock = document.createElement('button');
|
|
lock.type = 'button';
|
|
lock.className = 'btn btn-outline-secondary btn-sm media-gallery-action';
|
|
lock.disabled = true;
|
|
lock.title = 'Media is in use';
|
|
lock.innerHTML = '<i class="bi bi-lock" aria-hidden="true"></i><span class="visually-hidden">Media is in use</span>';
|
|
header.appendChild(lock);
|
|
} else {
|
|
const form = document.createElement('form');
|
|
form.method = 'post';
|
|
form.action = '/media-library/' + encodeURIComponent(asset.id) + '/delete';
|
|
form.dataset.confirmMessage = 'Delete this media?';
|
|
form.className = 'media-gallery-action';
|
|
form.innerHTML = '<button type="submit" class="btn btn-outline-danger btn-sm" title="Delete media"><i class="bi bi-trash" aria-hidden="true"></i><span class="visually-hidden">Delete media</span></button>';
|
|
header.appendChild(form);
|
|
}
|
|
}
|
|
const meta = document.createElement('div');
|
|
meta.className = 'media-gallery-meta';
|
|
meta.textContent = (asset.displayFileSize || '') + ' · Used ' + Number(asset.referenceCount || 0) + ' time' + (Number(asset.referenceCount || 0) === 1 ? '' : 's');
|
|
details.appendChild(header);
|
|
details.appendChild(meta);
|
|
article.appendChild(preview);
|
|
article.appendChild(details);
|
|
column.appendChild(article);
|
|
gallery.querySelector('.media-gallery-scroll .row').appendChild(column);
|
|
galleryItems.push(column);
|
|
column.querySelector('.media-gallery-card').classList.toggle('media-gallery-card-selected', selectedAssetIds.has(String(asset.id || '')));
|
|
}
|
|
|
|
function applyCropRatio(value) {
|
|
if (!cropper) return;
|
|
cropper.setAspectRatio(value === 'free' ? NaN : Number(value.split(':')[0]) / Number(value.split(':')[1]));
|
|
cropModal.querySelectorAll('[data-media-library-crop-action="ratio"]').forEach(function (button) {
|
|
const active = button.dataset.mediaLibraryCropRatio === value;
|
|
button.classList.toggle('active', active);
|
|
button.setAttribute('aria-pressed', active ? 'true' : 'false');
|
|
});
|
|
}
|
|
|
|
function initMediaCropper() {
|
|
if (!cropSourceFile || !cropImage || !window.Cropper || cropper) return;
|
|
if (cropFrame) cropFrame.classList.add('is-loading');
|
|
cropper = new window.Cropper(cropImage, {
|
|
aspectRatio: NaN,
|
|
autoCropArea: 1,
|
|
background: false,
|
|
dragMode: 'move',
|
|
initialAspectRatio: NaN,
|
|
movable: true,
|
|
responsive: true,
|
|
rotatable: true,
|
|
scalable: true,
|
|
viewMode: 1,
|
|
zoomOnTouch: true,
|
|
zoomOnWheel: true,
|
|
ready: function () {
|
|
if (cropFrame) cropFrame.classList.remove('is-loading');
|
|
if (cropper && cropper.container) {
|
|
cropper.container.style.width = '100%';
|
|
cropper.container.style.height = '560px';
|
|
cropper.container.style.maxHeight = '70vh';
|
|
}
|
|
const containerData = cropper.getContainerData();
|
|
const imageData = cropper.getImageData();
|
|
const fitRatio = Math.min(Number(containerData.width || 0) / Number(imageData.naturalWidth || 1), Number(containerData.height || 0) / Number(imageData.naturalHeight || 1), 1);
|
|
if (fitRatio > 0) cropper.zoomTo(fitRatio);
|
|
applyCropRatio('free');
|
|
setCropperActionState(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
function setUploadFile(file, shouldCrop) {
|
|
if (!uploadInput || !file) {
|
|
return;
|
|
}
|
|
const allowedTypes = String(uploadInput.accept || '').split(',').map(function (value) { return value.trim().toLowerCase(); }).filter(Boolean);
|
|
const fileType = String(file.type || '').toLowerCase();
|
|
const matchesType = allowedTypes.length === 0 || allowedTypes.indexOf(fileType) !== -1;
|
|
const maxBytes = fileType.indexOf('video/') === 0 ? Number(uploadInput.dataset.videoMaxBytes) : Number(uploadInput.dataset.imageMaxBytes);
|
|
if (!matchesType) {
|
|
showUploadMessage('This media type is disabled in Media Uploads settings.');
|
|
uploadInput.value = '';
|
|
return;
|
|
}
|
|
if (maxBytes && file.size > maxBytes) {
|
|
showUploadMessage('This file is larger than the configured upload limit.');
|
|
uploadInput.value = '';
|
|
return;
|
|
}
|
|
|
|
const transfer = new DataTransfer();
|
|
transfer.items.add(file);
|
|
uploadInput.files = transfer.files;
|
|
if (uploadName) {
|
|
uploadName.textContent = file.name;
|
|
}
|
|
|
|
if (shouldCrop && fileType.indexOf('image/') === 0 && cropModal && cropImage && window.Cropper) {
|
|
clearCropper();
|
|
setCropperActionState(true);
|
|
cropSourceFile = file;
|
|
cropObjectUrl = URL.createObjectURL(file);
|
|
cropImage.src = cropObjectUrl;
|
|
if (cropFrame) cropFrame.classList.add('is-loading');
|
|
showModal(cropModal);
|
|
}
|
|
}
|
|
|
|
function submitUpload() {
|
|
if (!uploadForm) {
|
|
return;
|
|
}
|
|
if (typeof uploadForm.requestSubmit === 'function') {
|
|
uploadForm.requestSubmit();
|
|
} else {
|
|
uploadForm.submit();
|
|
}
|
|
}
|
|
|
|
if (uploadInput) {
|
|
uploadInput.addEventListener('change', function () {
|
|
const file = uploadInput.files && uploadInput.files[0];
|
|
if (file) {
|
|
setUploadFile(file, true);
|
|
if (String(file.type || '').toLowerCase().indexOf('image/') !== 0 || !(cropModal && cropImage && window.Cropper)) {
|
|
submitUpload();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (uploadZone) {
|
|
uploadZone.addEventListener('dragover', function (event) {
|
|
event.preventDefault();
|
|
uploadZone.classList.add('is-dragover');
|
|
});
|
|
uploadZone.addEventListener('dragleave', function () {
|
|
uploadZone.classList.remove('is-dragover');
|
|
});
|
|
uploadZone.addEventListener('drop', function (event) {
|
|
event.preventDefault();
|
|
uploadZone.classList.remove('is-dragover');
|
|
const file = event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0];
|
|
if (file) {
|
|
setUploadFile(file, true);
|
|
if (String(file.type || '').toLowerCase().indexOf('image/') !== 0 || !(cropModal && cropImage && window.Cropper)) {
|
|
submitUpload();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (cropApply) {
|
|
cropApply.addEventListener('click', function () {
|
|
if (!cropper || !cropSourceFile || !uploadInput) {
|
|
hideModal(cropModal);
|
|
return;
|
|
}
|
|
const outputType = cropSourceFile.type === 'image/jpeg' || cropSourceFile.type === 'image/webp' ? cropSourceFile.type : 'image/png';
|
|
cropper.getCroppedCanvas().toBlob(function (blob) {
|
|
if (!blob) {
|
|
showUploadMessage('Unable to crop this image.');
|
|
return;
|
|
}
|
|
const extension = outputType === 'image/jpeg' ? '.jpg' : outputType === 'image/webp' ? '.webp' : '.png';
|
|
const croppedFile = new File([blob], cropSourceFile.name.replace(/\.[^.]+$/, '') + extension, { type: outputType, lastModified: Date.now() });
|
|
clearCropper();
|
|
setUploadFile(croppedFile, false);
|
|
hideModal(cropModal);
|
|
submitUpload();
|
|
}, outputType, 0.92);
|
|
});
|
|
}
|
|
|
|
if (cropCancel) {
|
|
cropCancel.addEventListener('click', function () {
|
|
clearCropper();
|
|
if (uploadInput) uploadInput.value = '';
|
|
if (uploadName) uploadName.textContent = 'No file selected';
|
|
hideModal(cropModal);
|
|
});
|
|
}
|
|
|
|
if (cropModal) {
|
|
cropModal.addEventListener('click', function (event) {
|
|
const button = event.target && event.target.closest ? event.target.closest('[data-media-library-crop-action]') : null;
|
|
if (!button || !cropper) return;
|
|
const action = button.dataset.mediaLibraryCropAction;
|
|
if (action === 'rotate-left') cropper.rotate(-90);
|
|
if (action === 'rotate-right') cropper.rotate(90);
|
|
if (action === 'flip-horizontal') {
|
|
cropFlipX *= -1;
|
|
cropper.scaleX(cropFlipX);
|
|
}
|
|
if (action === 'flip-vertical') {
|
|
cropFlipY *= -1;
|
|
cropper.scaleY(cropFlipY);
|
|
}
|
|
if (action === 'ratio') applyCropRatio(button.dataset.mediaLibraryCropRatio || 'free');
|
|
if (action === 'reset') {
|
|
cropper.reset();
|
|
cropFlipX = 1;
|
|
cropFlipY = 1;
|
|
applyCropRatio('free');
|
|
}
|
|
});
|
|
}
|
|
|
|
if (cropModal) {
|
|
cropModal.addEventListener('shown.bs.modal', function () {
|
|
if (cropSourceFile && cropImage && window.Cropper && !cropper) {
|
|
initMediaCropper();
|
|
}
|
|
});
|
|
cropModal.addEventListener('hidden.bs.modal', function () {
|
|
clearCropper();
|
|
});
|
|
}
|
|
|
|
if (uploadForm) {
|
|
uploadForm.addEventListener('submit', function (event) {
|
|
if (uploadInput && !uploadInput.files.length) {
|
|
event.preventDefault();
|
|
showUploadMessage('Choose an image or video to upload.');
|
|
}
|
|
});
|
|
}
|
|
|
|
function getGalleryQuery(offset, limit) {
|
|
const params = new URLSearchParams();
|
|
params.set('offset', String(offset));
|
|
params.set('limit', String(limit));
|
|
params.set('search', String(search && search.value || '').trim());
|
|
params.set('type', typeFilter ? typeFilter.value : 'all');
|
|
params.set('usage', usageFilter ? usageFilter.value : 'all');
|
|
params.set('sort', sort ? sort.value : 'date-desc');
|
|
return params.toString();
|
|
}
|
|
|
|
function updateSearchResults() {
|
|
const columnsPerRow = getColumnsPerRow();
|
|
const visibleItemLimit = visibleRowLimit * columnsPerRow;
|
|
let visibleCount = 0;
|
|
galleryItems.forEach(function (card) {
|
|
card.hidden = visibleCount >= visibleItemLimit;
|
|
if (!card.hidden) {
|
|
visibleCount += 1;
|
|
}
|
|
});
|
|
|
|
if (galleryCount) {
|
|
galleryCount.textContent = String(galleryTotal);
|
|
}
|
|
if (noResults) {
|
|
noResults.hidden = galleryTotal > 0;
|
|
}
|
|
if (loadMoreWrap) {
|
|
loadMoreWrap.hidden = !galleryHasMore || galleryTotal === 0;
|
|
}
|
|
updateBulkDeleteActions();
|
|
}
|
|
|
|
function updateBulkDeleteActions() {
|
|
if (selectModeButton) {
|
|
selectModeButton.setAttribute('aria-pressed', selectionMode ? 'true' : 'false');
|
|
selectModeButton.textContent = selectionMode ? 'Cancel' : 'Select';
|
|
}
|
|
if (deleteSelectedButton) {
|
|
deleteSelectedButton.hidden = !selectionMode;
|
|
deleteSelectedButton.disabled = selectedAssetIds.size === 0;
|
|
}
|
|
galleryItems.forEach(function (item) {
|
|
const id = String(item.dataset.mediaId || '');
|
|
const card = item.querySelector('.media-gallery-card');
|
|
if (card) {
|
|
card.classList.toggle('media-gallery-card-selected', selectionMode && selectedAssetIds.has(id));
|
|
card.classList.toggle('media-gallery-card-selection-disabled', selectionMode && item.dataset.mediaUsed === 'true');
|
|
}
|
|
});
|
|
}
|
|
|
|
function clearSelectedAssets() {
|
|
selectedAssetIds.clear();
|
|
}
|
|
|
|
function setSelectionMode(enabled) {
|
|
selectionMode = Boolean(enabled);
|
|
if (!selectionMode) clearSelectedAssets();
|
|
if (gallery) gallery.classList.toggle('media-gallery-selection-mode', selectionMode);
|
|
updateBulkDeleteActions();
|
|
}
|
|
|
|
function submitBulkDelete() {
|
|
if (!selectedAssetIds.size || !window.confirm('Delete ' + selectedAssetIds.size + ' selected media asset' + (selectedAssetIds.size === 1 ? '' : 's') + '?')) {
|
|
return;
|
|
}
|
|
const form = document.createElement('form');
|
|
form.method = 'post';
|
|
form.action = '/media-library/delete';
|
|
selectedAssetIds.forEach(function (id) {
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = 'assetIds[]';
|
|
input.value = id;
|
|
form.appendChild(input);
|
|
});
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
|
|
async function refreshGallery() {
|
|
const requestSequence = ++galleryRefreshSequence;
|
|
try {
|
|
const response = await fetch('/media-library/assets?' + getGalleryQuery(0, 4 * getColumnsPerRow()), { headers: { Accept: 'application/json' } });
|
|
if (!response.ok) throw new Error('Unable to refresh media.');
|
|
const result = await response.json();
|
|
if (requestSequence !== galleryRefreshSequence) return;
|
|
galleryItems.forEach(function (item) { item.remove(); });
|
|
galleryItems = [];
|
|
clearSelectedAssets();
|
|
(result.assets || []).forEach(appendGalleryAsset);
|
|
galleryOffset = Number(result.nextOffset || 0);
|
|
galleryHasMore = Boolean(result.hasMore);
|
|
galleryTotal = Number(result.total || 0);
|
|
visibleRowLimit = 4;
|
|
updateSearchResults();
|
|
} catch (error) {
|
|
showUploadMessage(error.message || 'Unable to refresh media.');
|
|
}
|
|
}
|
|
|
|
function resetVisibleItemLimit() {
|
|
visibleRowLimit = 4;
|
|
refreshGallery();
|
|
}
|
|
|
|
if (search) {
|
|
search.addEventListener('input', resetVisibleItemLimit);
|
|
}
|
|
if (typeFilter) typeFilter.addEventListener('change', resetVisibleItemLimit);
|
|
if (usageFilter) usageFilter.addEventListener('change', resetVisibleItemLimit);
|
|
if (sort) sort.addEventListener('change', resetVisibleItemLimit);
|
|
if (gallery) {
|
|
gallery.addEventListener('click', function (event) {
|
|
if (!selectionMode) return;
|
|
const column = event.target && event.target.closest ? event.target.closest('[data-media-gallery-column]') : null;
|
|
if (!column || !gallery.contains(column)) return;
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
if (column.dataset.mediaUsed === 'true') {
|
|
showUploadMessage('This media is in use and cannot be selected.');
|
|
return;
|
|
}
|
|
const id = String(column.dataset.mediaId || '');
|
|
if (!id) return;
|
|
if (selectedAssetIds.has(id)) selectedAssetIds.delete(id);
|
|
else selectedAssetIds.add(id);
|
|
updateBulkDeleteActions();
|
|
});
|
|
}
|
|
if (selectModeButton) selectModeButton.addEventListener('click', function () { setSelectionMode(!selectionMode); });
|
|
if (deleteSelectedButton) deleteSelectedButton.addEventListener('click', submitBulkDelete);
|
|
if (loadMoreButton) {
|
|
loadMoreButton.addEventListener('click', async function () {
|
|
loadMoreButton.disabled = true;
|
|
try {
|
|
const response = await fetch('/media-library/assets?' + getGalleryQuery(galleryOffset, 4 * getColumnsPerRow()), { headers: { Accept: 'application/json' } });
|
|
if (!response.ok) throw new Error('Unable to load more media.');
|
|
const result = await response.json();
|
|
(result.assets || []).forEach(appendGalleryAsset);
|
|
galleryOffset = Number(result.nextOffset || galleryOffset);
|
|
galleryHasMore = Boolean(result.hasMore);
|
|
galleryTotal = Number(result.total || galleryTotal);
|
|
visibleRowLimit += 4;
|
|
updateSearchResults();
|
|
} catch (error) {
|
|
showUploadMessage(error.message || 'Unable to load more media.');
|
|
} finally {
|
|
loadMoreButton.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
updateSearchResults();
|
|
|
|
function showPreviewModal() {
|
|
if (window.pulseModal && typeof window.pulseModal.show === 'function') {
|
|
window.pulseModal.show(modal);
|
|
} else if (window.bootstrap && window.bootstrap.Modal) {
|
|
window.bootstrap.Modal.getOrCreateInstance(modal).show();
|
|
}
|
|
}
|
|
|
|
if (modal && body) {
|
|
document.addEventListener('click', function (event) {
|
|
const preview = event.target && event.target.closest ? event.target.closest('[data-media-gallery-preview]') : null;
|
|
if (!preview) {
|
|
return;
|
|
}
|
|
|
|
const path = preview.getAttribute('data-media-path') || '';
|
|
const type = preview.getAttribute('data-media-type') || 'image';
|
|
const name = preview.getAttribute('data-media-name') || 'Media preview';
|
|
body.replaceChildren();
|
|
if (title) {
|
|
title.textContent = name;
|
|
}
|
|
|
|
const media = document.createElement(type === 'video' ? 'video' : 'img');
|
|
media.src = path;
|
|
media.alt = type === 'video' ? '' : name;
|
|
if (type === 'video') {
|
|
media.controls = true;
|
|
media.playsInline = true;
|
|
}
|
|
body.appendChild(media);
|
|
showPreviewModal();
|
|
});
|
|
|
|
modal.addEventListener('hidden.bs.modal', function () {
|
|
body.replaceChildren();
|
|
});
|
|
} |