您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
默认禁用。仅在白名单站点强制链接在新标签页打开。可通过右下角UI面板管理白/黑名单。
当前为
// ==UserScript== // @name 左键点击链接在新标签页打开 (白名单启用模式+UI) // @name:en Open Links in New Tab on Whitelist (with UI Panel) // @namespace http://greasyfork.icu/users/your-username // 建议替换为你的唯一命名空间 // @version 1.5 // @description 默认禁用。仅在白名单站点强制链接在新标签页打开。可通过右下角UI面板管理白/黑名单。 // @description:en Disabled by default. Forces links in new tab ONLY on whitelisted sites. Manage rules via UI panel. // @author AI Assistant // @match *://*/* // @grant GM_openInTab // @grant window.open // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @license MIT // ==/UserScript== (function() { 'use strict'; // --- 配置键名 --- const CONFIG_KEY_WHITELIST = 'openInNewTab_custom_whitelist_v1'; const CONFIG_KEY_BLACKLIST = 'openInNewTab_custom_blacklist_v1'; const CONFIG_KEY_PANEL_VISIBLE = 'openInNewTab_panelVisibleState_v1'; // --- 默认配置 --- const defaultWhitelistPatterns = [ // "https://example.com/always-open-new-tab/*" // 添加一些你希望默认启用的网站 ]; const defaultBlacklistPatterns = [ // "https://example.com/never-open-new-tab/*" ]; let userWhitelist = []; let userBlacklist = []; let panelVisible = GM_getValue(CONFIG_KEY_PANEL_VISIBLE, false); let uiPanel = null; // --- CSS 样式 --- GM_addStyle(` #openInNewTab-config-panel { position: fixed; right: 15px; bottom: 15px; width: 300px; max-height: calc(80vh - 30px); background-color: #f8f9fa; border: 1px solid #ced4da; border-radius: 8px; padding: 15px; z-index: 2147483647; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: 14px; color: #212529; box-shadow: 0 5px 15px rgba(0,0,0,0.15); display: none; flex-direction: column; } #openInNewTab-config-panel.panel-visible { display: flex; } #openInNewTab-config-panel .panel-content-scrollable { overflow-y: auto; flex-grow: 1; margin-bottom: 10px; } #openInNewTab-config-panel h3 { margin-top: 0; margin-bottom: 12px; font-size: 18px; color: #343a40; border-bottom: 1px solid #dee2e6; padding-bottom: 8px; text-align: center; } #openInNewTab-config-panel h4 { margin-top: 10px; margin-bottom: 8px; font-size: 15px; color: #495057; } #openInNewTab-config-panel .add-form { display: flex; margin-bottom: 10px; } #openInNewTab-config-panel .add-form input[type="text"] { flex-grow: 1; margin-right: 8px; padding: 6px 8px; border: 1px solid #ced4da; border-radius: 4px; font-size: 13px; } #openInNewTab-config-panel .add-form button { padding: 6px 10px; font-size: 13px; color: white; background-color: #007bff; border: 1px solid #007bff; border-radius: 4px; cursor: pointer; white-space: nowrap; } #openInNewTab-config-panel .add-form button:hover { background-color: #0056b3; } #openInNewTab-config-panel ul { list-style-type: none; padding-left: 0; margin: 0 0 10px 0; border: 1px solid #e9ecef; border-radius: 4px; background-color: #fff; } #openInNewTab-config-panel li { padding: 7px 10px; border-bottom: 1px solid #f1f3f5; display: flex; align-items: center; justify-content: space-between; font-size: 13px; } #openInNewTab-config-panel li:last-child { border-bottom: none; } #openInNewTab-config-panel li .pattern-text { word-break: break-all; margin-right: 8px; flex-grow: 1; } #openInNewTab-config-panel .delete-btn { color: #dc3545; background-color: transparent; border: none; cursor: pointer; font-weight: bold; font-size: 18px; padding: 0 5px; line-height: 1; opacity: 0.6; } #openInNewTab-config-panel .delete-btn:hover { color: #c82333; opacity: 1; } #openInNewTab-config-panel .panel-empty-msg { font-size: 13px; color: #6c757d; padding: 10px; text-align: center; background-color: #fff; border-radius: 4px; } #openInNewTab-config-panel .close-panel-btn { display: block; width: 100%; padding: 8px 12px; font-size: 14px; color: #fff; background-color: #6c757d; border: none; border-radius: 4px; cursor: pointer; } #openInNewTab-config-panel .close-panel-btn:hover { background-color: #5a6268; } `); function createAddForm(listType, listArray, configKey, parentElement) { const form = document.createElement('div'); form.className = 'add-form'; const input = document.createElement('input'); input.type = 'text'; input.placeholder = `添加新${listType === 'white' ? '白' : '黑'}名单模式...`; input.addEventListener('keypress', function(e) { if (e.key === 'Enter') { addButton.click(); } }); const addButton = document.createElement('button'); addButton.textContent = '添加'; addButton.onclick = () => { const pattern = input.value.trim(); if (pattern) { if (listArray.includes(pattern)) { alert(`模式 "${pattern}" 已存在于${listType === 'white' ? '白' : '黑'}名单中!`); return; } listArray.push(pattern); GM_setValue(configKey, listArray.join(',')); input.value = ''; renderListsUI(); } else { alert('请输入有效的URL模式!'); } }; form.appendChild(input); form.appendChild(addButton); parentElement.appendChild(form); } function createUIPanel() { if (!document.body) { setTimeout(createUIPanel, 100); return; } if (document.getElementById('openInNewTab-config-panel')) { uiPanel = document.getElementById('openInNewTab-config-panel'); renderListsUI(); uiPanel.classList.toggle('panel-visible', panelVisible); return; } uiPanel = document.createElement('div'); uiPanel.id = 'openInNewTab-config-panel'; const title = document.createElement('h3'); title.textContent = '链接新标签页打开 - 规则管理'; uiPanel.appendChild(title); const scrollableContent = document.createElement('div'); scrollableContent.className = 'panel-content-scrollable'; ['whitelist', 'blacklist'].forEach(type => { const section = document.createElement('div'); section.id = `openInNewTab-${type}-section`; const sectionTitle = document.createElement('h4'); sectionTitle.textContent = type === 'whitelist' ? '白名单 (强制启用):' : '黑名单 (明确禁用):'; section.appendChild(sectionTitle); createAddForm(type, type === 'whitelist' ? userWhitelist : userBlacklist, type === 'whitelist' ? CONFIG_KEY_WHITELIST : CONFIG_KEY_BLACKLIST, section); const ul = document.createElement('ul'); ul.id = `openInNewTab-${type}-ul`; section.appendChild(ul); scrollableContent.appendChild(section); }); uiPanel.appendChild(scrollableContent); const closeButton = document.createElement('button'); closeButton.textContent = '关闭面板'; closeButton.className = 'close-panel-btn'; closeButton.onclick = togglePanelVisibility; uiPanel.appendChild(closeButton); document.body.appendChild(uiPanel); renderListsUI(); uiPanel.classList.toggle('panel-visible', panelVisible); } function renderListsUI() { if (!uiPanel || !document.body.contains(uiPanel)) return; const renderUlContent = (listArray, ulElementId, listType) => { const ul = uiPanel.querySelector('#' + ulElementId); if (!ul) return; ul.innerHTML = ''; if (listArray.length === 0) { const emptyMsgLi = document.createElement('li'); emptyMsgLi.textContent = '(列表为空)'; emptyMsgLi.className = 'panel-empty-msg'; emptyMsgLi.style.justifyContent = 'center'; emptyMsgLi.style.padding = '10px'; ul.appendChild(emptyMsgLi); return; } listArray.forEach((pattern, index) => { const li = document.createElement('li'); const patternText = document.createElement('span'); patternText.className = 'pattern-text'; patternText.textContent = pattern; const deleteBtn = document.createElement('button'); deleteBtn.innerHTML = '×'; deleteBtn.className = 'delete-btn'; deleteBtn.title = '删除此条规则'; deleteBtn.onclick = function() { if (confirm(`确定要从${listType === 'white' ? '白' : '黑'}名单中删除 "${pattern}" 吗?`)) { listArray.splice(index, 1); GM_setValue(listType === 'white' ? CONFIG_KEY_WHITELIST : CONFIG_KEY_BLACKLIST, listArray.join(',')); renderListsUI(); } }; li.appendChild(patternText); li.appendChild(deleteBtn); ul.appendChild(li); }); }; renderUlContent(userWhitelist, 'openInNewTab-whitelist-ul', 'white'); renderUlContent(userBlacklist, 'openInNewTab-blacklist-ul', 'black'); } function togglePanelVisibility() { panelVisible = !panelVisible; GM_setValue(CONFIG_KEY_PANEL_VISIBLE, panelVisible); if (panelVisible) { if (!uiPanel || !document.body.contains(uiPanel)) { createUIPanel(); } else { renderListsUI(); uiPanel.classList.add('panel-visible'); } } else { if (uiPanel) { uiPanel.classList.remove('panel-visible'); } } } function loadConfig() { const storedWhitelistStr = GM_getValue(CONFIG_KEY_WHITELIST); const storedBlacklistStr = GM_getValue(CONFIG_KEY_BLACKLIST); userWhitelist = (typeof storedWhitelistStr === 'string' && storedWhitelistStr.trim() !== '') ? storedWhitelistStr.split(',').map(s => s.trim()).filter(s => s) : (typeof storedWhitelistStr === 'undefined' ? (GM_setValue(CONFIG_KEY_WHITELIST, defaultWhitelistPatterns.join(',')), [...defaultWhitelistPatterns]) : []); userBlacklist = (typeof storedBlacklistStr === 'string' && storedBlacklistStr.trim() !== '') ? storedBlacklistStr.split(',').map(s => s.trim()).filter(s => s) : (typeof storedBlacklistStr === 'undefined' ? (GM_setValue(CONFIG_KEY_BLACKLIST, defaultBlacklistPatterns.join(',')), [...defaultBlacklistPatterns]) : []); if (uiPanel && panelVisible && document.body.contains(uiPanel)) { renderListsUI(); } } function urlMatchesPattern(url, pattern) { if (!pattern || !url) return false; let currentUrl = url; let p = pattern.trim(); if (!p.includes("://")) { currentUrl = currentUrl.replace(/^https?:\/\//, ""); } if (!p.startsWith("www.") && !p.includes("://") && currentUrl.startsWith("www.")) { currentUrl = currentUrl.replace(/^www\./, "");} const escapedPattern = p.replace(/[.+?^${}()|[\]\\]/g, '\\$&'); const regexString = '^' + escapedPattern.replace(/\\\*/g, '.*') + '$'; try { return new RegExp(regexString, 'i').test(currentUrl); } catch (e) { return false; } } if (typeof GM_registerMenuCommand === 'function' && typeof GM_getValue === 'function' && typeof GM_setValue === 'function') { GM_registerMenuCommand('配置 白名单 (Prompt)', function() { const current = GM_getValue(CONFIG_KEY_WHITELIST, userWhitelist.join(',')); const newList = prompt('白名单 (强制启用),用逗号 "," 分隔:', current); if (newList !== null) { GM_setValue(CONFIG_KEY_WHITELIST, newList); loadConfig(); alert('白名单已更新!');} }, 'W'); GM_registerMenuCommand('配置 黑名单 (Prompt)', function() { const current = GM_getValue(CONFIG_KEY_BLACKLIST, userBlacklist.join(',')); const newList = prompt('黑名单 (明确禁用),用逗号 "," 分隔:', current); if (newList !== null) { GM_setValue(CONFIG_KEY_BLACKLIST, newList); loadConfig(); alert('黑名单已更新!');} }, 'B'); GM_registerMenuCommand('显示/隐藏 规则管理面板', togglePanelVisibility, 'M'); // 'M' for Manage } loadConfig(); const ensureInitialPanelState = () => { if (panelVisible) { // panelVisible 已从存储中加载 if (!uiPanel || !document.body.contains(uiPanel)) { createUIPanel(); } else { uiPanel.classList.add('panel-visible'); renderListsUI(); } } }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", ensureInitialPanelState); } else { ensureInitialPanelState(); } document.addEventListener('click', function(event) { const currentPageUrl = window.location.href; let scriptShouldRunOnThisPage = false; // 1. 默认禁用 // 2. 检查白名单 const isWhitelisted = userWhitelist.some(pattern => urlMatchesPattern(currentPageUrl, pattern)); if (isWhitelisted) { scriptShouldRunOnThisPage = true; // 白名单匹配,则启用 } else { // 3. 如果不在白名单中,检查黑名单 const isBlacklisted = userBlacklist.some(pattern => urlMatchesPattern(currentPageUrl, pattern)); if (isBlacklisted) { scriptShouldRunOnThisPage = false; // 在黑名单中(且不在白名单),则明确禁用 } else { // 既不在白名单,也不在黑名单,保持默认禁用状态 scriptShouldRunOnThisPage = false; } } if (!scriptShouldRunOnThisPage) { // console.log('左键新标签页脚本:当前页面未启用此功能。'); return; } // console.log('左键新标签页脚本:当前页面已启用此功能。'); if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return; let targetElement = event.target; let anchorElement = null; for (let i = 0; i < 5 && targetElement && targetElement !== document.body; i++) { if (targetElement.tagName === 'A') { anchorElement = targetElement; break; } targetElement = targetElement.parentElement; } if (anchorElement) { const href = anchorElement.href; const rawHref = anchorElement.getAttribute('href'); if (!href || (rawHref && rawHref.startsWith('#')) || href.startsWith('javascript:')) return; if (anchorElement.hasAttribute('download')) return; if (event.altKey && event.shiftKey) { return; } // Alt+Shift+Click 绕过脚本 event.preventDefault(); event.stopPropagation(); if (typeof GM_openInTab === 'function') { GM_openInTab(href, { active: true, insert: true }); } else if (typeof window.open === 'function') { window.open(href, '_blank'); } else { console.warn('无法在新标签页中打开链接:GM_openInTab 和 window.open 均不可用。'); } } }, true); })();