// UI Manager Module // Responsible for creating and managing the user interface elements class UIManager { constructor(settings) { this.settings = settings || { debugMode: false, }; this.buttonCreated = false; this.analysisResults = null; this.pageType = 'general'; this.suspiciousSiteCheck = null; } log(message, data = null) { if (this.settings.debugMode) { console.log(`UIManager: ${message}`, data || ""); } } setPageType(pageType) { this.pageType = pageType; } createButton(analysisResults = null) { if (analysisResults) { this.analysisResults = analysisResults; } if (!this.analysisResults) { console.error('DIMA: Aucun résultat d\'analyse disponible pour créer le bouton'); return; } // Vérifier si le site est suspect this.suspiciousSiteCheck = window.checkSuspiciousSite ? window.checkSuspiciousSite(window.location.href) : { isSuspicious: false }; try { // Supprimer bouton existant document.getElementById('dima-btn')?.remove(); document.getElementById('dima-suspicious-alert')?.remove(); if (this.buttonCreated) return; // Créer le bouton principal const button = document.createElement('div'); button.id = 'dima-btn'; button.innerHTML = `
🧠 ${this.analysisResults.globalScore} ${this.analysisResults.riskLevel}
`; button.style.cssText = ` position: fixed !important; top: 20px !important; right: 20px !important; z-index: 999999 !important; background: linear-gradient(135deg, ${this.analysisResults.riskColor}, ${this.adjustColor(this.analysisResults.riskColor, -20)}) !important; color: white !important; padding: 12px 16px !important; border-radius: 25px !important; cursor: pointer !important; font-family: 'Segoe UI', Arial, sans-serif !important; font-size: 14px !important; box-shadow: 0 4px 15px rgba(0,0,0,0.2), 0 2px 5px rgba(0,0,0,0.1) !important; border: 2px solid rgba(255,255,255,0.2) !important; user-select: none !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; backdrop-filter: blur(10px) !important; `; button.title = this.generateTooltip(); // Événements button.addEventListener('click', () => this.showModal()); button.addEventListener('mouseenter', () => { button.style.transform = 'scale(1.05) translateY(-2px)'; button.style.boxShadow = '0 6px 20px rgba(0,0,0,0.3), 0 4px 8px rgba(0,0,0,0.2)'; }); button.addEventListener('mouseleave', () => { button.style.transform = 'scale(1) translateY(0)'; button.style.boxShadow = '0 4px 15px rgba(0,0,0,0.2), 0 2px 5px rgba(0,0,0,0.1)'; }); document.body?.appendChild(button); // Créer l'alerte de site suspect si nécessaire if (this.suspiciousSiteCheck.isSuspicious) { this.createSuspiciousSiteAlert(); } this.buttonCreated = true; this.log('Bouton créé avec succès'); } catch (error) { console.error('DIMA: Erreur création bouton:', error); } } createSuspiciousSiteAlert() { const { siteInfo, riskConfig } = this.suspiciousSiteCheck; const alert = document.createElement('div'); alert.id = 'dima-suspicious-alert'; alert.innerHTML = `
${riskConfig.icon}
${riskConfig.label}
Vigilance : ce site appartient à un dispositif de manipulation de l'information identifié.
`; alert.style.cssText = ` position: fixed !important; top: 70px !important; right: 20px !important; z-index: 999998 !important; background: linear-gradient(135deg, ${riskConfig.color}, ${this.adjustColor(riskConfig.color, -15)}) !important; color: white !important; padding: 16px !important; border-radius: 12px !important; max-width: 350px !important; font-family: 'Segoe UI', Arial, sans-serif !important; box-shadow: 0 6px 20px rgba(0,0,0,0.3) !important; border: 2px solid rgba(255,255,255,0.2) !important; animation: slideInRight 0.4s ease-out !important; backdrop-filter: blur(10px) !important; `; document.body?.appendChild(alert); // Événements document.getElementById('dima-suspicious-details')?.addEventListener('click', () => { this.showSuspiciousSiteDetails(); }); document.getElementById('dima-suspicious-close')?.addEventListener('click', () => { alert.remove(); }); // Hover effects const detailsBtn = document.getElementById('dima-suspicious-details'); if (detailsBtn) { detailsBtn.addEventListener('mouseenter', () => { detailsBtn.style.transform = 'translateY(-1px)'; detailsBtn.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)'; }); detailsBtn.addEventListener('mouseleave', () => { detailsBtn.style.transform = 'translateY(0)'; detailsBtn.style.boxShadow = 'none'; }); } const closeBtn = document.getElementById('dima-suspicious-close'); if (closeBtn) { closeBtn.addEventListener('mouseenter', () => { closeBtn.style.opacity = '1'; }); closeBtn.addEventListener('mouseleave', () => { closeBtn.style.opacity = '0.7'; }); } } showSuspiciousSiteDetails() { const { siteInfo, riskConfig } = this.suspiciousSiteCheck; // Créer modal avec détails const detailsModal = document.createElement('div'); detailsModal.id = 'dima-suspicious-details-modal'; detailsModal.style.cssText = ` position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; background: rgba(0,0,0,0.75) !important; backdrop-filter: blur(5px) !important; z-index: 10000000 !important; display: flex !important; align-items: center !important; justify-content: center !important; font-family: 'Segoe UI', Arial, sans-serif !important; animation: fadeIn 0.3s ease-out !important; `; const logoUrl = chrome.runtime.getURL('M82-logo-16.png'); detailsModal.innerHTML = `
M82 Project

