Text To link

Turn plain text URLs into clickable links, 把文字链接转换为可点击链接

当前为 2017-08-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Text To link
  3. // @description Turn plain text URLs into clickable links, 把文字链接转换为可点击链接
  4. // @author lkytal
  5. // @namespace Lkytal
  6. // @homepage https://lkytal.github.io/
  7. // @include *
  8. // @exclude *pan.baidu.com/*
  9. // @exclude *renren.com/*
  10. // @exclude *exhentai.org/*
  11. // @exclude *music.google.com/*
  12. // @exclude *play.google.com/music/*
  13. // @exclude *mail.google.com/*
  14. // @exclude *docs.google.com/*
  15. // @exclude *www.google.*
  16. // @exclude *acid3.acidtests.org/*
  17. // @exclude *.163.com/*
  18. // @exclude *.alipay.com/*
  19. // @version 2.8.3
  20. // @icon http://lkytal.qiniudn.com/link.png
  21. // @grant unsafeWindow
  22. // @homepageURL https://git.oschina.net/coldfire/GM
  23. // ==/UserScript==
  24.  
  25. "use strict";
  26. var clearLink, excludedTags, linkFilter, linkMixInit, linkPack, linkify, observePage, observer, setLink, urlPrefixes, url_regexp, xPath;
  27.  
  28. url_regexp = /((https?:\/\/|www\.)[\x21-\x7e]+[\w\/]|(\w[\w._-]+\.(com|cn|org|net|info|tv|cc|gov|xxx))(\/[\x21-\x7e]*[\w\/])?|ed2k:\/\/[\x21-\x7e]+\|\/|thunder:\/\/[\x21-\x7e]+=)/gi;
  29.  
  30. urlPrefixes = ['http://', 'https://', 'ftp://', 'thunder://', 'ed2k://'];
  31.  
  32. clearLink = function(event) {
  33. var j, len, link, prefix, ref, url;
  34. link = (ref = event.originalTarget) != null ? ref : event.target;
  35. if (!((link != null) && link.localName === "a" && link.className.indexOf("textToLink") !== -1)) {
  36. return;
  37. }
  38. url = link.getAttribute("href");
  39. for (j = 0, len = urlPrefixes.length; j < len; j++) {
  40. prefix = urlPrefixes[j];
  41. if (url.indexOf(prefix) === 0) {
  42. return;
  43. }
  44. }
  45. return link.setAttribute("href", "http://" + url);
  46. };
  47.  
  48. document.addEventListener("mouseover", clearLink);
  49.  
  50. setLink = function(candidate) {
  51. var span, text;
  52. if ((candidate == null) || candidate.parentNode.className.indexOf("textToLink") !== -1 || candidate.nodeName === "#cdata-section") {
  53. return;
  54. }
  55. text = candidate.textContent.replace(url_regexp, '<a href="$1" target="_blank" class="textToLink">$1</a>');
  56. if (candidate.textContent.length === text.length) {
  57. return;
  58. }
  59. span = document.createElement("span");
  60. span.innerHTML = text;
  61. return candidate.parentNode.replaceChild(span, candidate);
  62. };
  63.  
  64. excludedTags = "a,svg,canvas,applet,input,button,area,pre,embed,frame,frameset,head,iframe,img,option,map,meta,noscript,object,script,style,textarea,code".split(",");
  65.  
  66. xPath = "//text()[not(ancestor::" + (excludedTags.join(') and not(ancestor::')) + ")]";
  67.  
  68. linkPack = function(result, start) {
  69. var i, j, k, ref, ref1, ref2, ref3, startTime;
  70. startTime = Date.now();
  71. while (start + 10000 < result.snapshotLength) {
  72. for (i = j = ref = start, ref1 = start + 10000; ref <= ref1 ? j <= ref1 : j >= ref1; i = ref <= ref1 ? ++j : --j) {
  73. setLink(result.snapshotItem(i));
  74. }
  75. start += 10000;
  76. if (Date.now() - startTime > 2500) {
  77. return;
  78. }
  79. }
  80. for (i = k = ref2 = start, ref3 = result.snapshotLength; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) {
  81. setLink(result.snapshotItem(i));
  82. }
  83. };
  84.  
  85. linkify = function(node) {
  86. var result;
  87. result = document.evaluate(xPath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  88. return linkPack(result, 0);
  89. };
  90.  
  91. linkFilter = function(node) {
  92. var j, len, tag;
  93. for (j = 0, len = excludedTags.length; j < len; j++) {
  94. tag = excludedTags[j];
  95. if (tag === node.parentNode.localName.toLowerCase()) {
  96. return NodeFilter.FILTER_REJECT;
  97. }
  98. }
  99. return NodeFilter.FILTER_ACCEPT;
  100. };
  101.  
  102. observePage = function(root) {
  103. var tW;
  104. tW = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
  105. acceptNode: linkFilter
  106. }, false);
  107. while (tW.nextNode()) {
  108. setLink(tW.currentNode);
  109. }
  110. };
  111.  
  112. observer = new window.MutationObserver(function(mutations) {
  113. var Node, j, k, len, len1, mutation, ref;
  114. for (j = 0, len = mutations.length; j < len; j++) {
  115. mutation = mutations[j];
  116. if (mutation.type === "childList") {
  117. ref = mutation.addedNodes;
  118. for (k = 0, len1 = ref.length; k < len1; k++) {
  119. Node = ref[k];
  120. observePage(Node);
  121. }
  122. }
  123. }
  124. });
  125.  
  126. linkMixInit = function() {
  127. if (window !== window.top || window.document.title === "") {
  128. return;
  129. }
  130. linkify(document.body);
  131. return observer.observe(document.body, {
  132. childList: true,
  133. subtree: true
  134. });
  135. };
  136.  
  137. setTimeout(linkMixInit, 100);