LE COURSIER || Journal d'Investigation & Géopolitique // script.js - Scripts personnalisés et utilitaires // Utilitaires généraux class LeCoursierUtils { static debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } static throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } } } static formatDate(date, locale = 'fr-FR') { return new Date(date).toLocaleDateString(locale, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } static truncateText(text, maxLength) { if (text.length <= maxLength) return text; return text.substr(0, maxLength).trim() + '...'; } static getRandomColor() { const colors = [ 'var(--rouge-panafricain)', 'var(--jaune-panafricain)', 'var(--vert-panafricain)' ]; return colors[Math.floor(Math.random() * colors.length)]; } } // Gestionnaire de cookies class CookieManager { static setCookie(name, value, days) { let expires = ""; if (days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = "; expires=" + date.toUTCString(); } document.cookie = name + "=" + (value || "") + expires + "; path=/"; } static getCookie(name) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) === ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); } return null; } static eraseCookie(name) { document.cookie = name + '=; Max-Age=-99999999;'; } } // Gestionnaire de thème class ThemeManager { constructor() { this.currentTheme = this.getStoredTheme() || 'light'; this.init(); } init() { this.applyTheme(); this.setupThemeToggle(); } getStoredTheme() { return CookieManager.getCookie('theme') || localStorage.getItem('lecoursier-theme'); } storeTheme(theme) { CookieManager.setCookie('theme', theme, 365); localStorage.setItem('lecoursier-theme', theme); } applyTheme() { document.documentElement.setAttribute('data-theme', this.currentTheme); // Appliquer les variables CSS spécifiques au thème if (this.currentTheme === 'dark') { document.documentElement.style.setProperty('--background', '#1a1a1a'); document.documentElement.style.setProperty('--text', '#ffffff'); document.documentElement.style.setProperty('--card-bg', '#2d2d2d'); document.documentElement.style.setProperty('--border-color', '#444'); } else { document.documentElement.style.setProperty('--background', '#ffffff'); document.documentElement.style.setProperty('--text', '#333333'); document.documentElement.style.setProperty('--card-bg', '#ffffff'); document.documentElement.style.setProperty('--border-color', '#ddd'); } } setupThemeToggle() { // Dans une implémentation réelle, on pourrait ajouter un bouton de changement de thème console.log('Theme manager initialisé. Thème actuel:', this.currentTheme); } toggleTheme() { this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light'; this.storeTheme(this.currentTheme); this.applyTheme(); } } // Gestionnaire d'analytics class AnalyticsManager { static trackEvent(category, action, label = null, value = null) { if (typeof gtag !== 'undefined') { gtag('event', action, { 'event_category': category, 'event_label': label, 'value': value }); } // Log pour le développement console.log(`Analytics: ${category} - ${action}`, { label, value }); } static trackPageView(pagePath) { if (typeof gtag !== 'undefined') { gtag('config', 'G-3VBXLVPQJ0', { 'page_path': pagePath }); } } } // Initialisation des fonctionnalités avancées document.addEventListener('DOMContentLoaded', function() { // Initialiser le gestionnaire de thème const themeManager = new ThemeManager(); // Suivre les événements utilisateur setupAnalyticsTracking(); // Gérer les formulaires avancés setupFormValidation(); // Initialiser les tooltips Bootstrap initBootstrapComponents(); // Configurer le service worker pour PWA (optionnel) if ('serviceWorker' in navigator) { registerServiceWorker(); } console.log('Scripts personnalisés initialisés'); }); function setupAnalyticsTracking() { // Suivre les clics sur les liens externes document.querySelectorAll('a[href^="http"]').forEach(link => { if (!link.href.includes(window.location.hostname)) { link.addEventListener('click', function() { AnalyticsManager.trackEvent( 'external_link', 'click', this.href, this.textContent.trim() ); }); } }); // Suivre les téléchargements document.querySelectorAll('a[href$=".pdf"], a[href$=".doc"], a[href$=".docx"]').forEach(link => { link.addEventListener('click', function() { AnalyticsManager.trackEvent( 'download', 'click', this.href, this.textContent.trim() ); }); }); // Suivre les soumissions de formulaire document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', function() { AnalyticsManager.trackEvent( 'form', 'submit', this.id || this.className, 1 ); }); }); // Suivre le temps passé sur la page let timeOnPage = 0; const interval = setInterval(() => { timeOnPage += 5; // Envoyer des événements à des intervalles spécifiques if (timeOnPage === 30) { AnalyticsManager.trackEvent('engagement', '30_seconds', window.location.pathname); } if (timeOnPage === 60) { AnalyticsManager.trackEvent('engagement', '1_minute', window.location.pathname); } if (timeOnPage === 180) { AnalyticsManager.trackEvent('engagement', '3_minutes', window.location.pathname); clearInterval(interval); } }, 5000); // Nettoyer l'intervalle quand la page est déchargée window.addEventListener('beforeunload', () => { clearInterval(interval); AnalyticsManager.trackEvent('engagement', 'time_on_page', window.location.pathname, timeOnPage); }); } function setupFormValidation() { const forms = document.querySelectorAll('form[data-validate]'); forms.forEach(form => { form.addEventListener('submit', function(e) { if (!validateForm(this)) { e.preventDefault(); showFormErrors(this); } }); // Validation en temps réel const inputs = form.querySelectorAll('input[required], textarea[required]'); inputs.forEach(input => { input.addEventListener('blur', function() { validateInput(this); }); }); }); } function validateForm(form) { let isValid = true; const inputs = form.querySelectorAll('input[required], textarea[required]'); inputs.forEach(input => { if (!validateInput(input)) { isValid = false; } }); return isValid; } function validateInput(input) { const value = input.value.trim(); let isValid = true; let errorMessage = ''; // Réinitialiser les styles d'erreur input.classList.remove('error'); const existingError = input.nextElementSibling; if (existingError && existingError.classList.contains('error-message')) { existingError.remove(); } // Validation de base if (!value) { isValid = false; errorMessage = 'Ce champ est requis'; } else if (input.type === 'email' && !isValidEmail(value)) { isValid = false; errorMessage = 'Veuillez entrer une adresse email valide'; } else if (input.type === 'tel' && !isValidPhone(value)) { isValid = false; errorMessage = 'Veuillez entrer un numéro de téléphone valide'; } // Afficher l'erreur si nécessaire if (!isValid) { input.classList.add('error'); const errorElement = document.createElement('div'); errorElement.className = 'error-message'; errorElement.textContent = errorMessage; errorElement.style.cssText = ` color: var(--rouge-panafricain); font-size: 0.8rem; margin-top: 5px; `; input.parentNode.insertBefore(errorElement, input.nextSibling); } return isValid; } function isValidEmail(email) { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); } function isValidPhone(phone) { const re = /^[\+]?[0-9\s\-\(\)]+$/; return re.test(phone); } function showFormErrors(form) { // Animation pour attirer l'attention sur les erreurs const firstError = form.querySelector('.error'); if (firstError) { firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Animation de pulsation firstError.style.animation = 'pulse 0.5s ease-in-out 3'; setTimeout(() => { firstError.style.animation = ''; }, 1500); } // Ajouter l'animation CSS const style = document.createElement('style'); style.textContent = ` @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(227, 27, 35, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(227, 27, 35, 0); } 100% { box-shadow: 0 0 0 0 rgba(227, 27, 35, 0); } } .error { border-color: var(--rouge-panafricain) !important; background-color: rgba(227, 27, 35, 0.05) !important; } `; document.head.appendChild(style); setTimeout(() => { if (style.parentNode) { style.parentNode.removeChild(style); } }, 2000); } function initBootstrapComponents() { // Initialiser les tooltips const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); // Initialiser les popovers const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')); popoverTriggerList.map(function (popoverTriggerEl) { return new bootstrap.Popover(popoverTriggerEl); }); } function registerServiceWorker() { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js').then(registration => { console.log('ServiceWorker enregistré avec succès:', registration.scope); }).catch(error => { console.log('Échec de l\'enregistrement du ServiceWorker:', error); }); }); } // Export pour utilisation dans d'autres modules if (typeof module !== 'undefined' && module.exports) { module.exports = { LeCoursierUtils, CookieManager, ThemeManager, AnalyticsManager }; }

