/* ========================================================================== js/render.js — dueño B: pinta el chat de WhatsApp dentro del iPhone. API (SPEC §2): WAM.render / renderHeader / renderMensaje / anadirMensajeDOM / setTema / setEscribiendo / scrollAbajo / abrirSheet / cerrarSheet / tick. Campos por tipo: SPEC §1. Colores, geometría y tipografía: docs/research-ui.md. Cero listeners de flujo (los clics los resuelve js/interactivity.js con los data-* estampados aquí; main.js abre el sheet del list con el data-flujo "plano" del botón). Listeners propios: cierre en #sheet-fondo (elemento creado por B), scroll de puntos del carousel y despliegue del plegado ">3 botones". No toca DOM al cargar. ========================================================================== */ (function () { "use strict"; window.WAM = window.WAM || {}; /* ------------------------------ helpers ------------------------------ */ function byId(id) { return document.getElementById(id); } function esc(s) { return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]; }); } function vacio(s) { return s == null || String(s) === ""; } function estado() { return WAM.estado || { cuenta: {}, mensajes: [] }; } var ESCRIBIENDO = false; /* Placeholder local; en la práctica usa WAM.svgPlaceholder (js/store.js). */ function placeholder(texto) { if (typeof WAM.svgPlaceholder === "function") { try { var u = WAM.svgPlaceholder(String(texto == null ? "" : texto)); if (u) return u; } catch (e) { /* fallback abajo */ } } var t = esc(String(texto == null ? "" : texto).slice(0, 42)); var svg = '' + '' + '' + '' + '' + '' + t + ""; return "data:image/svg+xml," + encodeURIComponent(svg); } /* ------------------------------ iconos SVG inline ------------------------------ */ function svgChevronAtras() { return ''; } function svgChevronDer(px) { var s = px || 14; return ''; } function svgVideoLlamada() { return ''; } function svgLlamada(px) { var s = px || 23; return ''; } function svgVerificado() { return ''; } function svgPlay(px) { var s = px || 18; return ''; } function svgMicrofono(px) { var s = px || 19; return ''; } function svgMusica(px) { var s = px || 19; return ''; } function svgDescarga(px) { var s = px || 15; return ''; } function svgEnlace(px) { var s = px || 18; return ''; } function svgCorreo(px) { var s = px || 15; return ''; } function svgEmpresa(px) { var s = px || 15; return ''; } /* Icono de página coloreado por extensión (research-ui §6.6) */ var COLORES_DOC = { pdf: "#e2574c", doc: "#4577e0", docx: "#4577e0", xls: "#2f9e5b", xlsx: "#2f9e5b", csv: "#2f9e5b", ppt: "#e5813d", pptx: "#e5813d", txt: "#8592a0", zip: "#a5855e", rar: "#a5855e" }; function extDe(nombre) { var n = String(nombre == null ? "" : nombre); var partes = n.split("."); return partes.length > 1 ? partes.pop().toLowerCase() : "doc"; } function docIcon(ext, px) { var w = px || 30; var h = Math.round(w * 36 / 30); var color = COLORES_DOC[ext] || "#7c8894"; var etiqueta = ext.length <= 4 ? ext.toUpperCase() : "DOC"; return '"; } /* Mapa estático con pin rojo (research-ui §6.8, data-URI sin red) */ function svgMapa() { var svg = '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ""; return "data:image/svg+xml," + encodeURIComponent(svg); } /* ------------------------------ texto enriquecido ------------------------------ */ /* Formato WhatsApp (research-api §2): *negrita* _cursiva_ ~tachado~ ```mono``` + URLs hipervinculadas (color --wa-link, sin subrayado). */ function formatear(txt) { var partes = String(txt == null ? "" : txt).split(/(https?:\/\/[^\s<>"]+)/g); var html = ""; for (var i = 0; i < partes.length; i++) { var p = partes[i]; if (p === "") continue; if (/^https?:\/\//.test(p)) { html += '' + esc(p) + ""; } else { var t = esc(p); t = t.replace(/```([\s\S]+?)```/g, "$1"); t = t.replace(/\*([^*\n]+)\*/g, "$1"); t = t.replace(/(^|[^\w])_([^_\n]+)_(?=[^\w]|$)/g, "$1$2"); t = t.replace(/(^|[^\w])~([^~\n]+)~(?=[^\w]|$)/g, "$1$2"); html += t; } } return html; } /* ------------------------------ ticks y meta ------------------------------ */ /* ✓ enviado (gris) / ✓✓ entregado (gris) / ✓✓ leído (celeste #53bdeb) */ var TRAZO_TICK = ''; WAM.tick = function (estadoTick) { var uno = '"; var dos = ''; if (estadoTick === "read") return dos.replace('class="tick"', 'class="tick tick-read"'); if (estadoTick === "delivered") return dos; return uno; }; /* Hora (+ ticks solo en OUT) dentro de la burbuja */ function metaHTML(m, extra) { var mm = m || {}; var html = '' + esc(vacio(mm.hora) ? "" : mm.hora); if (mm.dir === "out") html += WAM.tick(mm.estado || "sent"); return html + ""; } /* ------------------------------ piezas de burbujas ------------------------------ */ function insigniaPlay(px) { return '' + svgPlay(px || 26) + ""; } function burbujaTexto(m) { return '
"; } /* image / video: media full-bleed; caption debajo; hora encima o en caption. El placeholder SVG (data:image/svg+xml) solo lo decodifican los : un