mirror of https://github.com/interlegis/sapl.git
4 changed files with 591 additions and 61 deletions
@ -0,0 +1,293 @@ |
|||
/** |
|||
* materia_impressao_em_massa.js |
|||
* |
|||
* Impressão / download em massa de matérias legislativas. |
|||
* |
|||
* Funcionalidades: |
|||
* - Ativa modo de seleção ao clicar em "Imprimir Selecionados" (barra de ações) |
|||
* - Exibe checkbox em cada linha de resultado |
|||
* - Toolbar flutuante mostra contagem e ações (Imprimir / Baixar PDF / Limpar) |
|||
* - Botão "Todos" seleciona/desseleciona todos da página atual |
|||
* - Ao clicar Imprimir: chama /materia/pdf-multiplos/?ids=... → abre PDF no |
|||
* browser para impressão direta via window.print() em novo tab |
|||
* - Ao clicar Baixar PDF: mesmo endpoint mas força download via blob |
|||
*/ |
|||
|
|||
(function () { |
|||
'use strict'; |
|||
|
|||
var URL_PDF_MULTIPLOS = '/materia/pdf-multiplos/'; |
|||
var MAX_SELECAO = 200; |
|||
|
|||
var modoAtivo = false; |
|||
|
|||
// ── Elementos ────────────────────────────────────────────────────────────
|
|||
var btnImprimirSelecionados = null; // botão na barra de ações (topo)
|
|||
var btnSelecionarTodos = null; |
|||
var toolbar = null; |
|||
var toolbarCount = null; |
|||
var toolbarBtnImprimir = null; |
|||
var toolbarBtnDownload = null; |
|||
var toolbarBtnLimpar = null; |
|||
var toolbarLoading = null; |
|||
|
|||
// ── Inicialização ─────────────────────────────────────────────────────────
|
|||
function init() { |
|||
btnImprimirSelecionados = document.getElementById('btn-imprimir-selecionados'); |
|||
btnSelecionarTodos = document.getElementById('btn-selecionar-todos-print'); |
|||
toolbar = document.getElementById('print-toolbar'); |
|||
toolbarCount = document.getElementById('print-toolbar-count'); |
|||
toolbarBtnImprimir = document.getElementById('print-toolbar-btn-imprimir'); |
|||
toolbarBtnDownload = document.getElementById('print-toolbar-btn-download'); |
|||
toolbarBtnLimpar = document.getElementById('print-toolbar-btn-limpar'); |
|||
toolbarLoading = document.getElementById('print-toolbar-loading'); |
|||
|
|||
if (!btnImprimirSelecionados || !toolbar) return; // não está na página de resultados
|
|||
|
|||
// Botões já visíveis no novo layout — garante estado inicial correto
|
|||
btnImprimirSelecionados.style.display = ''; |
|||
if (btnSelecionarTodos) btnSelecionarTodos.style.display = 'none'; // aparece só quando modo ativo
|
|||
|
|||
btnImprimirSelecionados.addEventListener('click', function () { |
|||
if (!modoAtivo) { |
|||
ativarModo(); |
|||
} else { |
|||
var ids = getIdsSelecionados(); |
|||
if (ids.length === 0) { |
|||
mostrarAlerta('Selecione ao menos um documento para imprimir.'); |
|||
return; |
|||
} |
|||
abrirPDF(ids, true); |
|||
} |
|||
}); |
|||
|
|||
btnSelecionarTodos.addEventListener('click', function () { |
|||
if (!modoAtivo) { ativarModo(); } |
|||
var checks = document.querySelectorAll('.print-chk'); |
|||
var todasMarcadas = Array.from(checks).every(function (c) { return c.checked; }); |
|||
checks.forEach(function (c) { c.checked = !todasMarcadas; }); |
|||
atualizarContagem(); |
|||
}); |
|||
|
|||
toolbarBtnImprimir.addEventListener('click', function () { |
|||
var ids = getIdsSelecionados(); |
|||
if (ids.length === 0) { mostrarAlerta('Selecione ao menos um documento.'); return; } |
|||
abrirPDF(ids, true); |
|||
}); |
|||
|
|||
toolbarBtnDownload.addEventListener('click', function () { |
|||
var ids = getIdsSelecionados(); |
|||
if (ids.length === 0) { mostrarAlerta('Selecione ao menos um documento.'); return; } |
|||
baixarPDF(ids); |
|||
}); |
|||
|
|||
toolbarBtnLimpar.addEventListener('click', function () { |
|||
desativarModo(); |
|||
}); |
|||
|
|||
// Delegação de eventos nos checkboxes (gerados dinamicamente)
|
|||
document.addEventListener('change', function (e) { |
|||
if (e.target && e.target.classList.contains('print-chk')) { |
|||
atualizarContagem(); |
|||
} |
|||
}); |
|||
|
|||
// Clique na linha inteira (quando modo ativo) seleciona o checkbox
|
|||
document.addEventListener('click', function (e) { |
|||
if (!modoAtivo) return; |
|||
var row = e.target.closest('.materia-row'); |
|||
if (!row) return; |
|||
// Evita toggle duplo se clicou direto no checkbox ou num link
|
|||
if (e.target.classList.contains('print-chk')) return; |
|||
if (e.target.closest('a')) return; |
|||
var chk = row.querySelector('.print-chk'); |
|||
if (chk) { |
|||
chk.checked = !chk.checked; |
|||
atualizarContagem(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// ── Modo de seleção ───────────────────────────────────────────────────────
|
|||
function ativarModo() { |
|||
modoAtivo = true; |
|||
// Mostra checkboxes em todas as linhas
|
|||
document.querySelectorAll('.print-select-col').forEach(function (el) { |
|||
el.style.display = 'inline-block'; |
|||
}); |
|||
// Estilo visual nas linhas
|
|||
document.querySelectorAll('.materia-row').forEach(function (row) { |
|||
row.style.cursor = 'pointer'; |
|||
}); |
|||
// Atualiza botão de ações — destaca em vermelho sólido
|
|||
btnImprimirSelecionados.classList.replace('btn-outline-danger', 'btn-danger'); |
|||
// Mostra badge e botão Todos
|
|||
var badge = document.getElementById('badge-print-total'); |
|||
if (badge) badge.style.display = ''; |
|||
if (btnSelecionarTodos) btnSelecionarTodos.style.display = ''; |
|||
|
|||
toolbar.style.display = 'block'; |
|||
atualizarContagem(); |
|||
} |
|||
|
|||
function desativarModo() { |
|||
modoAtivo = false; |
|||
// Desmarca todos e oculta checkboxes
|
|||
document.querySelectorAll('.print-chk').forEach(function (c) { c.checked = false; }); |
|||
document.querySelectorAll('.print-select-col').forEach(function (el) { |
|||
el.style.display = 'none'; |
|||
}); |
|||
document.querySelectorAll('.materia-row').forEach(function (row) { |
|||
row.style.cursor = ''; |
|||
row.classList.remove('table-active'); |
|||
}); |
|||
// Restaura botão para outline
|
|||
btnImprimirSelecionados.classList.replace('btn-danger', 'btn-outline-danger'); |
|||
// Oculta badge e botão Todos
|
|||
var badge = document.getElementById('badge-print-total'); |
|||
if (badge) { badge.style.display = 'none'; badge.textContent = '0'; } |
|||
if (btnSelecionarTodos) btnSelecionarTodos.style.display = 'none'; |
|||
|
|||
toolbar.style.display = 'none'; |
|||
ocultarAlertaToolbar(); |
|||
} |
|||
|
|||
// ── Contagem ──────────────────────────────────────────────────────────────
|
|||
function getIdsSelecionados() { |
|||
return Array.from(document.querySelectorAll('.print-chk:checked')) |
|||
.map(function (c) { return parseInt(c.getAttribute('data-materia-id'), 10); }) |
|||
.slice(0, MAX_SELECAO); |
|||
} |
|||
|
|||
function atualizarContagem() { |
|||
var ids = getIdsSelecionados(); |
|||
var n = ids.length; |
|||
|
|||
// Badge na toolbar flutuante
|
|||
if (toolbarCount) toolbarCount.textContent = n; |
|||
|
|||
// Badge no botão de ações
|
|||
var badge = document.getElementById('badge-print-total'); |
|||
if (badge) badge.textContent = n; |
|||
|
|||
// Destaque visual nas linhas selecionadas
|
|||
document.querySelectorAll('.materia-row').forEach(function (row) { |
|||
var chk = row.querySelector('.print-chk'); |
|||
if (chk && chk.checked) { |
|||
row.classList.add('table-active'); |
|||
} else { |
|||
row.classList.remove('table-active'); |
|||
} |
|||
}); |
|||
|
|||
// Aviso de limite
|
|||
if (n >= MAX_SELECAO) { |
|||
mostrarAlertaToolbar('Limite de ' + MAX_SELECAO + ' documentos atingido. Desmarque alguns para selecionar outros.'); |
|||
} else { |
|||
ocultarAlertaToolbar(); |
|||
} |
|||
} |
|||
|
|||
// ── PDF: imprimir ─────────────────────────────────────────────────────────
|
|||
function abrirPDF(ids, imprimir) { |
|||
setLoading(true); |
|||
var url = URL_PDF_MULTIPLOS + '?ids=' + ids.join(','); |
|||
|
|||
// Abre em nova aba; quando carregado o browser oferece impressão
|
|||
var win = window.open(url, '_blank'); |
|||
if (!win) { |
|||
// Pop-up bloqueado — fallback: link direto
|
|||
var a = document.createElement('a'); |
|||
a.href = url; |
|||
a.target = '_blank'; |
|||
a.rel = 'noopener'; |
|||
document.body.appendChild(a); |
|||
a.click(); |
|||
document.body.removeChild(a); |
|||
} |
|||
// Aguarda pequeno delay e remove loading (não temos evento de "carregou" na outra aba)
|
|||
setTimeout(function () { setLoading(false); }, 2000); |
|||
} |
|||
|
|||
// ── PDF: baixar como arquivo ──────────────────────────────────────────────
|
|||
function baixarPDF(ids) { |
|||
setLoading(true); |
|||
var url = URL_PDF_MULTIPLOS + '?ids=' + ids.join(','); |
|||
|
|||
fetch(url, { credentials: 'same-origin' }) |
|||
.then(function (resp) { |
|||
if (!resp.ok) { |
|||
return resp.json().then(function (d) { |
|||
throw new Error(d.error || ('Erro HTTP ' + resp.status)); |
|||
}); |
|||
} |
|||
return resp.blob(); |
|||
}) |
|||
.then(function (blob) { |
|||
var blobUrl = window.URL.createObjectURL(blob); |
|||
var a = document.createElement('a'); |
|||
a.href = blobUrl; |
|||
a.download = 'materias_selecionadas.pdf'; |
|||
a.style.display = 'none'; |
|||
document.body.appendChild(a); |
|||
a.click(); |
|||
document.body.removeChild(a); |
|||
window.URL.revokeObjectURL(blobUrl); |
|||
setLoading(false); |
|||
}) |
|||
.catch(function (err) { |
|||
setLoading(false); |
|||
mostrarAlerta('Erro ao gerar PDF: ' + err.message); |
|||
}); |
|||
} |
|||
|
|||
// ── Helpers UI ────────────────────────────────────────────────────────────
|
|||
function setLoading(on) { |
|||
if (!toolbarLoading) return; |
|||
toolbarLoading.style.display = on ? 'block' : 'none'; |
|||
if (toolbarBtnImprimir) toolbarBtnImprimir.disabled = on; |
|||
if (toolbarBtnDownload) toolbarBtnDownload.disabled = on; |
|||
} |
|||
|
|||
function mostrarAlerta(msg) { |
|||
// Toast simples usando Bootstrap alert
|
|||
var div = document.createElement('div'); |
|||
div.className = 'alert alert-warning alert-dismissible fade show'; |
|||
div.style.cssText = 'position:fixed;top:20px;right:20px;z-index:9999;min-width:300px;max-width:500px;'; |
|||
div.innerHTML = '<i class="fas fa-exclamation-triangle"></i> ' + escHtml(msg) + |
|||
'<button type="button" class="close" data-dismiss="alert"><span>×</span></button>'; |
|||
document.body.appendChild(div); |
|||
setTimeout(function () { |
|||
if (div.parentNode) div.parentNode.removeChild(div); |
|||
}, 5000); |
|||
} |
|||
|
|||
function mostrarAlertaToolbar(msg) { |
|||
var existing = document.getElementById('print-toolbar-limit-alert'); |
|||
if (existing) return; |
|||
var div = document.createElement('div'); |
|||
div.id = 'print-toolbar-limit-alert'; |
|||
div.className = 'alert alert-warning py-1 px-2 mt-2 mb-0 small'; |
|||
div.innerHTML = '<i class="fas fa-exclamation-triangle"></i> ' + escHtml(msg); |
|||
if (toolbar) toolbar.appendChild(div); |
|||
} |
|||
|
|||
function ocultarAlertaToolbar() { |
|||
var el = document.getElementById('print-toolbar-limit-alert'); |
|||
if (el && el.parentNode) el.parentNode.removeChild(el); |
|||
} |
|||
|
|||
function escHtml(s) { |
|||
return String(s) |
|||
.replace(/&/g, '&').replace(/</g, '<') |
|||
.replace(/>/g, '>').replace(/"/g, '"'); |
|||
} |
|||
|
|||
// ── Arranque ──────────────────────────────────────────────────────────────
|
|||
if (document.readyState === 'loading') { |
|||
document.addEventListener('DOMContentLoaded', init); |
|||
} else { |
|||
init(); |
|||
} |
|||
|
|||
})(); |
|||
Loading…
Reference in new issue