// Question Navigator Module class QuestionNavigator { constructor(containerId, options = {}) { this.containerId = containerId; this.questions = []; this.currentIndex = 0; this.visitedQuestions = new Set(); this.onQuestionSelect = options.onQuestionSelect || (() => {}); this.storagePrefix = options.storagePrefix || 'navigator'; this.init(); } init() { this.setupEventListeners(); } setupEventListeners() { // Jump button const jumpBtn = document.getElementById('jump-btn'); if (jumpBtn) { jumpBtn.addEventListener('click', () => this.jumpToQuestion()); } // Jump input const jumpInput = document.getElementById('jump-to-question'); if (jumpInput) { jumpInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.jumpToQuestion(); } }); } // Reset button const resetBtn = document.getElementById('reset-visited-btn'); if (resetBtn) { resetBtn.addEventListener('click', () => this.resetVisitedQuestions()); } } setQuestions(questions) { this.questions = questions; this.createNavigator(); this.loadVisitedFromStorage(); this.updateNavigator(); } createNavigator() { const container = document.getElementById(this.containerId); if (!container) return; container.innerHTML = ''; this.questions.forEach((question, index) => { const button = document.createElement('button'); button.className = 'question-nav-btn'; button.textContent = question.id; button.setAttribute('data-index', index); button.title = `Pregunta ${question.id}`; button.addEventListener('click', () => { this.selectQuestion(index); }); container.appendChild(button); }); } selectQuestion(index) { if (index >= 0 && index < this.questions.length) { this.currentIndex = index; this.visitedQuestions.add(index); this.saveVisitedToStorage(); this.updateNavigator(); this.onQuestionSelect(index); } } updateNavigator() { const buttons = document.querySelectorAll(`#${this.containerId} .question-nav-btn`); buttons.forEach((button, index) => { button.classList.remove('current', 'visited'); if (index === this.currentIndex) { button.classList.add('current'); this.visitedQuestions.add(index); this.saveVisitedToStorage(); // Scroll to current button button.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); } else if (this.visitedQuestions.has(index)) { button.classList.add('visited'); } }); this.updateProgress(); this.updateJumpInputMax(); } updateProgress() { const progressEl = document.getElementById('navigator-progress'); if (progressEl) { progressEl.textContent = `${this.visitedQuestions.size} de ${this.questions.length} visitadas`; } } updateJumpInputMax() { const jumpInput = document.getElementById('jump-to-question'); if (jumpInput && this.questions.length > 0) { jumpInput.max = this.questions[this.questions.length - 1].id; } } jumpToQuestion() { const jumpInput = document.getElementById('jump-to-question'); if (!jumpInput) return; const questionId = parseInt(jumpInput.value); if (!questionId || questionId < 1) { this.showNotification('Por favor ingresa un número de pregunta válido', 'warning'); return; } const questionIndex = this.questions.findIndex(q => q.id === questionId); if (questionIndex === -1) { this.showNotification(`La pregunta ${questionId} no está en el rango actual`, 'warning'); return; } this.selectQuestion(questionIndex); jumpInput.value = ''; this.playSound('click'); this.showNotification(`Navegando a pregunta ${questionId}`, 'success', 2000); } resetVisitedQuestions() { if (this.visitedQuestions.size === 0) { this.showNotification('No hay preguntas visitadas para limpiar', 'info', 3000); return; } const confirmReset = confirm( `¿Estás seguro de que quieres limpiar el progreso de ${this.visitedQuestions.size} preguntas visitadas?` ); if (confirmReset) { // Clear visited questions but keep current question this.visitedQuestions.clear(); this.visitedQuestions.add(this.currentIndex); this.saveVisitedToStorage(); this.updateNavigator(); this.playSound('complete'); this.showNotification('Progreso de preguntas visitadas limpiado', 'success', 3000); // Animation for reset button const resetBtn = document.getElementById('reset-visited-btn'); if (resetBtn) { resetBtn.style.transform = 'scale(0.9)'; setTimeout(() => { resetBtn.style.transform = 'scale(1)'; }, 150); } } } saveVisitedToStorage() { try { const storageKey = `${this.storagePrefix}_visited`; localStorage.setItem(storageKey, JSON.stringify(Array.from(this.visitedQuestions))); } catch (error) { console.warn('Could not save visited questions to localStorage:', error); } } loadVisitedFromStorage() { try { const storageKey = `${this.storagePrefix}_visited`; const saved = localStorage.getItem(storageKey); if (saved) { const visitedArray = JSON.parse(saved); this.visitedQuestions = new Set(visitedArray); } else { this.visitedQuestions = new Set(); } } catch (error) { console.warn('Could not load visited questions from localStorage:', error); this.visitedQuestions = new Set(); } } setCurrentIndex(index) { this.currentIndex = index; this.updateNavigator(); } // Utility methods showNotification(message, type = 'info', duration = 3000) { if (window.Utils) { Utils.showNotification(message, type, duration); } else { alert(message); } } playSound(type) { if (window.Utils) { Utils.playSound(type); } } } // Export for global use window.QuestionNavigator = QuestionNavigator;