| | |
| | |
| | |
| | |
| | console.log("[proa.js v14] Script cargado. Esperando DOMContentLoaded..."); |
| | window.addEventListener('DOMContentLoaded', () => { |
| | console.log("[proa.js v14] DOMContentLoaded detectado. Iniciando setup..."); |
| |
|
| | |
| | const guideSelector = document.getElementById('guideSelector'); |
| | const diagnosisSelectorContainer = document.getElementById('diagnosis-selector-container'); |
| | const diagnosisSelector = document.getElementById('diagnosisSelector'); |
| | const guideContentDisplay = document.getElementById('guide-content-display'); |
| | const togglePediatricCheckbox = document.getElementById('togglePediatric'); |
| |
|
| | |
| | const guidesDataUrl = './data/guides_data.json'; |
| |
|
| | |
| | if (!guideSelector || !diagnosisSelectorContainer || !diagnosisSelector || !guideContentDisplay || !togglePediatricCheckbox) { |
| | console.error("[proa.js v14] Error Crítico: No se encontraron elementos DOM esenciales."); |
| | guideContentDisplay.innerHTML = '<p class="text-red-500 font-semibold text-center py-10">Error: Interfaz no inicializada correctamente.</p>'; |
| | return; |
| | } |
| | console.log("[proa.js v14] Elementos DOM encontrados."); |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | let allGuides = []; |
| | let currentSelectedGuideData = null; |
| | let currentGuideHTMLContent = null; |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | async function loadGuidesData() { |
| | console.log(`[proa.js v14] Iniciando loadGuidesData desde: ${guidesDataUrl}`); |
| | guideSelector.innerHTML = '<option value="">Cargando...</option>'; |
| | guideSelector.disabled = true; |
| | resetUI(); |
| |
|
| | try { |
| | console.log("[proa.js v14] Realizando fetch..."); |
| | const response = await fetch(guidesDataUrl); |
| | console.log(`[proa.js v14] Fetch completado. Status: ${response.status}`); |
| | if (!response.ok) throw new Error(`Error HTTP ${response.status} al cargar ${guidesDataUrl}. Verifica que el archivo exista y sea accesible.`); |
| |
|
| | console.log("[proa.js v14] Parseando JSON..."); |
| | const rawData = await response.json(); |
| | console.log("[proa.js v14] JSON parseado."); |
| |
|
| | if (!Array.isArray(rawData)) throw new Error("El formato del JSON no es un array válido."); |
| |
|
| | allGuides = rawData.filter(g => g.id && g.title && g.file && typeof g.isPediatric === 'boolean'); |
| | console.log(`[proa.js v14] Guías válidas iniciales: ${allGuides.length}`); |
| |
|
| | allGuides = allGuides.map(g => { |
| | if (g.hasDiagnoses === true) { |
| | if (!Array.isArray(g.diagnoses) || g.diagnoses.some(d => !d.id || !d.title)) { |
| | console.warn(`[proa.js v14] Guía '${g.title}' marcada con 'hasDiagnoses' pero la estructura 'diagnoses' es inválida. Se tratará como guía normal.`); |
| | return { ...g, hasDiagnoses: false, diagnoses: undefined }; |
| | } |
| | } |
| | return g; |
| | }); |
| |
|
| | if (allGuides.length === 0) throw new Error("No se encontraron guías válidas en los datos después de la validación."); |
| |
|
| | allGuides.sort((a, b) => a.title.localeCompare(b.title)); |
| |
|
| | console.log("[proa.js v14] Llamando a populateGuideSelector (mostrará Adultos por defecto)..."); |
| | populateGuideSelector(); |
| | guideSelector.disabled = false; |
| | console.log("[proa.js v14] Carga inicial de datos completada."); |
| |
|
| | } catch (error) { |
| | console.error("[proa.js v14] Error durante loadGuidesData:", error); |
| | guideSelector.innerHTML = `<option value="">Error al cargar</option>`; |
| | guideSelector.disabled = true; |
| | guideContentDisplay.innerHTML = `<p class="text-red-600 font-semibold text-center py-10">Error crítico al cargar datos: ${error.message}. Revisa la consola y el archivo '${guidesDataUrl}'.</p>`; |
| | } |
| | } |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | function resetUI(fullReset = true) { |
| | guideContentDisplay.innerHTML = '<div class="text-center py-16 text-gray-400"><i class="fas fa-file-alt text-5xl mb-4"></i><p>Selecciona una guía del desplegable.</p></div>'; |
| | diagnosisSelector.innerHTML = '<option value="">-- Seleccione Diagnóstico --</option>'; |
| | diagnosisSelectorContainer.classList.add('hidden'); |
| | currentSelectedGuideData = null; |
| | currentGuideHTMLContent = null; |
| |
|
| | if(fullReset && guideSelector.options.length > 1) { |
| | guideSelector.value = ""; |
| | } |
| | } |
| |
|
| | function populateGuideSelector() { |
| | const showOnlyPediatric = togglePediatricCheckbox.checked; |
| | console.log(`[proa.js v14] Poblando selector principal. Mostrar Pediátricas: ${showOnlyPediatric}`); |
| |
|
| | const filteredGuides = allGuides.filter(guide => guide.isPediatric === showOnlyPediatric); |
| | filteredGuides.sort((a, b) => a.title.localeCompare(b.title)); |
| |
|
| | guideSelector.innerHTML = `<option value="">-- Seleccione Guía (${showOnlyPediatric ? 'Pediátricas' : 'Adultos'}) --</option>`; |
| |
|
| | if (filteredGuides.length > 0) { |
| | const fragment = document.createDocumentFragment(); |
| | filteredGuides.forEach(guide => { |
| | const option = document.createElement('option'); |
| | option.value = guide.id; |
| | option.textContent = guide.isPediatric ? `${guide.title} (PED)` : guide.title; |
| | option.dataset.hasDiagnoses = guide.hasDiagnoses || false; |
| | option.dataset.file = guide.file; |
| | fragment.appendChild(option); |
| | }); |
| | guideSelector.appendChild(fragment); |
| | console.log(`[proa.js v14] Selector principal poblado con ${filteredGuides.length} guías.`); |
| | } else { |
| | guideSelector.innerHTML = `<option value="">-- No hay guías ${showOnlyPediatric ? 'Pediátricas' : 'Adultos'} --</option>`; |
| | console.log(`[proa.js v14] No se encontraron guías para el filtro actual.`); |
| | } |
| | resetUI(false); |
| | } |
| |
|
| | function populateDiagnosisSelector(guideData) { |
| | console.log(`[proa.js v14] Poblando selector de diagnósticos para: ${guideData.title}`); |
| | diagnosisSelector.innerHTML = '<option value="">-- Seleccione Diagnóstico --</option>'; |
| |
|
| | if (guideData.hasDiagnoses && Array.isArray(guideData.diagnoses)) { |
| | const fragment = document.createDocumentFragment(); |
| | guideData.diagnoses.forEach(diagnosis => { |
| | const option = document.createElement('option'); |
| | option.value = diagnosis.id; |
| | option.textContent = diagnosis.title; |
| | fragment.appendChild(option); |
| | }); |
| | diagnosisSelector.appendChild(fragment); |
| | diagnosisSelectorContainer.classList.remove('hidden'); |
| | console.log(`[proa.js v14] Selector de diagnósticos poblado con ${guideData.diagnoses.length} opciones.`); |
| | } else { |
| | console.warn("[proa.js v14] Se intentó poblar diagnósticos para una guía sin ellos o con datos inválidos."); |
| | diagnosisSelectorContainer.classList.add('hidden'); |
| | } |
| | } |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | async function loadFullGuideContent(guideFile) { |
| | if (!guideFile) { |
| | resetUI(); |
| | return; |
| | } |
| | |
| | const guideUrl = guideFile; |
| | console.log(`[proa.js v14] Solicitando contenido COMPLETO de: ${guideUrl}`); |
| | guideContentDisplay.innerHTML = '<div class="text-center py-20"><i class="fas fa-spinner fa-spin text-3xl text-gray-400"></i><p class="mt-2 text-gray-500">Cargando guía completa...</p></div>'; |
| | currentGuideHTMLContent = null; |
| |
|
| | try { |
| | const response = await fetch(guideUrl); |
| | if (!response.ok) throw new Error(`Error HTTP ${response.status} al cargar ${guideUrl}`); |
| | const htmlText = await response.text(); |
| |
|
| | const parser = new DOMParser(); |
| | const doc = parser.parseFromString(htmlText, 'text/html'); |
| | |
| | const contentNode = doc.querySelector('.treatment-card') || doc.body; |
| |
|
| | if (contentNode) { |
| | const clonedContent = contentNode.cloneNode(true); |
| | const scripts = clonedContent.querySelectorAll('script'); |
| | scripts.forEach(script => script.remove()); |
| | if (scripts.length > 0) console.log(`[proa.js v14] Eliminados ${scripts.length} script(s) de ${guideUrl}.`); |
| |
|
| | guideContentDisplay.innerHTML = ''; |
| | guideContentDisplay.appendChild(clonedContent); |
| | console.log(`[proa.js v14] Contenido COMPLETO de ${guideUrl} mostrado.`); |
| | guideContentDisplay.scrollTop = 0; |
| | } else { |
| | |
| | const bodyNode = doc.body; |
| | if(bodyNode){ |
| | const clonedBody = bodyNode.cloneNode(true); |
| | const scripts = clonedBody.querySelectorAll('script'); |
| | scripts.forEach(script => script.remove()); |
| | guideContentDisplay.innerHTML = ''; |
| | guideContentDisplay.appendChild(clonedBody); |
| | console.warn(`[proa.js v14] No se encontró .treatment-card en '${guideUrl}'. Mostrando contenido del body.`); |
| | guideContentDisplay.scrollTop = 0; |
| | } else { |
| | throw new Error(`No se encontró nodo de contenido principal (ni .treatment-card ni body) en '${guideUrl}'.`); |
| | } |
| | } |
| | } catch (error) { |
| | console.error(`[proa.js v14] Error al cargar/mostrar contenido COMPLETO de ${guideUrl}:`, error); |
| | guideContentDisplay.innerHTML = `<div class="text-center py-20 text-red-600">Error al cargar contenido: ${error.message}</div>`; |
| | } |
| | } |
| |
|
| | async function loadAndDisplayDiagnosisContent(guideData, diagnosisId) { |
| | |
| | const guideFileUrl = guideData.file; |
| | console.log(`[proa.js v14] Solicitando diagnóstico '${diagnosisId}' de la guía '${guideData.title}' (${guideFileUrl})`); |
| | guideContentDisplay.innerHTML = '<div class="text-center py-20"><i class="fas fa-spinner fa-spin text-3xl text-gray-400"></i><p class="mt-2 text-gray-500">Cargando diagnóstico...</p></div>'; |
| |
|
| | try { |
| | if (!currentGuideHTMLContent) { |
| | console.log(`[proa.js v14] HTML de ${guideFileUrl} no cacheado. Realizando fetch...`); |
| | const response = await fetch(guideFileUrl); |
| | if (!response.ok) throw new Error(`Error HTTP ${response.status} al cargar ${guideFileUrl}`); |
| | currentGuideHTMLContent = await response.text(); |
| | console.log(`[proa.js v14] HTML de ${guideFileUrl} cargado y cacheado.`); |
| | } else { |
| | console.log(`[proa.js v14] Usando HTML cacheado de ${guideFileUrl}.`); |
| | } |
| |
|
| | const parser = new DOMParser(); |
| | const doc = parser.parseFromString(currentGuideHTMLContent, 'text/html'); |
| | const diagnosisNode = doc.getElementById(diagnosisId); |
| |
|
| | if (diagnosisNode) { |
| | console.log(`[proa.js v14] Nodo para diagnóstico ID '${diagnosisId}' encontrado.`); |
| | const clonedDiagnosisContent = diagnosisNode.cloneNode(true); |
| | const scripts = clonedDiagnosisContent.querySelectorAll('script'); |
| | scripts.forEach(script => script.remove()); |
| | if (scripts.length > 0) console.log(`[proa.js v14] Eliminados ${scripts.length} script(s) del nodo de diagnóstico.`); |
| |
|
| | guideContentDisplay.innerHTML = ''; |
| | guideContentDisplay.appendChild(clonedDiagnosisContent); |
| | console.log(`[proa.js v14] Contenido del diagnóstico '${diagnosisId}' mostrado.`); |
| | guideContentDisplay.scrollTop = 0; |
| | } else { |
| | throw new Error(`No se encontró el elemento con ID '${diagnosisId}' dentro de '${guideFileUrl}'. Verifica la estructura del HTML de la guía.`); |
| | } |
| | } catch (error) { |
| | console.error(`[proa.js v14] Error al cargar/mostrar diagnóstico '${diagnosisId}' de ${guideFileUrl}:`, error); |
| | guideContentDisplay.innerHTML = `<div class="text-center py-20 text-red-600">Error al cargar diagnóstico: ${error.message}</div>`; |
| | } |
| | } |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | guideSelector.addEventListener('change', (event) => { |
| | const selectedOption = event.target.selectedOptions[0]; |
| | const guideId = selectedOption.value; |
| | console.log(`[proa.js v14] Cambió la guía principal seleccionada. ID: ${guideId}`); |
| | resetUI(false); |
| |
|
| | if (!guideId) { |
| | return; |
| | } |
| |
|
| | currentSelectedGuideData = allGuides.find(g => g.id === guideId); |
| |
|
| | if (!currentSelectedGuideData) { |
| | console.error(`[proa.js v14] No se encontraron datos para la guía con ID: ${guideId}`); |
| | guideContentDisplay.innerHTML = '<p class="text-red-500 text-center py-10">Error: Datos de guía no encontrados.</p>'; |
| | return; |
| | } |
| |
|
| | if (currentSelectedGuideData.hasDiagnoses === true) { |
| | console.log(`[proa.js v14] La guía '${currentSelectedGuideData.title}' tiene diagnósticos. Poblando selector secundario.`); |
| | populateDiagnosisSelector(currentSelectedGuideData); |
| | guideContentDisplay.innerHTML = '<div class="text-center py-16 text-gray-400"><i class="fas fa-stethoscope text-5xl mb-4"></i><p>Selecciona un diagnóstico específico del desplegable superior.</p></div>'; |
| | } else { |
| | console.log(`[proa.js v14] La guía '${currentSelectedGuideData.title}' no tiene diagnósticos. Cargando contenido completo.`); |
| | diagnosisSelectorContainer.classList.add('hidden'); |
| | loadFullGuideContent(currentSelectedGuideData.file); |
| | } |
| | }); |
| |
|
| | diagnosisSelector.addEventListener('change', (event) => { |
| | const diagnosisId = event.target.value; |
| | console.log(`[proa.js v14] Cambió el diagnóstico seleccionado. ID: ${diagnosisId}`); |
| |
|
| | if (!diagnosisId) { |
| | guideContentDisplay.innerHTML = '<div class="text-center py-16 text-gray-400"><i class="fas fa-stethoscope text-5xl mb-4"></i><p>Selecciona un diagnóstico específico del desplegable superior.</p></div>'; |
| | return; |
| | } |
| |
|
| | if (currentSelectedGuideData && currentSelectedGuideData.hasDiagnoses) { |
| | loadAndDisplayDiagnosisContent(currentSelectedGuideData, diagnosisId); |
| | } else { |
| | console.error("[proa.js v14] Se intentó cargar un diagnóstico pero no hay guía con diagnósticos seleccionada."); |
| | guideContentDisplay.innerHTML = '<p class="text-red-500 text-center py-10">Error: Guía base no seleccionada correctamente.</p>'; |
| | } |
| | }); |
| |
|
| | togglePediatricCheckbox.addEventListener('change', () => { |
| | console.log('[proa.js v14] Cambiado filtro pediátrico.'); |
| | populateGuideSelector(); |
| | }); |
| |
|
| | console.log("[proa.js v14] Listeners añadidos."); |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | loadGuidesData(); |
| | |
| | |
| | |
| |
|
| | }); |
| | console.log("[proa.js v14] Script completamente definido."); |
| |
|