Linkify Plus Plus

Based on Linkify Plus. Turn plain text URLs into links.

目前為 2014-08-17 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Linkify Plus Plus
  3. // @version 2.2.1
  4. // @namespace eight04.blogspot.com
  5. // @description Based on Linkify Plus. Turn plain text URLs into links.
  6. // @include http*
  7. // @exclude http://www.google.tld/search*
  8. // @exclude https://www.google.tld/search*
  9. // @exclude http://music.google.com/*
  10. // @exclude https://music.google.com/*
  11. // @exclude http://mail.google.com/*
  12. // @exclude https://mail.google.com/*
  13. // @exclude http://docs.google.com/*
  14. // @exclude https://docs.google.com/*
  15. // @exclude http://mxr.mozilla.org/*
  16. // @grant GM_addStyle
  17. // ==/UserScript==
  18. //
  19. // Copyright (c) 2011, Anthony Lieuallen
  20. // All rights reserved.
  21. //
  22. // Redistribution and use in source and binary forms, with or without
  23. // modification, are permitted provided that the following conditions are met:
  24. //
  25. // * Redistributions of source code must retain the above copyright notice,
  26. // this list of conditions and the following disclaimer.
  27. // * Redistributions in binary form must reproduce the above copyright notice,
  28. // this list of conditions and the following disclaimer in the documentation
  29. // and/or other materials provided with the distribution.
  30. // * Neither the name of Anthony Lieuallen nor the names of its contributors
  31. // may be used to endorse or promote products derived from this software
  32. // without specific prior written permission.
  33. //
  34. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  35. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  38. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  39. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  40. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  41. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  42. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  43. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  44. // POSSIBILITY OF SUCH DAMAGE.
  45. //
  46.  
  47. /*******************************************************************************
  48. Loosely based on the Linkify script located at:
  49. http://downloads.mozdev.org/greasemonkey/linkify.user.js
  50.  
  51. Version history:
  52. Version 2.2.1 (Aug 17, 2014):
  53. - Ignore .highlight container.
  54. Version 2.2 (Aug 15, 2014):
  55. - Add images support.
  56. - Use Observer instead of DOMNodeInserted.
  57. Version 2.1.4 (Aug 12, 2012):
  58. - Bug fix for when (only some) nodes have been removed from the document.
  59. Version 2.1.3 (Oct 24, 2011):
  60. - More excludes.
  61. Version 2.1.2:
  62. - Some bug fixes.
  63. Version 2.1.1:
  64. - Ignore certain "highlighter" script containers.
  65. Version 2.1:
  66. - Rewrite the regular expression to be more readable.
  67. - Fix trailing "." characters.
  68. Version 2.0.3:
  69. - Fix infinite recursion on X(HT)ML pages.
  70. Version 2.0.2:
  71. - Limit @include, for greater site/plugin compatibility.
  72. Version 2.0.1:
  73. - Fix aberrant 'mailto:' where it does not belong.
  74. Version 2.0:
  75. - Apply incrementally, so the browser does not hang on large pages.
  76. - Continually apply to new content added to the page (i.e. AJAX).
  77. Version 1.1.4:
  78. - Basic "don't screw up xml pretty printing" exception case
  79. Version 1.1.3:
  80. - Include "+" in the username of email addresses.
  81. Version 1.1.2:
  82. - Include "." in the username of email addresses.
  83. Version 1.1:
  84. - Fixed a big that caused the first link in a piece of text to
  85. be skipped (i.e. not linkified).
  86. *******************************************************************************/
  87.  
  88. "use strict";
  89.  
  90. var notInTags = [
  91. 'a', 'code', 'head', 'noscript', 'option', 'script', 'style',
  92. 'title', 'textarea'];
  93. var textNodeXpath =
  94. ".//text()[not(ancestor::" + notInTags.join(') and not(ancestor::') + ")]";
  95.  
  96. var urlRE = /(\b|$)(?:[-a-z]+:\/\/|www\.(?!\.))[^\s'"<>(),\u0080-\uffff]+|\b[\w.%+-]+@[\w-.]+\.\w{2,4}\b/gi;
  97. var queue = [];
  98.  
  99. /******************************************************************************/
  100.  
  101. linkifyContainer(document.body);
  102.  
  103. var observerHandler = function(mutations){
  104. var i, j;
  105. for(i = 0; i < mutations.length; i++){
  106. if(mutations[i].type != "childList"){
  107. continue;
  108. }
  109. // console.log(mutations[i]);
  110. for(j = 0; j < mutations[i].addedNodes.length; j++){
  111. linkifyContainer(mutations[i].addedNodes[j]);
  112. }
  113. }
  114. };
  115.  
  116. var observerConfig = {
  117. childList: true,
  118. subtree: true
  119. };
  120.  
  121. new MutationObserver(observerHandler, false)
  122. .observe(document.body, observerConfig);
  123.  
  124. /******************************************************************************/
  125.  
  126. var notInTagSet = function(){
  127. var o = {}, i;
  128. for(i = 0; i < notInTags.length; i++){
  129. o[ notInTags[i].toUpperCase() ] = true;
  130. }
  131. return o;
  132. }();
  133.  
  134. var hasValidParent = function(node){
  135. while(node = node.parentNode){
  136. if (node.tagName == 'PRE' && node.className){
  137. return false;
  138. }
  139. if (node.nodeName && node.nodeName in notInTagSet){
  140. return false;
  141. }
  142. if (node.classList && node.classList.contains("highlight")){
  143. return false;
  144. }
  145. }
  146. return true;
  147. };
  148.  
  149. function linkifyContainer(container) {
  150. // Prevent infinite recursion, in case X(HT)ML documents with namespaces
  151. // break the XPath's attempt to do so. (Don't evaluate spans we put our
  152. // classname into.)
  153. if (container.className && container.className.match(/\blinkifyplus\b/)) {
  154. return;
  155. }
  156. if(container.nodeType && container.nodeType == 3){
  157. if(hasValidParent(container)){
  158. linkifyTextNode(container);
  159. }
  160. return;
  161. }
  162.  
  163. var xpathResult = document.evaluate(
  164. textNodeXpath, container, null,
  165. XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null
  166. );
  167.  
  168. var i = 0;
  169. function continuation() {
  170. var node = null, counter = 0;
  171. while (node = xpathResult.snapshotItem(i++)) {
  172. if (!hasValidParent(node)) {
  173. continue;
  174. }
  175. linkifyTextNode(node);
  176.  
  177. if (++counter > 50) {
  178. return setTimeout(continuation, 0);
  179. }
  180. }
  181. }
  182. setTimeout(continuation, 0);
  183. }
  184.  
  185. function linkifyTextNode(node) {
  186. var l, m;
  187. var txt = node.textContent;
  188. var span = null;
  189. var p = 0;
  190. while (m = urlRE.exec(txt)) {
  191. if (!span) {
  192. // Create a span to hold the new text with links in it.
  193. span = document.createElement('span');
  194. span.className = 'linkifyplus';
  195. }
  196.  
  197. //get the link without trailing dots
  198. l = m[0].replace(/\.*$/, '');
  199. var lLen = l.length;
  200. //put in text up to the link
  201. span.appendChild(document.createTextNode(txt.substring(p, m.index)));
  202. //create a link and put it in the span
  203. var a = document.createElement('a');
  204. a.className = 'linkifyplus';
  205. if(/(\.jpg|\.png|\.gif)$/i.test(l)){
  206. var img = document.createElement("img");
  207. img.src = l;
  208. a.appendChild(img);
  209. }else{
  210. a.appendChild(document.createTextNode(l));
  211. }
  212. if (l.indexOf(":/") < 0) {
  213. if (l.indexOf("@") > 0) {
  214. l = "mailto:" + l;
  215. } else {
  216. l = "http://" + l;
  217. }
  218. }
  219. a.setAttribute('href', l);
  220. span.appendChild(a);
  221. //track insertion point
  222. p = m.index + lLen;
  223. }
  224. if (span) {
  225. //take the text after the last link
  226. span.appendChild(document.createTextNode(txt.substring(p, txt.length)));
  227. //replace the original text with the new span
  228. node.parentNode.replaceChild(span, node);
  229. }
  230. }
  231.  
  232. if(window.GM_addStyle){
  233. GM_addStyle('\
  234. .linkifyplus img {\
  235. max-width: 100%;\
  236. }\
  237. ');
  238. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址