Convert Any links to Clickable Links (Lightweight)

URLやドメイン名をクリック可能なリンクに変換(軽量化版)

当前为 2025-03-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Convert Any links to Clickable Links (Lightweight)
  3. // @namespace kdroidwin.hatenablog.com
  4. // @version 2.4
  5. // @description URLやドメイン名をクリック可能なリンクに変換(軽量化版)
  6. // @author Kdroidwin
  7. // @match *://*/*
  8. // @exclude *://github.com/*
  9. // @exclude *://chat.openai.com/*
  10. // @exclude *://blog.hatena.ne.jp/*
  11. // @grant none
  12. // @license GPL-3.0
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. const urlPattern = /\b(?:h?ttps?:\/\/[^\s<>"]+|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(?:\/[^\s<>"]*)?)\b/g;
  19.  
  20. function isEditable(node) {
  21. while (node) {
  22. if (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA' ||
  23. (node.getAttribute && node.getAttribute('contenteditable') === 'true')) return true;
  24. node = node.parentNode;
  25. }
  26. return false;
  27. }
  28.  
  29. function convertTextToLinks(root) {
  30. const textNodes = [];
  31. root.querySelectorAll(':not(a):not(input):not(textarea):not([contenteditable])').forEach(el => {
  32. for (let node of el.childNodes) {
  33. if (node.nodeType === 3 && urlPattern.test(node.nodeValue)) textNodes.push(node);
  34. }
  35. });
  36.  
  37. textNodes.forEach(node => {
  38. const frag = document.createDocumentFragment();
  39. let lastIndex = 0;
  40. node.nodeValue.replace(urlPattern, (match, offset) => {
  41. frag.appendChild(document.createTextNode(node.nodeValue.slice(lastIndex, offset)));
  42.  
  43. const a = document.createElement('a');
  44. a.href = match.startsWith('ttp') ? 'h' + match : match.includes('://') ? match : 'https://' + match;
  45. a.textContent = match;
  46. a.target = '_blank';
  47. frag.appendChild(a);
  48.  
  49. lastIndex = offset + match.length;
  50. });
  51. frag.appendChild(document.createTextNode(node.nodeValue.slice(lastIndex)));
  52. node.parentNode.replaceChild(frag, node);
  53. });
  54. }
  55.  
  56. const observer = new MutationObserver(() => {
  57. convertTextToLinks(document.body);
  58. });
  59.  
  60. observer.observe(document.body, { childList: true, subtree: true });
  61.  
  62. convertTextToLinks(document.body);
  63. })();