Files
automatic/javascript/imageViewer.js
T
Kubuxu 3ca3964171 Fix image viewer
Short click (<100 ms) will keep the image open.
Click and hold will close the image after the mouse button is released.
Click, hold and move mouse won't close the image.
No changes regarding mobile, it will still need work in that regard.
2023-07-08 22:10:21 +01:00

227 lines
7.8 KiB
JavaScript

// A full size 'lightbox' preview modal shown when left clicking on gallery previews
function closeModal() {
gradioApp().getElementById('lightboxModal').style.display = 'none';
}
let preventImmediateClose = false;
function showModal(event) {
const source = event.target || event.srcElement;
const modalImage = gradioApp().getElementById('modalImage');
const lb = gradioApp().getElementById('lightboxModal');
modalImage.src = source.src;
if (modalImage.style.display === 'none') lb.style.setProperty('background-image', `url(${source.src})`);
lb.style.display = 'flex';
lb.focus();
const tabTxt2Img = gradioApp().getElementById('tab_txt2img');
const tabImg2Img = gradioApp().getElementById('tab_img2img');
// show the save button in modal only on txt2img or img2img tabs
if (tabTxt2Img.style.display != 'none' || tabImg2Img.style.display != 'none') gradioApp().getElementById('modal_save').style.display = 'inline';
else gradioApp().getElementById('modal_save').style.display = 'none';
const ignoreEvent = (ev) => {ev.stopImmediatePropagation()}
preventImmediateClose = true
setTimeout(() => {
preventImmediateClose = false
}, 100)
event.stopPropagation();
}
function negmod(n, m) {
return ((n % m) + m) % m;
}
function updateOnBackgroundChange() {
const modalImage = gradioApp().getElementById('modalImage');
if (modalImage && modalImage.offsetParent) {
const currentButton = selected_gallery_button();
if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
modalImage.src = currentButton.children[0].src;
if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${modalImage.src})`);
}
}
}
function modalImageSwitch(offset) {
const galleryButtons = all_gallery_buttons();
if (galleryButtons.length > 1) {
const currentButton = selected_gallery_button();
let result = -1;
galleryButtons.forEach((v, i) => {
if (v == currentButton) result = i;
});
if (result != -1) {
nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];
nextButton.click();
const modalImage = gradioApp().getElementById('modalImage');
const modal = gradioApp().getElementById('lightboxModal');
modalImage.src = nextButton.children[0].src;
if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${modalImage.src})`);
setTimeout(() => modal.focus(), 10);
}
}
}
function saveImage() {
const tabTxt2Img = gradioApp().getElementById('tab_txt2img');
const tabImg2Img = gradioApp().getElementById('tab_img2img');
const saveTxt2Img = 'save_txt2img';
const saveImg2Img = 'save_img2img';
if (tabTxt2Img.style.display != 'none') gradioApp().getElementById(saveTxt2Img).click();
else if (tabImg2Img.style.display != 'none') gradioApp().getElementById(saveImg2Img).click();
else console.error('missing implementation for saving modal of this type');
}
function modalSaveImage(event) {
saveImage();
event.stopPropagation();
}
function modalNextImage(event) {
modalImageSwitch(1);
event.stopPropagation();
}
function modalPrevImage(event) {
modalImageSwitch(-1);
event.stopPropagation();
}
function modalKeyHandler(event) {
switch (event.key) {
case 's':
saveImage();
break;
case 'ArrowLeft':
modalPrevImage(event);
break;
case 'ArrowRight':
modalNextImage(event);
break;
case 'Escape':
closeModal();
break;
}
}
function modalZoomSet(modalImage, enable) {
localStorage.setItem('modalZoom', enable ? 'yes' : 'no');
if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);
}
function setupImageForLightbox(e) {
if (e.dataset.modded) return;
e.dataset.modded = true;
e.style.cursor = 'pointer';
e.style.userSelect = 'none';
e.addEventListener('mousedown', (evt) => {
if (evt.button != 0) return;
const initialZoom = (localStorage.getItem('modalZoom') || true) == 'yes';
modalZoomSet(gradioApp().getElementById('modalImage'), initialZoom);
evt.preventDefault();
showModal(evt);
}, true);
}
function modalZoomToggle(event) {
const modalImage = gradioApp().getElementById('modalImage');
modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'));
event.stopPropagation();
}
function modalTileImageToggle(event) {
const modalImage = gradioApp().getElementById('modalImage');
const modal = gradioApp().getElementById('lightboxModal');
const isTiling = modalImage.style.display === 'none';
if (isTiling) {
modalImage.style.display = 'block';
modal.style.setProperty('background-image', 'none');
} else {
modalImage.style.display = 'none';
modal.style.setProperty('background-image', `url(${modalImage.src})`);
}
event.stopPropagation();
}
function galleryImageHandler(e) {
e.onclick = showGalleryImage;
}
onAfterUiUpdate(() => {
fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img');
if (fullImg_preview != null) fullImg_preview.forEach(setupImageForLightbox);
updateOnBackgroundChange();
});
document.addEventListener('DOMContentLoaded', () => {
const modal = document.createElement('div');
modal.id = 'lightboxModal';
modal.tabIndex = 0;
modal.addEventListener('keydown', modalKeyHandler, true);
const modalPreviewZone = document.createElement('div');
modalPreviewZone.className = 'lightboxModalPreviewZone'
modalPreviewZone.tabIndex = 0;
const modalControls = document.createElement('div');
modalControls.className = 'modalControls gradio-container';
modal.append(modalControls);
const modalZoom = document.createElement('span');
modalZoom.className = 'modalZoom cursor';
modalZoom.innerHTML = '&#10529;';
modalZoom.addEventListener('click', modalZoomToggle, true);
modalZoom.title = 'Toggle zoomed view';
modalControls.appendChild(modalZoom);
const modalTileImage = document.createElement('span');
modalTileImage.className = 'modalTileImage cursor';
modalTileImage.innerHTML = '&#8862;';
modalTileImage.addEventListener('click', modalTileImageToggle, true);
modalTileImage.title = 'Preview tiling';
modalControls.appendChild(modalTileImage);
const modalSave = document.createElement('span');
modalSave.className = 'modalSave cursor';
modalSave.id = 'modal_save';
modalSave.innerHTML = '&#x1F5AB;';
modalSave.addEventListener('click', modalSaveImage, true);
modalSave.title = 'Save Image(s)';
modalControls.appendChild(modalSave);
const modalImage = document.createElement('img');
modalImage.id = 'modalImage';
modalImage.tabIndex = 0;
modalImage.addEventListener('keydown', modalKeyHandler, true);
modalPreviewZone.appendChild(modalImage);
modalImage.onload = () => panzoom(modalImage, { zoomSpeed: 0.025, minZoom: 0.25, maxZoom: 4.0 });
let drag = false;
modalPreviewZone.addEventListener('mousedown', () => drag = false);
modalPreviewZone.addEventListener('mousemove', () => drag = true);
modalPreviewZone.addEventListener('scroll', () => drag = true);
modalPreviewZone.addEventListener('mouseup', () => { if (!drag && !preventImmediateClose) closeModal(); });
const modalPrev = document.createElement('a');
modalPrev.className = 'modalPrev';
modalPrev.innerHTML = '&#10094;';
modalPrev.tabIndex = 0;
modalPrev.addEventListener('click', modalPrevImage, true);
modalPrev.addEventListener('keydown', modalKeyHandler, true);
modal.appendChild(modalPrev);
modal.appendChild(modalPreviewZone);
const modalNext = document.createElement('a');
modalNext.className = 'modalNext';
modalNext.innerHTML = '&#10095;';
modalNext.tabIndex = 0;
modalNext.addEventListener('click', modalNextImage, true);
modalNext.addEventListener('keydown', modalKeyHandler, true);
modal.appendChild(modalNext);
try { gradioApp().appendChild(modal); } catch (e) { gradioApp().body.appendChild(modal); }
});