// Contrato Índice–Visor v1. Importación anticipada, nunca dentro de una pulsación. // El Gestor es dueño de la acción, la pestaña, los mensajes y las estadísticas. import { abrirArticulo } from '/gestor-revistas/assets/indice-visor.mjs'; function readingError(link) { let message = link.parentElement.querySelector('[data-reader-error]'); if (!message) { message = document.createElement('p'); message.dataset.readerError = ''; message.className = 'small availability'; message.setAttribute('role', 'alert'); link.parentElement.appendChild(message); } message.textContent = 'No se pudo abrir el artículo. Vuelve a pulsar para intentarlo de nuevo o utiliza «Abrir revista completa».'; } document.addEventListener('click', event => { const link = event.target instanceof Element ? event.target.closest('a[data-reader-article]') : null; // Los enlaces y los gestos explícitos de abrir otra pestaña conservan su respaldo HTML. if (!link || event.defaultPrevented || !event.isTrusted || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return; const slug = link.dataset.readerSlug; const rawPage = link.dataset.readerPage || ''; const rawContent = link.dataset.readerContent || ''; if (!/^Selva_[1-9][0-9]*_(0[1-9]|1[0-2])_[0-9]{2}$/i.test(slug || '') || !/^[1-9][0-9]*$/.test(rawPage) || !/^[1-9][0-9]*$/.test(rawContent)) return; const pagina = Number(rawPage); const contenido = Number(rawContent); if (!Number.isSafeInteger(pagina) || !Number.isSafeInteger(contenido)) return; event.preventDefault(); const previousError = link.parentElement.querySelector('[data-reader-error]'); if (previousError) previousError.remove(); try { // Se llama sin esperas, dentro del gesto real. Nunca se reutiliza la acción del href. const result = abrirArticulo({ slug, pagina, contenido }); if (result && typeof result.catch === 'function') result.catch(() => readingError(link)); } catch (error) { // No se abre por otra vía ni se reenvía: podría duplicar una acción ya entregada. readingError(link); } });