Class_generator/Legacy/js/core/utils.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

176 lines
5.0 KiB
JavaScript

// === UTILITIES GÉNÉRALES ===
const Utils = {
// Gestion des paramètres URL
getUrlParams() {
const params = new URLSearchParams(window.location.search);
return {
page: params.get('page') || 'home',
game: params.get('game') || null,
content: params.get('content') || null
};
},
setUrlParams(params) {
const url = new URL(window.location);
Object.keys(params).forEach(key => {
if (params[key]) {
url.searchParams.set(key, params[key]);
} else {
url.searchParams.delete(key);
}
});
window.history.pushState({}, '', url);
},
// Affichage/masquage du loading
showLoading() {
document.getElementById('loading').classList.add('show');
},
hideLoading() {
document.getElementById('loading').classList.remove('show');
},
// Notifications toast
showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? 'var(--secondary-color)' :
type === 'error' ? 'var(--error-color)' : 'var(--primary-color)'};
color: white;
padding: 15px 20px;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
z-index: 1001;
animation: slideIn 0.3s ease-out;
`;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideOut 0.3s ease-in';
setTimeout(() => document.body.removeChild(toast), 300);
}, 3000);
},
// Animation d'éléments
animateElement(element, animation, duration = 300) {
return new Promise(resolve => {
element.style.animation = `${animation} ${duration}ms ease-out`;
setTimeout(() => {
element.style.animation = '';
resolve();
}, duration);
});
},
// Génération d'ID unique
generateId() {
return Math.random().toString(36).substr(2, 9);
},
// Mélange d'array (Fisher-Yates)
shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
},
// Sélection aléatoire d'éléments
getRandomItems(array, count) {
const shuffled = this.shuffleArray(array);
return shuffled.slice(0, count);
},
// Formatage du temps
formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, '0')}`;
},
// Debounce pour événements
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
// Vérification de support audio
canPlayAudio() {
return 'Audio' in window;
},
// Chargement d'image avec promise
loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
},
// Stockage local sécurisé
storage: {
set(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (e) {
logSh('LocalStorage not available:', e, 'WARN');
}
},
get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (e) {
logSh('LocalStorage read error:', e, 'WARN');
return defaultValue;
}
},
remove(key) {
try {
localStorage.removeItem(key);
} catch (e) {
logSh('LocalStorage remove error:', e, 'WARN');
}
}
}
};
// Ajout de styles CSS dynamiques pour les animations
const styleSheet = document.createElement('style');
styleSheet.textContent = `
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(100%); opacity: 0; }
}
`;
document.head.appendChild(styleSheet);
// Export global
window.Utils = Utils;