LE COURSIER

Devoir d'enquêter, Courage de révéler

Média indépendant spécialisé dans l'enquête approfondie et l'analyse géopolitique. Notre mission : exercer un "devoir d'enquêter" et un "courage de révéler" pour informer le public, promouvoir la transparence et tenir les puissants responsables.

Notre Histoire & Mission

Fondé en 2017, LE COURSIER s'est imposé comme une référence pour ceux qui cherchent des informations vérifiées et des analyses approfondies sur les enjeux internationaux.

Investigation Rigoureuse

Nous recourons à des sources variées, multiplions les recoupements et résistons à la tentation de l'exclusivité pour garantir la fiabilité de nos informations.

Analyse Géopolitique

Décryptage des dynamiques internationales, des relations entre États et des enjeux stratégiques qui façonnent notre monde.

Indépendance Totale

Nous sommes indépendants de tous les pouvoirs économiques, politiques et idéologiques. Seuls nos lecteurs peuvent nous acheter.

Thèmes abordés

Politique étrangère Conflits & Sécurité Économie mondiale Mouvements sociaux Environnement Diplomatie Droits humains Technologie

Notre Équipe

Une équipe internationale de journalistes d'investigation, d'analystes géopolitiques et de chercheurs universitaires.

Gara Takpara

Gara Takpara

