`;
} else {
this.frmGroups.innerHTML = this.groups.map(grupo => `
${(grupo.inputs || []).map(input => this.criarElementoInput(input)).join('')}
`).join('');
this.adicionarEventListenersGrupos();
}
}
criarElementoInput(input) {
if (input.tipo === 'text') {
return `
`;
} else if (input.tipo === 'radio') {
const radioOptions = input.options.map((option, index) => {
const rotulo = typeof option === 'object' ? option.rotulo : option;
const texto = typeof option === 'object' ? option.texto : option;
const valor = typeof option === 'object' ? texto : option;
return `
`}).join('');
return `
${radioOptions}
ID: ${input.id} | Tipo: ${input.tipo}
`;
} else if (input.tipo === 'tratamento') {
const radioOptions = input.options.map((option, index) => `
`).join('');
return `
${radioOptions}
ID: ${input.id} | Tipo: ${input.tipo} | Opções fixas: ele, ela
`;
}
return '';
}
adicionarEventListenersGrupos() {
// Botões editar grupo
document.querySelectorAll('.edit-group').forEach(btn => {
btn.addEventListener('click', () => {
const groupId = btn.dataset.groupId;
this.openGroupModal(groupId);
});
});
// Botões excluir grupo
document.querySelectorAll('.delete-group').forEach(btn => {
btn.addEventListener('click', () => {
const groupId = btn.dataset.groupId;
this.excluirGrupo(groupId);
});
});
// Botões adicionar campo texto
document.querySelectorAll('.add-input-btn').forEach(btn => {
btn.addEventListener('click', () => {
const groupId = btn.dataset.groupId;
this.openInputModal(groupId);
});
});
// Botões adicionar campo radio
document.querySelectorAll('.add-radio-btn').forEach(btn => {
btn.addEventListener('click', () => {
const groupId = btn.dataset.groupId;
this.openRadioModal(groupId);
});
});
// Botões adicionar campo tratamento
document.querySelectorAll('.add-tratamento-btn').forEach(btn => {
btn.addEventListener('click', () => {
const groupId = btn.dataset.groupId;
this.openTratamentoModal(groupId);
});
});
// Botões editar inputs
document.querySelectorAll('.edit-input-btn').forEach(btn => {
btn.addEventListener('click', () => {
const inputId = btn.dataset.inputId;
const groupId = btn.closest('.frm-group').dataset.groupId;
this.openEditInputModal(groupId, inputId);
});
});
// Botões editar radio
document.querySelectorAll('.edit-radio-btn').forEach(btn => {
btn.addEventListener('click', () => {
const inputId = btn.dataset.inputId;
const groupId = btn.closest('.frm-group').dataset.groupId;
this.openEditRadioModal(groupId, inputId);
});
});
// Botões editar tratamento
document.querySelectorAll('.edit-tratamento-btn').forEach(btn => {
btn.addEventListener('click', () => {
const inputId = btn.dataset.inputId;
const groupId = btn.closest('.frm-group').dataset.groupId;
this.openEditTratamentoModal(groupId, inputId);
});
});
// Botões remover inputs
document.querySelectorAll('.btn-remove-input').forEach(btn => {
btn.addEventListener('click', () => {
const inputId = btn.dataset.inputId;
const groupId = btn.closest('.frm-group').dataset.groupId;
this.excluirInput(groupId, inputId);
});
});
// Eventos para inputs de texto (salvar em blur, tab, enter)
document.querySelectorAll('.custom-input').forEach(input => {
input.addEventListener('blur', () => {
const inputId = input.dataset.inputId;
const groupId = input.closest('.frm-group').dataset.groupId;
this.atualizarValorInput(groupId, inputId, input.value);
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Tab' || e.key === 'Enter') {
const inputId = input.dataset.inputId;
const groupId = input.closest('.frm-group').dataset.groupId;
this.atualizarValorInput(groupId, inputId, input.value);
}
});
});
// Eventos para radio buttons
document.querySelectorAll('.radio-option').forEach(radio => {
radio.addEventListener('change', () => {
if (radio.checked) {
const inputId = radio.dataset.inputId;
const groupId = radio.closest('.frm-group').dataset.groupId;
this.atualizarValorRadio(groupId, inputId, radio.value);
}
});
});
}
excluirGrupo(groupId) {
if (confirm('Tem certeza que deseja excluir este grupo? Todos os campos serão perdidos.')) {
this.groups = this.groups.filter(g => g.id !== groupId);
// USAR apenas estrutura para não alterar o código
this.atualizarEstruturaFormulario();
this.renderizarGrupos();
this.showNotification('Grupo excluído com sucesso!');
}
}
excluirInput(groupId, inputId) {
if (confirm('Tem certeza que deseja excluir este campo?')) {
const grupo = this.groups.find(g => g.id === groupId);
grupo.inputs = grupo.inputs.filter(i => i.id !== inputId);
// USAR apenas estrutura para não alterar o código
this.atualizarEstruturaFormulario();
this.renderizarGrupos();
this.showNotification('Campo excluído com sucesso!');
}
}
atualizarValorInput(groupId, inputId, valor) {
const grupo = this.groups.find(g => g.id === groupId);
const input = grupo.inputs.find(i => i.id === inputId);
if (input) {
input.value = valor;
// USAR apenas estrutura para não alterar o código
this.atualizarEstruturaFormulario();
}
}
atualizarValorRadio(groupId, inputId, valor) {
const grupo = this.groups.find(g => g.id === groupId);
const input = grupo.inputs.find(i => i.id === inputId);
if (input) {
input.selected = valor;
// USAR apenas estrutura para não alterar o código
this.atualizarEstruturaFormulario();
}
}
showNotification(message, isError = false) {
this.notification.textContent = message;
this.notification.className = 'notification';
if (isError) {
this.notification.classList.add('error');
}
this.notification.classList.add('show');
setTimeout(() => {
this.notification.classList.remove('show');
}, 3000);
}
escapeHtml(unsafe) {
if (!unsafe) return '';
return unsafe
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
atualizarPreviewInputId() {
const label = this.inputLabel.value.trim();
if (label) {
const idPadronizado = this.rotuloPadronizado(label);
this.inputIdPreview.textContent = `ID gerado: campo-${idPadronizado}`;
} else {
this.inputIdPreview.textContent = 'ID gerado: ';
}
}
atualizarPreviewRadioId() {
const label = this.radioLabel.value.trim();
if (label) {
const idPadronizado = this.rotuloPadronizado(label);
this.radioIdPreview.textContent = `ID gerado: campo-radio-${idPadronizado}`;
} else {
this.radioIdPreview.textContent = 'ID gerado: ';
}
}
atualizarPreviewTratamentoId() {
const label = this.tratamentoLabel.value.trim();
if (label) {
const idPadronizado = this.rotuloPadronizado(label);
this.tratamentoIdPreview.textContent = `ID gerado: campo-tratamento-${idPadronizado}`;
} else {
this.tratamentoIdPreview.textContent = 'ID gerado: ';
}
}
// MÉTODO NOVO FORMULÁRIO - CORRIGIDO (AGORA LIMPA TAMBÉM O CAMPO-RELATORIO)
novoFormulario() {
if (confirm('Deseja criar um novo formulário? Todos os dados não salvos serão perdidos.')) {
// Resetar título
this.projectTitle.textContent = 'Formulário';
// Resetar grupos
this.groups = [];
// CORREÇÃO: Resetar código - placeholder vazio e valor vazio
this.campoCodigo.value = '';
this.campoCodigo.placeholder = '';
// CORREÇÃO COMPLETA: Resetar relatório - limpar o conteúdo e resetar altura
if (this.campoRelatorio) {
this.campoRelatorio.value = '';
this.campoRelatorio.placeholder = 'Bom dia João Silva.';
this.campoRelatorio.style.height = '200px'; // resetar altura padrão
this.campoRelatorio.style.display = 'block'; // mostrar textarea novamente
// Remover container HTML se existir
const htmlContainer = document.getElementById('relatorio-html-container');
if (htmlContainer) {
htmlContainer.remove();
}
// Parar observer se existir
if (this.relatorioObserver) {
this.relatorioObserver.disconnect();
this.relatorioObserver = null;
}
}
// CORREÇÃO: Resetar formulário no localStorage com código vazio
this.formulario = {
nome: 'Formulário',
grupos: [],
codigo: '', // Código vazio
dataCriacao: new Date().toISOString(),
dataAtualizacao: new Date().toISOString()
};
localStorage.setItem('formulario', JSON.stringify(this.formulario));
// Re-renderizar interface
this.renderizarGrupos();
this.showNotification('Novo formulário criado com sucesso!');
console.log('Formulário resetado para estado padrão:', this.formulario);
}
}
salvarBackup() {
// Primeiro atualiza o formulário com os dados atuais
this.atualizarFormularioCompleto();
// Obter o nome do projeto para sugerir como nome do arquivo
const nomeProjeto = this.projectTitle.textContent || 'formulario';
// Criar nome do arquivo padronizado
const nomeArquivo = `${this.rotuloPadronizado(nomeProjeto)}.json`;
// Criar o blob com o conteúdo do formulário
const dados = JSON.stringify(this.formulario, null, 2);
const blob = new Blob([dados], { type: 'application/json' });
// Criar URL temporária para download
const url = URL.createObjectURL(blob);
// Criar elemento de link para download
const link = document.createElement('a');
link.href = url;
link.download = nomeArquivo;
// Adicionar ao DOM, clicar e remover
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Liberar a URL
URL.revokeObjectURL(url);
this.showNotification(`Formulário salvo como: ${nomeArquivo}`);
console.log('Formulário salvo como arquivo:', nomeArquivo, this.formulario);
}
abrirBackup() {
this.fileInput.click();
}
// MÉTODO PARA VALIDAR ESTRUTURA DO FORMULÁRIO
validarEstruturaFormulario(formulario) {
if (!formulario || typeof formulario !== 'object') {
return false;
}
// Verificar propriedades básicas
const propriedadesRequeridas = ['nome', 'grupos', 'codigo'];
for (const prop of propriedadesRequeridas) {
if (!formulario.hasOwnProperty(prop)) {
return false;
}
}
// Validar que grupos é um array
if (!Array.isArray(formulario.grupos)) {
return false;
}
return true;
}
// MÉTODO PARA ATUALIZAR INTERFACE APÓS CARREGAR FORMULÁRIO
atualizarInterfaceComFormularioCarregado() {
// Atualizar título do projeto
if (this.formulario.nome) {
this.projectTitle.textContent = this.formulario.nome;
}
// Atualizar grupos
if (this.formulario.grupos) {
this.groups = this.formulario.grupos;
} else {
this.groups = [];
}
// Atualizar código
if (this.formulario.codigo && this.campoCodigo) {
this.campoCodigo.value = this.formulario.codigo;
} else {
this.campoCodigo.value = '';
}
// Re-renderizar grupos
this.renderizarGrupos();
console.log('Interface atualizada com formulário carregado');
}
// MÉTODO CARREGAR ARQUIVO - CORRIGIDO E FUNCIONAL
carregarArquivo(e) {
const file = e.target.files[0];
if (!file) return;
// Verificar se é um arquivo JSON
if (!file.name.endsWith('.json')) {
this.showNotification('Por favor, selecione um arquivo JSON.', true);
this.fileInput.value = ''; // Limpar seleção
return;
}
const reader = new FileReader();
reader.onload = (event) => {
try {
const conteudo = event.target.result;
const formularioCarregado = JSON.parse(conteudo);
// Validar estrutura básica do arquivo
if (!formularioCarregado || typeof formularioCarregado !== 'object') {
throw new Error('Arquivo JSON inválido');
}
// Verificar estrutura mínima esperada
if (!this.validarEstruturaFormulario(formularioCarregado)) {
throw new Error('Estrutura do arquivo inválida. Deve conter: nome, grupos (array) e codigo');
}
// Confirmar substituição com o usuário
if (confirm('Deseja carregar este formulário? Todos os dados atuais serão substituídos.')) {
// Sobrescrever o formulário no localStorage
this.formulario = formularioCarregado;
localStorage.setItem('formulario', JSON.stringify(this.formulario));
// Atualizar a interface
this.atualizarInterfaceComFormularioCarregado();
this.showNotification('Formulário carregado com sucesso!');
console.log('Formulário carregado:', this.formulario);
}
} catch (error) {
console.error('Erro ao carregar arquivo:', error);
this.showNotification(`Erro ao carregar arquivo: ${error.message}`, true);
} finally {
// Limpar o input de arquivo para permitir recarregar o mesmo arquivo
this.fileInput.value = '';
}
};
reader.onerror = () => {
this.showNotification('Erro ao ler o arquivo.', true);
this.fileInput.value = ''; // Limpar seleção
};
reader.readAsText(file);
}
}
// Inicializar a aplicação quando o DOM estiver carregado
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM carregado - inicializando FormularioDinamico');
window.formularioApp = new FormularioDinamico();
});