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 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Google Sheets Diff alerts mods: Remover cabeçalhos de linhas e Modificar Links do Google
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.4
  5. // @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
  6. // @author luascfl
  7. // @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
  8. // @match https://docs.google.com/spreadsheets/d/*/notify/show*
  9. // @match https://docs.google.com/spreadsheets/u/*/d/*/revisions/show*
  10. // @home https://github.com/luascfl/gsheets-diff-alerts-mods
  11. // @supportURL https://github.com/luascfl/gsheets-diff-alerts-mods/issues
  12. // @license MIT
  13. // @grant none
  14. // @run-at document-start
  15. // ==/UserScript==
  16. (function() {
  17. 'use strict';
  18. const INTERVALO = 100; // Intervalo em milissegundos
  19.  
  20. // Função para remover os row headers
  21. function removerElementos() {
  22. document.querySelectorAll('.row-header-wrapper').forEach(el => {
  23. el.remove();
  24. });
  25. }
  26.  
  27. // Função para modificar os links do Google
  28. function modificarLinks() {
  29. // Primeiro processa todos os links na página
  30. document.querySelectorAll('a').forEach(link => {
  31. processarLink(link);
  32. });
  33.  
  34. // Depois processa especificamente os links dentro de tbody
  35. document.querySelectorAll('tbody a').forEach(link => {
  36. decodificarEncodingNoLink(link);
  37. });
  38.  
  39. // Processa todos os elementos textuais dentro de tbody
  40. decodificarTextosEmTbody();
  41. }
  42.  
  43. // Função para processar cada link individualmente
  44. function processarLink(link) {
  45. if (link.href.startsWith('https://www.google.com/url?q=')) {
  46. // Extrai a URL real removendo o prefixo e tudo depois de &sa=
  47. let novaUrl = link.href.replace('https://www.google.com/url?q=', '');
  48.  
  49. // Se tiver o parâmetro &sa=, remove ele e tudo o que vem depois
  50. const index = novaUrl.indexOf('&sa=');
  51. if (index !== -1) {
  52. novaUrl = novaUrl.substring(0, index);
  53. }
  54.  
  55. link.href = novaUrl;
  56.  
  57. // Atualizar também o atributo data-href se existir
  58. if (link.hasAttribute('data-href')) {
  59. const dataHref = link.getAttribute('data-href');
  60. if (dataHref.startsWith('https://www.google.com/url?q=')) {
  61. let novoDataHref = dataHref.replace('https://www.google.com/url?q=', '');
  62.  
  63. // Se tiver o parâmetro &sa=, remove ele e tudo o que vem depois
  64. const dataIndex = novoDataHref.indexOf('&sa=');
  65. if (dataIndex !== -1) {
  66. novoDataHref = novoDataHref.substring(0, dataIndex);
  67. }
  68.  
  69. link.setAttribute('data-href', novoDataHref);
  70. }
  71. }
  72. }
  73. }
  74.  
  75. // Função específica para decodificar %3D para = nos links dentro de tbody
  76. function decodificarEncodingNoLink(link) {
  77. // Decodifica %3D para = no href (tanto no atributo quanto no valor real)
  78. if (link.href.includes('%3D')) {
  79. // Define o novo href decodificado
  80. link.href = link.href.replaceAll('%3D', '=');
  81. }
  82.  
  83. // Também verifica e corrige o atributo href diretamente
  84. // (isso é importante porque às vezes link.href normaliza a URL enquanto o atributo original permanece)
  85. if (link.hasAttribute('href')) {
  86. const hrefAttr = link.getAttribute('href');
  87. if (hrefAttr.includes('%3D')) {
  88. link.setAttribute('href', hrefAttr.replaceAll('%3D', '='));
  89. }
  90. }
  91.  
  92. // Decodifica %3D para = no data-href se existir
  93. if (link.hasAttribute('data-href')) {
  94. const dataHref = link.getAttribute('data-href');
  95. if (dataHref.includes('%3D')) {
  96. link.setAttribute('data-href', dataHref.replaceAll('%3D', '='));
  97. }
  98. }
  99.  
  100. // Decodifica %3D para = no texto do link se necessário
  101. if (link.textContent.includes('%3D')) {
  102. link.textContent = link.textContent.replaceAll('%3D', '=');
  103. }
  104.  
  105. // Verifica se o texto visível está correto mas o href não
  106. // (como no exemplo: texto é "codigoVaga=5520104" mas href é "codigoVaga%3D5520104")
  107. if (!link.textContent.includes('%3D') && link.textContent.includes('=')) {
  108. // Tenta encontrar todos os parâmetros no texto visível
  109. const paramsInText = link.textContent.match(/[?&][^?&=]+=[^?&=]+/g);
  110. if (paramsInText) {
  111. let hrefAtual = link.getAttribute('href');
  112. // Para cada parâmetro encontrado no texto
  113. paramsInText.forEach(param => {
  114. // Extrai nome e valor do parâmetro
  115. const [paramName, paramValue] = param.substring(1).split('=');
  116. // Verifica se esse mesmo parâmetro existe no href mas com %3D
  117. const encodedParam = `${paramName}%3D${paramValue}`;
  118. if (hrefAtual.includes(encodedParam)) {
  119. // Substitui a versão codificada pela decodificada
  120. hrefAtual = hrefAtual.replace(encodedParam, `${paramName}=${paramValue}`);
  121. }
  122. });
  123. // Atualiza o href se houve mudanças
  124. if (hrefAtual !== link.getAttribute('href')) {
  125. link.setAttribute('href', hrefAtual);
  126. }
  127. }
  128. }
  129. }
  130.  
  131. // Função para decodificar %3D em todos os elementos de texto dentro de tbody
  132. function decodificarTextosEmTbody() {
  133. // Seleciona todos os elementos tbody na página
  134. document.querySelectorAll('tbody').forEach(tbody => {
  135. // Itera sobre todos os elementos dentro do tbody
  136. iterarESusbstituirTextoEmElemento(tbody);
  137. });
  138. }
  139.  
  140. // Função recursiva para iterar sobre todos os nós filhos e substituir texto
  141. function iterarESusbstituirTextoEmElemento(elemento) {
  142. // Para cada nó filho do elemento
  143. Array.from(elemento.childNodes).forEach(node => {
  144. // Se for um nó de texto
  145. if (node.nodeType === Node.TEXT_NODE) {
  146. if (node.textContent.includes('%3D')) {
  147. node.textContent = node.textContent.replaceAll('%3D', '=');
  148. }
  149. }
  150. // Se for um elemento (como div, span, td, etc.) e não for um link (já tratado separadamente)
  151. else if (node.nodeType === Node.ELEMENT_NODE && node.nodeName !== 'A') {
  152. // Processo para td, th ou outros elementos com valor
  153. if (node.value && typeof node.value === 'string' && node.value.includes('%3D')) {
  154. node.value = node.value.replaceAll('%3D', '=');
  155. }
  156.  
  157. // Processa atributos comuns que podem conter texto
  158. ['title', 'alt', 'placeholder', 'data-text'].forEach(attr => {
  159. if (node.hasAttribute(attr)) {
  160. const attrValue = node.getAttribute(attr);
  161. if (attrValue.includes('%3D')) {
  162. node.setAttribute(attr, attrValue.replaceAll('%3D', '='));
  163. }
  164. }
  165. });
  166.  
  167. // Continua a recursão para os filhos deste elemento
  168. iterarESusbstituirTextoEmElemento(node);
  169. }
  170. });
  171. }
  172.  
  173. // Função que combina todas as funcionalidades
  174. function processarPagina() {
  175. removerElementos();
  176. modificarLinks();
  177. }
  178.  
  179. // Configuração do observer para detectar mudanças no DOM
  180. let observer;
  181. const callback = () => {
  182. processarPagina();
  183. if (!observer) {
  184. observer = new MutationObserver(processarPagina);
  185. observer.observe(document.documentElement, {
  186. childList: true,
  187. subtree: true
  188. });
  189. }
  190. };
  191.  
  192. // Executa imediatamente e mantém intervalo
  193. (function loop() {
  194. processarPagina();
  195. setTimeout(loop, INTERVALO);
  196. })();
  197.  
  198. // Garante execução após o carregamento completo
  199. window.addEventListener('load', () => {
  200. processarPagina();
  201. });
  202.  
  203. // Adicionar listener para os links que são adicionados dinamicamente
  204. document.addEventListener('DOMNodeInserted', function(event) {
  205. if (event.target.nodeName === 'A' ||
  206. (event.target.nodeType === 1 && event.target.querySelectorAll)) {
  207. modificarLinks();
  208. }
  209. }, false);
  210. })();