Rédacteur en chef

15 ans d'expérience en journalisme d'investigation

Amara Diallo

Amara Diallo

Analyste géopolitique

Docteure en relations internationales

Sophie N'Guessan

Sophie N'Guessan

Journaliste d'investigation

Spécialiste des questions économiques

Articles Récents

Découvrez nos dernières enquêtes

Aperçu complet des enjeux géopolitiques clés

Cette section présente des analyses centrales qui offrent des perspectives approfondies sur les conflits mondiaux et les développements sociétaux.

85

Analyses internationales

Cette explication décrit précisément la première étude géopolitique significative.

180

Rapports sur les conflits

Cette description met en lumière un aspect important des tensions mondiales.

220

Mouvements sociaux

Cette explication se concentre en détail sur le quatrième développement sociétal central.

Restez informé - commencez maintenant !

Profitez d'aperçus exclusifs et d'analyses approfondies qui élargiront votre perspective sur les événements mondiaux.

Découvrir plus

Soutenez notre indépendance

Notre indépendance financière garantit notre liberté éditoriale. Soutenez un journalisme d'investigation de qualité.

Abonnement Premium

Accédez à tous nos contenus exclusifs et analyses approfondies

9,99€ /mois
S'abonner

Faire un don

Soutenez notre travail avec un don ponctuel ou régulier

Devenir Membre

Rejoignez notre communauté et participez à nos événements exclusifs

Adhérer à la communauté

Starkes panafrikanisches Design mit prägnanter Botschaft

Unabhängiger Journalismus mit prägnantem Fokus

This section provides a detailed and comprehensive overview of your company’s mission, values, and history. It highlights the key principles and values that drive the purpose, goals, and long-term success of your brand and business operations.

Le Coursier

LE COURSIER präsentiert sorgfältig recherchierte Analysen und Berichte, die tiefere Einblicke in globale Zusammenhänge bieten und zum kritischen Denken anregen.

Tiefgehende Einblicke in geopolitische Konflikte und Sicherheit

Unsere sorgfältig recherchierten Artikel bieten fundiertes Wissen und kritische Analysen zu globalen Herausforderungen.

Internationale Beziehungen

Verstehen Sie die Dynamiken zwischen Staaten und ihre Auswirkungen auf die Weltpolitik.

Globale Sicherheit

Analysieren Sie komplexe Sicherheitsfragen und deren Einfluss auf internationale Stabilität.

Wirtschaft und Gesellschaft

Entdecken Sie die Zusammenhänge zwischen weltwirtschaftlichen Entwicklungen und sozialen Bewegungen.

Unabhängige Berichte, die den Mächtigen auf den Zahn fühlen

Entdecken Sie, wie wir tiefgehende Recherchen durchführen und komplexe geopolitische Zusammenhänge verständlich aufbereiten

Wie investigative Analyse globale Machtstrukturen offenlegt

Diese Reportage erläutert, wie gründliche Recherche und Faktenprüfung zur Aufdeckung internationaler Beziehungsgeflechte beitragen und Missstände offenlegen

Mit fundierter Recherche nachhaltigen Journalismus fördern

Dieser Beitrag zeigt, wie LE COURSIER durch kritische Analysen globale Themen beleuchtet und zur gesellschaftlichen Verantwortung anregt

Vertiefte Einblicke gewinnen durch unabhängige geopolitische Analyse

Dieser Artikel demonstriert, wie detaillierte Reportagen komplexe Außenpolitik, Konflikte und Wirtschaftsfragen verständlich machen