// === MODULE TEXT READER === class TextReaderGame { constructor(options) { this.container = options.container; this.content = options.content; this.onScoreUpdate = options.onScoreUpdate || (() => {}); this.onGameEnd = options.onGameEnd || (() => {}); // État du lecteur this.currentTextIndex = 0; this.currentSentenceIndex = 0; this.isRunning = false; // Données de lecture this.texts = this.extractTexts(this.content); this.currentText = null; this.sentences = []; this.showingFullText = false; this.init(); } init() { // Vérifier que nous avons des textes if (!this.texts || this.texts.length === 0) { console.error('Aucun texte disponible pour Text Reader'); this.showInitError(); return; } this.createReaderInterface(); this.setupEventListeners(); this.loadText(); } showInitError() { this.container.innerHTML = `

❌ Error loading

This content doesn't contain texts compatible with Text Reader.

The reader needs texts to display.

`; } extractTexts(content) { let texts = []; console.log('📖 Extracting texts from:', content?.name || 'content'); // Use raw module content if available if (content.rawContent) { console.log('📦 Using raw module content'); return this.extractTextsFromRaw(content.rawContent); } // Format with texts array if (content.texts && Array.isArray(content.texts)) { console.log('📝 Texts format detected'); texts = content.texts.filter(text => text.content && text.content.trim() !== '' ); } // Modern format with contentItems else if (content.contentItems && Array.isArray(content.contentItems)) { console.log('🆕 ContentItems format detected'); texts = content.contentItems .filter(item => item.type === 'text' && item.content) .map(item => ({ title: item.title || 'Text', content: item.content })); } return this.finalizeTexts(texts); } extractTextsFromRaw(rawContent) { console.log('🔧 Extracting from raw content:', rawContent.name || 'Module'); let texts = []; // Simple format (texts array) if (rawContent.texts && Array.isArray(rawContent.texts)) { texts = rawContent.texts.filter(text => text.content && text.content.trim() !== '' ); console.log(`📝 ${texts.length} texts extracted from texts array`); } // ContentItems format else if (rawContent.contentItems && Array.isArray(rawContent.contentItems)) { texts = rawContent.contentItems .filter(item => item.type === 'text' && item.content) .map(item => ({ title: item.title || 'Text', content: item.content })); console.log(`🆕 ${texts.length} texts extracted from contentItems`); } return this.finalizeTexts(texts); } finalizeTexts(texts) { // Validation and cleanup texts = texts.filter(text => text && typeof text.content === 'string' && text.content.trim() !== '' ); if (texts.length === 0) { console.error('❌ No valid texts found'); // Demo texts as fallback texts = [ { title: "Demo Text", content: "This is a demo text. It has multiple sentences. Each sentence will be displayed one by one. You can navigate using the buttons below." } ]; console.warn('🚨 Using demo texts'); } console.log(`✅ Text Reader: ${texts.length} texts finalized`); return texts; } createReaderInterface() { this.container.innerHTML = `
1 / 1
Use Next/Previous buttons to navigate through sentences
`; } setupEventListeners() { document.getElementById('next-sentence-btn').addEventListener('click', () => this.nextSentence()); document.getElementById('prev-sentence-btn').addEventListener('click', () => this.prevSentence()); document.getElementById('show-full-btn').addEventListener('click', () => this.showFullText()); document.getElementById('back-to-reading-btn').addEventListener('click', () => this.backToReading()); document.getElementById('text-selector').addEventListener('change', (e) => this.selectText(parseInt(e.target.value))); // Keyboard navigation document.addEventListener('keydown', (e) => { if (!this.isRunning) return; if (this.showingFullText) { if (e.key === 'Escape') this.backToReading(); } else { if (e.key === 'ArrowLeft') this.prevSentence(); else if (e.key === 'ArrowRight') this.nextSentence(); else if (e.key === 'Enter' || e.key === ' ') this.showFullText(); } }); } start() { console.log('📖 Text Reader: Starting'); this.isRunning = true; } restart() { console.log('🔄 Text Reader: Restarting'); this.reset(); this.start(); } reset() { this.currentTextIndex = 0; this.currentSentenceIndex = 0; this.isRunning = false; this.showingFullText = false; this.loadText(); } loadText() { if (this.currentTextIndex >= this.texts.length) { this.currentTextIndex = 0; } this.currentText = this.texts[this.currentTextIndex]; this.sentences = this.splitIntoSentences(this.currentText.content); this.currentSentenceIndex = 0; this.showingFullText = false; this.populateTextSelector(); this.updateDisplay(); this.updateUI(); } populateTextSelector() { const selector = document.getElementById('text-selector'); selector.innerHTML = ''; this.texts.forEach((text, index) => { const option = document.createElement('option'); option.value = index; option.textContent = text.title || `Text ${index + 1}`; if (index === this.currentTextIndex) { option.selected = true; } selector.appendChild(option); }); } selectText(textIndex) { if (textIndex >= 0 && textIndex < this.texts.length) { this.currentTextIndex = textIndex; this.currentText = this.texts[this.currentTextIndex]; this.sentences = this.splitIntoSentences(this.currentText.content); this.currentSentenceIndex = 0; // Always go back to sentence reading when changing text if (this.showingFullText) { this.backToReading(); } else { this.updateDisplay(); this.updateUI(); } this.showFeedback(`Switched to: ${this.currentText.title}`, 'info'); } } splitIntoSentences(text) { // Split by periods, exclamation marks, and question marks // Keep the punctuation with the sentence const sentences = text.split(/(?<=[.!?])\s+/) .filter(sentence => sentence.trim() !== '') .map(sentence => sentence.trim()); return sentences.length > 0 ? sentences : [text]; } nextSentence() { if (this.currentSentenceIndex < this.sentences.length - 1) { this.currentSentenceIndex++; this.updateDisplay(); this.updateUI(); } else { // End of sentences, show full text automatically this.showFullText(); } } prevSentence() { if (this.currentSentenceIndex > 0) { this.currentSentenceIndex--; this.updateDisplay(); this.updateUI(); } } showFullText() { this.showingFullText = true; document.getElementById('sentence-display').style.display = 'none'; document.getElementById('full-text-display').style.display = 'block'; document.getElementById('full-text-display').innerHTML = `

