- Add intelligent content-game compatibility system with visual badges - Fix Adventure Reader to work with Dragon's Pearl content structure - Implement multi-column games grid for faster navigation - Add pronunciation display for Chinese vocabulary and sentences - Fix navigation breadcrumb to show proper hierarchy (Home > Levels > Content) - Add back buttons to all navigation pages - Improve JSONContentLoader to preserve story structure - Add comprehensive debugging and diagnostic tools 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
457 lines
21 KiB
HTML
457 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>🔄 Test: JS → JSON Ultra-Modulaire</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 20px;
|
|
background: #f5f5f5;
|
|
}
|
|
.test-section {
|
|
background: white;
|
|
padding: 20px;
|
|
margin: 10px 0;
|
|
border-radius: 8px;
|
|
border-left: 4px solid #3B82F6;
|
|
}
|
|
.success { border-left-color: #10B981; }
|
|
.error { border-left-color: #EF4444; }
|
|
pre {
|
|
background: #f8f9fa;
|
|
padding: 15px;
|
|
border-radius: 6px;
|
|
overflow-x: auto;
|
|
max-height: 500px;
|
|
font-size: 0.9rem;
|
|
line-height: 1.4;
|
|
}
|
|
.stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 15px;
|
|
margin: 15px 0;
|
|
}
|
|
.stat-card {
|
|
background: #f8f9fa;
|
|
padding: 15px;
|
|
border-radius: 6px;
|
|
text-align: center;
|
|
}
|
|
.stat-number {
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
color: #3B82F6;
|
|
}
|
|
.btn {
|
|
background: #3B82F6;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
margin: 10px 5px;
|
|
}
|
|
.btn:hover {
|
|
background: #2563eb;
|
|
}
|
|
.capabilities {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: 10px;
|
|
margin: 15px 0;
|
|
}
|
|
.capability {
|
|
background: #f0fdf4;
|
|
border: 1px solid #16a34a;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
font-size: 0.9rem;
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>🔄 Test: Conversion JS → JSON Ultra-Modulaire</h1>
|
|
<p>Démonstration complète du système : partir d'un module JS existant et générer un JSON ultra-modulaire</p>
|
|
|
|
<div id="results"></div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="js/core/websocket-logger.js"></script>
|
|
<script src="js/core/env-config.js"></script>
|
|
<script src="js/core/utils.js"></script>
|
|
<script src="js/core/json-content-loader.js"></script>
|
|
<script src="js/core/content-scanner.js"></script>
|
|
<script src="js/tools/ultra-modular-validator.js"></script>
|
|
<script src="js/content/sbs-level-7-8-new.js"></script>
|
|
|
|
<script>
|
|
class ReverseConverter {
|
|
constructor() {
|
|
this.results = document.getElementById('results');
|
|
this.contentScanner = new ContentScanner();
|
|
this.validator = new UltraModularValidator();
|
|
}
|
|
|
|
addResult(title, content, type = 'info') {
|
|
const div = document.createElement('div');
|
|
div.className = `test-section ${type}`;
|
|
div.innerHTML = `<h3>${title}</h3>${content}`;
|
|
this.results.appendChild(div);
|
|
}
|
|
|
|
async runConversion() {
|
|
this.addResult('🚀 Démarrage de la conversion inverse', 'Conversion JS → JSON Ultra-Modulaire...');
|
|
|
|
try {
|
|
// 1. Récupérer le module JS chargé
|
|
const jsModule = window.ContentModules?.SBSLevel78New;
|
|
if (!jsModule) {
|
|
throw new Error('Module SBSLevel78New non trouvé - vérifiez le chargement du script');
|
|
}
|
|
|
|
this.addResult('✅ Module JS Chargé',
|
|
`<p>Module trouvé: <strong>SBSLevel78New</strong></p>
|
|
<p>Contient: ${Object.keys(jsModule).join(', ')}</p>`,
|
|
'success');
|
|
|
|
// 2. Analyser les capacités du module existant
|
|
const capabilities = this.contentScanner.analyzeContentCapabilities(jsModule);
|
|
const compatibility = this.contentScanner.calculateGameCompatibility(capabilities);
|
|
|
|
this.displayCapabilities(capabilities, compatibility);
|
|
|
|
// 3. Créer la spécification JSON ultra-modulaire
|
|
const ultraModularSpec = this.convertToUltraModular(jsModule, capabilities, compatibility);
|
|
|
|
this.addResult('🛠️ Spécification Ultra-Modulaire Générée',
|
|
`<p>Conversion réussie vers le format ultra-modulaire complet!</p>
|
|
<pre>${JSON.stringify(ultraModularSpec, null, 2)}</pre>`,
|
|
'success');
|
|
|
|
// 4. Valider la spécification générée
|
|
const validation = await this.validator.validateSpecification(ultraModularSpec);
|
|
|
|
this.addResult('🔍 Validation de la Spécification Générée',
|
|
`<p><strong>Score de Qualité:</strong> ${validation.score}/100</p>
|
|
<p><strong>Valide:</strong> ${validation.valid ? '✅ Oui' : '❌ Non'}</p>
|
|
<p><strong>Erreurs:</strong> ${validation.errors.length}</p>
|
|
<p><strong>Avertissements:</strong> ${validation.warnings.length}</p>
|
|
<p><strong>Suggestions:</strong> ${validation.suggestions.length}</p>`,
|
|
validation.valid ? 'success' : 'error');
|
|
|
|
// 5. Créer le fichier JSON
|
|
this.generateJSONFile(ultraModularSpec);
|
|
|
|
this.addResult('✅ Test Complet Réussi',
|
|
'<p>La conversion JS → JSON Ultra-Modulaire fonctionne parfaitement!</p>' +
|
|
'<button class="btn" onclick="downloadJSON()">📥 Télécharger le JSON</button>',
|
|
'success');
|
|
|
|
} catch (error) {
|
|
this.addResult('❌ Erreur de Conversion', `Erreur: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
displayCapabilities(capabilities, compatibility) {
|
|
const activeCapabilities = Object.entries(capabilities)
|
|
.filter(([key, value]) => value === true || (typeof value === 'number' && value > 0))
|
|
.map(([key, value]) => typeof value === 'number' ? `${key}: ${value}` : key);
|
|
|
|
const compatibleGames = Object.entries(compatibility)
|
|
.filter(([game, compat]) => compat.compatible)
|
|
.map(([game, compat]) => `${game} (${compat.score}%)`);
|
|
|
|
this.addResult('📊 Analyse du Module JS',
|
|
`<div class="stats">
|
|
<div class="stat-card">
|
|
<div class="stat-number">${Object.keys(window.ContentModules.SBSLevel78New.vocabulary || {}).length}</div>
|
|
<div>Mots de vocabulaire</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">${capabilities.vocabularyDepth}</div>
|
|
<div>Profondeur vocab (1-6)</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">${compatibleGames.length}</div>
|
|
<div>Jeux compatibles</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">${capabilities.contentRichness.toFixed(1)}</div>
|
|
<div>Richesse contenu</div>
|
|
</div>
|
|
</div>
|
|
<h4>🎯 Capacités Détectées:</h4>
|
|
<div class="capabilities">
|
|
${activeCapabilities.map(cap => `<div class="capability">${cap}</div>`).join('')}
|
|
</div>
|
|
<h4>🎮 Jeux Compatibles:</h4>
|
|
<div class="capabilities">
|
|
${compatibleGames.map(game => `<div class="capability">${game}</div>`).join('')}
|
|
</div>`,
|
|
'success');
|
|
}
|
|
|
|
convertToUltraModular(jsModule, capabilities, compatibility) {
|
|
// Générer l'ID basé sur le nom du module
|
|
const moduleId = 'sbs_level_7_8_converted_from_js';
|
|
|
|
// Analyser le vocabulaire pour détecter la complexité
|
|
const vocabularyAnalysis = this.analyzeVocabularyComplexity(jsModule.vocabulary || {});
|
|
|
|
// Créer la spécification ultra-modulaire complète
|
|
const ultraModularSpec = {
|
|
// ========================================================================================================
|
|
// CORE METADATA SECTION
|
|
// ========================================================================================================
|
|
id: moduleId,
|
|
name: "SBS Level 7-8 (Converted from JS)",
|
|
description: "Comprehensive English learning content covering housing, clothing, and cultural topics - converted from legacy JavaScript format to ultra-modular specification",
|
|
|
|
// Difficulty system (1-10 scale)
|
|
difficulty_level: 6, // Intermediate level based on content analysis
|
|
|
|
// Language configuration (original_lang/user_lang pattern)
|
|
original_lang: "english",
|
|
user_lang: "chinese",
|
|
|
|
// Icon system with fallback
|
|
icon: {
|
|
primary: "🏠",
|
|
fallback: "📚",
|
|
emoji: "🏠"
|
|
},
|
|
|
|
// Enhanced metadata
|
|
tags: ["housing", "clothing", "daily_life", "vocabulary", "sbs_textbook", "intermediate"],
|
|
skills_covered: ["vocabulary_acquisition", "reading_comprehension", "cultural_awareness", "daily_communication"],
|
|
target_audience: {
|
|
age_range: [12, 16],
|
|
proficiency_level: "intermediate",
|
|
learning_goals: ["daily_vocabulary", "cultural_understanding"]
|
|
},
|
|
estimated_duration: 45,
|
|
pedagogical_approach: "communicative_language_teaching",
|
|
|
|
// ========================================================================================================
|
|
// VOCABULARY SECTION (Progressive Enhancement)
|
|
// ========================================================================================================
|
|
vocabulary: this.enhanceVocabulary(jsModule.vocabulary || {}, vocabularyAnalysis),
|
|
|
|
// ========================================================================================================
|
|
// SENTENCES SECTION
|
|
// ========================================================================================================
|
|
sentences: this.enhanceSentences(jsModule.sentences || []),
|
|
|
|
// ========================================================================================================
|
|
// METADATA AND ANALYTICS
|
|
// ========================================================================================================
|
|
content_analytics: {
|
|
vocabulary_count: Object.keys(jsModule.vocabulary || {}).length,
|
|
sentence_count: (jsModule.sentences || []).length,
|
|
difficulty_distribution: vocabularyAnalysis.difficultyDistribution,
|
|
topic_coverage: this.extractTopics(jsModule.vocabulary || {}),
|
|
converted_from: "legacy_javascript",
|
|
conversion_timestamp: new Date().toISOString(),
|
|
detected_capabilities: capabilities,
|
|
game_compatibility: compatibility
|
|
},
|
|
|
|
// ========================================================================================================
|
|
// SYSTEM METADATA
|
|
// ========================================================================================================
|
|
system_metadata: {
|
|
format_version: "2.0",
|
|
specification: "ultra_modular",
|
|
backwards_compatible: true,
|
|
generated_by: "reverse_converter",
|
|
validation_required: false
|
|
}
|
|
};
|
|
|
|
// Stocker globalement pour l'export
|
|
window.generatedUltraModularSpec = ultraModularSpec;
|
|
|
|
return ultraModularSpec;
|
|
}
|
|
|
|
analyzeVocabularyComplexity(vocabulary) {
|
|
const analysis = {
|
|
totalWords: Object.keys(vocabulary).length,
|
|
simpleTranslations: 0,
|
|
complexPhrases: 0,
|
|
categories: new Set(),
|
|
difficultyDistribution: { basic: 0, intermediate: 0, advanced: 0 }
|
|
};
|
|
|
|
for (const [word, translation] of Object.entries(vocabulary)) {
|
|
// Analyser la complexité
|
|
if (word.includes(' ') || word.includes('/')) {
|
|
analysis.complexPhrases++;
|
|
analysis.difficultyDistribution.intermediate++;
|
|
} else if (word.length > 10) {
|
|
analysis.difficultyDistribution.advanced++;
|
|
} else {
|
|
analysis.simpleTranslations++;
|
|
analysis.difficultyDistribution.basic++;
|
|
}
|
|
|
|
// Extraire les catégories
|
|
if (word.includes('shirt') || word.includes('coat') || word.includes('dress')) {
|
|
analysis.categories.add('clothing');
|
|
} else if (word.includes('building') || word.includes('apartment')) {
|
|
analysis.categories.add('housing');
|
|
} else if (word.includes('street') || word.includes('town')) {
|
|
analysis.categories.add('places');
|
|
}
|
|
}
|
|
|
|
analysis.categories = Array.from(analysis.categories);
|
|
return analysis;
|
|
}
|
|
|
|
enhanceVocabulary(originalVocab, analysis) {
|
|
const enhanced = {};
|
|
|
|
for (const [word, translation] of Object.entries(originalVocab)) {
|
|
// Créer des objets enrichis de niveau 2-3
|
|
enhanced[word] = {
|
|
user_language: translation,
|
|
original_language: word,
|
|
type: this.detectWordType(word),
|
|
|
|
// Ajouter des contextes spécifiques selon le type
|
|
usage_context: this.getUsageContext(word),
|
|
|
|
// Niveau de difficulté basé sur l'analyse
|
|
difficulty_level: this.getWordDifficulty(word),
|
|
|
|
// Catégorie sémantique
|
|
semantic_category: this.getSemanticCategory(word)
|
|
};
|
|
}
|
|
|
|
return enhanced;
|
|
}
|
|
|
|
enhanceSentences(originalSentences) {
|
|
return originalSentences.map((sentence, index) => ({
|
|
id: `sentence_${index + 1}`,
|
|
original_language: sentence.english,
|
|
user_language: sentence.chinese,
|
|
difficulty_level: sentence.english.split(' ').length > 8 ? 7 : 5,
|
|
grammatical_focus: this.detectGrammarFocus(sentence.english),
|
|
communicative_function: this.detectCommunicativeFunction(sentence.english),
|
|
cultural_context: this.detectCulturalContext(sentence.english)
|
|
}));
|
|
}
|
|
|
|
// Helper methods
|
|
detectWordType(word) {
|
|
if (word.endsWith('ing')) return 'verb_gerund';
|
|
if (word.endsWith('ed')) return 'verb_past';
|
|
if (word.includes(' ')) return 'phrase';
|
|
if (word.endsWith('s') && !word.endsWith('ss')) return 'noun_plural';
|
|
return 'noun';
|
|
}
|
|
|
|
getUsageContext(word) {
|
|
if (word.includes('apartment') || word.includes('building')) return 'housing_description';
|
|
if (word.includes('shirt') || word.includes('coat')) return 'clothing_description';
|
|
if (word.includes('street') || word.includes('town')) return 'location_description';
|
|
return 'general_communication';
|
|
}
|
|
|
|
getWordDifficulty(word) {
|
|
if (word.length <= 5) return 3;
|
|
if (word.length <= 8) return 5;
|
|
if (word.includes(' ') || word.includes('/')) return 6;
|
|
return 7;
|
|
}
|
|
|
|
getSemanticCategory(word) {
|
|
if (word.match(/shirt|coat|dress|pants|jacket|shoes/)) return 'clothing';
|
|
if (word.match(/building|apartment|house|room|elevator/)) return 'housing';
|
|
if (word.match(/street|town|center|avenue|sidewalk/)) return 'locations';
|
|
if (word.match(/noise|convenient|upset|central/)) return 'descriptive';
|
|
return 'general';
|
|
}
|
|
|
|
detectGrammarFocus(sentence) {
|
|
if (sentence.includes('is in') || sentence.includes('are in')) return 'location_prepositions';
|
|
if (sentence.includes("'s")) return 'possessive_case';
|
|
if (sentence.includes('There\'s') || sentence.includes('There are')) return 'existential_there';
|
|
return 'declarative_statement';
|
|
}
|
|
|
|
detectCommunicativeFunction(sentence) {
|
|
if (sentence.includes('?')) return 'questioning';
|
|
if (sentence.includes('!')) return 'exclamation';
|
|
if (sentence.toLowerCase().includes('please')) return 'request';
|
|
return 'description';
|
|
}
|
|
|
|
detectCulturalContext(sentence) {
|
|
if (sentence.includes('apartment building')) return 'urban_living';
|
|
if (sentence.includes('center of town')) return 'city_geography';
|
|
if (sentence.includes('noise')) return 'urban_challenges';
|
|
return 'daily_life';
|
|
}
|
|
|
|
extractTopics(vocabulary) {
|
|
const topics = new Set();
|
|
for (const word of Object.keys(vocabulary)) {
|
|
if (word.match(/shirt|coat|dress|pants|jacket|shoes|clothing/)) topics.add('clothing');
|
|
if (word.match(/building|apartment|house|room|elevator|housing/)) topics.add('housing');
|
|
if (word.match(/street|town|center|avenue|places/)) topics.add('places');
|
|
}
|
|
return Array.from(topics);
|
|
}
|
|
|
|
generateJSONFile(spec) {
|
|
// Créer le contenu JSON avec beautification
|
|
const jsonContent = JSON.stringify(spec, null, 2);
|
|
|
|
// Stocker pour le téléchargement
|
|
window.downloadableJSON = jsonContent;
|
|
|
|
this.addResult('📁 Fichier JSON Généré',
|
|
`<p>Fichier JSON ultra-modulaire créé avec succès!</p>
|
|
<p><strong>Taille:</strong> ${(jsonContent.length / 1024).toFixed(1)} KB</p>
|
|
<p><strong>Lignes:</strong> ${jsonContent.split('\\n').length}</p>
|
|
<button class="btn" onclick="downloadJSON()">📥 Télécharger JSON</button>
|
|
<button class="btn" onclick="copyToClipboard()">📋 Copier JSON</button>`);
|
|
}
|
|
}
|
|
|
|
// Fonctions globales
|
|
function downloadJSON() {
|
|
const content = window.downloadableJSON;
|
|
const blob = new Blob([content], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'sbs-level-7-8-ultra-modular.json';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
function copyToClipboard() {
|
|
navigator.clipboard.writeText(window.downloadableJSON).then(() => {
|
|
alert('JSON copié dans le presse-papier !');
|
|
});
|
|
}
|
|
|
|
// Démarrer le test
|
|
document.addEventListener('DOMContentLoaded', async function() {
|
|
const converter = new ReverseConverter();
|
|
await converter.runConversion();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |