imageviewer.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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 = "block";
  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 allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
  32. let currentButton = null
  33. allcurrentButtons.forEach(function(elem) {
  34. if (elem.parentElement.offsetParent) {
  35. currentButton = elem;
  36. }
  37. })
  38. if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
  39. modalImage.src = currentButton.children[0].src;
  40. if (modalImage.style.display === 'none') {
  41. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  42. }
  43. }
  44. }
  45. }
  46. function modalImageSwitch(offset) {
  47. var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all")
  48. var galleryButtons = []
  49. allgalleryButtons.forEach(function(elem) {
  50. if (elem.parentElement.offsetParent) {
  51. galleryButtons.push(elem);
  52. }
  53. })
  54. if (galleryButtons.length > 1) {
  55. var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
  56. var currentButton = null
  57. allcurrentButtons.forEach(function(elem) {
  58. if (elem.parentElement.offsetParent) {
  59. currentButton = elem;
  60. }
  61. })
  62. var result = -1
  63. galleryButtons.forEach(function(v, i) {
  64. if (v == currentButton) {
  65. result = i
  66. }
  67. })
  68. if (result != -1) {
  69. nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]
  70. nextButton.click()
  71. const modalImage = gradioApp().getElementById("modalImage");
  72. const modal = gradioApp().getElementById("lightboxModal");
  73. modalImage.src = nextButton.children[0].src;
  74. if (modalImage.style.display === 'none') {
  75. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  76. }
  77. setTimeout(function() {
  78. modal.focus()
  79. }, 10)
  80. }
  81. }
  82. }
  83. function saveImage(){
  84. const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
  85. const tabImg2Img = gradioApp().getElementById("tab_img2img")
  86. const saveTxt2Img = "save_txt2img"
  87. const saveImg2Img = "save_img2img"
  88. if (tabTxt2Img.style.display != "none") {
  89. gradioApp().getElementById(saveTxt2Img).click()
  90. } else if (tabImg2Img.style.display != "none") {
  91. gradioApp().getElementById(saveImg2Img).click()
  92. } else {
  93. console.error("missing implementation for saving modal of this type")
  94. }
  95. }
  96. function modalSaveImage(event) {
  97. saveImage()
  98. event.stopPropagation()
  99. }
  100. function modalNextImage(event) {
  101. modalImageSwitch(1)
  102. event.stopPropagation()
  103. }
  104. function modalPrevImage(event) {
  105. modalImageSwitch(-1)
  106. event.stopPropagation()
  107. }
  108. function modalKeyHandler(event) {
  109. switch (event.key) {
  110. case "s":
  111. saveImage()
  112. break;
  113. case "ArrowLeft":
  114. modalPrevImage(event)
  115. break;
  116. case "ArrowRight":
  117. modalNextImage(event)
  118. break;
  119. case "Escape":
  120. closeModal();
  121. break;
  122. }
  123. }
  124. function showGalleryImage() {
  125. setTimeout(function() {
  126. fullImg_preview = gradioApp().querySelectorAll('img.w-full.object-contain')
  127. if (fullImg_preview != null) {
  128. fullImg_preview.forEach(function function_name(e) {
  129. if (e.dataset.modded)
  130. return;
  131. e.dataset.modded = true;
  132. if(e && e.parentElement.tagName == 'DIV'){
  133. e.style.cursor='pointer'
  134. e.style.userSelect='none'
  135. var isFirefox = isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
  136. // For Firefox, listening on click first switched to next image then shows the lightbox.
  137. // If you know how to fix this without switching to mousedown event, please.
  138. // For other browsers the event is click to make it possiblr to drag picture.
  139. var event = isFirefox ? 'mousedown' : 'click'
  140. e.addEventListener(event, function (evt) {
  141. if(!opts.js_modal_lightbox || evt.button != 0) return;
  142. modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
  143. evt.preventDefault()
  144. showModal(evt)
  145. }, true);
  146. }
  147. });
  148. }
  149. }, 100);
  150. }
  151. function modalZoomSet(modalImage, enable) {
  152. if (enable) {
  153. modalImage.classList.add('modalImageFullscreen');
  154. } else {
  155. modalImage.classList.remove('modalImageFullscreen');
  156. }
  157. }
  158. function modalZoomToggle(event) {
  159. modalImage = gradioApp().getElementById("modalImage");
  160. modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
  161. event.stopPropagation()
  162. }
  163. function modalTileImageToggle(event) {
  164. const modalImage = gradioApp().getElementById("modalImage");
  165. const modal = gradioApp().getElementById("lightboxModal");
  166. const isTiling = modalImage.style.display === 'none';
  167. if (isTiling) {
  168. modalImage.style.display = 'block';
  169. modal.style.setProperty('background-image', 'none')
  170. } else {
  171. modalImage.style.display = 'none';
  172. modal.style.setProperty('background-image', `url(${modalImage.src})`)
  173. }
  174. event.stopPropagation()
  175. }
  176. function galleryImageHandler(e) {
  177. if (e && e.parentElement.tagName == 'BUTTON') {
  178. e.onclick = showGalleryImage;
  179. }
  180. }
  181. onUiUpdate(function() {
  182. fullImg_preview = gradioApp().querySelectorAll('img.w-full')
  183. if (fullImg_preview != null) {
  184. fullImg_preview.forEach(galleryImageHandler);
  185. }
  186. updateOnBackgroundChange();
  187. })
  188. document.addEventListener("DOMContentLoaded", function() {
  189. const modalFragment = document.createDocumentFragment();
  190. const modal = document.createElement('div')
  191. modal.onclick = closeModal;
  192. modal.id = "lightboxModal";
  193. modal.tabIndex = 0
  194. modal.addEventListener('keydown', modalKeyHandler, true)
  195. // detect gamepads and enable related functionality
  196. let gamepadScript = document.createElement('script');
  197. gamepadScript.src = 'imageviewerGamepad.js';
  198. document.body.appendChild(gamepadScript);
  199. const modalControls = document.createElement('div')
  200. modalControls.className = 'modalControls gradio-container';
  201. modal.append(modalControls);
  202. const modalZoom = document.createElement('span')
  203. modalZoom.className = 'modalZoom cursor';
  204. modalZoom.innerHTML = '⤡'
  205. modalZoom.addEventListener('click', modalZoomToggle, true)
  206. modalZoom.title = "Toggle zoomed view";
  207. modalControls.appendChild(modalZoom)
  208. const modalTileImage = document.createElement('span')
  209. modalTileImage.className = 'modalTileImage cursor';
  210. modalTileImage.innerHTML = '⊞'
  211. modalTileImage.addEventListener('click', modalTileImageToggle, true)
  212. modalTileImage.title = "Preview tiling";
  213. modalControls.appendChild(modalTileImage)
  214. const modalSave = document.createElement("span")
  215. modalSave.className = "modalSave cursor"
  216. modalSave.id = "modal_save"
  217. modalSave.innerHTML = "🖫"
  218. modalSave.addEventListener("click", modalSaveImage, true)
  219. modalSave.title = "Save Image(s)"
  220. modalControls.appendChild(modalSave)
  221. const modalClose = document.createElement('span')
  222. modalClose.className = 'modalClose cursor';
  223. modalClose.innerHTML = '×'
  224. modalClose.onclick = closeModal;
  225. modalClose.title = "Close image viewer";
  226. modalControls.appendChild(modalClose)
  227. const modalImage = document.createElement('img')
  228. modalImage.id = 'modalImage';
  229. modalImage.onclick = closeModal;
  230. modalImage.tabIndex = 0
  231. modalImage.addEventListener('keydown', modalKeyHandler, true)
  232. modal.appendChild(modalImage)
  233. const modalPrev = document.createElement('a')
  234. modalPrev.className = 'modalPrev';
  235. modalPrev.innerHTML = '❮'
  236. modalPrev.tabIndex = 0
  237. modalPrev.addEventListener('click', modalPrevImage, true);
  238. modalPrev.addEventListener('keydown', modalKeyHandler, true)
  239. modal.appendChild(modalPrev)
  240. const modalNext = document.createElement('a')
  241. modalNext.className = 'modalNext';
  242. modalNext.innerHTML = '❯'
  243. modalNext.tabIndex = 0
  244. modalNext.addEventListener('click', modalNextImage, true);
  245. modalNext.addEventListener('keydown', modalKeyHandler, true)
  246. modal.appendChild(modalNext)
  247. gradioApp().getRootNode().appendChild(modal)
  248. document.body.appendChild(modalFragment);
  249. });