${this.currentText.content}

`; // Show full text navigation controls document.querySelector('.reader-controls').style.display = 'none'; document.getElementById('full-text-navigation').style.display = 'flex'; this.showFeedback('Full text displayed. Use dropdown to change text.', 'info'); } backToReading() { this.showingFullText = false; document.getElementById('sentence-display').style.display = 'block'; document.getElementById('full-text-display').style.display = 'none'; // Show sentence navigation controls document.querySelector('.reader-controls').style.display = 'flex'; document.getElementById('full-text-navigation').style.display = 'none'; this.updateDisplay(); this.updateUI(); this.showFeedback('Back to sentence-by-sentence reading.', 'info'); } // Text navigation methods removed - using dropdown instead updateDisplay() { if (this.showingFullText) return; const sentenceDisplay = document.getElementById('sentence-display'); const currentSentence = this.sentences[this.currentSentenceIndex]; sentenceDisplay.innerHTML = `
${currentSentence}
`; } updateUI() { // Update counters document.getElementById('sentence-counter').textContent = `${this.currentSentenceIndex + 1} / ${this.sentences.length}`; // Update button states document.getElementById('prev-sentence-btn').disabled = this.currentSentenceIndex === 0; document.getElementById('next-sentence-btn').disabled = false; document.getElementById('next-sentence-btn').textContent = this.currentSentenceIndex === this.sentences.length - 1 ? 'Full Text →' : 'Next →'; } // updateTextNavigation method removed - using dropdown instead showFeedback(message, type = 'info') { const feedbackArea = document.getElementById('feedback-area'); feedbackArea.innerHTML = `
${message}
`; } destroy() { this.isRunning = false; this.container.innerHTML = ''; } } // Module registration window.GameModules = window.GameModules || {}; window.GameModules.TextReader = TextReaderGame;