Greasy Fork is available in English.

Google Search Go To Cache

Show a tooltip with Google Cache link for external links in Google search results

  1. // ==UserScript==
  2. // @name Google Search Go To Cache
  3. // @namespace UserScript
  4. // @version 0.2.0
  5. // @description Show a tooltip with Google Cache link for external links in Google search results
  6. // @author CY Fung
  7. // @license MIT
  8. // @match https://www.google.com/search*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. const filterRule = '#search a[href]'
  16. const forceHTTPS = false;
  17.  
  18.  
  19. function isGoogleHost(hostname) {
  20.  
  21. if (hostname === 'www.google.com') return true;
  22. if (hostname === 'google.com') return true;
  23. if (hostname.endsWith('.google.com')) return true;
  24. return false;
  25. }
  26.  
  27. let tooltipTimeout;
  28. const tooltip = document.createElement('div');
  29. let tooltipInner = document.createElement('div');
  30. tooltipInner.className = 'cache-tooltip-inner'
  31. tooltip.className = 'cache-tooltip';
  32. tooltipInner.textContent = 'Cache page';
  33. tooltip.style.position = 'absolute';
  34. tooltipInner.style.backgroundColor = 'black';
  35. tooltipInner.style.color = 'white';
  36. tooltipInner.style.padding = '5px';
  37. tooltipInner.style.borderRadius = '5px';
  38. tooltip.style.zIndex = '1000';
  39. tooltip.style.cursor = 'pointer';
  40. tooltip.style.display = 'none';
  41. tooltipInner.style.display='inline-block'
  42. tooltip.appendChild(tooltipInner);
  43.  
  44. tooltip.addEventListener('click', function() {
  45. window.location.href = tooltip.dataset.cacheLink;
  46. });
  47.  
  48. document.body.appendChild(tooltip);
  49.  
  50. document.addEventListener('mouseenter', function(event) {
  51. if (event.target.tagName === 'A' && event.target.href && event.target.matches(filterRule)) {
  52. const link = event.target.href;
  53. const url = new URL(link);
  54. if (!isGoogleHost(url.hostname)) {
  55.  
  56. clearTimeout(tooltipTimeout);
  57. showTooltip(event.target);
  58. }
  59. }
  60. }, true);
  61.  
  62. document.addEventListener('mouseleave', function(event) {
  63. if (event.target.tagName === 'A' && event.target.href) {
  64. hideTooltipWithDelay();
  65. }
  66. }, true);
  67.  
  68. tooltip.addEventListener('mouseleave', function() {
  69. hideTooltipWithDelay();
  70. });
  71.  
  72. tooltip.addEventListener('mouseenter', function() {
  73. clearTimeout(tooltipTimeout);
  74. });
  75.  
  76. let cssAdded = false;
  77. function showTooltip(element) {
  78.  
  79. if(!cssAdded){
  80. cssAdded = true;
  81. document.head.appendChild(document.createElement('style')).textContent = `
  82. .cache-tooltip{
  83. opacity: 0.75;
  84. user-select: none;
  85. z-index: 999;
  86. }
  87. .cache-tooltip:hover {
  88. opacity: 1;
  89. }
  90.  
  91.  
  92. `
  93. }
  94.  
  95. let link = element.href;
  96. if(forceHTTPS) link = link.replace(/^http\:\/\//, 'https://');
  97. const cacheLink = `https://webcache.googleusercontent.com/search?q=cache:${encodeURIComponent(link)}`;
  98.  
  99. tooltip.dataset.cacheLink = cacheLink;
  100. const rect = element.getBoundingClientRect();
  101. tooltip.style.top = `${rect.top + window.scrollY + rect.height}px`;
  102. tooltip.style.left = `${rect.left + window.scrollX}px`;
  103. tooltip.style.display = 'block';
  104. tooltip.style.width = `${rect.width}px`;
  105. }
  106.  
  107. function hideTooltipWithDelay() {
  108. clearTimeout(tooltipTimeout);
  109. tooltipTimeout = setTimeout(() => {
  110. tooltip.style.display = 'none';
  111. }, 160); // Delay before hiding the tooltip
  112. }
  113. })();