imageviewer.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // A full size 'lightbox' preview modal shown when left clicking on gallery previews
  2. function closeModal() {
  3. gradioApp().getElementById("lightboxModal").style.display = "none";
  4. }
  5. function showModal(event) {
  6. const source = event.target || event.srcElement;
  7. const modalImage = gradioApp().getElementById("modalImage")
  8. const lb = gradioApp().getElementById("lightboxModal")
  9. modalImage.src = source.src
  10. if (modalImage.style.display === 'none') {
  11. lb.style.setProperty('background-image', 'url(' + source.src + ')');
  12. }
  13. lb.style.display = "flex";
  14. lb.focus()
  15. const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
  16. const tabImg2Img = gradioApp().getElementById("tab_img2img")
  17. // show the save button in modal only on txt2img or img2img tabs
  18. if (tabTxt2Img.style.display != "none" || tabImg2Img.style.display != "none") {
  19. gradioApp().getElementById("modal_save").style.display = "inline"
  20. } else {
  21. gradioApp().getElementById("modal_save").style.display = "none"
  22. }
  23. event.stopPropagation()
  24. }
  25. function negmod(n, m) {
  26. return ((n % m) + m) % m;
  27. }
  28. function updateOnBackgroundChange() {
  29. const modalImage = gradioApp().getElementById("modalImage")
  30. if (modalImage && modalImage.offsetParent) {
  31. let currentButton = selected_gallery_button();
  32. if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
  33. modalImage.src = currentButton.children[0].src;
  34. if (modalImage.style.display === 'none') {
  35. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  36. }
  37. }
  38. }
  39. }
  40. function modalImageSwitch(offset) {
  41. var galleryButtons = all_gallery_buttons();
  42. if (galleryButtons.length > 1) {
  43. var currentButton = selected_gallery_button();
  44. var result = -1
  45. galleryButtons.forEach(function(v, i) {
  46. if (v == currentButton) {
  47. result = i
  48. }
  49. })
  50. if (result != -1) {
  51. nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]
  52. nextButton.click()
  53. const modalImage = gradioApp().getElementById("modalImage");
  54. const modal = gradioApp().getElementById("lightboxModal");
  55. modalImage.src = nextButton.children[0].src;
  56. if (modalImage.style.display === 'none') {
  57. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  58. }
  59. setTimeout(function() {
  60. modal.focus()
  61. }, 10)
  62. }
  63. }
  64. }
  65. function saveImage(){
  66. const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
  67. const tabImg2Img = gradioApp().getElementById("tab_img2img")
  68. const saveTxt2Img = "save_txt2img"
  69. const saveImg2Img = "save_img2img"
  70. if (tabTxt2Img.style.display != "none") {
  71. gradioApp().getElementById(saveTxt2Img).click()
  72. } else if (tabImg2Img.style.display != "none") {
  73. gradioApp().getElementById(saveImg2Img).click()
  74. } else {
  75. console.error("missing implementation for saving modal of this type")
  76. }
  77. }
  78. function modalSaveImage(event) {
  79. saveImage()
  80. event.stopPropagation()
  81. }
  82. function modalNextImage(event) {
  83. modalImageSwitch(1)
  84. event.stopPropagation()
  85. }
  86. function modalPrevImage(event) {
  87. modalImageSwitch(-1)
  88. event.stopPropagation()
  89. }
  90. function modalKeyHandler(event) {
  91. switch (event.key) {
  92. case "s":
  93. saveImage()
  94. break;
  95. case "ArrowLeft":
  96. modalPrevImage(event)
  97. break;
  98. case "ArrowRight":
  99. modalNextImage(event)
  100. break;
  101. case "Escape":
  102. closeModal();
  103. break;
  104. }
  105. }
  106. function setupImageForLightbox(e) {
  107. if (e.dataset.modded)
  108. return;
  109. e.dataset.modded = true;
  110. e.style.cursor='pointer'
  111. e.style.userSelect='none'
  112. var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
  113. // For Firefox, listening on click first switched to next image then shows the lightbox.
  114. // If you know how to fix this without switching to mousedown event, please.
  115. // For other browsers the event is click to make it possiblr to drag picture.
  116. var event = isFirefox ? 'mousedown' : 'click'
  117. e.addEventListener(event, function (evt) {
  118. if(!opts.js_modal_lightbox || evt.button != 0) return;
  119. modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
  120. evt.preventDefault()
  121. showModal(evt)
  122. }, true);
  123. }
  124. function modalZoomSet(modalImage, enable) {
  125. if (enable) {
  126. modalImage.classList.add('modalImageFullscreen');
  127. } else {
  128. modalImage.classList.remove('modalImageFullscreen');
  129. }
  130. }
  131. function modalZoomToggle(event) {
  132. modalImage = gradioApp().getElementById("modalImage");
  133. modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
  134. event.stopPropagation()
  135. }
  136. function modalTileImageToggle(event) {
  137. const modalImage = gradioApp().getElementById("modalImage");
  138. const modal = gradioApp().getElementById("lightboxModal");
  139. const isTiling = modalImage.style.display === 'none';
  140. if (isTiling) {
  141. modalImage.style.display = 'block';
  142. modal.style.setProperty('background-image', 'none')
  143. } else {
  144. modalImage.style.display = 'none';
  145. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  146. }
  147. event.stopPropagation()
  148. }
  149. function galleryImageHandler(e) {
  150. //if (e && e.parentElement.tagName == 'BUTTON') {
  151. e.onclick = showGalleryImage;
  152. //}
  153. }
  154. onUiUpdate(function() {
  155. fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img')
  156. if (fullImg_preview != null) {
  157. fullImg_preview.forEach(setupImageForLightbox);
  158. }
  159. updateOnBackgroundChange();
  160. })
  161. document.addEventListener("DOMContentLoaded", function() {
  162. //const modalFragment = document.createDocumentFragment();
  163. const modal = document.createElement('div')
  164. modal.onclick = closeModal;
  165. modal.id = "lightboxModal";
  166. modal.tabIndex = 0
  167. modal.addEventListener('keydown', modalKeyHandler, true)
  168. const modalControls = document.createElement('div')
  169. modalControls.className = 'modalControls gradio-container';
  170. modal.append(modalControls);
  171. const modalZoom = document.createElement('span')
  172. modalZoom.className = 'modalZoom cursor';
  173. modalZoom.innerHTML = '⤡'
  174. modalZoom.addEventListener('click', modalZoomToggle, true)
  175. modalZoom.title = "Toggle zoomed view";
  176. modalControls.appendChild(modalZoom)
  177. const modalTileImage = document.createElement('span')
  178. modalTileImage.className = 'modalTileImage cursor';
  179. modalTileImage.innerHTML = '⊞'
  180. modalTileImage.addEventListener('click', modalTileImageToggle, true)
  181. modalTileImage.title = "Preview tiling";
  182. modalControls.appendChild(modalTileImage)
  183. const modalSave = document.createElement("span")
  184. modalSave.className = "modalSave cursor"
  185. modalSave.id = "modal_save"
  186. modalSave.innerHTML = "🖫"
  187. modalSave.addEventListener("click", modalSaveImage, true)
  188. modalSave.title = "Save Image(s)"
  189. modalControls.appendChild(modalSave)
  190. const modalClose = document.createElement('span')
  191. modalClose.className = 'modalClose cursor';
  192. modalClose.innerHTML = '×'
  193. modalClose.onclick = closeModal;
  194. modalClose.title = "Close image viewer";
  195. modalControls.appendChild(modalClose)
  196. const modalImage = document.createElement('img')
  197. modalImage.id = 'modalImage';
  198. modalImage.onclick = closeModal;
  199. modalImage.tabIndex = 0
  200. modalImage.addEventListener('keydown', modalKeyHandler, true)
  201. modal.appendChild(modalImage)
  202. const modalPrev = document.createElement('a')
  203. modalPrev.className = 'modalPrev';
  204. modalPrev.innerHTML = '❮'
  205. modalPrev.tabIndex = 0
  206. modalPrev.addEventListener('click', modalPrevImage, true);
  207. modalPrev.addEventListener('keydown', modalKeyHandler, true)
  208. modal.appendChild(modalPrev)
  209. const modalNext = document.createElement('a')
  210. modalNext.className = 'modalNext';
  211. modalNext.innerHTML = '❯'
  212. modalNext.tabIndex = 0
  213. modalNext.addEventListener('click', modalNextImage, true);
  214. modalNext.addEventListener('keydown', modalKeyHandler, true)
  215. modal.appendChild(modalNext)
  216. gradioApp().appendChild(modal)
  217. document.body.appendChild(modal);
  218. });