Quick search - Ctrl+Shift+F - 2.3

Horizontal floating search window with paste & search functionality

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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();
}

})();