Site Suspect Identifié

${riskConfig.icon} ${riskConfig.label}

⚠️ Avertissement

${riskConfig.message}

📋 Détails de l'identification

Raison :
${siteInfo.reason}
Source du rapport :
${siteInfo.source}
Date d'identification :
${new Date(siteInfo.identifiedDate).toLocaleDateString('fr-FR')}
${siteInfo.tags && siteInfo.tags.length > 0 ? `
Catégories :
${siteInfo.tags.map(tag => ` ${tag} `).join('')}
` : ''}

💡 Recommandations

  • Vérifiez les informations auprès de sources fiables
  • Consultez plusieurs sources avant de partager
  • Soyez attentif aux techniques de manipulation détectées
  • Signalez le contenu suspect si nécessaire
Base de données maintenue par M82 Project
`; detailsModal.addEventListener('click', (e) => { if (e.target === detailsModal) detailsModal.remove(); }); document.body.appendChild(detailsModal); } adjustColor(color, amount) { const num = parseInt(color.replace("#", ""), 16); const amt = Math.round(2.55 * amount); const R = (num >> 16) + amt; const G = (num >> 8 & 0x00FF) + amt; const B = (num & 0x0000FF) + amt; return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); } generateTooltip() { const techniques = this.analysisResults.detectedTechniques.slice(0, 3); let tooltip = `DIMA Score: ${this.analysisResults.globalScore} (${this.analysisResults.riskLevel}) ${this.analysisResults.detectedTechniques.length} techniques détectées ${techniques.map(t => `• ${t.nom}`).join('\n')}`; if (this.suspiciousSiteCheck.isSuspicious) { tooltip += `\n\n⚠️ SITE SUSPECT IDENTIFIÉ`; } tooltip += `\nContenu: ${this.analysisResults.contentLength} caractères`; return tooltip; } generatePhaseAnalysis() { if (!this.analysisResults || !this.analysisResults.detectedTechniques || this.analysisResults.detectedTechniques.length === 0) { return ''; } // Analyser les techniques par phase const phaseStats = { 'Detect': { count: 0, totalScore: 0, techniques: [], icon: '👁️', color: '#3498db' }, 'Informer': { count: 0, totalScore: 0, techniques: [], icon: '📢', color: '#e67e22' }, 'Mémoriser': { count: 0, totalScore: 0, techniques: [], icon: '🧠', color: '#9b59b6' }, 'Agir': { count: 0, totalScore: 0, techniques: [], icon: '⚡', color: '#e74c3c' } }; this.analysisResults.detectedTechniques.forEach(technique => { const phase = technique.phase || 'Detect'; if (phaseStats[phase]) { phaseStats[phase].count++; phaseStats[phase].totalScore += technique.weightedScore || technique.score || 0; phaseStats[phase].techniques.push(technique); } }); // Calculer les pourcentages const totalTechniques = this.analysisResults.detectedTechniques.length; const totalScore = Object.values(phaseStats).reduce((sum, phase) => sum + phase.totalScore, 0); // Trouver la phase dominante let dominantPhase = null; let maxCount = 0; Object.entries(phaseStats).forEach(([phase, stats]) => { if (stats.count > maxCount) { maxCount = stats.count; dominantPhase = phase; } }); // Générer l'explication contextuelle const explanation = this.generatePhaseExplanation(dominantPhase, phaseStats, totalTechniques); // Générer le HTML return `

