imageviewer.js 8.3 KB
Newer Older
A
AUTOMATIC 已提交
1
// A full size 'lightbox' preview modal shown when left clicking on gallery previews
D
DepFA 已提交
2
function closeModal() {
3
    gradioApp().getElementById("lightboxModal").style.display = "none";
D
DepFA 已提交
4 5
}

6
function showModal(event) {
7 8 9 10 11 12 13
    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 + ')');
    }
14
    lb.style.display = "flex";
15
    lb.focus()
16 17 18 19 20 21 22 23 24

    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"
    }
25
    event.stopPropagation()
D
DepFA 已提交
26 27
}

28
function negmod(n, m) {
29
    return ((n % m) + m) % m;
30 31
}

32 33 34
function updateOnBackgroundChange() {
    const modalImage = gradioApp().getElementById("modalImage")
    if (modalImage && modalImage.offsetParent) {
S
space-nuko 已提交
35
        let currentButton = selected_gallery_button();
36

37
        if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
38 39 40 41 42
            modalImage.src = currentButton.children[0].src;
            if (modalImage.style.display === 'none') {
                modal.style.setProperty('background-image', `url(${modalImage.src})`)
            }
        }
43
    }
44 45 46
}

function modalImageSwitch(offset) {
S
space-nuko 已提交
47
    var galleryButtons = all_gallery_buttons();
48 49

    if (galleryButtons.length > 1) {
S
space-nuko 已提交
50
        var currentButton = selected_gallery_button();
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

        var result = -1
        galleryButtons.forEach(function(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(function() {
                modal.focus()
            }, 10)
71
        }
72
    }
73
}
D
DepFA 已提交
74

75 76 77 78 79
function saveImage(){
    const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
    const tabImg2Img = gradioApp().getElementById("tab_img2img")
    const saveTxt2Img = "save_txt2img"
    const saveImg2Img = "save_img2img"
80
    if (tabTxt2Img.style.display != "none") {
81
        gradioApp().getElementById(saveTxt2Img).click()
82
    } else if (tabImg2Img.style.display != "none") {
83 84 85 86 87 88 89 90 91 92 93
        gradioApp().getElementById(saveImg2Img).click()
    } else {
        console.error("missing implementation for saving modal of this type")
    }
}

function modalSaveImage(event) {
    saveImage()
    event.stopPropagation()
}

94 95 96
function modalNextImage(event) {
    modalImageSwitch(1)
    event.stopPropagation()
D
DepFA 已提交
97 98
}

99 100 101
function modalPrevImage(event) {
    modalImageSwitch(-1)
    event.stopPropagation()
102 103
}

104
function modalKeyHandler(event) {
105
    switch (event.key) {
106 107 108
        case "s":
            saveImage()
            break;
109 110 111 112 113 114
        case "ArrowLeft":
            modalPrevImage(event)
            break;
        case "ArrowRight":
            modalNextImage(event)
            break;
A
Adam Snodgrass 已提交
115 116 117
        case "Escape":
            closeModal();
            break;
118 119 120
    }
}

A
AUTOMATIC 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
function setupImageForLightbox(e) {
	if (e.dataset.modded)
		return;

	e.dataset.modded = true;
	e.style.cursor='pointer'
	e.style.userSelect='none'

	var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1

	// For Firefox, listening on click first switched to next image then shows the lightbox.
	// If you know how to fix this without switching to mousedown event, please.
	// For other browsers the event is click to make it possiblr to drag picture.
	var event = isFirefox ? 'mousedown' : 'click'

	e.addEventListener(event, function (evt) {
		if(!opts.js_modal_lightbox || evt.button != 0) return;

		modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
		evt.preventDefault()
		showModal(evt)
	}, true);
D
typo  
DepFA 已提交
143 144 145

}

146 147
function modalZoomSet(modalImage, enable) {
    if (enable) {
D
DepFA 已提交
148
        modalImage.classList.add('modalImageFullscreen');
149
    } else {
D
DepFA 已提交
150 151
        modalImage.classList.remove('modalImageFullscreen');
    }
152 153
}

154
function modalZoomToggle(event) {
155 156
    modalImage = gradioApp().getElementById("modalImage");
    modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
D
DepFA 已提交
157 158 159
    event.stopPropagation()
}

160
function modalTileImageToggle(event) {
161 162 163 164 165 166 167 168 169 170 171 172 173 174
    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()
}

175
function galleryImageHandler(e) {
A
AUTOMATIC 已提交
176
    //if (e && e.parentElement.tagName == 'BUTTON') {
D
typo  
DepFA 已提交
177
        e.onclick = showGalleryImage;
A
AUTOMATIC 已提交
178
    //}
D
typo  
DepFA 已提交
179 180
}

181
onUiUpdate(function() {
A
AUTOMATIC 已提交
182
    fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img')
183
    if (fullImg_preview != null) {
A
AUTOMATIC 已提交
184
        fullImg_preview.forEach(setupImageForLightbox);
D
DepFA 已提交
185
    }
186
    updateOnBackgroundChange();
A
AUTOMATIC 已提交
187
})
188 189

document.addEventListener("DOMContentLoaded", function() {
A
AUTOMATIC 已提交
190
    //const modalFragment = document.createDocumentFragment();
D
DepFA 已提交
191 192
    const modal = document.createElement('div')
    modal.onclick = closeModal;
D
DepFA 已提交
193
    modal.id = "lightboxModal";
194
    modal.tabIndex = 0
D
DepFA 已提交
195 196
    modal.addEventListener('keydown', modalKeyHandler, true)

197 198 199
    const modalControls = document.createElement('div')
    modalControls.className = 'modalControls gradio-container';
    modal.append(modalControls);
200

D
DepFA 已提交
201 202 203 204
    const modalZoom = document.createElement('span')
    modalZoom.className = 'modalZoom cursor';
    modalZoom.innerHTML = '⤡'
    modalZoom.addEventListener('click', modalZoomToggle, true)
205
    modalZoom.title = "Toggle zoomed view";
206 207
    modalControls.appendChild(modalZoom)

208 209 210
    const modalTileImage = document.createElement('span')
    modalTileImage.className = 'modalTileImage cursor';
    modalTileImage.innerHTML = '⊞'
211
    modalTileImage.addEventListener('click', modalTileImageToggle, true)
212
    modalTileImage.title = "Preview tiling";
213 214
    modalControls.appendChild(modalTileImage)

215 216
    const modalSave = document.createElement("span")
    modalSave.className = "modalSave cursor"
217
    modalSave.id = "modal_save"
218 219 220 221 222
    modalSave.innerHTML = "🖫"
    modalSave.addEventListener("click", modalSaveImage, true)
    modalSave.title = "Save Image(s)"
    modalControls.appendChild(modalSave)

223 224 225 226
    const modalClose = document.createElement('span')
    modalClose.className = 'modalClose cursor';
    modalClose.innerHTML = '×'
    modalClose.onclick = closeModal;
227
    modalClose.title = "Close image viewer";
228
    modalControls.appendChild(modalClose)
D
DepFA 已提交
229

D
DepFA 已提交
230 231 232
    const modalImage = document.createElement('img')
    modalImage.id = 'modalImage';
    modalImage.onclick = closeModal;
233
    modalImage.tabIndex = 0
234
    modalImage.addEventListener('keydown', modalKeyHandler, true)
D
DepFA 已提交
235 236
    modal.appendChild(modalImage)

237 238 239
    const modalPrev = document.createElement('a')
    modalPrev.className = 'modalPrev';
    modalPrev.innerHTML = '❮'
240 241
    modalPrev.tabIndex = 0
    modalPrev.addEventListener('click', modalPrevImage, true);
242 243 244 245 246 247
    modalPrev.addEventListener('keydown', modalKeyHandler, true)
    modal.appendChild(modalPrev)

    const modalNext = document.createElement('a')
    modalNext.className = 'modalNext';
    modalNext.innerHTML = '❯'
248 249
    modalNext.tabIndex = 0
    modalNext.addEventListener('click', modalNextImage, true);
250 251 252 253
    modalNext.addEventListener('keydown', modalKeyHandler, true)

    modal.appendChild(modalNext)

A
AlUlkesh 已提交
254 255 256 257 258
    try {
		gradioApp().appendChild(modal);
	} catch (e) {
		gradioApp().body.appendChild(modal);
	}
259

A
AUTOMATIC 已提交
260
    document.body.appendChild(modal);
261

262
});