Size
8.9 KB
Version
1.2.1
Created
Nov 9, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Résumé de liens Canopé
3// @description Affiche un résumé rapide des liens importants de la page
4// @version 1.2.1
5// @match https://*.reseau-canope.fr/*
6// @icon https://cdn.reseau-canope.fr/static-assets/Images/Favicon/rc/RC-favicon_FAV16.png
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Extension Résumé de liens Canopé démarrée');
12
13 // Fonction pour extraire les liens importants de la page
14 function extractImportantLinks() {
15 const links = [];
16 const seenUrls = new Set();
17
18 // Extraire les liens du menu principal
19 const mainNav = document.querySelector('nav[role="navigation"][aria-label="Menu principal"]');
20 if (mainNav) {
21 const navLinks = mainNav.querySelectorAll('a[href]');
22 navLinks.forEach(link => {
23 const url = link.href;
24 const text = link.textContent.trim();
25 if (url && text && !seenUrls.has(url)) {
26 seenUrls.add(url);
27 links.push({ text, url, category: 'Navigation' });
28 }
29 });
30 }
31
32 // Extraire les liens des actualités
33 const newsCards = document.querySelectorAll('.card--is-link a.card__link');
34 newsCards.forEach(link => {
35 const url = link.href;
36 const text = link.textContent.trim();
37 if (url && text && !seenUrls.has(url)) {
38 seenUrls.add(url);
39 links.push({ text, url, category: 'Actualités' });
40 }
41 });
42
43 // Extraire les liens du contenu principal
44 const mainContent = document.querySelector('main#main-content');
45 if (mainContent) {
46 const contentLinks = mainContent.querySelectorAll('a[href]:not(.card__link)');
47 contentLinks.forEach(link => {
48 const url = link.href;
49 const text = link.textContent.trim();
50 // Filtrer les liens vides ou trop courts
51 if (url && text && text.length > 3 && !seenUrls.has(url)) {
52 seenUrls.add(url);
53 links.push({ text, url, category: 'Contenu' });
54 }
55 });
56 }
57
58 console.log(`${links.length} liens extraits de la page`);
59 return links;
60 }
61
62 // Fonction pour créer le bouton flottant
63 function createFloatingButton() {
64 const button = document.createElement('button');
65 button.id = 'canope-summary-btn';
66 button.innerHTML = '📋';
67 button.title = 'Afficher le résumé des liens';
68 button.style.cssText = `
69 position: fixed;
70 bottom: 20px;
71 right: 20px;
72 width: 60px;
73 height: 60px;
74 border-radius: 50%;
75 background: linear-gradient(135deg, #0066cc 0%, #004999 100%);
76 color: white;
77 border: none;
78 font-size: 28px;
79 cursor: pointer;
80 box-shadow: 0 4px 12px rgba(0, 102, 204, 0.4);
81 z-index: 9999;
82 transition: all 0.3s ease;
83 display: flex;
84 align-items: center;
85 justify-content: center;
86 `;
87
88 button.addEventListener('mouseenter', () => {
89 button.style.transform = 'scale(1.1)';
90 button.style.boxShadow = '0 6px 16px rgba(0, 102, 204, 0.6)';
91 });
92
93 button.addEventListener('mouseleave', () => {
94 button.style.transform = 'scale(1)';
95 button.style.boxShadow = '0 4px 12px rgba(0, 102, 204, 0.4)';
96 });
97
98 button.addEventListener('click', () => {
99 toggleSummaryPanel();
100 });
101
102 document.body.appendChild(button);
103 console.log('Bouton flottant créé');
104 }
105
106 // Fonction pour créer le panneau de résumé
107 function createSummaryPanel() {
108 const panel = document.createElement('div');
109 panel.id = 'canope-summary-panel';
110 panel.style.cssText = `
111 position: fixed;
112 top: 50%;
113 right: 20px;
114 transform: translateY(-50%) translateX(450px);
115 width: 400px;
116 max-height: 80vh;
117 background: white;
118 border-radius: 12px;
119 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
120 z-index: 10000;
121 overflow: hidden;
122 transition: transform 0.3s ease;
123 display: flex;
124 flex-direction: column;
125 `;
126
127 // En-tête du panneau
128 const header = document.createElement('div');
129 header.style.cssText = `
130 background: linear-gradient(135deg, #0066cc 0%, #004999 100%);
131 color: white;
132 padding: 20px;
133 font-size: 18px;
134 font-weight: bold;
135 display: flex;
136 justify-content: space-between;
137 align-items: center;
138 `;
139 header.innerHTML = `
140 <span>📋 Résumé des liens</span>
141 <button id="canope-close-panel" style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; padding: 0; width: 30px; height: 30px;">×</button>
142 `;
143
144 // Contenu du panneau
145 const content = document.createElement('div');
146 content.id = 'canope-summary-content';
147 content.style.cssText = `
148 padding: 20px;
149 overflow-y: auto;
150 flex: 1;
151 `;
152
153 panel.appendChild(header);
154 panel.appendChild(content);
155 document.body.appendChild(panel);
156
157 // Événement pour fermer le panneau
158 document.getElementById('canope-close-panel').addEventListener('click', () => {
159 toggleSummaryPanel();
160 });
161
162 console.log('Panneau de résumé créé');
163 return panel;
164 }
165
166 // Fonction pour afficher les liens dans le panneau
167 function displayLinks(links) {
168 const content = document.getElementById('canope-summary-content');
169 if (!content) return;
170
171 if (links.length === 0) {
172 content.innerHTML = '<p style="color: #666; text-align: center;">Aucun lien trouvé sur cette page.</p>';
173 return;
174 }
175
176 // Grouper les liens par catégorie
177 const groupedLinks = {};
178 links.forEach(link => {
179 if (!groupedLinks[link.category]) {
180 groupedLinks[link.category] = [];
181 }
182 groupedLinks[link.category].push(link);
183 });
184
185 let html = '';
186 for (const [category, categoryLinks] of Object.entries(groupedLinks)) {
187 html += `
188 <div style="margin-bottom: 24px;">
189 <h3 style="color: #0066cc; font-size: 16px; font-weight: bold; margin-bottom: 12px; border-bottom: 2px solid #0066cc; padding-bottom: 8px;">
190 ${category} (${categoryLinks.length})
191 </h3>
192 <ul style="list-style: none; padding: 0; margin: 0;">
193 `;
194
195 categoryLinks.forEach(link => {
196 html += `
197 <li style="margin-bottom: 8px;">
198 <a href="${link.url}"
199 target="_blank"
200 style="color: #004999; text-decoration: none; display: block; padding: 8px; border-radius: 6px; transition: background 0.2s ease;"
201 onmouseover="this.style.background='#f0f7ff'"
202 onmouseout="this.style.background='transparent'">
203 🔗 ${link.text}
204 </a>
205 </li>
206 `;
207 });
208
209 html += `
210 </ul>
211 </div>
212 `;
213 }
214
215 content.innerHTML = html;
216 console.log('Liens affichés dans le panneau');
217 }
218
219 // Fonction pour basculer l'affichage du panneau
220 function toggleSummaryPanel() {
221 let panel = document.getElementById('canope-summary-panel');
222
223 if (!panel) {
224 panel = createSummaryPanel();
225 const links = extractImportantLinks();
226 displayLinks(links);
227 }
228
229 const isVisible = panel.style.transform === 'translateY(-50%) translateX(0px)';
230
231 if (isVisible) {
232 panel.style.transform = 'translateY(-50%) translateX(450px)';
233 console.log('Panneau masqué');
234 } else {
235 panel.style.transform = 'translateY(-50%) translateX(0px)';
236 console.log('Panneau affiché');
237 }
238 }
239
240 // Initialisation de l'extension
241 function init() {
242 console.log('Initialisation de l\'extension Résumé de liens Canopé');
243
244 // Attendre que le DOM soit complètement chargé
245 if (document.readyState === 'loading') {
246 document.addEventListener('DOMContentLoaded', () => {
247 createFloatingButton();
248 });
249 } else {
250 createFloatingButton();
251 }
252 }
253
254 // Démarrer l'extension
255 init();
256})();