imageviewer.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 modalToggleLivePreviewBtn = gradioApp().getElementById("modal_toggle_live_preview");
  9. modalToggleLivePreviewBtn.innerHTML = opts.js_live_preview_in_modal_lightbox ? "🗇" : "🗆";
  10. const lb = gradioApp().getElementById("lightboxModal");
  11. modalImage.src = source.src;
  12. if (modalImage.style.display === 'none') {
  13. lb.style.setProperty('background-image', 'url(' + source.src + ')');
  14. }
  15. updateModalImage();
  16. lb.style.display = "flex";
  17. lb.focus();
  18. const tabTxt2Img = gradioApp().getElementById("tab_txt2img");
  19. const tabImg2Img = gradioApp().getElementById("tab_img2img");
  20. // show the save button in modal only on txt2img or img2img tabs
  21. if (tabTxt2Img.style.display != "none" || tabImg2Img.style.display != "none") {
  22. gradioApp().getElementById("modal_save").style.display = "inline";
  23. } else {
  24. gradioApp().getElementById("modal_save").style.display = "none";
  25. }
  26. event.stopPropagation();
  27. }
  28. function negmod(n, m) {
  29. return ((n % m) + m) % m;
  30. }
  31. function updateModalImage() {
  32. const modalImage = gradioApp().getElementById("modalImage");
  33. let currentButton = selected_gallery_button();
  34. let preview = gradioApp().querySelectorAll('.livePreview > img');
  35. if (opts.js_live_preview_in_modal_lightbox && preview.length > 0) {
  36. // show preview image if available
  37. modalImage.src = preview[preview.length - 1].src;
  38. } else 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. const modal = gradioApp().getElementById("lightboxModal");
  42. modal.style.setProperty('background-image', `url(${modalImage.src})`);
  43. }
  44. }
  45. }
  46. function updateOnBackgroundChange() {
  47. const modalImage = gradioApp().getElementById("modalImage");
  48. if (modalImage && modalImage.offsetParent) {
  49. updateModalImage();
  50. }
  51. }
  52. function modalImageSwitch(offset) {
  53. var galleryButtons = all_gallery_buttons();
  54. if (galleryButtons.length > 1) {
  55. var result = selected_gallery_index();
  56. if (result != -1) {
  57. var nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];
  58. nextButton.click();
  59. const modalImage = gradioApp().getElementById("modalImage");
  60. const modal = gradioApp().getElementById("lightboxModal");
  61. modalImage.src = nextButton.children[0].src;
  62. if (modalImage.style.display === 'none') {
  63. modal.style.setProperty('background-image', `url(${modalImage.src})`);
  64. }
  65. setTimeout(function() {
  66. modal.focus();
  67. }, 10);
  68. }
  69. }
  70. }
  71. function saveImage() {
  72. const tabTxt2Img = gradioApp().getElementById("tab_txt2img");
  73. const tabImg2Img = gradioApp().getElementById("tab_img2img");
  74. const saveTxt2Img = "save_txt2img";
  75. const saveImg2Img = "save_img2img";
  76. if (tabTxt2Img.style.display != "none") {
  77. gradioApp().getElementById(saveTxt2Img).click();
  78. } else if (tabImg2Img.style.display != "none") {
  79. gradioApp().getElementById(saveImg2Img).click();
  80. } else {
  81. console.error("missing implementation for saving modal of this type");
  82. }
  83. }
  84. function modalSaveImage(event) {
  85. saveImage();
  86. event.stopPropagation();
  87. }
  88. function modalNextImage(event) {
  89. modalImageSwitch(1);
  90. event.stopPropagation();
  91. }
  92. function modalPrevImage(event) {
  93. modalImageSwitch(-1);
  94. event.stopPropagation();
  95. }
  96. function modalKeyHandler(event) {
  97. switch (event.key) {
  98. case "s":
  99. saveImage();
  100. break;
  101. case "ArrowLeft":
  102. modalPrevImage(event);
  103. break;
  104. case "ArrowRight":
  105. modalNextImage(event);
  106. break;
  107. case "Escape":
  108. closeModal();
  109. break;
  110. }
  111. }
  112. function setupImageForLightbox(e) {
  113. if (e.dataset.modded) {
  114. return;
  115. }
  116. e.dataset.modded = true;
  117. e.style.cursor = 'pointer';
  118. e.style.userSelect = 'none';
  119. e.addEventListener('mousedown', function(evt) {
  120. if (evt.button == 1) {
  121. open(evt.target.src);
  122. evt.preventDefault();
  123. return;
  124. }
  125. }, true);
  126. e.addEventListener('click', function(evt) {
  127. if (!opts.js_modal_lightbox || evt.button != 0) return;
  128. modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed);
  129. evt.preventDefault();
  130. showModal(evt);
  131. }, true);
  132. }
  133. function modalZoomSet(modalImage, enable) {
  134. if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);
  135. }
  136. function modalZoomToggle(event) {
  137. var modalImage = gradioApp().getElementById("modalImage");
  138. modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'));
  139. event.stopPropagation();
  140. }
  141. function modalLivePreviewToggle(event) {
  142. const modalToggleLivePreview = gradioApp().getElementById("modal_toggle_live_preview");
  143. opts.js_live_preview_in_modal_lightbox = !opts.js_live_preview_in_modal_lightbox;
  144. modalToggleLivePreview.innerHTML = opts.js_live_preview_in_modal_lightbox ? "🗇" : "🗆";
  145. event.stopPropagation();
  146. }
  147. function modalTileImageToggle(event) {
  148. const modalImage = gradioApp().getElementById("modalImage");
  149. const modal = gradioApp().getElementById("lightboxModal");
  150. const isTiling = modalImage.style.display === 'none';
  151. if (isTiling) {
  152. modalImage.style.display = 'block';
  153. modal.style.setProperty('background-image', 'none');
  154. } else {
  155. modalImage.style.display = 'none';
  156. modal.style.setProperty('background-image', `url(${modalImage.src})`);
  157. }
  158. event.stopPropagation();
  159. }
  160. onAfterUiUpdate(function() {
  161. var fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img');
  162. if (fullImg_preview != null) {
  163. fullImg_preview.forEach(setupImageForLightbox);
  164. }
  165. updateOnBackgroundChange();
  166. });
  167. document.addEventListener("DOMContentLoaded", function() {
  168. //const modalFragment = document.createDocumentFragment();
  169. const modal = document.createElement('div');
  170. modal.onclick = closeModal;
  171. modal.id = "lightboxModal";
  172. modal.tabIndex = 0;
  173. modal.addEventListener('keydown', modalKeyHandler, true);
  174. const modalControls = document.createElement('div');
  175. modalControls.className = 'modalControls gradio-container';
  176. modal.append(modalControls);
  177. const modalZoom = document.createElement('span');
  178. modalZoom.className = 'modalZoom cursor';
  179. modalZoom.innerHTML = '⤡';
  180. modalZoom.addEventListener('click', modalZoomToggle, true);
  181. modalZoom.title = "Toggle zoomed view";
  182. modalControls.appendChild(modalZoom);
  183. const modalTileImage = document.createElement('span');
  184. modalTileImage.className = 'modalTileImage cursor';
  185. modalTileImage.innerHTML = '⊞';
  186. modalTileImage.addEventListener('click', modalTileImageToggle, true);
  187. modalTileImage.title = "Preview tiling";
  188. modalControls.appendChild(modalTileImage);
  189. const modalSave = document.createElement("span");
  190. modalSave.className = "modalSave cursor";
  191. modalSave.id = "modal_save";
  192. modalSave.innerHTML = "🖫";
  193. modalSave.addEventListener("click", modalSaveImage, true);
  194. modalSave.title = "Save Image(s)";
  195. modalControls.appendChild(modalSave);
  196. const modalToggleLivePreview = document.createElement('span');
  197. modalToggleLivePreview.className = 'modalToggleLivePreview cursor';
  198. modalToggleLivePreview.id = "modal_toggle_live_preview";
  199. modalToggleLivePreview.innerHTML = "🗆";
  200. modalToggleLivePreview.onclick = modalLivePreviewToggle;
  201. modalToggleLivePreview.title = "Toggle live preview";
  202. modalControls.appendChild(modalToggleLivePreview);
  203. const modalClose = document.createElement('span');
  204. modalClose.className = 'modalClose cursor';
  205. modalClose.innerHTML = '×';
  206. modalClose.onclick = closeModal;
  207. modalClose.title = "Close image viewer";
  208. modalControls.appendChild(modalClose);
  209. const modalImage = document.createElement('img');
  210. modalImage.id = 'modalImage';
  211. modalImage.onclick = closeModal;
  212. modalImage.tabIndex = 0;
  213. modalImage.addEventListener('keydown', modalKeyHandler, true);
  214. modal.appendChild(modalImage);
  215. const modalPrev = document.createElement('a');
  216. modalPrev.className = 'modalPrev';
  217. modalPrev.innerHTML = '❮';
  218. modalPrev.tabIndex = 0;
  219. modalPrev.addEventListener('click', modalPrevImage, true);
  220. modalPrev.addEventListener('keydown', modalKeyHandler, true);
  221. modal.appendChild(modalPrev);
  222. const modalNext = document.createElement('a');
  223. modalNext.className = 'modalNext';
  224. modalNext.innerHTML = '❯';
  225. modalNext.tabIndex = 0;
  226. modalNext.addEventListener('click', modalNextImage, true);
  227. modalNext.addEventListener('keydown', modalKeyHandler, true);
  228. modal.appendChild(modalNext);
  229. try {
  230. gradioApp().appendChild(modal);
  231. } catch (e) {
  232. gradioApp().body.appendChild(modal);
  233. }
  234. document.body.appendChild(modal);
  235. });