/* EVENTO: DOMContentLoaded Se ejecuta cuando el HTML termina de cargarse Esto asegura que todos los elementos del DOM existan antes de intentar utilizarlos desde JavaScript */ document.addEventListener("DOMContentLoaded", () => { /* REFERENCIAS DEL DOM Obtenemos: - form -> formulario del chat - input -> input donde escribe el usuario - chatBox -> contenedor de mensajes */ const form = document.getElementById("chat-form"); const input = document.getElementById("mensaje"); const chatBox = document.getElementById("chat-box"); // Se detiene el script si no existe algún elemento if (!form || !input || !chatBox) return; // EVENTO SUBMIT -> se ejecuta cuando el usuario envía el formulario form.addEventListener("submit", async (e) => { // PREVENIR RECARGA -> Evita que el formulario recargue la página e.preventDefault(); // OBTENER MENSAJE const mensaje = input.value.trim(); // VALIDAR MENSAJE if (!mensaje) return; // MOSTRAR MENSAJE DEL USUARIO -> Se agrega inmediatamente al chat agregarMensaje("user", mensaje); // LIMPIAR INPUT input.value = ""; // MOSTRAR TYPING (ESCRIBIENDO...) mostrarTyping(); try { /* FETCH AJAX Realizamos una petición POST hacia chatbot.php */ const response = await fetch( window.location.origin + "/ajax/chatbot.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, /* BODY encodeURIComponent(): - Escapa caracteres especiales */ body: "mensaje=" + encodeURIComponent(mensaje) } ); // ELIMINAR TYPING removerTyping(); // CONVERTIR RESPUESTA JSON const data = await response.json(); // ERROR BACKEND -> success === false if (!data.success) { console.error(data.error); agregarMensaje( "bot", "Ocurrió un error al procesar la consulta." ); return; } // RESPUESTA IA agregarMensaje( "bot", data.respuesta ); } catch (error) { // ERROR FETCH / CONEXIÓN removerTyping(); console.error(error); agregarMensaje( "bot", "Error de conexión." ); } }); // Evita inyección HTML/XSS function escaparHTML(texto) { return texto .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // AGREGAR MENSAJE VISUAL AL CHAT -> tipo: user / bot function agregarMensaje(tipo, texto) { // CREAR DIV const div = document.createElement("div"); // CLASE CSS div.className = tipo === "user" ? "mensaje-user" : "mensaje-bot"; div.innerHTML = `
${escaparHTML(texto).replace(/\n/g, "
")}
`; // INSERTAR MENSAJE chatBox.appendChild(div); // AUTO SCROLL scrollBottom(); } // MOSTRAR TYPING function mostrarTyping() { const div = document.createElement("div"); div.id = "typing"; div.className = "mensaje-bot"; div.innerHTML = `
Escribiendo...
`; chatBox.appendChild(div); scrollBottom(); } // ELIMINAR TYPING function removerTyping() { const typing = document.getElementById("typing"); if (typing) { typing.remove(); } } // AUTO SCROLL -> Baja automáticamente el scroll del chat function scrollBottom() { chatBox.scrollTop = chatBox.scrollHeight; } }); /* EVENTO: load Se ejecuta cuando toda la página termina de cargar: HTML + CSS + imágenes + recursos Se usa para restaurar el scroll abajo al refrescar la página */ window.addEventListener("load", () => { const chatBox = document.getElementById("chat-box"); if (chatBox) { chatBox.scrollTop = chatBox.scrollHeight; } });