您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
防止网站覆盖浏览器内置的 Ctrl+F 搜索功能。
// ==UserScript== // @name Force Native Browser Find (Restore Ctrl+F Search) // @name:ar فرض البحث الأصلي للمتصفح (استعادة Ctrl+F) // @name:es Forzar Búsqueda Nativa del Navegador (Restaurar Ctrl+F) // @name:fr Forcer la Recherche Native du Navigateur (Restaurer Ctrl+F) // @name:hi मूल ब्राउज़र खोज को सक्षम करें (Ctrl+F को पुनर्स्थापित करें) // @name:id Paksa Pencarian Asli Browser (Kembalikan Ctrl+F) // @name:ja ブラウザ標準検索を強制使用(Ctrl+F復元) // @name:ko 브라우저 기본 검색 강제 사용 (Ctrl+F 복원) // @name:nl Forceer Standaard Browserzoeken (Herstel Ctrl+F) // @name:pt-BR Forçar Busca Nativa do Navegador (Restaurar Ctrl+F) // @name:ru Принудительный Поиск Браузера (Восстановить Ctrl+F) // @name:vi Bắt Buộc Tìm Kiếm Gốc Trình Duyệt (Khôi Phục Ctrl+F) // @name:zh-CN 强制浏览器原生搜索(恢复 Ctrl+F) // @name:zh-TW 強制瀏覽器原生搜尋(恢復 Ctrl+F) // @description Prevents websites from overriding the browser's built-in Ctrl+F search functionality. // @description:ar يمنع المواقع من تجاوز وظيفة البحث المدمجة Ctrl+F في المتصفح. // @description:es Evita que los sitios web anulen la función de búsqueda Ctrl+F integrada del navegador. // @description:fr Empêche les sites web de remplacer la fonction de recherche Ctrl+F intégrée du navigateur. // @description:hi वेबसाइटों को ब्राउज़र के अंतर्निहित Ctrl+F खोज कार्यक्षमता को बदलने से रोकता है। // @description:id Mencegah situs web mengganti fungsi pencarian Ctrl+F bawaan browser. // @description:ja ウェブサイトがブラウザ内蔵のCtrl+F検索機能を無効化することを防ぎます。 // @description:ko 웹사이트가 브라우저의 기본 Ctrl+F 검색 기능을 무력화하는 것을 방지합니다. // @description:nl Voorkomt dat websites de ingebouwde Ctrl+F zoekfunctie van de browser uitschakelen. // @description:pt-BR Impede que sites desabilitem a função de busca Ctrl+F integrada do navegador. // @description:ru Предотвращает отключение встроенной функции поиска Ctrl+F браузера сайтами. // @description:vi Ngăn các trang web vô hiệu hóa chức năng tìm kiếm Ctrl+F tích hợp của trình duyệt. // @description:zh-CN 防止网站覆盖浏览器内置的 Ctrl+F 搜索功能。 // @description:zh-TW 防止網站覆蓋瀏覽器內建的 Ctrl+F 搜尋功能。 // @namespace Bigrand // @version 1.0.1 // @match *://*/* // @license MIT // @grant GM_getValue // @grant GM_setValue // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // CONFIGURATION const CONFIG = { shortcuts: { toggleUI: GM_getValue('shortcut_ui', 'ctrl+shift+s'), quickToggle: GM_getValue('shortcut_toggle', 'ctrl+shift+d') }, keys: { SITE_PROTECTION: `ctrlf_${location.hostname}`, GLOBAL_PROTECTION: 'ctrlf_global', SHOW_UI: 'ctrlf_show_ui' }, ui: { showDelay: 500, notificationDuration: 3000, shortcutRecordTimeout: 5000 } }; // STATE MANAGEMENT const state = { global: GM_getValue(CONFIG.keys.GLOBAL_PROTECTION, true), site: GM_getValue(CONFIG.keys.SITE_PROTECTION, null), showUI: GM_getValue(CONFIG.keys.SHOW_UI, true), uiVisible: false, recordingShortcut: null, panel: null, cleanupFunctions: new Set() }; // CORE PROTECTION LOGIC const protection = { isEnabled() { return state.site !== null ? state.site : state.global; }, getSource() { return state.site !== null ? 'site' : 'global'; }, toggle() { if (state.site !== null) { state.site = !state.site; GM_setValue(CONFIG.keys.SITE_PROTECTION, state.site); } else { state.global = !state.global; GM_setValue(CONFIG.keys.GLOBAL_PROTECTION, state.global); } ui.update(); utils.showNotification( `Protection ${this.isEnabled() ? 'ON' : 'OFF'} ${this.getSource() === 'site' ? 'for this site' : 'globally'}` ); }, resetSite() { state.site = null; GM_setValue(CONFIG.keys.SITE_PROTECTION, null); ui.update(); } }; // KEYBOARD HANDLING const keyboard = { matchShortcut(e, shortcut) { const parts = shortcut.split('+'); const key = parts.pop(); return e.ctrlKey === parts.includes('ctrl') && e.shiftKey === parts.includes('shift') && e.altKey === parts.includes('alt') && !e.metaKey && e.key.toLowerCase() === key; }, handleKeydown(e) { if (state.recordingShortcut) return; if (this.matchShortcut(e, CONFIG.shortcuts.toggleUI)) { e.preventDefault(); e.stopImmediatePropagation(); ui.toggle(); return; } if (this.matchShortcut(e, CONFIG.shortcuts.quickToggle)) { e.preventDefault(); e.stopImmediatePropagation(); protection.toggle(); return; } // Protect Ctrl+F if (e.ctrlKey && !e.altKey && !e.metaKey && e.key.toLowerCase() === 'f') { if (protection.isEnabled()) { e.stopImmediatePropagation(); } } }, recordShortcut(btn) { if (state.recordingShortcut) return; const type = btn.dataset.type; const originalDisplay = btn.querySelector('.ctrlf-shortcut-display').textContent; state.recordingShortcut = type; btn.classList.add('recording'); btn.querySelector('.ctrlf-shortcut-hint').textContent = 'Press keys...'; let timeoutId; let keydownHandler; let escapeHandler; const cleanup = () => { btn.classList.remove('recording'); btn.querySelector('.ctrlf-shortcut-hint').textContent = 'Click to change'; if (keydownHandler) { document.removeEventListener('keydown', keydownHandler, true); keydownHandler = null; } if (escapeHandler) { document.removeEventListener('keydown', escapeHandler, true); escapeHandler = null; } if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } state.recordingShortcut = null; }; keydownHandler = (e) => { e.preventDefault(); e.stopPropagation(); // Handle escape to cancel if (e.key === 'Escape') { utils.showNotification('Shortcut recording cancelled'); cleanup(); return; } // Ignore modifier-only keys if (['Control', 'Shift', 'Alt', 'Meta'].includes(e.key)) return; const parts = []; if (e.ctrlKey) parts.push('ctrl'); if (e.shiftKey) parts.push('shift'); if (e.altKey) parts.push('alt'); // Validate key input const key = e.key.toLowerCase(); if (key.length === 1 && /[a-z0-9]/.test(key)) { parts.push(key); } else if (['enter', 'space', 'tab'].includes(key)) { parts.push(key); } else { utils.showNotification('Invalid key combination'); cleanup(); return; } const newShortcut = parts.join('+'); if (parts.length >= 2) { // Check for conflicts const existingShortcuts = Object.values(CONFIG.shortcuts); if (existingShortcuts.includes(newShortcut) && CONFIG.shortcuts[type] !== newShortcut) { utils.showNotification('Shortcut already in use'); cleanup(); return; } CONFIG.shortcuts[type] = newShortcut; GM_setValue(`shortcut_${type === 'toggleUI' ? 'ui' : 'toggle'}`, newShortcut); btn.querySelector('.ctrlf-shortcut-display').textContent = newShortcut; utils.showNotification(`Shortcut updated: ${newShortcut}`); cleanup(); } else { utils.showNotification('Shortcut must include modifier key'); cleanup(); } }; document.addEventListener('keydown', keydownHandler, true); // Auto-cleanup after timeout timeoutId = setTimeout(() => { utils.showNotification('Shortcut recording timed out'); cleanup(); }, CONFIG.ui.shortcutRecordTimeout); } }; // UI MANAGEMENT const ui = { toggle() { state.uiVisible ? this.hide() : this.show(); }, show() { if (state.panel) return; state.uiVisible = true; state.panel = utils.createElement('div', 'ctrlf-panel', this.getHTML()); utils.addStyles(); const cleanup = utils.makeDraggable(state.panel, state.panel.querySelector('.ctrlf-header')); state.cleanupFunctions.add(cleanup); this.setupEventListeners(); document.body.appendChild(state.panel); this.update(); }, hide() { if (state.panel) { // Cleanup all event listeners state.cleanupFunctions.forEach(cleanup => cleanup()); state.cleanupFunctions.clear(); state.panel.remove(); state.panel = null; state.uiVisible = false; } }, getHTML() { return ` <div class="ctrlf-header"> <span class="ctrlf-title">Ctrl+F Protection</span> <button class="ctrlf-close" title="Close (${CONFIG.shortcuts.toggleUI})">×</button> </div> <div class="ctrlf-content"> <div class="ctrlf-status"> <div class="ctrlf-status-indicator"></div> <span class="ctrlf-status-text"></span> </div> <div class="ctrlf-section"> <div class="ctrlf-control-group"> <label class="ctrlf-toggle-label"> <input type="checkbox" class="ctrlf-toggle" id="globalToggle"> <span class="ctrlf-toggle-slider"></span> <span class="ctrlf-toggle-text">Global Protection</span> </label> <small class="ctrlf-control-desc">Default protection for all websites</small> </div> <div class="ctrlf-control-group"> <label class="ctrlf-toggle-label"> <input type="checkbox" class="ctrlf-toggle" id="siteToggle"> <span class="ctrlf-toggle-slider"></span> <span class="ctrlf-toggle-text">Override for ${location.hostname}</span> </label> <small class="ctrlf-control-desc">Site-specific override (takes priority)</small> </div> <button class="ctrlf-reset-btn" id="resetSite">Reset to Global</button> </div> <div class="ctrlf-section"> <h4>Settings</h4> <div class="ctrlf-control-group"> <label class="ctrlf-toggle-label"> <input type="checkbox" class="ctrlf-toggle" id="showUIToggle"> <span class="ctrlf-toggle-slider"></span> <span class="ctrlf-toggle-text">Show UI on page load</span> </label> </div> </div> <div class="ctrlf-section"> <h4>Shortcuts</h4> <div class="ctrlf-shortcut-item"> <label>Toggle UI:</label> <button class="ctrlf-shortcut-btn" data-type="toggleUI"> <span class="ctrlf-shortcut-display">${CONFIG.shortcuts.toggleUI}</span> <span class="ctrlf-shortcut-hint">Click to change</span> </button> </div> <div class="ctrlf-shortcut-item"> <label>Quick toggle:</label> <button class="ctrlf-shortcut-btn" data-type="quickToggle"> <span class="ctrlf-shortcut-display">${CONFIG.shortcuts.quickToggle}</span> <span class="ctrlf-shortcut-hint">Click to change</span> </button> </div> </div> </div> `; }, update() { if (!state.panel) return; const isEnabled = protection.isEnabled(); const source = protection.getSource(); // Status indicator and text const indicator = state.panel.querySelector('.ctrlf-status-indicator'); const statusText = state.panel.querySelector('.ctrlf-status-text'); indicator.classList.toggle('active', isEnabled); statusText.textContent = `Protection ${isEnabled ? 'ON' : 'OFF'} (${source === 'site' ? 'site override' : 'global'})`; // Toggle states state.panel.querySelector('#globalToggle').checked = state.global; state.panel.querySelector('#siteToggle').checked = state.site !== null ? state.site : state.global; state.panel.querySelector('#showUIToggle').checked = state.showUI; // Reset button state const resetBtn = state.panel.querySelector('#resetSite'); resetBtn.disabled = state.site === null; resetBtn.style.opacity = state.site === null ? '0.5' : '1'; // Site toggle visual state const siteLabel = state.panel.querySelector('#siteToggle').closest('.ctrlf-toggle-label'); const siteText = siteLabel.querySelector('.ctrlf-toggle-text'); if (state.site !== null) { siteLabel.style.opacity = '1'; siteText.textContent = `Override for ${location.hostname} (${state.site ? 'ON' : 'OFF'})`; } else { siteLabel.style.opacity = '0.7'; siteText.textContent = `Override for ${location.hostname} (using global)`; } }, setupEventListeners() { const panel = state.panel; // Close button panel.querySelector('.ctrlf-close').addEventListener('click', () => this.hide()); // Global toggle panel.querySelector('#globalToggle').addEventListener('change', (e) => { state.global = e.target.checked; GM_setValue(CONFIG.keys.GLOBAL_PROTECTION, state.global); this.update(); }); // Site toggle panel.querySelector('#siteToggle').addEventListener('change', (e) => { if (state.site === null) { state.site = !state.global; } else { state.site = e.target.checked; } GM_setValue(CONFIG.keys.SITE_PROTECTION, state.site); this.update(); }); // Reset button panel.querySelector('#resetSite').addEventListener('click', () => { protection.resetSite(); }); // Show UI toggle panel.querySelector('#showUIToggle').addEventListener('change', (e) => { state.showUI = e.target.checked; GM_setValue(CONFIG.keys.SHOW_UI, state.showUI); }); // Shortcut buttons panel.querySelectorAll('.ctrlf-shortcut-btn').forEach(btn => { btn.addEventListener('click', () => keyboard.recordShortcut(btn)); }); } }; // UTILITY FUNCTIONS const utils = { createElement(tag, className, html) { const el = document.createElement(tag); el.className = className; el.innerHTML = html; return el; }, makeDraggable(element, handle) { let isDragging = false; let startX, startY, startLeft, startTop; const controller = new AbortController(); const options = { signal: controller.signal }; const handleMouseDown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; const rect = element.getBoundingClientRect(); startLeft = rect.left; startTop = rect.top; e.preventDefault(); }; const handleMouseMove = (e) => { if (!isDragging) return; const newLeft = Math.max(0, Math.min(window.innerWidth - element.offsetWidth, startLeft + e.clientX - startX)); const newTop = Math.max(0, Math.min(window.innerHeight - element.offsetHeight, startTop + e.clientY - startY)); element.style.left = newLeft + 'px'; element.style.top = newTop + 'px'; element.style.right = 'auto'; }; const handleMouseUp = () => { isDragging = false; }; handle.addEventListener('mousedown', handleMouseDown, options); document.addEventListener('mousemove', handleMouseMove, options); document.addEventListener('mouseup', handleMouseUp, options); // Return cleanup function return () => controller.abort(); }, showNotification(message) { // Ensure styles are added before creating notification this.addStyles(); const notification = this.createElement('div', 'ctrlf-notification', message); document.body.appendChild(notification); // Use requestAnimationFrame to ensure the element is in the DOM before animating requestAnimationFrame(() => { notification.style.opacity = '1'; notification.style.transform = 'translateX(-50%) translateY(0)'; }); setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(-50%) translateY(-10px)'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); }, CONFIG.ui.notificationDuration); }, addStyles() { if (document.querySelector('#ctrlf-styles')) return; const style = document.createElement('style'); style.id = 'ctrlf-styles'; style.textContent = ` .ctrlf-panel { position: fixed; top: 20px; right: 20px; width: 340px; background: rgba(255,255,255,0.95); color: #333; border-radius: 12px; font: 14px -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; z-index: 999999; box-shadow: 0 10px 40px rgba(0,0,0,0.15); backdrop-filter: blur(20px); border: 1px solid rgba(0,0,0,0.1); cursor: move; user-select: none; } @media (prefers-color-scheme: dark) { .ctrlf-panel { background: rgba(30,30,30,0.95); color: #fff; border: 1px solid rgba(255,255,255,0.1); } } .ctrlf-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid rgba(0,0,0,0.1); } @media (prefers-color-scheme: dark) { .ctrlf-header { border-bottom: 1px solid rgba(255,255,255,0.1); } } .ctrlf-title { font-weight: 600; font-size: 16px; } .ctrlf-close { background: none; border: none; color: currentColor; font-size: 24px; cursor: pointer; padding: 4px; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 6px; transition: background-color 0.2s; } .ctrlf-close:hover { background: rgba(0,0,0,0.1); } @media (prefers-color-scheme: dark) { .ctrlf-close:hover { background: rgba(255,255,255,0.1); } } .ctrlf-content { padding: 20px; } .ctrlf-section { margin-bottom: 24px; } .ctrlf-section:last-child { margin-bottom: 0; } .ctrlf-section h4 { margin: 0 0 12px 0; font-size: 14px; font-weight: 600; color: #666; } @media (prefers-color-scheme: dark) { .ctrlf-section h4 { color: #999; } } .ctrlf-status { display: flex; align-items: center; gap: 12px; padding: 16px; background: rgba(0,0,0,0.05); border-radius: 8px; margin-bottom: 24px; } @media (prefers-color-scheme: dark) { .ctrlf-status { background: rgba(255,255,255,0.05); } } .ctrlf-status-indicator { width: 12px; height: 12px; border-radius: 50%; background: #ef4444; transition: background-color 0.3s; } .ctrlf-status-indicator.active { background: #22c55e; } .ctrlf-status-text { font-weight: 500; font-size: 15px; } .ctrlf-control-group { margin-bottom: 16px; } .ctrlf-control-group:last-child { margin-bottom: 0; } .ctrlf-toggle-label { display: flex; align-items: center; gap: 12px; cursor: pointer; margin-bottom: 4px; } .ctrlf-toggle { display: none; } .ctrlf-toggle-slider { width: 44px; height: 24px; background: #ddd; border-radius: 12px; position: relative; transition: background-color 0.3s; flex-shrink: 0; } .ctrlf-toggle-slider::before { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: transform 0.3s; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .ctrlf-toggle:checked + .ctrlf-toggle-slider { background: #007acc; } .ctrlf-toggle:checked + .ctrlf-toggle-slider::before { transform: translateX(20px); } .ctrlf-toggle-text { font-weight: 500; } .ctrlf-control-desc { font-size: 12px; color: #666; margin-left: 56px; } @media (prefers-color-scheme: dark) { .ctrlf-control-desc { color: #999; } } .ctrlf-reset-btn { background: none; border: 1px solid #ddd; color: #666; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; transition: all 0.2s; margin-left: 56px; } .ctrlf-reset-btn:hover { background: rgba(0,0,0,0.05); border-color: #999; } @media (prefers-color-scheme: dark) { .ctrlf-reset-btn { border-color: #555; color: #999; } .ctrlf-reset-btn:hover { background: rgba(255,255,255,0.05); border-color: #777; } } .ctrlf-shortcut-item { display: flex; align-items: center; margin-bottom: 12px; } .ctrlf-shortcut-item label { width: 100px; font-size: 13px; color: #666; } @media (prefers-color-scheme: dark) { .ctrlf-shortcut-item label { color: #999; } } .ctrlf-shortcut-btn { flex: 1; padding: 8px 12px; background: rgba(0,0,0,0.05); border: 1px solid #ddd; border-radius: 6px; color: currentColor; font: 12px 'SF Mono',Monaco,monospace; cursor: pointer; transition: all 0.2s; text-align: left; } .ctrlf-shortcut-btn:hover { background: rgba(0,0,0,0.1); border-color: #999; } .ctrlf-shortcut-btn:focus, .ctrlf-shortcut-btn.recording { outline: none; border-color: #007acc; box-shadow: 0 0 0 3px rgba(0,122,204,0.1); background: rgba(0,122,204,0.05); } .ctrlf-shortcut-display { font-weight: 500; } .ctrlf-shortcut-hint { font-size: 10px; opacity: 0.6; margin-left: 8px; } .ctrlf-shortcut-btn.recording .ctrlf-shortcut-hint { opacity: 1; color: #007acc; } .ctrlf-notification { position: fixed; top: 20px; left: 50%; transform: translateX(-50%) translateY(-10px); background: rgba(0,0,0,0.85); color: white; padding: 12px 20px; border-radius: 8px; font-size: 14px; font-weight: 500; z-index: 1000000; pointer-events: none; backdrop-filter: blur(10px); box-shadow: 0 4px 20px rgba(0,0,0,0.3); opacity: 0; transition: all 0.3s ease; } @media (prefers-color-scheme: dark) { .ctrlf-shortcut-btn { background: rgba(255,255,255,0.05); border-color: #555; } .ctrlf-shortcut-btn:hover { background: rgba(255,255,255,0.1); border-color: #777; } .ctrlf-notification { background: rgba(255,255,255,0.9); color: #333; } } `; document.head.appendChild(style); } }; // INITIALIZATION function init() { window.addEventListener('keydown', (e) => keyboard.handleKeydown(e), true); // Show UI after delay if enabled if (state.showUI) { setTimeout(() => ui.show(), CONFIG.ui.showDelay); } console.log(`Force Ctrl+F loaded - Protection: ${protection.isEnabled() ? 'ON' : 'OFF'} (${protection.getSource()}), UI: ${state.showUI ? 'ON' : 'OFF'}`); } init(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址