您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
三击将文本URL转换为可点击链接
当前为
- // ==UserScript==
- // @name Link Helper - Triple Click Text to Link
- // @name:zh-CN 链接助手 - 三击自动转换
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description Convert text URLs to links on triple click
- // @description:zh-CN 三击将文本URL转换为可点击链接
- // @author Alex3236
- // @match *://*/*
- // @grant none
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- let clicks = [];
- const CLICK_TIMEOUT = 1000;
- const CLICK_THRESHOLD = 10;
- document.addEventListener('click', function(e) {
- const now = Date.now();
- clicks.push({
- time: now,
- x: e.clientX,
- y: e.clientY
- });
- if (clicks.length > 3) clicks.shift();
- if (clicks.length === 3) {
- const [first, second, third] = clicks;
- if (third.time - first.time < CLICK_TIMEOUT &&
- distance(first, second) < CLICK_THRESHOLD &&
- distance(second, third) < CLICK_THRESHOLD) {
- processTripleClick(e.clientX, e.clientY);
- clicks = []; // 重置点击记录
- }
- }
- });
- function distance(a, b) {
- return Math.hypot(a.x - b.x, a.y - b.y);
- }
- function processTripleClick(x, y) {
- const textNode = getTextNodeFromPoint(x, y);
- if (!textNode || isInsideLink(textNode)) return;
- const text = textNode.nodeValue;
- const matches = findUrls(text);
- if (matches.length > 0) {
- replaceTextWithLinks(textNode, matches);
- }
- }
- function getTextNodeFromPoint(x, y) {
- let range;
- if (document.caretRangeFromPoint) {
- range = document.caretRangeFromPoint(x, y);
- } else if (document.caretPositionFromPoint) {
- const pos = document.caretPositionFromPoint(x, y);
- if (!pos) return null;
- range = document.createRange();
- range.setStart(pos.offsetNode, pos.offset);
- range.collapse(true);
- }
- return range?.startContainer?.nodeType === Node.TEXT_NODE ? range.startContainer : null;
- }
- function isInsideLink(node) {
- let parent = node.parentNode;
- while (parent) {
- if (parent.tagName === 'A') return true;
- parent = parent.parentNode;
- }
- return false;
- }
- function findUrls(text) {
- const urlRegex = /(https?:\/\/[^\s<]+|www\.[^\s<]+\.[^\s<]{2,})/gi;
- const matches = [];
- let match;
- while ((match = urlRegex.exec(text)) !== null) {
- matches.push({
- start: match.index,
- end: match.index + match[0].length,
- url: match[0]
- });
- }
- return matches;
- }
- function replaceTextWithLinks(textNode, matches) {
- const parent = textNode.parentNode;
- const docFrag = document.createDocumentFragment();
- let lastIndex = 0;
- matches.forEach(match => {
- if (match.start > lastIndex) {
- docFrag.appendChild(document.createTextNode(
- textNode.nodeValue.slice(lastIndex, match.start)
- ));
- }
- const a = document.createElement('a');
- a.style = "color: #66ccff; background: #163E64";
- a.href = match.url.startsWith('http') ? match.url : `http://${match.url}`;
- a.textContent = match.url;
- a.target = '_blank';
- docFrag.appendChild(a);
- lastIndex = match.end;
- });
- if (lastIndex < textNode.nodeValue.length) {
- docFrag.appendChild(document.createTextNode(
- textNode.nodeValue.slice(lastIndex)
- ));
- }
- parent.replaceChild(docFrag, textNode);
- }
- })();