UNPKG

mcp-quiz-server

Version:

๐Ÿง  AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

166 lines โ€ข 7.47 kB
import { EventManagement } from './EventManagement'; export class AnswerHandler { constructor(store, settingsService) { this.currentSelectionTimeout = null; this.store = store; this.settingsService = settingsService; } setupAnswerHandling(container) { const settings = this.settingsService.getSettings(); const state = this.store.getState(); const isSingleMode = state.ui.viewMode === 'single'; if (this.currentSelectionTimeout) { clearTimeout(this.currentSelectionTimeout); this.currentSelectionTimeout = null; } EventManagement.cleanup(['answer-cards', 'radio-inputs']); const quizMode = settings.ui.quizMode || (settings.quiz.instantSubmission ? 'instant' : settings.ui.clickToSelectCards ? 'cards' : 'traditional'); console.log('๐ŸŽฎ Setting up answer handling for mode:', quizMode); if (quizMode === 'instant') { this.setupInstantSubmission(container); } else if (isSingleMode && quizMode === 'cards') { this.setupClickableCards(container); } else { this.setupTraditionalRadioButtons(container); } } setupInstantSubmission(container) { EventManagement.delegate(container, '.quiz-option-card', 'click', (event, target) => this.handleInstantSubmission(event, target), 'answer-cards-instant'); EventManagement.delegate(container, '.quiz-option-card', 'keydown', (event, target) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); this.handleInstantSubmission(event, target); } }, 'answer-cards-instant-keyboard'); } setupClickableCards(container) { EventManagement.delegate(container, '.quiz-option-card', 'click', (event, target) => this.handleClickableCard(event, target), 'answer-cards-clickable'); EventManagement.delegate(container, '.quiz-option-card', 'keydown', (event, target) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); this.handleClickableCard(event, target); } }, 'answer-cards-clickable-keyboard'); } setupTraditionalRadioButtons(container) { EventManagement.delegate(container, 'input[type=\"radio\"]', 'change', event => this.handleRadioSelection(event), 'radio-inputs'); } handleInstantSubmission(event, target) { const questionId = target.getAttribute('data-question-id'); const answer = target.getAttribute('data-answer'); if (!questionId || !answer) { console.error('๐Ÿšจ Missing question ID or answer in instant submission'); return; } console.log('โšก Instant submission:', { questionId, answer }); this.store.updateAnswer(questionId, answer); this.showAnswerFeedback(target, true); const settings = this.settingsService.getSettings(); if (settings.ui.autoAdvanceQuestions) { this.currentSelectionTimeout = setTimeout(() => { this.triggerNextQuestion(); }, 1500); } } handleClickableCard(event, target) { const questionId = target.getAttribute('data-question-id'); const answer = target.getAttribute('data-answer'); if (!questionId || !answer) { console.error('๐Ÿšจ Missing question ID or answer in clickable card'); return; } console.log('๐Ÿ‘† Card selection:', { questionId, answer }); this.store.updateAnswer(questionId, answer); this.updateCardSelection(questionId, answer); this.showContinueButton(); } handleRadioSelection(event) { const radio = event.target; const questionId = radio.name; const answer = radio.value; console.log('๐Ÿ“ป Radio selection:', { questionId, answer }); this.store.updateAnswer(questionId, answer); this.showContinueButton(); } updateCardSelection(questionId, selectedAnswer) { const cards = document.querySelectorAll(`[data-question-id=\"${questionId}\"]`); cards.forEach(card => { const cardAnswer = card.getAttribute('data-answer'); const isSelected = cardAnswer === selectedAnswer; if (isSelected) { card.classList.add('border-blue-500', 'bg-blue-50', 'dark:bg-blue-900/20', 'shadow-md'); card.classList.remove('border-gray-200', 'dark:border-gray-600'); card.setAttribute('aria-pressed', 'true'); } else { card.classList.remove('border-blue-500', 'bg-blue-50', 'dark:bg-blue-900/20', 'shadow-md'); card.classList.add('border-gray-200', 'dark:border-gray-600'); card.setAttribute('aria-pressed', 'false'); } const indicator = card.querySelector('.answer-indicator'); if (indicator) { if (isSelected) { indicator.classList.add('border-blue-500', 'bg-blue-500'); indicator.classList.remove('border-gray-300', 'dark:border-gray-500'); indicator.innerHTML = '<div class=\"w-2 h-2 bg-white rounded-full mx-auto mt-1\"></div>'; } else { indicator.classList.remove('border-blue-500', 'bg-blue-500'); indicator.classList.add('border-gray-300', 'dark:border-gray-500'); indicator.innerHTML = ''; } } }); } showAnswerFeedback(target, isCorrect) { if (isCorrect) { target.classList.add('bg-green-100', 'border-green-500', 'dark:bg-green-900/20'); } else { target.classList.add('bg-red-100', 'border-red-500', 'dark:bg-red-900/20'); } const announcement = isCorrect ? 'Answer selected' : 'Answer selected'; this.announceToScreenReader(announcement); } showContinueButton() { const continueContainer = document.querySelector('.continue-button-container'); const completeContainer = document.querySelector('.complete-quiz-container'); if (continueContainer) { continueContainer.style.display = ''; } if (completeContainer) { completeContainer.style.display = ''; } } triggerNextQuestion() { const event = new CustomEvent('quiz:next-question'); document.dispatchEvent(event); } announceToScreenReader(message) { const announcement = document.createElement('div'); announcement.setAttribute('aria-live', 'polite'); announcement.setAttribute('aria-atomic', 'true'); announcement.className = 'sr-only'; announcement.textContent = message; document.body.appendChild(announcement); setTimeout(() => { document.body.removeChild(announcement); }, 1000); } cleanup() { if (this.currentSelectionTimeout) { clearTimeout(this.currentSelectionTimeout); this.currentSelectionTimeout = null; } EventManagement.componentCleanup('answer-'); console.log('๐Ÿงน AnswerHandler cleanup completed'); } } //# sourceMappingURL=AnswerHandler.js.map