📊 Analyse par Phase DIMA (Detect, Informer, Mémoriser, Agir)

${phaseStats[dominantPhase]?.icon || '💡'}

Analyse : Phase dominante "${dominantPhase}"

${explanation}

${Object.entries(phaseStats).map(([phase, stats]) => { const percentage = totalTechniques > 0 ? Math.round((stats.count / totalTechniques) * 100) : 0; const scorePercentage = totalScore > 0 ? Math.round((stats.totalScore / totalScore) * 100) : 0; const isActive = stats.count > 0; return `
${stats.icon}
${phase}
${stats.count}
${percentage}% techniques
${isActive ? `
${scorePercentage}% du score
` : ''}
`; }).join('')}

Distribution du score par phase

${Object.entries(phaseStats).map(([phase, stats]) => { const percentage = totalScore > 0 ? (stats.totalScore / totalScore) * 100 : 0; const displayScore = stats.totalScore.toFixed(1); return `
${stats.icon} ${phase} ${displayScore} pts (${Math.round(percentage)}%)
`; }).join('')}
ℹ️ Comprendre les phases DIMA
👁️ Detect (Détecter) : Techniques visant à capter l'attention et identifier les cibles sensibles aux messages.
📢 Informer : Techniques de transmission et cadrage de l'information pour influencer la perception.
🧠 Mémoriser : Techniques d'ancrage mémoriel et de renforcement des messages dans la durée.
⚡ Agir : Techniques d'incitation à l'action et de mobilisation comportementale.
`; } generatePhaseExplanation(dominantPhase, phaseStats, totalTechniques) { const explanations = { 'Detect': `Le contenu utilise principalement des techniques de détection et captation d'attention (${phaseStats['Detect'].count}/${totalTechniques} techniques). Cela suggère une stratégie axée sur l'identification des publics réceptifs et l'accroche initiale. Le contenu cherche à attirer et cibler des audiences spécifiques.`, 'Informer': `Le contenu se concentre sur des techniques de transmission et cadrage de l'information (${phaseStats['Informer'].count}/${totalTechniques} techniques). L'objectif est de contrôler la perception de l'information via le choix des faits présentés, leur contextualisation, et les biais introduits dans le message.`, 'Mémoriser': `Le contenu privilégie des techniques de mémorisation et ancrage (${phaseStats['Mémoriser'].count}/${totalTechniques} techniques). Ces méthodes visent à inscrire durablement les messages dans la mémoire du public, souvent par répétition, simplification ou associations émotionnelles fortes.`, 'Agir': `Le contenu met l'accent sur des techniques d'incitation à l'action (${phaseStats['Agir'].count}/${totalTechniques} techniques). L'objectif est de mobiliser le public vers des comportements spécifiques : partage, engagement, manifestation, ou modification d'opinions et de votes.` }; // Si plusieurs phases sont également représentées const topPhases = Object.entries(phaseStats) .filter(([_, stats]) => stats.count > 0) .sort((a, b) => b[1].count - a[1].count) .slice(0, 2); if (topPhases.length > 1 && topPhases[0][1].count === topPhases[1][1].count) { return `Le contenu présente une stratégie équilibrée entre les phases "${topPhases[0][0]}" et "${topPhases[1][0]}" (${topPhases[0][1].count} techniques chacune). Cette combinaison indique une approche sophistiquée visant à la fois à attirer l'attention et à générer un impact durable.`; } return explanations[dominantPhase] || 'Analyse de la répartition des techniques de manipulation cognitive détectées selon le modèle DIMA.'; } showModal() { try { this.log('Affichage du modal'); document.getElementById('dima-modal')?.remove(); const modal = document.createElement('div'); modal.id = 'dima-modal'; modal.style.cssText = ` position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; background: rgba(0,0,0,0.75) !important; backdrop-filter: blur(5px) !important; z-index: 9999999 !important; display: flex !important; align-items: center !important; justify-content: center !important; font-family: 'Segoe UI', Arial, sans-serif !important; animation: fadeIn 0.3s ease-out !important; `; const logoUrl = chrome.runtime.getURL('M82-logo-16.png'); // Construire le contenu avec alerte site suspect si nécessaire let suspiciousAlert = ''; if (this.suspiciousSiteCheck.isSuspicious) { const { riskConfig, siteInfo } = this.suspiciousSiteCheck; suspiciousAlert = `
${riskConfig.icon}

