Greasy Fork 支持简体中文。

Clean Links

Clean up links. Remove targets, embedded redirects, and window.open() style links.

  1. // ==UserScript==
  2. // @name Clean Links
  3. // @namespace https://arantius.com/misc/greasemonkey/
  4. // @description Clean up links. Remove targets, embedded redirects, and window.open() style links.
  5. // @include http*
  6. // @exclude https://archive.org/web/*
  7. // @exclude https://www.google.com/search*
  8. // @version 8
  9. // @grant none
  10. // ==/UserScript==
  11. //
  12. // Updates:
  13. //
  14. // - 2012-12-06: Don't break Google log in links.
  15. // - 2012-07-04: Remove stray "j=0" that was unused.
  16. // - 2012-04-11: Unwrap even more javascript links.
  17. // - 2012-04-09: Unwrap more javascript window opening links.
  18. // - 2012-04-06: Exclude google search (don't obscure image source pages).
  19. // - 2012-03-18: Don't clean Google Docs Viewer links.
  20. // - 2012-03-14: Don't clean magnet links.
  21. // - 2011-10-23: Clean window.open() links. Remove status saver. Rename.
  22. // - 2010-09-11: Catch security manager viloations in top-frame-detection.
  23. // - 2009-10-13: Monitor for altered hrefs, and re-clean them.
  24. // - 2008-01-19: Deal with an inner link that is not slash terminated.
  25. // - 2006-09-18: Allow google "Custom" search links through.
  26. // - 2006-06-23: Properly handle clicks straight to https:// and cache cases
  27. // for Yahoo! and InternetArchive, minor other improvements.
  28. //
  29. // Copyright (c) 2011, Anthony Lieuallen
  30. // All rights reserved.
  31. //
  32. // Redistribution and use in source and binary forms, with or without
  33. // modification, are permitted provided that the following conditions are met:
  34. //
  35. // * Redistributions of source code must retain the above copyright notice,
  36. // this list of conditions and the following disclaimer.
  37. // * Redistributions in binary form must reproduce the above copyright notice,
  38. // this list of conditions and the following disclaimer in the documentation
  39. // and/or other materials provided with the distribution.
  40. // * Neither the name of Anthony Lieuallen nor the names of its contributors
  41. // may be used to endorse or promote products derived from this software
  42. // without specific prior written permission.
  43. //
  44. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  45. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  46. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  47. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  48. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  49. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  50. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  51. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  52. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  53. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  54. // POSSIBILITY OF SUCH DAMAGE.
  55. //
  56.  
  57. var inFrames=false;
  58. try { inFrames = (top!=self); } catch (e) { }
  59. var antiloop=0;
  60. var myHost=document.location.host+''; // "assign by value"
  61. var myDomain=myHost.replace(/.*\.(.*......)/, '$1');
  62.  
  63. var myDomainRegex=new RegExp('^[a-z]+://[^/]*'+myDomain+'(/|$)');
  64. var cacheRegex=/\/search(\?q=cache|\/cache\?)/;
  65. var intArchRegex=/^http:\/\/web.archive.org\/web\//;
  66.  
  67. function straightClick(el) {
  68. // make sure we don't do some crazy infinite loop
  69. if (antiloop++>20) return false;
  70.  
  71. if (el.href.indexOf('magnet:') === 0) return false;
  72.  
  73. // special case window-opening javascript
  74. var match = el.href.match(
  75. /^javascript:[a-z0-9._]+\(([\'\"])(http.+?)\1/i);
  76. if (!match) {
  77. match = el.href.match(
  78. /^javascript:((?:window\.)?open|MM_openBrWindow)\([\'\"]([^\'\"]+)/);
  79. }
  80. if (!match) {
  81. match = el.href.match(
  82. /^javascript:location.href\s*=\s*([\'\"])([^\'\"]+)/);
  83. }
  84. if (match) {
  85. el.href = match[2];
  86. }
  87.  
  88. // don't mess with javascript links
  89. if ('javascript:'==el.href.substr(0, 11)) return false;
  90. // special case to allow links to google/yahoo cache through
  91. if (cacheRegex.test(el.href)) return false;
  92. // let links to internet archive through
  93. if (intArchRegex.test(el.href)) return false;
  94. // let google docs viewer through
  95. if (el.href.indexOf('https://docs.google.com/viewer') == 0) return false;
  96. // let google log-in links through.
  97. if (-1 != el.href.indexOf('www.google.com/accounts/ServiceLogin')) return false;
  98.  
  99. var href=el.href+''; // "assign by value"
  100.  
  101. // trim the start of this href
  102. href=href.replace(/^https?:\/\//, '');
  103. href=href.replace(/^www\./, '');
  104.  
  105. // try to find an embedded link
  106. var m=href.match(/(www\.|https?:|https?%3A)[^&]+/i);
  107. if (!m) {
  108. // we didn't find one!
  109. return false;
  110. }
  111.  
  112. // pick out and use the embedded link
  113. href=unescape(m[0]);
  114.  
  115. // if it's to my own domain, don't mess with it
  116. if (myDomainRegex.test(href)) return false;
  117.  
  118. // make sure we have a protocol
  119. if (!href.match(/[a-z]+:\/\//)) href='http://'+href;
  120.  
  121. // stuff it in the element, and let caller know I did
  122. el.href=href;
  123. return true;
  124. }
  125.  
  126.  
  127. // find all links as a snapshot
  128. var els=document.links;
  129. // iterate over all elements
  130. for (var i=0, el; el=els[i]; i++) {
  131. //////////////////////////blank target
  132. if (null!=el.getAttribute('target') && !inFrames) {
  133. el.removeAttribute('target');
  134. }
  135.  
  136. //////////////////////////rewrite avoider
  137. el.removeAttribute('onmousedown');
  138.  
  139. //////////////////////////straight click
  140. antiloop=0;
  141. do { ;; } while (straightClick(el))
  142. }
  143.  
  144. var suspend=false;
  145. document.body.addEventListener('DOMAttrModified', function(event) {
  146. var el=event.target;
  147. if (!el || 'A'!=el.tagName) return;
  148. if ('href'!=event.attrName) return;
  149.  
  150. if (suspend) return;
  151. suspend=true;
  152.  
  153. //////////////////////////straight click
  154. antiloop=0;
  155. do { ;; } while (straightClick(el))
  156.  
  157. suspend=false;
  158. }, false);