Github Image Viewer

Preview images from within the listing.

  1. // ==UserScript==
  2. // @name Github Image Viewer
  3. // @id Github_Image_Viewer@https://github.com/jerone/UserScripts
  4. // @namespace https://github.com/jerone/UserScripts
  5. // @description Preview images from within the listing.
  6. // @author jerone
  7. // @copyright 2014+, jerone (https://github.com/jerone)
  8. // @license CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
  9. // @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
  10. // @homepage https://github.com/jerone/UserScripts/tree/master/Github_Image_Viewer
  11. // @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_Image_Viewer
  12. // @supportURL https://github.com/jerone/UserScripts/issues
  13. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VCYMHWQ7ZMBKW
  14. // @version 0.5.0
  15. // @icon https://github.githubassets.com/pinned-octocat.svg
  16. // @grant none
  17. // @run-at document-end
  18. // @include https://github.com/*
  19. // ==/UserScript==
  20.  
  21. /* eslint security/detect-object-injection: "off" */
  22.  
  23. (function () {
  24. String.format = function (string) {
  25. var args = Array.prototype.slice.call(arguments, 1, arguments.length);
  26. return string.replace(/{(\d+)}/g, function (match, number) {
  27. return typeof args[number] !== "undefined" ? args[number] : match;
  28. });
  29. };
  30.  
  31. function proxy(fn) {
  32. return function () {
  33. var that = this;
  34. return function (e) {
  35. var args = that.slice(0); // clone;
  36. args.unshift(e); // prepend event;
  37. fn.apply(this, args);
  38. };
  39. }.call([].slice.call(arguments, 1));
  40. }
  41.  
  42. var GithubImageViewer = {
  43. _floater: null,
  44. _floaterTitle: null,
  45. _floaterImage: null,
  46. _floaterMeta: null,
  47.  
  48. _imageUrl: null,
  49. _loaderSrc:
  50. "https://github.githubassets.com/images/spinners/octocat-spinner-32.gif",
  51. _imageRegex: /.+(\.jpe?g|\.png|\.gif|\.bmp|\.ico|\.tiff?)$/i,
  52.  
  53. Initialize: function () {
  54. var floater = (GithubImageViewer._floater =
  55. document.createElement("div"));
  56. floater.style.position = "absolute";
  57. floater.style.top = "0";
  58. floater.style.left = "0";
  59. floater.style.zIndex = "999";
  60. document.body.appendChild(floater);
  61.  
  62. var floaterMouseAlign = document.createElement("div");
  63. floaterMouseAlign.style.position = "absolute";
  64. floaterMouseAlign.style.bottom = "5px";
  65. floaterMouseAlign.style.left = "5px";
  66. floaterMouseAlign.style.border = "1px solid #b7c7cf";
  67. floaterMouseAlign.style.borderRadius = "3px";
  68. floaterMouseAlign.style.fontSize = "11px";
  69. floater.appendChild(floaterMouseAlign);
  70.  
  71. var floaterTitle = (GithubImageViewer._floaterTitle =
  72. document.createElement("div"));
  73. floaterTitle.style.backgroundColor = "#e6f1f6";
  74. floaterTitle.style.color = "black";
  75. floaterTitle.style.textAlign = "center";
  76. floaterTitle.style.borderBottom = "1px solid #d8e6ec";
  77. floaterTitle.style.padding = "3px 5px";
  78. floaterMouseAlign.appendChild(floaterTitle);
  79.  
  80. var floaterCenter = document.createElement("div");
  81. floaterCenter.style.minWidth = "40px";
  82. floaterCenter.style.minHeight = "40px";
  83. floaterCenter.style.display = "flex";
  84. floaterCenter.style.flexDirection = "column";
  85. floaterCenter.style.backgroundColor = "#f8f8f8";
  86. floaterCenter.style.padding = "3px";
  87. floaterMouseAlign.appendChild(floaterCenter);
  88.  
  89. var floaterImage = (GithubImageViewer._floaterImage =
  90. document.createElement("img"));
  91. floaterImage.setAttribute("src", GithubImageViewer._loaderSrc);
  92. floaterImage.style.margin = "auto";
  93. floaterImage.style.maxWidth = floaterImage.style.maxHeight =
  94. "200px";
  95. floaterCenter.appendChild(floaterImage);
  96.  
  97. var floaterMeta = (GithubImageViewer._floaterMeta =
  98. document.createElement("div"));
  99. floaterMeta.style.backgroundColor = "#f8f8f8";
  100. floaterMeta.style.color = "black";
  101. floaterMeta.style.padding = "3px";
  102. floaterMeta.style.textAlign = "center";
  103. floaterMeta.style.whiteSpace = "nowrap";
  104. floaterMouseAlign.appendChild(floaterMeta);
  105. GithubImageViewer.SetMeta();
  106.  
  107. GithubImageViewer.Attach();
  108. },
  109.  
  110. Attach: function () {
  111. document
  112. .getElementById("js-repo-pjax-container")
  113. .addEventListener("mousemove", function (e) {
  114. var target = e.target;
  115. if (
  116. target.classList &&
  117. target.classList.contains("js-navigation-open") &&
  118. GithubImageViewer._imageRegex.test(target.href)
  119. ) {
  120. if (target.getAttribute("title")) {
  121. target.dataset.title = target.getAttribute("title");
  122. target.removeAttribute("title");
  123. }
  124.  
  125. if (GithubImageViewer._visible) {
  126. GithubImageViewer.Show(e.pageX, e.pageY);
  127. } else {
  128. GithubImageViewer.AddTimer(
  129. proxy(function () {
  130. GithubImageViewer.ClearTimers();
  131.  
  132. GithubImageViewer.Show(e.pageX, e.pageY);
  133.  
  134. var href = target.href;
  135. if (GithubImageViewer._imageUrl !== href) {
  136. GithubImageViewer._imageUrl = href;
  137. GithubImageViewer.SetImage(
  138. GithubImageViewer._imageUrl,
  139. );
  140.  
  141. GithubImageViewer.SetTitle(
  142. target.dataset.title,
  143. );
  144. }
  145. }),
  146. );
  147. }
  148. } else {
  149. GithubImageViewer.Dispose();
  150. }
  151. });
  152. document.body.addEventListener("click", function () {
  153. GithubImageViewer.Dispose();
  154. });
  155. document.body.addEventListener("contextmenu", function () {
  156. GithubImageViewer.Dispose();
  157. });
  158. document.body.addEventListener("keydown", function (e) {
  159. if (e.keyCode === 27) {
  160. GithubImageViewer.Dispose();
  161. }
  162. });
  163. },
  164.  
  165. _visible: false,
  166. Show: function (x, y) {
  167. GithubImageViewer._visible = true;
  168. GithubImageViewer._floater.style.left = x + "px";
  169. GithubImageViewer._floater.style.top = y + "px";
  170. },
  171. Hide: function () {
  172. GithubImageViewer._visible = false;
  173. GithubImageViewer._floater.style.left = "-1000px";
  174. GithubImageViewer._floater.style.top = "-1000px";
  175. },
  176.  
  177. Dispose: function () {
  178. GithubImageViewer.ClearTimers();
  179.  
  180. GithubImageViewer.Hide();
  181.  
  182. GithubImageViewer._imageUrl = GithubImageViewer._loaderSrc;
  183. GithubImageViewer.SetImage(GithubImageViewer._imageUrl);
  184.  
  185. GithubImageViewer.SetTitle("Loading...");
  186. },
  187.  
  188. _timers: [],
  189. _timeout: 700,
  190. AddTimer: function (fn) {
  191. GithubImageViewer._timers.push(
  192. window.setTimeout(fn, GithubImageViewer._timeout),
  193. );
  194. },
  195. ClearTimers: function () {
  196. Array.prototype.forEach.call(
  197. GithubImageViewer._timers,
  198. function (timer) {
  199. window.clearTimeout(timer);
  200. },
  201. );
  202. },
  203.  
  204. SetTitle: function (text) {
  205. GithubImageViewer._floaterTitle.textContent = text;
  206. },
  207.  
  208. SetImage: function (src) {
  209. src = src.replace("/blob/", "/raw/");
  210. if (src !== GithubImageViewer._loaderSrc) {
  211. var temp = document.createElement("img");
  212. temp.style.visibility = "hidden";
  213. temp.addEventListener("load", function () {
  214. GithubImageViewer.SetMeta(this.width, this.height);
  215. this.parentNode.removeChild(temp);
  216. });
  217. temp.setAttribute("src", src);
  218. document.body.appendChild(temp);
  219. } else {
  220. GithubImageViewer.SetMeta();
  221. }
  222.  
  223. GithubImageViewer._floaterImage.setAttribute("src", src);
  224. },
  225.  
  226. SetMeta: function (w, h) {
  227. if (!w && !h) {
  228. GithubImageViewer._floaterMeta.style.display = "none";
  229. } else {
  230. GithubImageViewer._floaterMeta.style.display = "block";
  231. GithubImageViewer._floaterMeta.innerHTML = String.format(
  232. "<strong>W:</strong> {0}px | <strong>H:</strong> {1}px",
  233. w,
  234. h,
  235. );
  236. }
  237. },
  238. };
  239.  
  240. if (document.getElementById("js-repo-pjax-container")) {
  241. GithubImageViewer.Initialize();
  242. }
  243. })();