Google Sheets Diff alerts mods: Remover cabeçalhos de linhas e Modificar Links do Google

Remove elementos .row-header-wrapper, modifica links do Google removendo o prefixo de redirecionamento e decodifica %3D para = em todos os elementos de texto dentro de tabelas, garantindo que links como exemplo.com/?parametro%3Dvalor sejam corrigidos

当前为 2025-03-31 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Google Sheets Diff alerts mods: Remover cabeçalhos de linhas e Modificar Links do Google
// @namespace    http://tampermonkey.net/
// @version      3.4
// @description  Remove elementos .row-header-wrapper, modifica links do Google removendo o prefixo de redirecionamento e decodifica %3D para = em todos os elementos de texto dentro de tabelas, garantindo que links como exemplo.com/?parametro%3Dvalor sejam corrigidos
// @author       luascfl
// @icon         https://e7.pngegg.com/pngimages/660/350/png-clipart-green-and-white-sheet-icon-google-docs-google-sheets-spreadsheet-g-suite-google-angle-rectangle-thumbnail.png
// @match        https://docs.google.com/spreadsheets/d/*/notify/show*
// @match        https://docs.google.com/spreadsheets/u/*/d/*/revisions/show*
// @home         https://github.com/luascfl/gsheets-diff-alerts-mods
// @supportURL   https://github.com/luascfl/gsheets-diff-alerts-mods/issues
// @license      MIT
// @grant        none
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';
    const INTERVALO = 100; // Intervalo em milissegundos

    // Função para remover os row headers
    function removerElementos() {
        document.querySelectorAll('.row-header-wrapper').forEach(el => {
            el.remove();
        });
    }

    // Função para modificar os links do Google
    function modificarLinks() {
        // Primeiro processa todos os links na página
        document.querySelectorAll('a').forEach(link => {
            processarLink(link);
        });

        // Depois processa especificamente os links dentro de tbody
        document.querySelectorAll('tbody a').forEach(link => {
            decodificarEncodingNoLink(link);
        });

        // Processa todos os elementos textuais dentro de tbody
        decodificarTextosEmTbody();
    }

    // Função para processar cada link individualmente
    function processarLink(link) {
        if (link.href.startsWith('https://www.google.com/url?q=')) {
            // Extrai a URL real removendo o prefixo e tudo depois de &sa=
            let novaUrl = link.href.replace('https://www.google.com/url?q=', '');

            // Se tiver o parâmetro &sa=, remove ele e tudo o que vem depois
            const index = novaUrl.indexOf('&sa=');
            if (index !== -1) {
                novaUrl = novaUrl.substring(0, index);
            }

            link.href = novaUrl;

            // Atualizar também o atributo data-href se existir
            if (link.hasAttribute('data-href')) {
                const dataHref = link.getAttribute('data-href');
                if (dataHref.startsWith('https://www.google.com/url?q=')) {
                    let novoDataHref = dataHref.replace('https://www.google.com/url?q=', '');

                    // Se tiver o parâmetro &sa=, remove ele e tudo o que vem depois
                    const dataIndex = novoDataHref.indexOf('&sa=');
                    if (dataIndex !== -1) {
                        novoDataHref = novoDataHref.substring(0, dataIndex);
                    }

                    link.setAttribute('data-href', novoDataHref);
                }
            }
        }
    }

    // Função específica para decodificar %3D para = nos links dentro de tbody
    function decodificarEncodingNoLink(link) {
        // Decodifica %3D para = no href (tanto no atributo quanto no valor real)
        if (link.href.includes('%3D')) {
            // Define o novo href decodificado
            link.href = link.href.replaceAll('%3D', '=');
        }

        // Também verifica e corrige o atributo href diretamente
        // (isso é importante porque às vezes link.href normaliza a URL enquanto o atributo original permanece)
        if (link.hasAttribute('href')) {
            const hrefAttr = link.getAttribute('href');
            if (hrefAttr.includes('%3D')) {
                link.setAttribute('href', hrefAttr.replaceAll('%3D', '='));
            }
        }

        // Decodifica %3D para = no data-href se existir
        if (link.hasAttribute('data-href')) {
            const dataHref = link.getAttribute('data-href');
            if (dataHref.includes('%3D')) {
                link.setAttribute('data-href', dataHref.replaceAll('%3D', '='));
            }
        }

        // Decodifica %3D para = no texto do link se necessário
        if (link.textContent.includes('%3D')) {
            link.textContent = link.textContent.replaceAll('%3D', '=');
        }

        // Verifica se o texto visível está correto mas o href não
        // (como no exemplo: texto é "codigoVaga=5520104" mas href é "codigoVaga%3D5520104")
        if (!link.textContent.includes('%3D') && link.textContent.includes('=')) {
            // Tenta encontrar todos os parâmetros no texto visível
            const paramsInText = link.textContent.match(/[?&][^?&=]+=[^?&=]+/g);
            if (paramsInText) {
                let hrefAtual = link.getAttribute('href');
                // Para cada parâmetro encontrado no texto
                paramsInText.forEach(param => {
                    // Extrai nome e valor do parâmetro
                    const [paramName, paramValue] = param.substring(1).split('=');
                    // Verifica se esse mesmo parâmetro existe no href mas com %3D
                    const encodedParam = `${paramName}%3D${paramValue}`;
                    if (hrefAtual.includes(encodedParam)) {
                        // Substitui a versão codificada pela decodificada
                        hrefAtual = hrefAtual.replace(encodedParam, `${paramName}=${paramValue}`);
                    }
                });
                // Atualiza o href se houve mudanças
                if (hrefAtual !== link.getAttribute('href')) {
                    link.setAttribute('href', hrefAtual);
                }
            }
        }
    }

    // Função para decodificar %3D em todos os elementos de texto dentro de tbody
    function decodificarTextosEmTbody() {
        // Seleciona todos os elementos tbody na página
        document.querySelectorAll('tbody').forEach(tbody => {
            // Itera sobre todos os elementos dentro do tbody
            iterarESusbstituirTextoEmElemento(tbody);
        });
    }

    // Função recursiva para iterar sobre todos os nós filhos e substituir texto
    function iterarESusbstituirTextoEmElemento(elemento) {
        // Para cada nó filho do elemento
        Array.from(elemento.childNodes).forEach(node => {
            // Se for um nó de texto
            if (node.nodeType === Node.TEXT_NODE) {
                if (node.textContent.includes('%3D')) {
                    node.textContent = node.textContent.replaceAll('%3D', '=');
                }
            }
            // Se for um elemento (como div, span, td, etc.) e não for um link (já tratado separadamente)
            else if (node.nodeType === Node.ELEMENT_NODE && node.nodeName !== 'A') {
                // Processo para td, th ou outros elementos com valor
                if (node.value && typeof node.value === 'string' && node.value.includes('%3D')) {
                    node.value = node.value.replaceAll('%3D', '=');
                }

                // Processa atributos comuns que podem conter texto
                ['title', 'alt', 'placeholder', 'data-text'].forEach(attr => {
                    if (node.hasAttribute(attr)) {
                        const attrValue = node.getAttribute(attr);
                        if (attrValue.includes('%3D')) {
                            node.setAttribute(attr, attrValue.replaceAll('%3D', '='));
                        }
                    }
                });

                // Continua a recursão para os filhos deste elemento
                iterarESusbstituirTextoEmElemento(node);
            }
        });
    }

    // Função que combina todas as funcionalidades
    function processarPagina() {
        removerElementos();
        modificarLinks();
    }

    // Configuração do observer para detectar mudanças no DOM
    let observer;
    const callback = () => {
        processarPagina();
        if (!observer) {
            observer = new MutationObserver(processarPagina);
            observer.observe(document.documentElement, {
                childList: true,
                subtree: true
            });
        }
    };

    // Executa imediatamente e mantém intervalo
    (function loop() {
        processarPagina();
        setTimeout(loop, INTERVALO);
    })();

    // Garante execução após o carregamento completo
    window.addEventListener('load', () => {
        processarPagina();
    });

    // Adicionar listener para os links que são adicionados dinamicamente
    document.addEventListener('DOMNodeInserted', function(event) {
        if (event.target.nodeName === 'A' ||
            (event.target.nodeType === 1 && event.target.querySelectorAll)) {
            modificarLinks();
        }
    }, false);
})();