Painel de Atalhos Inteligente (v3.2 - Final)

Detecta a aba atual via seletores e texto, e navega de forma inteligente.

// ==UserScript==
// @name         Painel de Atalhos Inteligente (v3.2 - Final)
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  Detecta a aba atual via seletores e texto, e navega de forma inteligente.
// @author       Pejota e IA Gemini
// @match        http://10.72.200.50/sede/paginas/index.php*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

(async function() {
    'use strict';

    // --- 1. CONFIGURAÇÃO FINAL DAS ABAS ---
    // Mapeia o ID do botão de ação ao nome da aba, sua ordem, e o seletor do seu cabeçalho.
    const VIEW_CONFIG = {
        'loadNadirBtn':   { name: 'NADIR',   index: 0, headerSelector: '.nadir-header' },
        'loadObliqueBtn': { name: 'BACK',    index: 1, headerSelector: '.back-header' },
        'loadRightBtn':   { name: 'RIGHT',   index: 2, headerSelector: '.obliqua-header' },
        'loadForwardBtn': { name: 'FORWARD', index: 3, headerSelector: '.obliqua-header' },
        'loadLeftBtn':    { name: 'LEFT',    index: 4, headerSelector: '.obliqua-header' }
    };
    const VIEW_SEQUENCE = ['NADIR', 'BACK', 'RIGHT', 'FORWARD', 'LEFT'];


    // --- 2. ESTILO E HTML (SEM MUDANÇAS) ---
    const style = document.createElement('style');
    style.innerHTML = `
        #meu-painel-container { position: fixed; z-index: 9999; background-color: #f0f0f0; border: 1px solid #ccc; border-radius: 8px; box-shadow: 2px 2px 10px rgba(0,0,0,0.2); font-family: sans-serif; }
        #meu-painel-handle { padding: 10px 15px; cursor: grab; background-color: #e0e0e0; border-bottom: 1px solid #ccc; border-radius: 8px 8px 0 0; user-select: none; }
        #meu-painel-handle:active { cursor: grabbing; }
        #meu-painel-conteudo { display: flex; flex-direction: column; gap: 8px; padding: 10px; max-height: 0; overflow: hidden; transition: max-height 0.3s ease-in-out, padding 0.3s ease-in-out; }
        #meu-painel-container.painel-aberto #meu-painel-conteudo { max-height: 300px; padding: 10px; }
        #meu-painel-conteudo button { cursor: pointer; padding: 8px 12px; border: 1px solid #aaa; border-radius: 5px; background-color: #fff; text-align: left; }
        #meu-painel-conteudo button:hover { background-color: #e9e9e9; }
        #meu-painel-container .status-message { padding: 5px; font-size: 0.8em; text-align: center; background-color: #fffbe6; border-top: 1px solid #ccc; display: none; }
    `;
    document.head.appendChild(style);
    const painelContainer = document.createElement('div');
    painelContainer.id = 'meu-painel-container';
    painelContainer.innerHTML = `
        <div id="meu-painel-handle">☰ Atalhos</div>
        <div id="meu-painel-conteudo">
            <button data-target-id="loadNadirBtn">1. Imagem Nadir</button>
            <button data-target-id="loadObliqueBtn">2. Imagem Oblíqua (BACK)</button>
            <button data-target-id="loadRightBtn">3. Imagem Direita (RIGHT)</button>
            <button data-target-id="loadForwardBtn">4. Imagem Frontal (FORWARD)</button>
            <button data-target-id="loadLeftBtn">5. Imagem Esquerda (LEFT)</button>
        </div>
        <div class="status-message" id="meu-painel-status"></div>
    `;
    document.body.appendChild(painelContainer);


    // --- 3. FUNÇÕES AUXILIARES ---
    const statusDisplay = document.getElementById('meu-painel-status');
    function showStatus(message) { statusDisplay.textContent = message; statusDisplay.style.display = 'block'; }
    function hideStatus() { statusDisplay.style.display = 'none'; }
    function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

    // Agora temos duas funções de busca: uma para um elemento, outra para múltiplos
    async function findElementInFrames(selector) { const e=document.querySelector(selector);if(e)return e;const t=document.querySelectorAll("iframe");for(const o of t)try{const r=o.contentDocument||o.contentWindow.document,n=r.querySelector(selector);if(n)return n}catch(e){}return null}
    async function findElementsInFrames(selector) { let e=Array.from(document.querySelectorAll(selector));const t=document.querySelectorAll("iframe");for(const o of t)try{const r=o.contentDocument||o.contentWindow.document;e=e.concat(Array.from(r.querySelectorAll(selector)))}catch(e){}return e}
    async function waitForElement(selector, timeout = 7000) { return new Promise(async(e,t)=>{const o=Date.now();let r=await findElementInFrames(selector);if(r)return e(r);const n=setInterval(async()=>{r=await findElementInFrames(selector);if(r){clearInterval(n);e(r)}else if(Date.now()-o>timeout){clearInterval(n);t(new Error(`Elemento "${selector}" não encontrado`))}},200)})}

    // FUNÇÃO DE DETECÇÃO ATUALIZADA - A mais precisa de todas
    async function getCurrentView() {
        for (const config of Object.values(VIEW_CONFIG)) {
            const potentialHeaders = await findElementsInFrames(config.headerSelector);
            for (const header of potentialHeaders) {
                if (header.textContent.trim().toUpperCase() === config.name && header.offsetParent !== null) {
                    console.log('Aba atual detectada:', config.name);
                    return config.name;
                }
            }
        }
        console.error('Não foi possível detectar a aba atual.');
        return null;
    }


    // --- 4. LÓGICA PRINCIPAL (STATE MACHINE) ---
    const conteudo = document.getElementById('meu-painel-conteudo');
    let isActionRunning = false;

    conteudo.addEventListener('click', async (event) => {
        if (event.target.tagName !== 'BUTTON' || isActionRunning) return;

        isActionRunning = true;
        hideStatus();
        const targetId = event.target.getAttribute('data-target-id');
        const targetView = VIEW_CONFIG[targetId];

        try {
            showStatus('Detectando aba atual...');
            const currentViewName = await getCurrentView();
            if (!currentViewName) {
                throw new Error("Não foi possível identificar a aba atual. Verifique a configuração do script.");
            }
            const currentIndex = VIEW_SEQUENCE.indexOf(currentViewName);
            const targetIndex = targetView.index;
            const diff = targetIndex - currentIndex;

            if (diff !== 0) {
                const clicksNeeded = Math.abs(diff);
                const buttonSelector = diff > 0 ? 'button[onclick="carregarProximo()"]' : 'button[onclick="carregarAnterior()"]';
                const direction = diff > 0 ? 'Próximo' : 'Anterior';
                for (let i = 0; i < clicksNeeded; i++) {
                    showStatus(`Passo ${i + 1}/${clicksNeeded}: Clicando em "${direction}"`);
                    const navButton = await waitForElement(buttonSelector);
                    navButton.click();
                    await sleep(500);
                }
            }

            showStatus(`Na aba ${targetView.name}. Aguardando para carregar...`);
            await sleep(1000);

            showStatus(`Carregando imagem de ${targetView.name}...`);
            const finalButton = await waitForElement(`#${targetId}`);
            finalButton.click();
            showStatus('Ação concluída com sucesso!');
        } catch (error) {
            console.error(error);
            alert(`Ocorreu um erro: ${error.message}`);
            hideStatus();
        } finally {
            isActionRunning = false;
        }
    });

    // --- LÓGICA DE UI DO PAINEL (Arrastar, salvar, etc) ---
    const handle = document.getElementById('meu-painel-handle');
    handle.addEventListener('click', (e) => { if (painelContainer.wasDragged) { painelContainer.wasDragged = false; return; } painelContainer.classList.toggle('painel-aberto'); });
    let offsetX, offsetY, isDragging = false; handle.addEventListener('mousedown', (e) => { isDragging = true; painelContainer.wasDragged = false; offsetX = e.clientX - painelContainer.getBoundingClientRect().left; offsetY = e.clientY - painelContainer.getBoundingClientRect().top; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); function onMouseMove(e) { if (!isDragging) return; painelContainer.wasDragged = true; let newX = e.clientX - offsetX; let newY = e.clientY - offsetY; const w = window.innerWidth, h = window.innerHeight, pW = painelContainer.offsetWidth, pH = painelContainer.offsetHeight; newX = Math.max(0, Math.min(newX, w - pW)); newY = Math.max(0, Math.min(newY, h - pH)); painelContainer.style.left = `${newX}px`; painelContainer.style.top = `${newY}px`; } async function onMouseUp() { if (isDragging) { isDragging = false; await GM_setValue('painelPosX', painelContainer.style.left); await GM_setValue('painelPosY', painelContainer.style.top); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); } } const savedX = await GM_getValue('painelPosX', '20px'); const savedY = await GM_getValue('painelPosY', '20px'); painelContainer.style.right = ''; painelContainer.style.bottom = ''; painelContainer.style.left = savedX; painelContainer.style.top = savedY;
})();