element parse

Select elements, outline them in red, expand/shrink selection, and show a small copy box.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Вам потребуется установить расширение, например Tampermonkey или Violentmonkey, чтобы установить этот скрипт.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name element parse
// @namespace https://viayoo.com/
// @version 0.1
// @description Select elements, outline them in red, expand/shrink selection, and show a small copy box.
// @author You
// @run-at document-end
// @license me
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_setClipboard
// ==/UserScript==

(function() {
    'use strict';

    let isActive = false; // State of the selector (Active / Inactive)
    let currentElement = null;
    let elementHistory = [];

    // Inject CSS for the panel, outline, and the small Copy Box
    const style = document.createElement('style');
    style.innerHTML = `
        /* Top control panel */
        .custom-selector-panel {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            background: rgba(255, 255, 255, 0.95);
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            z-index: 999999;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 8px 0;
            font-family: Arial, sans-serif;
            font-size: 14px;
        }
        .custom-selector-info {
            color: #555;
            margin-bottom: 6px;
            font-weight: bold;
            font-size: 12px;
            max-width: 90%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .custom-selector-buttons {
            display: flex;
            gap: 15px;
        }
        .custom-selector-btn {
            background: none;
            border: none;
            font-size: 16px;
            font-weight: bold;
            color: #333;
            cursor: pointer;
            padding: 5px 10px;
        }
        .custom-selector-btn:active {
            color: red;
        }

        /* Small Copy Box Modal */
        .custom-copy-box {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            width: 90%;
            max-width: 400px;
            background: rgba(30, 30, 30, 0.95);
            color: #f4f4f4;
            border-radius: 8px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.4);
            z-index: 1000000;
            display: flex;
            flex-direction: column;
            padding: 10px;
            gap: 8px;
            font-family: Arial, sans-serif;
            border: 1px solid #444;
        }
        .custom-copy-input {
            width: 100%;
            background: #121212;
            color: #a5d6a7;
            border: 1px solid #333;
            border-radius: 4px;
            padding: 6px;
            font-size: 12px;
            font-family: monospace;
            box-sizing: border-box;
        }
        .custom-copy-actions {
            display: flex;
            justify-content: flex-end;
            gap: 8px;
        }
        .custom-copy-btn {
            background: #00e676;
            color: #121212;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            font-weight: bold;
        }
        .custom-copy-btn:active {
            background: #00b555;
        }
        .custom-close-btn {
            background: #ff5252;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            font-weight: bold;
        }
        .custom-close-btn:active {
            background: #d32f2f;
        }
    `;
    document.head.appendChild(style);

    // Create physical external outline box
    const outline = document.createElement('div');
    outline.style.cssText = `
        position: absolute;
        border: 4px solid red;
        outline: none;
        pointer-events: none;
        z-index: 999998;
        display: none;
        box-sizing: border-box;
        transition: all 0.1s ease;
    `;
    document.body.appendChild(outline);

    // Create top control panel
    const panel = document.createElement('div');
    panel.className = 'custom-selector-panel';
    panel.style.display = 'none';

    const infoLabel = document.createElement('div');
    infoLabel.className = 'custom-selector-info';

    const btnContainer = document.createElement('div');
    btnContainer.className = 'custom-selector-buttons';

    const expandBtn = document.createElement('button');
    expandBtn.className = 'custom-selector-btn';
    expandBtn.innerText = 'Expand';

    const shrinkBtn = document.createElement('button');
    shrinkBtn.className = 'custom-selector-btn';
    shrinkBtn.innerText = 'Shrink';

    const saveBtn = document.createElement('button');
    saveBtn.className = 'custom-selector-btn';
    saveBtn.innerText = 'Save';

    const cancelBtn = document.createElement('button');
    cancelBtn.className = 'custom-selector-btn';
    cancelBtn.innerText = 'Cancel';

    btnContainer.appendChild(expandBtn);
    btnContainer.appendChild(shrinkBtn);
    btnContainer.appendChild(saveBtn);
    btnContainer.appendChild(cancelBtn);
    panel.appendChild(infoLabel);
    panel.appendChild(btnContainer);
    document.body.appendChild(panel);

    // Create Small Copy Box
    const copyBox = document.createElement('div');
    copyBox.className = 'custom-copy-box';
    copyBox.style.display = 'none';

    const copyInput = document.createElement('input');
    copyInput.type = 'text';
    copyInput.className = 'custom-copy-input';
    copyInput.readOnly = true;

    const actionContainer = document.createElement('div');
    actionContainer.className = 'custom-copy-actions';

    const copyBtn = document.createElement('button');
    copyBtn.className = 'custom-copy-btn';
    copyBtn.innerText = 'Copy to Clipboard';

    const closeBtn = document.createElement('button');
    closeBtn.className = 'custom-close-btn';
    closeBtn.innerText = 'Close';

    actionContainer.appendChild(copyBtn);
    actionContainer.appendChild(closeBtn);
    copyBox.appendChild(copyInput);
    copyBox.appendChild(actionContainer);
    document.body.appendChild(copyBox);

    // Close Copy Box
    function hideCopyBox() {
        copyBox.style.display = 'none';
        copyInput.value = '';
    }
    closeBtn.addEventListener('click', hideCopyBox);

    // Clipboard Copy Helper
    function secureCopy(text) {
        function fallbackCopy(str) {
            const textArea = document.createElement('textarea');
            textArea.value = str;
            textArea.style.position = 'fixed';
            textArea.style.top = '0';
            textArea.style.left = '0';
            textArea.style.opacity = '0';
            document.body.appendChild(textArea);
            textArea.focus();
            textArea.select();
            try {
                document.execCommand('copy');
            } catch (err) {
                console.error('Fallback copy failed: ', err);
            }
            document.body.removeChild(textArea);
        }

        if (typeof GM_setClipboard !== 'undefined') {
            try {
                GM_setClipboard(text);
                return;
            } catch (e) {}
        }

        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text).catch(function() {
                fallbackCopy(text);
            });
        } else {
            fallbackCopy(text);
        }
    }

    copyBtn.addEventListener('click', function() {
        if (copyInput.value) {
            secureCopy(copyInput.value);
            alert('HTML Copied! 🎉');
            hideCopyBox();
        }
    });

    // Positions our external outline directly over the targeted element
    function highlightElement(el) {
        if (el && el !== document.body && el !== document.documentElement && !panel.contains(el) && !copyBox.contains(el)) {
            currentElement = el;
            
            const rect = el.getBoundingClientRect();
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
            const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
            
            outline.style.top = (rect.top + scrollTop) + 'px';
            outline.style.left = (rect.left + scrollLeft) + 'px';
            outline.style.width = rect.width + 'px';
            outline.style.height = rect.height + 'px';
            outline.style.display = 'block';
            
            let className = el.className && typeof el.className === 'string' ? '.' + Array.from(el.classList).join('.') : '';
            infoLabel.innerText = `${el.tagName.toLowerCase()}${className}`;
            panel.style.display = 'flex';
        } else {
            outline.style.display = 'none';
            panel.style.display = 'none';
        }
    }

    // Keep outline aligned with the element during scrolls
    window.addEventListener('scroll', function() {
        if (isActive && currentElement) {
            highlightElement(currentElement);
        }
    }, { passive: true });

    // Capture and highlight clicked element instantly if script is active
    document.addEventListener('click', function(e) {
        if (!isActive) return;
        if (panel.contains(e.target) || copyBox.contains(e.target)) return;

        e.preventDefault();
        e.stopPropagation();

        elementHistory = []; 
        highlightElement(e.target);
    }, true);

    // Expand button
    expandBtn.addEventListener('click', function() {
        if (currentElement && currentElement.parentElement && currentElement.parentElement !== document.body) {
            elementHistory.push(currentElement);
            highlightElement(currentElement.parentElement);
        }
    });

    // Shrink button
    shrinkBtn.addEventListener('click', function() {
        if (elementHistory.length > 0) {
            const previousElement = elementHistory.pop();
            highlightElement(previousElement);
        }
    });

    // Save button (Now opens the small, neat copy box)
    saveBtn.addEventListener('click', function() {
        if (currentElement) {
            const htmlContent = currentElement.outerHTML;
            copyInput.value = htmlContent;
            copyBox.style.display = 'flex';
            clearSelection();
        }
    });

    // Cancel button
    cancelBtn.addEventListener('click', function() {
        clearSelection();
    });

    function clearSelection() {
        outline.style.display = 'none';
        panel.style.display = 'none';
        currentElement = null;
        elementHistory = [];
        isActive = false;
    }

    // Register a static, crash-proof menu command for Via Browser
    if (typeof GM_registerMenuCommand !== 'undefined') {
        GM_registerMenuCommand('🔍 Toggle Element Selector', function() {
            isActive = !isActive;
            if (isActive) {
                alert('Element Selector: ACTIVE 🟢\nClick any element on the page to highlight it.');
            } else {
                clearSelection();
                alert('Element Selector: INACTIVE ⚪');
            }
        });
    }
})();