Text to URL

Конвертирует текст в виде ссылок в реальные ссылки, на которые можно кликнуть.

当前为 2018-05-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Text to URL
  3. // @namespace https://github.com/T1mL3arn
  4. // @description:ru Конвертирует текст в виде ссылок в реальные ссылки, на которые можно кликнуть.
  5. // @description:en Converts url-like text into clickable url.
  6. // @match *://*/*
  7. // @version 1.0
  8. // @run-at document-end
  9. // @license GPLv3
  10. // @supportURL https://greasyfork.org/en/scripts/367955-text-to-url/feedback
  11. // @homepageURL https://greasyfork.org/en/scripts/367955-text-to-url
  12. // @description Конвертирует текст в виде ссылок в реальные ссылки, на которые можно кликнуть.
  13. // ==/UserScript==
  14.  
  15. let linkEreg = /(https|http|ftp|file):\/\/.+?(?=\s|$)/gi;
  16. let linkEregLocal = /(https|http|ftp|file):\/\/.+?(?=\s|$)/i;
  17. let obsOptions = { childList: true, subtree: true };
  18. let wrappedCount = 0;
  19.  
  20. function printWrappedCount() {
  21. if (wrappedCount > 0) {
  22. console.info(`[ ${GM_info.script.name} ] wrapped links count: ${wrappedCount}`);
  23. }
  24. }
  25.  
  26. let obs = new MutationObserver((changes, obs) => {
  27. wrappedCount = 0;
  28. obs.disconnect();
  29. changes.forEach((change) => change.addedNodes.forEach((node) => fixLinks(node)) );
  30. obs.observe(document.body, obsOptions);
  31. printWrappedCount();
  32. });
  33.  
  34. function fixLinks(node) {
  35. if (node.tagName != 'A') {
  36. // this is a text node
  37. if (node.nodeType === 3) {
  38. let content = node.textContent;
  39. if (content && content != '') {
  40. if (linkEregLocal.test(content)) {
  41. wrapTextNode(node);
  42. }
  43. }
  44. } else if (node.childNodes && node.childNodes.length > 0) {
  45. node.childNodes.forEach(fixLinks);
  46. }
  47. }
  48. }
  49.  
  50. function wrapTextNode(node) {
  51. let match;
  52. let sibling = node;
  53. let content = node.textContent;
  54. linkEreg.lastIndex = 0;
  55. while ((match = linkEreg.exec(content)) != null) {
  56. let fullMatch = match[0];
  57. let anchor = document.createElement('a');
  58.  
  59. let range = document.createRange();
  60. range.setStart(sibling, linkEreg.lastIndex - match[0].length);
  61. range.setEnd(sibling, linkEreg.lastIndex);
  62. range.surroundContents(anchor);
  63.  
  64. wrappedCount++;
  65.  
  66. anchor.href = fullMatch;
  67. anchor.textContent = fullMatch;
  68. anchor.target = '_blank';
  69. anchor.title = 'open link in a new tab';
  70. linkEreg.lastIndex = 0;
  71. sibling = getNextTextSibling(anchor);
  72. if (sibling == null)
  73. break;
  74. else
  75. content = sibling.textContent;
  76. }
  77. }
  78.  
  79. function getNextTextSibling(node) {
  80. let next = node.nextSibling;
  81. while (next != null) {
  82. if (next.nodeType == 3)
  83. return next;
  84. else
  85. next = node.nextSibling;
  86. }
  87. return null;
  88. }
  89.  
  90. fixLinks(document.body);
  91. printWrappedCount();
  92. obs.observe(document.body, obsOptions);