Files
driving-academy/static/js/modules/question-navigator.js
2025-10-26 23:39:49 -05:00

224 lines
6.9 KiB
JavaScript

// 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;