[Global] Image Zoomer

Allows zooming into images without changing pages. Hold Ctrl+Shift when clicking on an image to load the extension. If the image is a thumbnail of the supported sites, the full image will be loaded instead.

目前為 2020-02-21 提交的版本,檢視 最新版本

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