Class_generator/Legacy/js/core/browser-logger.js
StillHammer 38920cc858 Complete architectural rewrite with ultra-modular system
Major Changes:
- Moved legacy system to Legacy/ folder for archival
- Built new modular architecture with strict separation of concerns
- Created core system: Module, EventBus, ModuleLoader, Router
- Added Application bootstrap with auto-start functionality
- Implemented development server with ES6 modules support
- Created comprehensive documentation and project context
- Converted SBS-7-8 content to JSON format
- Copied all legacy games and content to new structure

New Architecture Features:
- Sealed modules with WeakMap private data
- Strict dependency injection system
- Event-driven communication only
- Inviolable responsibility patterns
- Auto-initialization without commands
- Component-based UI foundation ready

Technical Stack:
- Vanilla JS/HTML/CSS only
- ES6 modules with proper imports/exports
- HTTP development server (no file:// protocol)
- Modular CSS with component scoping
- Comprehensive error handling and debugging

Ready for Phase 2: Converting legacy modules to new architecture

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 07:08:39 +08:00

360 lines
11 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ========================================
// FICHIER: js/core/browser-logger.js - VERSION NAVIGATEUR
// Système de logging adapté du système ErrorReporting.js pour le navigateur
// ========================================
class BrowserLogger {
constructor() {
this.logs = [];
this.maxLogs = 1000; // Limite pour éviter l'explosion mémoire
this.logContainer = null;
this.isVisible = false;
// Niveaux de log avec couleurs
this.levels = {
TRACE: { value: 10, color: '#6c757d', emoji: '🔍' },
DEBUG: { value: 20, color: '#007bff', emoji: '🐛' },
INFO: { value: 30, color: '#28a745', emoji: '' },
WARN: { value: 40, color: '#ffc107', emoji: '⚠️' },
ERROR: { value: 50, color: '#dc3545', emoji: '❌' }
};
this.minLevel = 'DEBUG'; // Niveau minimum affiché
this.init();
}
init() {
// Créer l'interface de log
this.createLogUI();
// Intercepter les erreurs globales
window.addEventListener('error', (event) => {
this.logSh(`Erreur JavaScript: ${event.error.message}`, 'ERROR');
});
window.addEventListener('unhandledrejection', (event) => {
this.logSh(`Promise rejetée: ${event.reason}`, 'ERROR');
});
logSh('🚀 BrowserLogger initialisé', 'INFO');
}
createLogUI() {
// Créer le conteneur de log
const logContainer = document.createElement('div');
logContainer.id = 'browser-logger';
logContainer.innerHTML = `
<div class="logger-header">
<h3>📋 System Logs</h3>
<div class="logger-controls">
<select id="log-level-filter">
<option value="TRACE">TRACE</option>
<option value="DEBUG" selected>DEBUG</option>
<option value="INFO">INFO</option>
<option value="WARN">WARN</option>
<option value="ERROR">ERROR</option>
</select>
<button id="clear-logs">🗑️</button>
<button id="toggle-logger">❌</button>
</div>
</div>
<div class="logger-content" id="logger-content">
<div class="log-entry info">
<span class="log-time">${this.formatTime(new Date())}</span>
<span class="log-level">INFO</span>
<span class="log-message">Logger initialisé</span>
</div>
</div>
`;
// Ajouter les styles CSS
const style = document.createElement('style');
style.textContent = `
#browser-logger {
position: fixed;
top: 80px;
right: 10px;
width: 400px;
max-height: 500px;
background: #fff;
border: 2px solid #007bff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
z-index: 10000;
display: none;
}
#browser-logger.visible {
display: block;
}
.logger-header {
background: #007bff;
color: white;
padding: 8px 12px;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 6px 6px 0 0;
}
.logger-header h3 {
margin: 0;
font-size: 14px;
}
.logger-controls {
display: flex;
gap: 5px;
align-items: center;
}
.logger-controls select {
padding: 2px 4px;
font-size: 11px;
border: none;
border-radius: 3px;
}
.logger-controls button {
background: rgba(255,255,255,0.2);
border: none;
color: white;
padding: 2px 6px;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
.logger-controls button:hover {
background: rgba(255,255,255,0.3);
}
.logger-content {
max-height: 400px;
overflow-y: auto;
padding: 0;
background: #f8f9fa;
}
.log-entry {
padding: 4px 8px;
border-bottom: 1px solid #e9ecef;
display: flex;
gap: 8px;
font-size: 11px;
line-height: 1.4;
}
.log-entry:hover {
background: #e9ecef;
}
.log-time {
color: #6c757d;
min-width: 60px;
font-weight: bold;
}
.log-level {
min-width: 50px;
font-weight: bold;
text-align: center;
border-radius: 3px;
padding: 1px 4px;
}
.log-level.trace { background: #f8f9fa; color: #6c757d; }
.log-level.debug { background: #cce5ff; color: #007bff; }
.log-level.info { background: #d4edda; color: #28a745; }
.log-level.warn { background: #fff3cd; color: #856404; }
.log-level.error { background: #f8d7da; color: #721c24; }
.log-message {
flex: 1;
word-break: break-word;
}
.log-message.trace { color: #6c757d; }
.log-message.network { color: #17a2b8; font-weight: bold; }
.log-message.auth { color: #6610f2; font-weight: bold; }
`;
document.head.appendChild(style);
document.body.appendChild(logContainer);
this.logContainer = logContainer;
this.logContent = logContainer.querySelector('#logger-content');
// Event listeners
document.getElementById('toggle-logger').addEventListener('click', () => {
this.toggle();
});
document.getElementById('clear-logs').addEventListener('click', () => {
this.clear();
});
document.getElementById('log-level-filter').addEventListener('change', (e) => {
this.minLevel = e.target.value;
this.refreshDisplay();
});
// Raccourci clavier pour toggle
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'L') {
this.toggle();
}
});
}
formatTime(date) {
return date.toLocaleTimeString('fr-FR', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
logSh(message, level = 'INFO') {
// Sécuriser le level pour éviter les erreurs
if (typeof level !== 'string') {
level = 'INFO';
}
const timestamp = new Date();
const logEntry = {
timestamp,
level: level.toUpperCase(),
message,
id: Date.now() + Math.random()
};
// Ajouter à la liste des logs
this.logs.push(logEntry);
// Limiter le nombre de logs en mémoire
if (this.logs.length > this.maxLogs) {
this.logs.shift();
}
// Log aussi dans la console navigateur (gardé pour le debugging)
if (level !== 'TRACE' && level !== 'DEBUG') { // Éviter le spam en console
const consoleMethod = level.toLowerCase() === 'error' ? 'error' :
level.toLowerCase() === 'warn' ? 'warn' : 'log';
console[consoleMethod](`[${this.formatTime(timestamp)}] ${level}: ${message}`);
}
// Mettre à jour l'affichage si visible
if (this.isVisible) {
this.addLogToDisplay(logEntry);
}
return logEntry;
}
addLogToDisplay(logEntry) {
const levelInfo = this.levels[logEntry.level] || this.levels.INFO;
// Vérifier si on doit afficher ce niveau
if (levelInfo.value < this.levels[this.minLevel].value) {
return;
}
const logElement = document.createElement('div');
logElement.className = `log-entry ${logEntry.level.toLowerCase()}`;
logElement.innerHTML = `
<span class="log-time">${this.formatTime(logEntry.timestamp)}</span>
<span class="log-level ${logEntry.level.toLowerCase()}">${logEntry.level}</span>
<span class="log-message ${this.getMessageClass(logEntry.message)}">${this.formatMessage(logEntry.message)}</span>
`;
this.logContent.appendChild(logElement);
// Auto-scroll vers le bas
this.logContent.scrollTop = this.logContent.scrollHeight;
// Limiter les éléments DOM affichés
const entries = this.logContent.querySelectorAll('.log-entry');
if (entries.length > 200) {
entries[0].remove();
}
}
getMessageClass(message) {
if (message.includes('🌐') || message.includes('📡') || message.includes('connexion')) {
return 'network';
}
if (message.includes('🔐') || message.includes('auth') || message.includes('Headers')) {
return 'auth';
}
return '';
}
formatMessage(message) {
// Échapper le HTML mais garder les emojis
return message.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
refreshDisplay() {
if (!this.isVisible) return;
this.logContent.innerHTML = '';
this.logs.forEach(logEntry => {
this.addLogToDisplay(logEntry);
});
}
show() {
this.isVisible = true;
this.logContainer.classList.add('visible');
this.refreshDisplay();
this.logSh('Logger affiché', 'DEBUG');
}
hide() {
this.isVisible = false;
this.logContainer.classList.remove('visible');
this.logSh('Logger masqué', 'DEBUG');
}
toggle() {
if (this.isVisible) {
this.hide();
} else {
this.show();
}
}
clear() {
this.logs = [];
if (this.logContent) {
this.logContent.innerHTML = '';
}
this.logSh('Logs effacés', 'INFO');
}
// Méthodes de convenance
trace(message) { return this.logSh(message, 'TRACE'); }
debug(message) { return this.logSh(message, 'DEBUG'); }
info(message) { return this.logSh(message, 'INFO'); }
warn(message) { return this.logSh(message, 'WARN'); }
error(message) { return this.logSh(message, 'ERROR'); }
}
// Instance globale
window.logger = new BrowserLogger();
// Fonction globale compatible avec le système original
window.logSh = (message, level = 'INFO') => {
return window.logger.logSh(message, level);
};
// Export pour compatibilité
if (typeof module !== 'undefined' && module.exports) {
module.exports = { BrowserLogger };
}