Spaces:
Runtime error
Runtime error
| // A full size 'lightbox' preview modal shown when left clicking on gallery previews | |
| let previewDrag = false; | |
| let modalPreviewZone; | |
| let previewInstance; | |
| function closeModal(evt, force = false) { | |
| if (force) gradioApp().getElementById('lightboxModal').style.display = 'none'; | |
| if (previewDrag) return; | |
| if (evt?.button !== 0) return; | |
| gradioApp().getElementById('lightboxModal').style.display = 'none'; | |
| } | |
| 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; | |
| }); | |
| const negmod = (n, m) => ((n % m) + m) % m; | |
| if (result !== -1) { | |
| const 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})`); | |
| } | |
| } | |
| } | |
| function modalSaveImage(event) { | |
| if (gradioApp().getElementById('tab_txt2img').style.display !== 'none') gradioApp().getElementById('save_txt2img').click(); | |
| else if (gradioApp().getElementById('tab_img2img').style.display !== 'none') gradioApp().getElementById('save_img2img').click(); | |
| else if (gradioApp().getElementById('tab_process').style.display !== 'none') gradioApp().getElementById('save_extras').click(); | |
| } | |
| function modalKeyHandler(event) { | |
| switch (event.key) { | |
| case 's': | |
| modalSaveImage(); | |
| break; | |
| case 'ArrowLeft': | |
| modalImageSwitch(-1); | |
| break; | |
| case 'ArrowRight': | |
| modalImageSwitch(1); | |
| break; | |
| case 'Escape': | |
| closeModal(null, true); | |
| break; | |
| } | |
| event.stopPropagation(); | |
| } | |
| async function displayExif(el) { | |
| const modalExif = gradioApp().getElementById('modalExif'); | |
| modalExif.innerHTML = ''; | |
| const exif = await window.exifr.parse(el); | |
| if (!exif) return; | |
| // log('exif', exif); | |
| try { | |
| let html = ` | |
| <b>Image</b> <a href="${el.src}" target="_blank">${el.src}</a> <b>Size</b> ${el.naturalWidth}x${el.naturalHeight}<br> | |
| <b>Prompt</b> ${exif.parameters || ''}<br> | |
| `; | |
| html = html.replace('\n', '<br>'); | |
| html = html.replace('Negative prompt:', '<br><b>Negative</b>'); | |
| html = html.replace('Steps:', '<br><b>Params</b> Steps:'); | |
| modalExif.innerHTML = html; | |
| } catch (e) { } | |
| } | |
| function showModal(event) { | |
| const source = event.target || event.srcElement; | |
| const modalImage = gradioApp().getElementById('modalImage'); | |
| const lb = gradioApp().getElementById('lightboxModal'); | |
| lb.ownerSVGElement = modalImage; | |
| modalImage.onload = () => { | |
| previewInstance.moveTo(0, 0); | |
| modalPreviewZone.focus(); | |
| displayExif(modalImage); | |
| }; | |
| modalImage.src = source.src; | |
| if (modalImage.style.display === 'none') lb.style.setProperty('background-image', `url(${source.src})`); | |
| lb.style.display = 'flex'; | |
| lb.onkeydown = modalKeyHandler; | |
| event.stopPropagation(); | |
| } | |
| function modalDownloadImage() { | |
| const link = document.createElement('a'); | |
| link.style.display = 'none'; | |
| link.href = gradioApp().getElementById('modalImage').src; | |
| link.download = 'image'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| setTimeout(() => { | |
| URL.revokeObjectURL(link.href); | |
| link.parentNode.removeChild(link); | |
| }, 0); | |
| } | |
| function modalZoomSet(modalImage, enable) { | |
| localStorage.setItem('modalZoom', enable ? 'yes' : 'no'); | |
| if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable); | |
| } | |
| function setupImageForLightbox(image) { | |
| if (image.dataset.modded) return; | |
| image.dataset.modded = 'true'; | |
| image.style.cursor = 'pointer'; | |
| image.style.userSelect = 'none'; | |
| } | |
| function modalZoomToggle(event) { | |
| const modalImage = gradioApp().getElementById('modalImage'); | |
| modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen')); | |
| event.stopPropagation(); | |
| } | |
| function modalTileToggle(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 modalResetInstance(event) { | |
| const modalImage = document.getElementById('modalImage'); | |
| previewInstance.dispose(); | |
| previewInstance = panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true }); | |
| } | |
| let imageViewerInitialized = false; | |
| function galleryClickEventHandler(event) { | |
| if (event.button !== 0) return; | |
| if (event.target.nodeName === 'IMG' && !event.target.parentNode.classList.contains('thumbnail-item')) { | |
| const initialZoom = (localStorage.getItem('modalZoom') || true) === 'yes'; | |
| modalZoomSet(gradioApp().getElementById('modalImage'), initialZoom); | |
| event.preventDefault(); | |
| showModal(event); | |
| } | |
| } | |
| async function initImageViewer() { | |
| // Each tab has its own gradio-gallery | |
| const galleryPreviews = gradioApp().querySelectorAll('.gradio-gallery > div.preview'); | |
| if (galleryPreviews.length > 0) { | |
| for (const galleryPreview of galleryPreviews) { | |
| const fullImgPreview = galleryPreview.querySelectorAll('img'); | |
| if (fullImgPreview.length > 0) { | |
| galleryPreview.addEventListener('click', galleryClickEventHandler, true); | |
| fullImgPreview.forEach(setupImageForLightbox); | |
| } | |
| } | |
| } | |
| if (imageViewerInitialized) return; | |
| imageViewerInitialized = true; | |
| // main elements | |
| const modal = document.createElement('div'); | |
| modal.id = 'lightboxModal'; | |
| modalPreviewZone = document.createElement('div'); | |
| modalPreviewZone.className = 'lightboxModalPreviewZone'; | |
| const modalImage = document.createElement('img'); | |
| modalImage.id = 'modalImage'; | |
| modalPreviewZone.appendChild(modalImage); | |
| previewInstance = panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true }); | |
| // toolbar | |
| const modalZoom = document.createElement('span'); | |
| modalZoom.id = 'modal_zoom'; | |
| modalZoom.className = 'cursor'; | |
| modalZoom.innerHTML = '\uf531'; | |
| modalZoom.title = 'Toggle zoomed view'; | |
| modalZoom.addEventListener('click', modalZoomToggle, true); | |
| const modalReset = document.createElement('span'); | |
| modalReset.id = 'modal_reset'; | |
| modalReset.className = 'cursor'; | |
| modalReset.innerHTML = '\uf532'; | |
| modalReset.title = 'Reset zoomed view'; | |
| modalReset.addEventListener('click', modalResetInstance, true); | |
| const modalTile = document.createElement('span'); | |
| modalTile.id = 'modal_tile'; | |
| modalTile.className = 'cursor'; | |
| modalTile.innerHTML = '\udb81\udd70'; | |
| modalTile.title = 'Preview tiling'; | |
| modalTile.addEventListener('click', modalTileToggle, true); | |
| const modalSave = document.createElement('span'); | |
| modalSave.id = 'modal_save'; | |
| modalSave.className = 'cursor'; | |
| modalSave.innerHTML = '\udb80\udd93'; | |
| modalSave.title = 'Save Image'; | |
| modalSave.addEventListener('click', modalSaveImage, true); | |
| const modalDownload = document.createElement('span'); | |
| modalDownload.id = 'modal_download'; | |
| modalDownload.className = 'cursor'; | |
| modalDownload.innerHTML = '\udb85\udc62'; | |
| modalDownload.title = 'Download Image'; | |
| modalDownload.addEventListener('click', modalDownloadImage, true); | |
| const modalClose = document.createElement('span'); | |
| modalClose.id = 'modal_close'; | |
| modalClose.className = 'cursor'; | |
| modalClose.innerHTML = '\udb80\udd57'; | |
| modalClose.title = 'Close'; | |
| modalClose.addEventListener('click', (evt) => closeModal(evt, true), true); | |
| // exif | |
| const modalExif = document.createElement('div'); | |
| modalExif.id = 'modalExif'; | |
| modalExif.style = 'position: absolute; bottom: 0px; width: 98%; background-color: rgba(0, 0, 0, 0.5); color: var(--neutral-300); padding: 1em; font-size: small;'; | |
| // handlers | |
| modalPreviewZone.addEventListener('mousedown', () => { previewDrag = false; }); | |
| modalPreviewZone.addEventListener('touchstart', () => { previewDrag = false; }, { passive: true }); | |
| modalPreviewZone.addEventListener('mousemove', () => { previewDrag = true; }); | |
| modalPreviewZone.addEventListener('touchmove', () => { previewDrag = true; }, { passive: true }); | |
| modalPreviewZone.addEventListener('scroll', () => { previewDrag = true; }); | |
| modalPreviewZone.addEventListener('mouseup', (evt) => closeModal(evt)); | |
| modalPreviewZone.addEventListener('touchend', (evt) => closeModal(evt)); | |
| const modalPrev = document.createElement('a'); | |
| modalPrev.className = 'modalPrev'; | |
| modalPrev.innerHTML = '❮'; | |
| modalPrev.addEventListener('click', () => modalImageSwitch(-1), true); | |
| // modalPrev.addEventListener('keydown', modalKeyHandler, true); | |
| const modalNext = document.createElement('a'); | |
| modalNext.className = 'modalNext'; | |
| modalNext.innerHTML = '❯'; | |
| modalNext.addEventListener('click', () => modalImageSwitch(1), true); | |
| // modalNext.addEventListener('keydown', modalKeyHandler, true); | |
| const modalControls = document.createElement('div'); | |
| modalControls.className = 'modalControls gradio-container'; | |
| // build interface | |
| modal.appendChild(modalPrev); | |
| modal.appendChild(modalPreviewZone); | |
| modal.appendChild(modalNext); | |
| modal.append(modalControls); | |
| modal.append(modalExif); | |
| modalControls.appendChild(modalZoom); | |
| modalControls.appendChild(modalReset); | |
| modalControls.appendChild(modalTile); | |
| modalControls.appendChild(modalSave); | |
| modalControls.appendChild(modalDownload); | |
| modalControls.appendChild(modalClose); | |
| gradioApp().appendChild(modal); | |
| log('initImageViewer'); | |
| } | |
| onAfterUiUpdate(initImageViewer); | |