imageviewer.js 8.7 KB

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