${riskConfig.label}

${riskConfig.message}

`; } modal.innerHTML = `
M82 Project

Analyse DIMA

Détection de techniques de manipulation cognitive par M82 Project

${suspiciousAlert}
${this.analysisResults.globalScore}
Score Global
${this.analysisResults.detectedTechniques.length}
Techniques
${this.analysisResults.riskLevel}
Niveau Risque
${this.analysisResults.contentLength}
Caractères
${this.generatePhaseAnalysis()}

📄 Page analysée

${this.analysisResults.title}
${this.analysisResults.url}
Analysé le ${new Date(this.analysisResults.timestamp).toLocaleString('fr-FR')} • ${this.analysisResults.analyzedText} caractères traités • Type: ${this.pageType}
${this.analysisResults.detectedTechniques.length === 0 ? `
Aucune manipulation détectée
Le contenu analysé semble exempt de techniques de manipulation cognitive manifestes
` : `

⚠️ Techniques de manipulation détectées

${this.analysisResults.detectedTechniques.slice(0, 8).map(technique => `
${technique.phase === 'Detect' ? '👁️' : technique.phase === 'Informer' ? '📢' : technique.phase === 'Mémoriser' ? '🧠' : '⚡'} ${technique.index}: ${technique.nom}
${technique.tactic ? `
↳ Tactique: ${technique.tactic}
` : ''} ${technique.description ? `
${technique.description}
` : ''}
${technique.confidence}%
${technique.phase}
Score pondéré: ${technique.weightedScore?.toFixed(1) || technique.score}
${technique.matchedKeywords?.length > 0 ? `
🔎 Mots-clés détectés:
${technique.matchedKeywords.slice(0, 4).map(keyword => ` ${keyword.keyword} ${(keyword.count > 1) ? `(×${keyword.count})` : ''} ` ).join('')} ${technique.matchedKeywords.length > 4 ? `+${technique.matchedKeywords.length - 4} autres...` : '' }
` : ''}
`).join('')}
`}
`; modal.addEventListener('click', (e) => { if (e.target === modal) modal.remove(); }); // Ajouter l'événement pour le bouton des détails du site suspect modal.querySelector('.suspicious-details-btn')?.addEventListener('click', () => { this.showSuspiciousSiteDetails(); }); document.body.appendChild(modal); this.log('Modal affiché'); } catch (error) { console.error('DIMA: Erreur modal:', error); } } } // Make UIManager available globally for Chrome extension window.UIManager = UIManager;