您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Copy hrefs from selected links with toast at top; toast clickable to show copied links; user can set keyboard shortcut via menu command
// ==UserScript== // @name EZLinkZ // @namespace https://github.com/codeMonkeyHopeful/EZLinkZ // @homepage https://github.com/codeMonkeyHopeful/EZLinkZ // @version 1.4 // @description Copy hrefs from selected links with toast at top; toast clickable to show copied links; user can set keyboard shortcut via menu command // @author CodeMonkeyHopeful // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @supportURL https://github.com/codeMonkeyHopeful/EZLinkZ // @license MIT // ==/UserScript== (function () { "use strict"; // Default shortcut keys (Ctrl+Shift+C) let shortcut = { ctrlKey: true, shiftKey: true, altKey: false, metaKey: false, key: "c", }; // Load saved shortcut from storage async function loadShortcut() { const saved = await GM_getValue("shortcut"); if (saved) { try { const parsed = JSON.parse(saved); if (parsed.key) shortcut = parsed; } catch {} } } // Save shortcut to storage async function saveShortcut(newShortcut) { await GM_setValue("shortcut", JSON.stringify(newShortcut)); shortcut = newShortcut; showToast(`Shortcut updated to ${formatShortcut(newShortcut)}`); } function formatShortcut(sc) { let parts = []; if (sc.ctrlKey) parts.push("Ctrl"); if (sc.shiftKey) parts.push("Shift"); if (sc.altKey) parts.push("Alt"); if (sc.metaKey) parts.push("Meta"); parts.push(sc.key.toUpperCase()); return parts.join("+"); } // Prompt user to enter new shortcut (simple example, expects something like "Ctrl+Shift+X") async function promptShortcut() { const input = prompt( `Enter new shortcut keys separated by +\nExample: Ctrl+Shift+X\nCurrent: ${formatShortcut( shortcut )}` ); if (!input) return; // Parse input const parts = input .toLowerCase() .split("+") .map((s) => s.trim()); const newSc = { ctrlKey: parts.includes("ctrl"), shiftKey: parts.includes("shift"), altKey: parts.includes("alt"), metaKey: parts.includes("meta"), key: parts.find((k) => !["ctrl", "shift", "alt", "meta"].includes(k)) || "c", }; await saveShortcut(newSc); } // Toast and popup elements const toast = document.createElement("div"); const popup = document.createElement("div"); const closeBtn = document.createElement("button"); let popupVisible = false; // Style toast (top center) Object.assign(toast.style, { position: "fixed", top: "20px", left: "50%", transform: "translateX(-50%)", backgroundColor: "rgba(60,60,60,0.9)", color: "#fff", padding: "10px 20px", borderRadius: "5px", fontSize: "14px", fontFamily: "sans-serif", zIndex: 9999, opacity: "0", transition: "opacity 0.3s ease", pointerEvents: "auto", cursor: "pointer", userSelect: "none", maxWidth: "80vw", boxSizing: "border-box", }); document.body.appendChild(toast); // Style popup (hidden by default) Object.assign(popup.style, { position: "fixed", top: "60px", left: "50%", transform: "translateX(-50%)", backgroundColor: "rgba(30,30,30,0.95)", color: "#fff", padding: "15px 20px 20px 20px", borderRadius: "8px", fontSize: "13px", fontFamily: "monospace", zIndex: 10000, maxHeight: "300px", maxWidth: "90vw", overflowY: "auto", boxSizing: "border-box", display: "none", whiteSpace: "pre-wrap", wordBreak: "break-word", }); document.body.appendChild(popup); // Close button inside popup closeBtn.textContent = "×"; Object.assign(closeBtn.style, { position: "absolute", top: "5px", right: "10px", background: "transparent", border: "none", color: "#fff", fontSize: "20px", cursor: "pointer", userSelect: "none", }); popup.appendChild(closeBtn); // Show toast message for duration (ms) let toastTimeout; function showToast(message, duration = 2500) { if (popupVisible) return; // don't show toast if popup open toast.textContent = message; toast.style.opacity = "1"; clearTimeout(toastTimeout); toastTimeout = setTimeout(() => { toast.style.opacity = "0"; }, duration); } // Show popup with links text function showPopup(text) { popup.textContent = text; popup.appendChild(closeBtn); popup.style.display = "block"; popupVisible = true; toast.style.opacity = "0"; } // Hide popup function hidePopup() { popup.style.display = "none"; popupVisible = false; } // Get links from selection function getSelectedLinks() { const selection = window.getSelection(); if (!selection || selection.rangeCount === 0 || selection.isCollapsed) { return null; } const range = selection.getRangeAt(0); const container = document.createElement("div"); container.appendChild(range.cloneContents()); const links = container.querySelectorAll("a"); const hrefs = Array.from(links) .map((a) => a.href) .filter((href) => href); return hrefs.length > 0 ? hrefs : null; } // Copy selected links and handle UI function copySelectedLinks() { const hrefs = getSelectedLinks(); if (!hrefs) { showToast("No links found in selection"); return; } const textToCopy = hrefs.join("\n"); navigator.clipboard .writeText(textToCopy) .then(() => { showToast(`Copied ${hrefs.length} link(s) to clipboard`); // When toast clicked, show popup with links toast.onclick = () => showPopup(textToCopy); }) .catch(() => showToast("Failed to copy to clipboard")); } // Hide popup when clicking outside it document.addEventListener("click", (e) => { if (!popupVisible) return; if (popup.contains(e.target) || toast.contains(e.target)) return; hidePopup(); }); // Close button click closeBtn.addEventListener("click", () => { hidePopup(); }); // Keyboard shortcut listener document.addEventListener("keydown", (e) => { const keyMatches = e.key.toLowerCase() === shortcut.key.toLowerCase() && e.ctrlKey === !!shortcut.ctrlKey && e.shiftKey === !!shortcut.shiftKey && e.altKey === !!shortcut.altKey && e.metaKey === !!shortcut.metaKey; if (keyMatches) { e.preventDefault(); copySelectedLinks(); } }); // Register Tampermonkey menu command to set shortcut GM_registerMenuCommand("Set Keyboard Shortcut", promptShortcut); // Load shortcut from storage on start loadShortcut(); })();