1document.addEventListener('DOMContentLoaded', function () { 2 //bloqueando input de consulta 3 // const inputBusca = document.getElementById('descricao'); 4 // const placeholderOriginal = inputBusca.placeholder; 5 6 // inputBusca.disabled = true; 7 // inputBusca.placeholder = 'Carregando informações...'; 8 9 // delay para garantir que o menu seja numerado antes da busca 10 // const tempoEspera = 3000 11 // const tempoEspera = 0 12 // setTimeout(() => { 13 // busca_menu(); 14 // inputBusca.disabled = false; 15 // inputBusca.placeholder = placeholderOriginal; 16 // }, tempoEspera); 17 18 busca_menu(); 19 20}); 21 22 23function busca_menu() { 24 25 var PAGINAS = [ 26 { caminho: '/transparencia', cor: 'amarelo' }, 27 { caminho: '/acessoinformacao', cor: 'azul' }, 28 { caminho: '/servicosonline', cor: 'verde' }, 29 { caminho: '/informacoesgerais', cor: 'vermelho' } 30 ]; 31 var CORES_ORIGEM = { 32 amarelo: { fundo: '#fffbe6', hover: '#fff3b0', icone: '#d4a017', texto: '#6b4c00' }, 33 azul: { fundo: '#e8f4fd', hover: '#c5e3f7', icone: '#2980b9', texto: '#0c3558' }, 34 verde: { fundo: '#eafaf1', hover: '#c3f0d5', icone: '#27ae60', texto: '#0d4a26' }, 35 vermelho: { fundo: '#fdecea', hover: '#f9c9c5', icone: '#c0392b', texto: '#5c0c08' } 36 }; 37 38 var SINONIMOS = { 39 // 2. INFORMAÃÃES INSTITUCIONAIS 40 'atribuicoes': [ 41 'Secretarias (Competências e Responsáveis)' 42 ], 43 // 'contatos': [ 44 // 'Pedido de Informação', 45 // 'Ouvidoria', 46 // 'Saúde - Local e horário de atendimento' 47 // ], 48 'telefone': [ 49 'Ouvidoria', 50 'Pedido de Informação' 51 ], 52 'respostas': [ 53 'Dúvidas e Perguntas Frequêntes' 54 ], 55 56 // 4. DESPESAS 57 'fornecedores': [ 58 'Credores' 59 ], 60 61 // 5. CONVÃNIOS 62 'convenio': [ 63 'Transferências Voluntárias Recebidas', 64 'Transferências Voluntárias Realizadas' 65 ], 66 'acordo': [ 67 'Convênios Recebidos', 68 'Relação de parcerias (Lei nº 13.019/2014, art. 10)' 69 ], 70 'acordos firmados': [ 71 'Convênios Recebidos', 72 'Relação de parcerias (Lei nº 13.019/2014, art. 10)' 73 ], 74 75 // 6. RH 76 'funcionarios': [ 77 'Servidores Ativos' 78 ], 79 'salario': [ 80 'Padrão de remunerações', 81 // 'Contracheque Online 2018 aos Atuais', 82 // 'Contracheque Online 2017 e anteriores' 83 ], 84 'remuneracao': [ 85 'Padrão de remunerações' 86 ], 87 'remuneracao nominal': [ 88 'Padrão de remunerações' 89 ], 90 91 // 8. LICITAÃÃES 92 'contratacoes': [ 93 'Contratos Administrativos', 94 'Planos de Contratações Anual' 95 ], 96 // 9. CONTRATOS 97 'termos aditivos': [ 98 'Contratos Administrativos' 99 ], 100 101 // 12. SIC 102 'sic': [ 103 'Pedido de Informação' 104 ], 105 'esic': [ 106 'Pedido de Informação' 107 ], 108 'lai': [ 109 'decretos', 110 'portarias' 111 ], 112 'relatorio anual estatistico':[ 113 'EstatÃsticas de Atendimento' 114 ], 115 'relatorio estatistico': [ 116 'EstatÃsticas de Atendimento' 117 ], 118 'lista de documentos classificados': [ 119 'Rol de documentos classificados em cada grau de sigilo, com identificação para referência futura' 120 ], 121 'lista de informacoes desclassificadas': [ 122 'Rol das informações que tenham sido desclassificadas nos últimos 12 (doze) meses' 123 ], 124 'informacoes desclassificadas': [ 125 'Rol das informações que tenham sido desclassificadas nos últimos 12 (doze) meses' 126 ], 127 128 // 14. OUVIDORIA 129 'denuncia': [ 130 'Ouvidoria' 131 ], 132 'reclamacao': [ 133 'Ouvidoria' 134 ], 135 }; 136 137 var campoBusca = document.getElementById('descricao'); 138 var formulario = document.getElementById('form_pesquisa'); 139 140 if (!campoBusca || !formulario) return; 141 142 formulario.parentNode.style.position = 'relative'; 143 144 var dropdown = document.createElement('div'); 145 dropdown.id = 'dropdown-filtro'; 146 formulario.parentNode.appendChild(dropdown); 147 148 adicionarEstilos(); 149 150 var todosOsItens = []; 151 var itemSelecionado = -1; 152 153 // Inicia carregando os itens das 4 páginas 154 coletarItensDe4Paginas().then(function (itens) { 155 todosOsItens = itens; 156 }); 157 158 // Monta a URL base do servidor para fazer a as buscas nos 4 módulos do portal 159 function obterOrigemServidor() { 160 var origem = window.location.origin; 161 var pathname = window.location.pathname; 162 163 //pega apenas a url + nome municipio
164 var urlComNomeMunicipio = pathname.split('/').filter(function(seg) { 165 return seg !== ''; 166 })[0]; 167 168 return origem + (urlComNomeMunicipio ? '/' + urlComNomeMunicipio : ''); 169 } 170 171 // Busca o HTML de uma página e extrai os itens do menu 172 function buscarItensDePagina(urlCompleta, cor) { 173 return fetch(urlCompleta, { credentials: 'same-origin' }) 174 .then(function (resposta) { 175 if (!resposta.ok) throw new Error('Falha ao carregar: ' + urlCompleta); 176 return resposta.text(); 177 }) 178 .then(function (html) { 179 var parser = new DOMParser(); 180 var doc = parser.parseFromString(html, 'text/html'); 181 return coletarItensDoMenu(doc, cor); 182 }) 183 .catch(function (erro) { 184 console.warn('[Filtro Busca] Não foi possÃvel carregar ' + urlCompleta + ':', erro); 185 return []; 186 }); 187 } 188 189 // Coleta itens de todas as 4 páginas 190 function coletarItensDe4Paginas() { 191 var baseUrl = obterOrigemServidor(); 192 193 var promessas = PAGINAS.map(function (pagina) { 194 var url = baseUrl + pagina.caminho; 195 return buscarItensDePagina(url, pagina.cor); 196 }); 197 198 return Promise.all(promessas).then(function (resultadosPorPagina) { 199 var itensCombinados = []; 200 resultadosPorPagina.forEach(function (itens) { 201 itensCombinados = itensCombinados.concat(itens); 202 }); 203 return itensCombinados; 204 }); 205 } 206 207 function buscar(textoBuscado) { 208 var termo = textoBuscado.trim(); 209 dropdown.innerHTML = ''; 210 itemSelecionado = -1; 211 212 if (!termo) { 213 fechar(); 214 return; 215 } 216 // Mostra mensagem de carregamento 217 dropdown.innerHTML = '<div class="sem-resultado">Procurando resultados...</div>'; 218 abrir(); 219 220 // Delay antes de processar 221 setTimeout(function() { 222 var termoSemAcento = removerAcentos(termo); 223 if (termoSemAcento == 'sic'){ 224 resultados = []; 225 226 }else{ 227 var resultados = todosOsItens.filter(function (item) { 228 var nomeItem = removerAcentos(item.nome); 229 var categoriaItem = removerAcentos(item.categoria); 230 return nomeItem.includes(termoSemAcento) || c
230ategoriaItem.includes(termoSemAcento); 231 }); 232 } 233 if (resultados.length === 0) { 234 var sinonimos = buscarSinonimos(termo); 235 236 if (sinonimos.length > 0) { 237 resultados = todosOsItens.filter(function (item) { 238 var nomeItem = removerAcentos(item.nome); 239 var categoriaItem = removerAcentos(item.categoria); 240 241 // Verifica se algum sinônimo está presente no nome ou categoria 242 return sinonimos.some(function (sinonimo) { 243 var sinonimoNormalizado = removerAcentos(sinonimo); 244 return nomeItem.includes(sinonimoNormalizado) || 245 categoriaItem.includes(sinonimoNormalizado); 246 }); 247 }); 248 } 249 } 250 251 dropdown.innerHTML = ''; 252 if (resultados.length === 0) { 253 dropdown.innerHTML = '<div class="sem-resultado">Nenhum resultado encontrado.</div>'; 254 abrir(); 255 return; 256 } 257 258 mostrarResultados(resultados); 259 // abrir(); 260 }, 300); 261 } 262 263 // Busca os sinônimos de um termo (palavra completa apenas) 264 function buscarSinonimos(termo) { 265 var termoNormalizado = removerAcentos(termo.toLowerCase().trim()); 266 267 // Verifica se existe uma entrada exata no dicionário de sinônimos 268 if (SINONIMOS.hasOwnProperty(termoNormalizado)) { 269 return SINONIMOS[termoNormalizado]; 270 } 271 272 return []; 273 } 274 275 276 // Organiza e exibe os resultados 277 function mostrarResultados(resultados) { 278 var porCategoria = {}; 279 var ordemCategorias = []; 280 281 // Agrupa por categoria 282 resultados.forEach(function (item) { 283 if (!porCategoria[item.categoria]) { 284 porCategoria[item.categoria] = []; 285 ordemCategorias.push(item.categoria); 286 } 287 porCategoria[item.categoria].push(item); 288 }); 289 290 ordemCategorias.forEach(function (categoria) { 291 var titulo = document.createElement('div'); 292 titulo.className = 'grupo-categoria'; 293 titulo.textContent = categoria; 294 dropdown.appendChild(titulo); 295 296 porCategoria[categoria].forEach(function (item) { 297 var itemDiv = criarItemSugestao(item); 298 dropdown.appendChild(itemDiv); 299 }); 300 }); 301 } 302 303 304 function criarItemSugestao(item) { 305 var div = document.createElement('div'); 306 div.className = 'item-sugestao'; 307 div.setAttribute('data-href', item.link); 308 div.setAttribute('data-cor', item.cor || ''); 309 div.innerHTML = protegerHTML(item.nome); 310 311 aplicarCorOrigem(div, item.cor, false); 312 313 div.addEventListener('mouseover', function () { 314 aplicarCorOrigem(div, item.cor, true); 315 }); 316 div.addEventListener('mouseout', function () { 317 aplicarCorOrigem(div, item.cor, false); 318 }); 319 div.addEventListener('mousedown', function (e) { 320 e.preventDefault(); 321 if (item.link) window.location.href = item.link; 322 }); 323 324 return div; 325 } 326 327 // Aplica cor de fundo e texto de acordo com a origem 328 function aplicarCorOrigem(elemento, cor, hover) { 329 var cores = CORES_ORIGEM[cor]; 330 if (!cores) return; 331 332 elemento.style.backgroundColor = hover ? cores.hover : cores.fundo; 333 elemento.style.color = cores.texto; 334 } 335 336 function abrir() { 337 dropdown.style.display = 'block'; 338 } 339 340 function fechar() { 341 dropdown.style.display = 'none'; 342 itemSelecionado = -1; 343 } 344 345 // Remove acentos para busca (c encontra ç, a encontra á, etc) 346 function removerAcentos(texto) { 347 return texto 348 .toLowerCase() 349 .normalize('NFD') 350 .replace(/[\u0300-\u036f]/g, ''); 351 } 352 353 // Protege contra XSS 354 function protegerHTML(texto) { 355 return texto 356 .replace(/&/g, '&') 357 .replace(/</g, '<') 358 .replace(/>/g, '>'); 359 } 360
361 function coletarItensDoMenu(doc, cor) { 362 var itens = []; 363 var menuPrincipal = doc.querySelector('ul.nav.nav-pills'); 364 365 if (!menuPrincipal) return itens; 366 367 var secoes = menuPrincipal.querySelectorAll(':scope > li.nav-item.bg-warning'); 368 369 secoes.forEach(function (secao) { 370 var linkPrincipal = secao.querySelector(':scope > a'); 371 var nomeCategoria = linkPrincipal ? limparTexto(linkPrincipal) : ''; 372 var linkCategoria = (linkPrincipal && !linkPrincipal.getAttribute('data-toggle')) 373 ? linkPrincipal.getAttribute('href') : null; 374 375 if (linkCategoria) { 376 itens.push({ 377 categoria: nomeCategoria, 378 nome: nomeCategoria, 379 link: linkCategoria, 380 cor: cor 381 }); 382 } 383 384 var subItens1 = secao.querySelectorAll(':scope > .collapse > ul > li.nav-item'); 385 386 subItens1.forEach(function (subItem) { 387 var link = subItem.querySelector(':scope > a'); 388 var nome = link ? limparTexto(link) : ''; 389 var href = (link && !link.getAttribute('data-toggle')) ? link.getAttribute('href') : null; 390 391 if (href) { 392 itens.push({ 393 categoria: nomeCategoria, 394 nome: nome, 395 link: href, 396 cor: cor 397 }); 398 } 399 400 var subItens2 = subItem.querySelectorAll(':scope > .collapse > ul > li.nav-item'); 401 402 subItens2.forEach(function (subItem2) { 403 var link2 = subItem2.querySelector(':scope > a'); 404 var nome2 = link2 ? limparTexto(link2) : ''; 405 var href2 = (link2 && !link2.getAttribute('data-toggle')) ? link2.getAttribute('href') : null; 406 407 if (href2) { 408 itens.push({ 409 categoria: nomeCategoria + ' ⺠' + nome, 410 nome: nome2, 411 link: href2, 412 cor: cor 413 }); 414 } 415 }); 416 }); 417 }); 418 419 return itens; 420 } 421 422 function limparTexto(elemento) { 423 var clone = elemento.cloneNode(true); 424 clone.querySelectorAll('i, .fa, svg').forEach(function (icone) { 425 icone.remove(); 426 }); 427 return clone.textContent.replace(/\s+/g, ' ').trim(); 428 } 429 430 function adicionarEstilos() { 431 var estilos = document.createElement('style'); 432 estilos.textContent = ` 433 #dropdown-filtro { 434 position: absolute; 435 top: 100%; 436 left: 0; 437 min-width: 450px; 438 max-width: 480px; 439 max-height: 380px; 440 overflow-y: auto; 441 background: #fff; 442 border: 1px solid #d0d7de; 443 border-radius: 0 0 8px 8px; 444 box-shadow: 0 8px 24px rgba(0,0,0,0.13); 445 z-index: 9999; 446 display: none; 447 font-family: "Roboto Condensed", sans-serif; 448 } 449 #dropdown-filtro .grupo-categoria { 450 padding: 6px 14px 2px 14px; 451 font-size: 15px; 452 font-weight: 700; 453 text-transform: uppercase; 454 letter-spacing: .08em; 455 color: #888; 456 background: #f8f8f8; 457 border-top: 1px solid #eee; 458 user-select: none; 459 } 460 #dropdown-filtro .grupo-categoria:first-child { 461 border-top: none; 462 } 463 #dropdown-filtro .item-sugestao { 464 display: flex; 465 align-items: center; 466 padding: 9px 14px 9px 20px; 467 cursor: pointer; 468 font-size: 17px; 469 border-bottom: 1px solid #f3f3f3; 470 transition: background-color .15s, color .15s; 471 gap: 8px; 472 } 473 474 #dropdown-filtro .sem-resultado { 475 padding: 12px 14px; 476 color: #999; 477 font-size: 13px; 478 text-align: center; 479 } 480 `; 481 document.head.appendChild(estilos); 482 } 483 484 485 campoBusca.addEventListener('input', function () { 486 buscar(this.value); 487 }); 488 489 campoBusca.addEventListener('focus', function () { 490 if (this.value.trim()) buscar(this.value); 491 }); 492 493 campoBusca.addEventListener('blur', function () { 494 setTimeout(fechar, 180); 495 }); 496 497 document.addEventListener('click', function (e) { 498 if (!formulario.parentNode.contains(e.target)) { 499 fechar(); 500 } 501 }); 502 503 console.log('busca pronta!'); 504};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.