Quick search - Ctrl+Shift+F - 2.3

Horizontal floating search window with paste & search functionality

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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

})();