4chan Linkify

Linkification of text links.

  1. // ==UserScript==
  2. // @name 4chan Linkify
  3. // @namespace csimi
  4. // @author csimi
  5. // @description Linkification of text links.
  6. // @homepage http://userscripts.org/users/156405/scripts
  7. // @version 2.0.5
  8. // @icon http://i.imgur.com/JHVzK.png
  9. // @include http://boards.4chan.org/*
  10. // @include https://boards.4chan.org/*
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_deleteValue
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. var self = {
  19. ready: function () {
  20. var MutationObserver;
  21. if (MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.OMutationObserver) {
  22. observer = new MutationObserver(function (mutations) {
  23. mutations.forEach(function (mutation) {
  24. for (var i = 0; i < mutation.addedNodes.length; i++) {
  25. self.check(mutation.addedNodes[i]);
  26. }
  27. });
  28. });
  29. observer.observe(self.qs('body'), {
  30. childList: true,
  31. subtree: true
  32. });
  33. }
  34. else {
  35. document.addEventListener('DOMNodeInserted', function (event) {
  36. self.check(event.target);
  37. }, false);
  38. }
  39. var func = function () {
  40. self.incrementalize(self.qsa('.board > .thread > .postContainer'));
  41. };
  42. if (document.readyState == 'loading') {
  43. document.addEventListener('DOMContentLoaded', func, false);
  44. }
  45. else func();
  46. if (typeof GM_registerMenuCommand == 'function' && typeof GM_getValue == 'function' && typeof GM_setValue == 'function' && typeof GM_deleteValue == 'function') {
  47. var menucommand = function () {
  48. if (!GM_getValue('blank')) {
  49. GM_setValue('blank', true);
  50. alert('Links now open in a blank window.');
  51. }
  52. else {
  53. GM_deleteValue('blank');
  54. alert('Links don\'t open in a blank window anymore.');
  55. }
  56. };
  57. GM_registerMenuCommand('4chan Linkify toggle blank window', menucommand, '');
  58. }
  59. },
  60. qs: function (a, b) {
  61. return (b || document).querySelector(a);
  62. },
  63. qsa: function (a, b) {
  64. return (b || document).querySelectorAll(a);
  65. },
  66. check: function (node) {
  67. if (node.nodeType && node.nodeType == 1 && node.classList.contains('postContainer')) {
  68. var bq = self.qs('blockquote', node);
  69. if (!bq || !bq.parentNode || !bq.childNodes || !bq.childNodes.length) return;
  70. for (var i = 0; i < bq.childNodes.length; i++) {
  71. self.process(bq.childNodes[i]);
  72. }
  73. }
  74. if (node.nodeType && node.nodeType == 1 && node.nodeName.toLowerCase() == 'blockquote') {
  75. for (var i = 0; i < node.childNodes.length; i++) {
  76. self.process(node.childNodes[i]);
  77. }
  78. }
  79. },
  80. create: function (s) {
  81. node = document.createElement('a');
  82. node.className = 'chanlinkify';
  83. node.href = s;
  84. node.appendChild(document.createTextNode(s));
  85. if (typeof GM_getValue == 'function' && GM_getValue('blank')) node.target = '_blank';
  86. return node;
  87. },
  88. next: function (node) {
  89. if (!node.nextSibling) return;
  90. if (node.nextSibling.nodeName.toLowerCase() == 'wbr') {
  91. node.appendChild(node.nextSibling);
  92. }
  93. var sib = node.nextSibling;
  94. if (sib && sib.nodeType == 3) {
  95. var m = sib.nodeValue.match(/^[^\s]+/);
  96. if (!m) return;
  97. var s = m[0];
  98. node.href = node.textContent+s;
  99. node.appendChild(document.createTextNode(s));
  100. if (sib.nodeValue.length == s.length) {
  101. node.parentNode.removeChild(sib);
  102. }
  103. else {
  104. sib.nodeValue = sib.nodeValue.substring(s.length);
  105. }
  106. self.next(node);
  107. }
  108. },
  109. process: function (node) {
  110. if (node.nodeType == 1 && node.childNodes.length && (node.classList.contains('quote') || node.nodeName.toLowerCase() == 's')) return self.process(node.childNodes[0]);
  111. if (node.nodeType != 3) return;
  112. var m;
  113. m = node.nodeValue.match(/[a-zA-Z][a-zA-Z0-9+-.]+:\/\/[^\s]+/);
  114. if (!m) m = node.nodeValue.match(/mailto:[^\s]+/);
  115. if (!m) m = node.nodeValue.match(/magnet:[^\s]+/);
  116. if (!m) m = node.nodeValue.match(/news:[^\s]+/);
  117. if (m && node.parentNode.nodeName.toLowerCase() != 'a') {
  118. var s = m[0];
  119. var a = self.create(s);
  120. if (node.nodeValue.length == s.length) {
  121. node.parentNode.replaceChild(a, node);
  122. }
  123. else {
  124. var pos = node.nodeValue.indexOf(s);
  125. if (pos != 0) node.parentNode.insertBefore(document.createTextNode(node.nodeValue.substring(0, pos)), node);
  126. node.parentNode.insertBefore(a, node);
  127. node.nodeValue = node.nodeValue.substring(pos+s.length);
  128. if (!node.nodeValue) node.parentNode.removeChild(node);
  129. }
  130. self.next(a);
  131. }
  132. },
  133. incrementalize: function (nodes) {
  134. var i = 0;
  135. var func = function () {
  136. for(var j = 0; i < nodes.length; i++, j++) {
  137. self.check(nodes[i]);
  138. if (j == 10) break;
  139. }
  140. if (i < nodes.length) window.setTimeout(func, 10);
  141. };
  142. func();
  143. },
  144. };
  145. self.ready();
  146. })();

QingJ © 2025

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