[Global] Image Zoomer

Allows zooming into images without changing pages. Hold Ctrl+Shift (Cmd+Shift on MAC) when clicking on an image to load it with the extension.

  1. // ==UserScript==
  2. // @name [Global] Image Zoomer
  3. // @description Allows zooming into images without changing pages. Hold Ctrl+Shift (Cmd+Shift on MAC) when clicking on an image to load it with the extension.
  4. // @author MetalTxus
  5. // @version 1.3.9
  6.  
  7. // @include *
  8. // @exclude *youtube.com/embed*
  9.  
  10. // @icon https://dl.dropbox.com/s/4mnevtuyvt1eden/48.png
  11. // @require http://code.jquery.com/jquery-3.2.1.min.js
  12. // @require https://greasyfork.org/scripts/396703-key-navigation/code/Key%20navigation.js
  13. // @namespace https://greasyfork.org/users/8682
  14. // ==/UserScript==
  15.  
  16. const ENABLED_FOR_LINKS = true;
  17. const preloader = 'https://dl.dropbox.com/s/xbxkvw77dfsrum4/preloader.svg';
  18. const extensions = ['.jpg', '.jpeg', '.png', '.gif'];
  19.  
  20. const jQuery = window.jQuery;
  21. const setUpKeyNavigation = window.setUpKeyNavigation;
  22.  
  23. const gizContainer = jQuery(`<div id="giz-container">`);
  24. const gizAnchor = jQuery(`<a target="_blank" id="giz-link">`);
  25. const gizImage = jQuery(`<img class="centered" id="giz-image">`);
  26. const gizPreloader = jQuery(`<img class="centered" id="giz-preloader" src="${preloader}">`);
  27. const gizClose = jQuery(`<span id="giz-close">`);
  28.  
  29. const initialize = () => {
  30. jQuery(`<style>
  31. #giz-container { position: fixed; top: 0; left: 0; height: 100%; width: 100%; background-color: rgba(0, 0, 0, .9); z-index: 10000; display: none; }
  32. #giz-container .centered { position: fixed; left: 50%; top: 50%; }
  33. #giz-preloader { margin-left: -32px; margin-top: -33px; z-index: 10001; filter: drop-shadow(0 0 2px rgba(255, 255, 255, 1)); }
  34. #giz-image { max-height: 100%; max-width: 100%; cursor: url(https://dl.dropbox.com/s/32kv0rup3zw5lho/zoom-in.cur), zoom-in; }
  35. #giz-close { width: 32px; height: 32px; right: 0; margin: 4px; position: absolute; display: block; cursor: pointer; background: url(https://dl.dropbox.com/s/7smpm0ohq2ymfey/close.svg); }
  36. </style>`).appendTo('head');
  37.  
  38. gizContainer.click(hideContainer);
  39. gizClose.click(hideContainer);
  40.  
  41. gizAnchor.append(gizImage);
  42. gizContainer.append(gizAnchor);
  43. gizContainer.append(gizPreloader);
  44. gizContainer.append(gizClose);
  45.  
  46. jQuery('body').append(gizContainer);
  47.  
  48. gizImage
  49. .on('load', event => {
  50. const newUrl = event.target.src;
  51. gizAnchor.attr('href', newUrl);
  52. showImage();
  53. })
  54. .on('error', () => {
  55. const url = gizImage.attr('src');
  56.  
  57. for (var i = 0; i < extensions.length; i++) {
  58. if (url.includes(extensions[i])) {
  59. const newUrl = url.replace(extensions[i], extensions[i + 1]);
  60. gizImage.attr('src', newUrl);
  61. break;
  62. }
  63. }
  64. });
  65.  
  66. jQuery(document).click(event => {
  67. if (
  68. (event.ctrlKey || event.metaKey) &&
  69. event.shiftKey &&
  70. event.target.nodeName.toLowerCase() === 'img' &&
  71. (ENABLED_FOR_LINKS || event.parentElement.target.nodeName !== 'A')
  72. ) {
  73. event.preventDefault();
  74. loadPreview(event.target);
  75. }
  76. });
  77.  
  78. jQuery(window).resize(() => {
  79. if (gizContainer.is(':visible')) {
  80. relocateImage();
  81. }
  82. });
  83.  
  84. setUpKeyNavigation({
  85. onLeftPressed: e => isContainerVisible() && loadSiblingImage(-1) && e.preventDefault(),
  86. onRightPressed: e => isContainerVisible() && loadSiblingImage(1) && e.preventDefault(),
  87. onDownPressed: e => isContainerVisible() && hideContainer() && e.preventDefault(),
  88. onUpPressed: e => isContainerVisible() && e.preventDefault(),
  89. });
  90.  
  91. console.info('Script "Global Image Zoomer" ready for its use');
  92. };
  93.  
  94. const loadPreview = element => {
  95. let newURL = element.src;
  96.  
  97. if (newURL !== undefined && element.nodeName === 'IMG') {
  98. newURL = parseURL(newURL);
  99.  
  100. if (removeExtension(newURL) !== removeExtension(gizImage.attr('src')) && newURL !== preloader) {
  101. loadImageUrl(newURL);
  102. }
  103.  
  104. showContainer();
  105. }
  106. };
  107.  
  108. const loadImageUrl = newURL => {
  109. showPreloader();
  110.  
  111. gizImage.attr('src', newURL);
  112. gizAnchor.attr('href', newURL);
  113. };
  114.  
  115. const loadSiblingImage = increment => {
  116. if (!isContainerVisible()) return;
  117.  
  118. const imagesUrls = [
  119. ...new Set(
  120. jQuery('img')
  121. .map((i, img) => img.src)
  122. .toArray()
  123. )
  124. ];
  125. const currentImageUrl = gizImage.attr('src');
  126. const currentIndex = imagesUrls.indexOf(currentImageUrl);
  127. const requestedIndex = currentIndex + increment;
  128. if (requestedIndex < 0 || requestedIndex >= imagesUrls.length) {
  129. hideContainer();
  130. }
  131. /*const newIndex = requestedIndex < 0 ? 0 : requestedIndex >= imagesUrls.length ? imagesUrls.length - 1 : requestedIndex;*/
  132. const newIndex = requestedIndex;
  133. loadImageUrl(imagesUrls[newIndex]);
  134. };
  135.  
  136. const parseURL = url => {
  137. if (urlContains('deviantart.com')) {
  138. url = url.replace('/200H/', '/').replace('/150/', '/');
  139. } else if (urlContains('zerochan.net')) {
  140. url = url.replace('s3.', 'static.').replace('.240.', '.full.');
  141. }
  142.  
  143. return url;
  144. };
  145.  
  146. const urlContains = text => {
  147. return window.location.href.includes(text);
  148. };
  149.  
  150. const removeExtension = url => {
  151. if (url) {
  152. extensions.forEach(extension => {
  153. url = url.replace(extension, '');
  154. });
  155. }
  156. return url;
  157. };
  158.  
  159. const relocateImage = () => {
  160. return gizImage.css('margin', `${-Math.ceil(gizImage.height() / 2)}px ${-Math.ceil(gizImage.width() / 2)}px`);
  161. };
  162.  
  163. const hideContainer = () => {
  164. return gizContainer.fadeOut(100);
  165. };
  166. const showContainer = () => {
  167. return gizContainer.fadeIn(100);
  168. };
  169. const isContainerVisible = () => {
  170. return !jQuery('#giz-container').is(':hidden');
  171. }
  172.  
  173. const hidePreloader = () => {
  174. return gizPreloader.hide();
  175. };
  176. const showPreloader = () => {
  177. return hideImage() && gizPreloader.show();
  178. };
  179.  
  180. const hideImage = () => {
  181. return gizImage.hide();
  182. };
  183. const showImage = () => {
  184. return relocateImage() && hidePreloader() && gizImage.show();
  185. };
  186.  
  187. setTimeout(() => {
  188. if (!jQuery('#giz-container').length) {
  189. initialize();
  190. }
  191. });