Quick search - Ctrl+Shift+F - 2.3

Horizontal floating search window with paste & search functionality

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Quick search - Ctrl+Shift+F - 2.3
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Horizontal floating search window with paste & search functionality
// @author       </j0tsarup>
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_addElement
// @run-at       document-start
// ==/UserScript==

/*
 * 
 * • Keyboard shortcuts: Ctrl+Shift+F (open), ESC (close)

 * FEATURES:
 * • Floating search window with drag-to-move functionality
 * • Paste & search directly from clipboard
 * • Multiple search engines: Google, Bing, DuckDuckGo, Yahoo
 * • Optional location-based search
 * • Toggle bubble for quick access
 * • Clean, modern UI with smooth animations
 * 
 * CHANGELOG v2.3:
 * • Added version number to script name
 * • Added formatted header with feature list
 * • Updated author information
 * • Improved code documentation
 * 
 * ═══════════════════════════════════════════════════════════════════════════
 */

(function() {
    'use strict';

    // Wait for document to be ready
    function init() {
        // Add CSS styles with higher priority
        GM_addStyle(`
        #floatingSearchWindow {
            position: fixed !important;
            top: 50% !important;
            left: 50% !important;
            transform: translate(-50%, -50%) !important;
            width: 900px !important;
            max-width: 90vw !important;
            background: #ffffff !important;
            border-radius: 12px !important;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15) !important;
            z-index: 2147483647 !important;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif !important;
            display: none !important;
            padding: 20px !important;
        }

        #floatingSearchWindow.active {
            display: block !important;
        }

        .search-header {
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            margin-bottom: 16px !important;
            padding-bottom: 12px !important;
            border-bottom: 1px solid #e5e5e5 !important;
        }

        .search-title {
            font-size: 14px !important;
            font-weight: 500 !important;
            color: #000000 !important;
            margin: 0 !important;
        }

        .header-controls {
            display: flex !important;
            gap: 8px !important;
            align-items: center !important;
        }

        .bubble-toggle {
            font-size: 11px !important;
            padding: 6px 12px !important;
            background: #f5f5f5 !important;
            border: 1px solid #ddd !important;
            border-radius: 6px !important;
            cursor: pointer !important;
            color: #000000 !important;
            transition: all 0.2s !important;
        }

        .bubble-toggle:hover {
            background: #e8e8e8 !important;
        }

        .bubble-toggle.enabled {
            background: #000000 !important;
            color: #ffffff !important;
            border-color: #000000 !important;
        }

        .close-btn {
            background: none !important;
            border: none !important;
            font-size: 20px !important;
            color: #666 !important;
            cursor: pointer !important;
            padding: 0 !important;
            width: 24px !important;
            height: 24px !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            border-radius: 4px !important;
            transition: all 0.2s !important;
        }

        .close-btn:hover {
            background: #f0f0f0 !important;
            color: #000 !important;
        }

        .search-main {
            display: flex !important;
            gap: 12px !important;
            align-items: stretch !important;
            margin-bottom: 16px !important;
        }

        .search-input-wrapper {
            flex: 1 !important;
            position: relative !important;
        }

        .search-input {
            width: 100% !important;
            padding: 14px 16px !important;
            border: 2px solid #e5e5e5 !important;
            border-radius: 8px !important;
            font-size: 14px !important;
            transition: all 0.2s !important;
            box-sizing: border-box !important;
            font-family: inherit !important;
            color: #000000 !important;
        }

        .search-input::placeholder {
            color: #999 !important;
        }

        .search-input:focus {
            outline: none !important;
            border-color: #000000 !important;
        }

        .search-btn {
            padding: 14px 28px !important;
            background: #000000 !important;
            color: #ffffff !important;
            border: none !important;
            border-radius: 8px !important;
            font-size: 14px !important;
            font-weight: 500 !important;
            cursor: pointer !important;
            transition: all 0.2s !important;
            white-space: nowrap !important;
        }

        .search-btn:hover {
            background: #333333 !important;
        }

        .paste-search-btn {
            padding: 14px 24px !important;
            background: #f5f5f5 !important;
            color: #000000 !important;
            border: 2px solid #e5e5e5 !important;
            border-radius: 8px !important;
            font-size: 14px !important;
            font-weight: 500 !important;
            cursor: pointer !important;
            transition: all 0.2s !important;
            white-space: nowrap !important;
        }

        .paste-search-btn:hover {
            background: #e8e8e8 !important;
            border-color: #000000 !important;
        }

        .search-options {
            display: flex !important;
            gap: 8px !important;
            flex-wrap: wrap !important;
        }

        .option-group {
            display: flex !important;
            gap: 6px !important;
        }

        .option-btn {
            padding: 8px 16px !important;
            background: #f5f5f5 !important;
            color: #000000 !important;
            border: 2px solid #e5e5e5 !important;
            border-radius: 6px !important;
            font-size: 13px !important;
            cursor: pointer !important;
            transition: all 0.2s !important;
            font-weight: 500 !important;
        }

        .option-btn:hover {
            background: #e8e8e8 !important;
        }

        .option-btn.active {
            background: #000000 !important;
            color: #ffffff !important;
            border-color: #000000 !important;
        }

        .location-input {
            padding: 8px 14px !important;
            border: 2px solid #e5e5e5 !important;
            border-radius: 6px !important;
            font-size: 13px !important;
            font-family: inherit !important;
            color: #000000 !important;
            min-width: 150px !important;
        }

        .location-input::placeholder {
            color: #999 !important;
        }

        .location-input:focus {
            outline: none !important;
            border-color: #000000 !important;
        }

        .toggle-bubble {
            position: fixed !important;
            bottom: 30px !important;
            right: 30px !important;
            width: 56px !important;
            height: 56px !important;
            background: #000000 !important;
            border: none !important;
            border-radius: 50% !important;
            color: white !important;
            font-size: 20px !important;
            cursor: pointer !important;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2) !important;
            z-index: 2147483646 !important;
            transition: all 0.3s !important;
            display: none !important;
        }

        .toggle-bubble.visible {
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
        }

        .toggle-bubble:hover {
            transform: scale(1.1) !important;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3) !important;
        }

        .draggable-handle {
            position: absolute !important;
            top: 0 !important;
            left: 0 !important;
            right: 0 !important;
            height: 12px !important;
            cursor: move !important;
        }
    `);

    // Create the floating window HTML
    const searchWindow = document.createElement('div');
    searchWindow.id = 'floatingSearchWindow';
    searchWindow.innerHTML = `
        <div class="draggable-handle"></div>
        <div class="search-header">
            <h2 class="search-title">rumpsy's quick search</h2>
            <div class="header-controls">
                <button class="bubble-toggle" id="bubbleToggle">bubble: off</button>
                <button class="close-btn" id="closeSearch">×</button>
            </div>
        </div>
        <div class="search-main">
            <div class="search-input-wrapper">
                <input type="text" class="search-input" id="searchQuery" placeholder="search query">
            </div>
            <button class="search-btn" id="executeSearch">search</button>
            <button class="paste-search-btn" id="pasteSearch">paste & search</button>
        </div>
        <div class="search-options">
            <div class="option-group">
                <button class="option-btn active" data-engine="google">google</button>
                <button class="option-btn" data-engine="bing">bing</button>
                <button class="option-btn" data-engine="duckduckgo">duckduckgo</button>
                <button class="option-btn" data-engine="yahoo">yahoo</button>
            </div>
            <input type="text" class="location-input" id="searchLocation" placeholder="location (optional)">
        </div>
    `;

    // Create toggle bubble
    const toggleBubble = document.createElement('button');
    toggleBubble.className = 'toggle-bubble';
    toggleBubble.innerHTML = '🔍';
    toggleBubble.title = 'Open Search (Ctrl+Shift+F)';

    // Append to body
    if (document.body) {
        document.body.appendChild(searchWindow);
        document.body.appendChild(toggleBubble);
    } else {
        // Wait for body to be available
        const observer = new MutationObserver(() => {
            if (document.body) {
                document.body.appendChild(searchWindow);
                document.body.appendChild(toggleBubble);
                observer.disconnect();
            }
        });
        observer.observe(document.documentElement, { childList: true });
    }

    // State
    let selectedEngine = 'google';
    let bubbleEnabled = false;

    // Toggle window visibility
    function toggleWindow() {
        searchWindow.classList.toggle('active');
        if (searchWindow.classList.contains('active')) {
            document.getElementById('searchQuery').focus();
        }
    }

    toggleBubble.addEventListener('click', toggleWindow);

    // Close button
    document.getElementById('closeSearch').addEventListener('click', () => {
        searchWindow.classList.remove('active');
    });

    // Bubble toggle
    document.getElementById('bubbleToggle').addEventListener('click', () => {
        bubbleEnabled = !bubbleEnabled;
        const bubbleBtn = document.getElementById('bubbleToggle');
        if (bubbleEnabled) {
            toggleBubble.classList.add('visible');
            bubbleBtn.classList.add('enabled');
            bubbleBtn.textContent = 'bubble: on';
        } else {
            toggleBubble.classList.remove('visible');
            bubbleBtn.classList.remove('enabled');
            bubbleBtn.textContent = 'bubble: off';
        }
    });

    // Engine selection
    document.querySelectorAll('.option-btn[data-engine]').forEach(btn => {
        btn.addEventListener('click', () => {
            document.querySelectorAll('.option-btn[data-engine]').forEach(b => b.classList.remove('active'));
            btn.classList.add('active');
            selectedEngine = btn.dataset.engine;
        });
    });

    // Make window draggable
    let isDragging = false;
    let currentX;
    let currentY;
    let initialX;
    let initialY;

    const dragHandle = searchWindow.querySelector('.draggable-handle');

    dragHandle.addEventListener('mousedown', (e) => {
        isDragging = true;
        initialX = e.clientX - searchWindow.offsetLeft;
        initialY = e.clientY - searchWindow.offsetTop;
    });

    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            e.preventDefault();
            currentX = e.clientX - initialX;
            currentY = e.clientY - initialY;
            searchWindow.style.transform = 'none';
            searchWindow.style.left = currentX + 'px';
            searchWindow.style.top = currentY + 'px';
        }
    });

    document.addEventListener('mouseup', () => {
        isDragging = false;
    });

    // Search functionality
    function performSearch(query = null) {
        const searchQuery = query || document.getElementById('searchQuery').value.trim();
        const location = document.getElementById('searchLocation').value.trim();

        if (!searchQuery) {
            alert('Please enter a search query');
            return;
        }

        let fullQuery = searchQuery;
        if (location) {
            fullQuery += ' ' + location;
        }

        const encodedQuery = encodeURIComponent(fullQuery);
        let searchURL = '';

        switch(selectedEngine) {
            case 'google':
                searchURL = `https://www.google.com/search?q=${encodedQuery}`;
                break;
            case 'bing':
                searchURL = `https://www.bing.com/search?q=${encodedQuery}`;
                break;
            case 'duckduckgo':
                searchURL = `https://duckduckgo.com/?q=${encodedQuery}`;
                break;
            case 'yahoo':
                searchURL = `https://search.yahoo.com/search?p=${encodedQuery}`;
                break;
        }

        window.open(searchURL, '_blank');
    }

    document.getElementById('executeSearch').addEventListener('click', () => performSearch());

    document.getElementById('searchQuery').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            performSearch();
        }
    });

    // Paste and search functionality
    document.getElementById('pasteSearch').addEventListener('click', async () => {
        try {
            const text = await navigator.clipboard.readText();
            if (text) {
                performSearch(text);
            } else {
                alert('Clipboard is empty');
            }
        } catch (err) {
            alert('Unable to read clipboard. Please paste manually.');
        }
    });

    // Keyboard shortcut: Ctrl+Shift+F to toggle
    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.shiftKey && e.key === 'F') {
            e.preventDefault();
            toggleWindow();
        }
        // ESC to close
        if (e.key === 'Escape' && searchWindow.classList.contains('active')) {
            searchWindow.classList.remove('active');
        }
    });

    // Close window when clicking outside
    searchWindow.addEventListener('click', (e) => {
        if (e.target === searchWindow) {
            searchWindow.classList.remove('active');
        }
    });

}

// Initialize when DOM is ready
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
} else {
    init();
}

})();