1(function () { 2 "use strict"; 3 4 var body = document.body; 5 var menuButton = document.querySelector(".menu-toggle"); 6 var menu = document.getElementById("navigation-principale"); 7 var menuOverlay = document.querySelector("[data-menu-close]"); 8 var searchButton = document.querySelector(".search-toggle"); 9 var searchPanel = document.getElementById("header-search"); 10 var backToTop = document.querySelector(".back-to-top"); 11 var siteHeader = document.getElementById("site-header"); 12 var currentDate = document.querySelector("[data-current-date]"); 13 var weather = document.querySelector("[data-weather]"); 14 var urgentBanner = document.querySelector("[data-urgent-banner]"); 15 16 if (urgentBanner) { 17 var urgentLifetime = 12 * 60 * 60 * 1000; 18 var updateUrgentBanner = function () { 19 var now = Date.now(); 20 21 urgentBanner.querySelectorAll("[data-urgent-item]").forEach(function (item) { 22 var publishedAt = Date.parse(item.getAttribute("data-published")); 23 var isActive = Number.isFinite(publishedAt) && publishedAt <= now && now - publishedAt < urgentLifetime; 24 25 item.hidden = !isActive; 26 }); 27 28 var primaryList = urgentBanner.querySelector(".urgent-list:not(.urgent-copy)"); 29 var activeCount = primaryList ? primaryList.querySelectorAll("[data-urgent-item]:not([hidden])").length : 0; 30 31 urgentBanner.hidden = activeCount === 0; 32 urgentBanner.classList.toggle("is-static", activeCount <= 1); 33 }; 34 35 updateUrgentBanner(); 36 window.setInterval(updateUrgentBanner, 60000); 37 } 38 39 if (currentDate) { 40 var librevilleDate = new Intl.DateTimeFormat("fr-FR", { 41 weekday: "long", 42 day: "numeric", 43 month: "long", 44 year: "numeric", 45 timeZone: "Africa/Libreville" 46 }).format(new Date()); 47 48 currentDate.textContent = librevilleDate.charAt(0).toUpperCase() + librevilleDate.slice(1); 49 currentDate.setAttribute("datetime", new Intl.DateTimeFormat("fr-CA", { 50 year: "numeric", 51 month: "2-digit", 52 day: "2-digit", 53 timeZone: "Africa/Libreville" 54 }).format(new Date())); 55 } 56 57 if (weather) { 58 var weatherTemperature = weather.querySelector("[data-weather-temperature]"); 59 var weatherDescription = weather.querySelector("[data-weather-description]"); 60 var weatherCacheKey = "gmatin-libreville-weather"; 61 var weatherLabels = { 62 0: "Ciel dégagé", 63 1: "Peu nuageux", 64 2: "Partiellement nuageux", 65 3: "Couvert", 66 45: "Brouillard", 67 48: "Brouillard givrant", 68 51: "Bruine légère", 69 53: "Bruine", 70 55: "Bruine forte", 71 61: "Pluie légère", 72 63: "Pluie modérée", 73 65: "Forte pluie", 74 80: "Averses légères", 75 81: "Averses", 76 82: "Fortes averses", 77 95: "Orage", 78 96: "Orage et grêle", 79 99: "Fort orage et grêle" 80 }; 81 82 var renderWeather = function (data) { 83 if (!data || !Number.isFinite(Number(data.temperature))) { 84 return false; 85 } 86 87 weatherTemperature.textContent = Math.round(Number(data.temperature)) + "°"; 88 weatherDescription.textContent = weatherLabels[data.code] || "Conditions variables"; 89 return true; 90 }; 91 92 var cachedWeather; 93 94 try { 95 cachedWeather = JSON.parse(window.localStorage.getItem(weatherCacheKey)); 96 } catch (error) { 97 cachedWeather = null; 98 } 99 100 if (cachedWeather) { 101 renderWeather(cachedWeather); 102 } 103 104 var weatherController = typeof AbortController === "function" ? new AbortController() : null; 105 var weatherTimeout = window.setTimeout(function () { 106 if (weatherController) { 107 weatherController.abort(); 108 } 109 }, 6500); 110 111 fetch("https://api.open-meteo.com/v1/forecast?latitude=0.3901&longitude=9.4544¤t=temperature_2m,weather_code&timezone=Africa%2FLibreville", weatherController ? { signal: weatherController.signal } : {}) 112 .then(function (response) { 113 if (!response.ok) { 114 throw new Error("weather-unavailable"); 115 } 116 return response.json(); 117 }) 118 .then(function (data) { 119 var current = data && data.current; 120 var normalized = current ? { 121 temperature: current.temperature_2m, 122 code: current.weather_code, 123 savedAt: Date.now() 124 } : null; 125 126 if (!renderWeather(normalized)) { 127 throw new Error("weather-invalid"); 128 } 129 130 try { 131 window.localStorage.setItem(weatherCacheKey, JSON.stringify(normalized)); 132 } catch (error) { 133 // Lâaffichage reste fonctionnel lorsque le stockage local est bloqué. 134 } 135 }) 136 .catch(function () { 137 if (!cachedWeather) { 138 weatherTemperature.textContent = "--°"; 139 weatherDescription.textContent = "Météo indisponible"; 140 } 141 }) 142 .then(function () { 143 window.clearTimeout(weatherTimeout); 144 }); 145 } 146 147 function setMenu(open) { 148 if (!menuButton || !menu) { 149 return; 150 } 151
152 body.classList.toggle("nav-open", open); 153 menuButton.setAttribute("aria-expanded", String(open)); 154 menuButton.setAttribute("aria-label", open ? "Fermer le menu" : "Ouvrir le menu"); 155 156 if (menuOverlay) { 157 menuOverlay.hidden = !open; 158 } 159 } 160 161 function setSearch(open) { 162 if (!searchButton || !searchPanel) { 163 return; 164 } 165 166 searchPanel.hidden = !open; 167 searchButton.setAttribute("aria-expanded", String(open)); 168 searchButton.setAttribute("aria-label", open ? "Fermer la recherche" : "Ouvrir la recherche"); 169 170 if (open) { 171 setMenu(false); 172 window.setTimeout(function () { 173 var field = searchPanel.querySelector('input[type="search"]'); 174 if (field) { 175 field.focus(); 176 } 177 }, 30); 178 } 179 } 180 181 if (menuButton && menu) { 182 menuButton.addEventListener("click", function () { 183 setMenu(menuButton.getAttribute("aria-expanded") !== "true"); 184 }); 185 } 186 187 if (menuOverlay) { 188 menuOverlay.addEventListener("click", function () { 189 setMenu(false); 190 }); 191 } 192 193 if (searchButton && searchPanel) { 194 searchButton.addEventListener("click", function () { 195 setSearch(searchButton.getAttribute("aria-expanded") !== "true"); 196 }); 197 } 198 199 document.querySelectorAll(".submenu-toggle").forEach(function (button) { 200 button.addEventListener("click", function () { 201 var item = button.closest(".menu-item"); 202 var open = button.getAttribute("aria-expanded") !== "true"; 203 204 if (!item) { 205 return; 206 } 207 208 item.parentElement.querySelectorAll(".menu-item.is-open").forEach(function (otherItem) { 209 if (otherItem !== item) { 210 otherItem.classList.remove("is-open"); 211 var otherButton = otherItem.querySelector(".submenu-toggle"); 212 if (otherButton) { 213 otherButton.setAttribute("aria-expanded", "false"); 214 } 215 } 216 }); 217 218 item.classList.toggle("is-open", open); 219 button.setAttribute("aria-expanded", String(open)); 220 }); 221 }); 222 223 document.addEventListener("click", function (event) { 224 if ( 225 searchPanel && 226 searchButton && 227 !searchPanel.hidden && 228 !searchPanel.contains(event.target) && 229 !searchButton.contains(event.target) 230 ) { 231 setSearch(false); 232 } 233 }); 234 235 document.addEventListener("keydown", function (event) { 236 if (event.key === "Escape") { 237 setMenu(false); 238 setSearch(false); 239 } 240 }); 241 242 window.addEventListener("resize", function () { 243 if (window.innerWidth > 900) { 244 setMenu(false); 245 } 246 }); 247 248 if (siteHeader) { 249 var updateCompactHeader = function () { 250 siteHeader.classList.toggle("is-compact", window.innerWidth > 900 && window.scrollY >= 148); 251 }; 252 253 window.addEventListener("scroll", updateCompactHeader, { passive: true }); 254 window.addEventListener("resize", updateCompactHeader); 255 updateCompactHeader(); 256 } 257 258 document.querySelectorAll("[data-print]").forEach(function (button) { 259 button.addEventListener("click", function () { 260 window.print(); 261 }); 262 }); 263 264 document.querySelectorAll("[data-copy-article]").forEach(function (button) { 265 var originalLabel = button.textContent; 266 var resetTimer; 267 268 var setFeedback = function (label, success) { 269 button.textContent = label; 270 button.classList.toggle("is-copied", success); 271 window.clearTimeout(resetTimer); 272 resetTimer = window.setTimeout(function () { 273 button.textContent = originalLabel; 274 button.classList.remove("is-copied"); 275 }, 2200); 276 }; 277 278 var copyFallback = function (textToCopy) { 279 var field = document.createElement("textarea"); 280 var copied; 281 282 field.value = textToCopy; 283 field.setAttribute("readonly", ""); 284 field.style.position = "fixed"; 285 field.style.opacity = "0"; 286 document.body.appendChild(field); 287 field.select(); 288 copied = document.execCommand("copy"); 289 document.body.removeChild(field); 290 291 return copied ? Promise.resolve() : Promise.reject(new Error("copy-failed")); 292 }; 293 294 button.addEventListener("click", function () { 295 var title = button.getAttribute("data-copy-title") || document.title; 296 var url = button.getAttribute("data-copy-url") || window.location.href; 297 var textToCopy = title + "\n" + url; 298 var copyOperation = navigator.clipboard && window.isSecureContext 299 ? navigator.clipboard.writeText(textToCopy) 300 : copyFallback(textToCopy); 301 302 copyOperation.then(function () { 303 setFeedback("Titre et lien copiés", true); 304 }).catch(function () { 305 setFeedback("Copie impossible", false); 306 }); 307 }); 308 }); 309 310 document.querySelectorAll("[data-tabs]").forEach(function (tabs) { 311 var buttons = Array.prototype.slice.call(tabs.querySelectorAll("[data-tab-target]")); 312 var panels = Array.prototype.slice.call(tabs.querySelectorAll("[data-tab-panel]")); 313 314 var activateTab = function (button, moveFocus) { 315 var targetId = button.getAttribute("data-tab-target"); 316 317 buttons.forEach(function (item) { 318 var active = item === button; 319 item.classList.toggle("is-active", active); 320 item.setAttribute("aria-selected", String(active)); 321 item.setAttribute("tabindex", active ? "0" : "-1"); 322 }); 323
324 panels.forEach(function (panel) { 325 panel.hidden = panel.id !== targetId; 326 }); 327 328 if (moveFocus) { 329 button.focus(); 330 } 331 }; 332 333 buttons.forEach(function (button, index) { 334 button.addEventListener("click", function () { 335 activateTab(button, false); 336 }); 337 338 button.addEventListener("keydown", function (event) { 339 var nextIndex; 340 341 if (event.key === "ArrowRight") { 342 nextIndex = (index + 1) % buttons.length; 343 } else if (event.key === "ArrowLeft") { 344 nextIndex = (index - 1 + buttons.length) % buttons.length; 345 } else { 346 return; 347 } 348 349 event.preventDefault(); 350 activateTab(buttons[nextIndex], true); 351 }); 352 }); 353 }); 354 355 document.querySelectorAll("[data-countdown]").forEach(function (countdown) { 356 var target = new Date(countdown.getAttribute("data-countdown")).getTime(); 357 358 if (Number.isNaN(target)) { 359 countdown.hidden = true; 360 return; 361 } 362 363 var fields = { 364 days: countdown.querySelector("[data-countdown-days]"), 365 hours: countdown.querySelector("[data-countdown-hours]"), 366 minutes: countdown.querySelector("[data-countdown-minutes]"), 367 seconds: countdown.querySelector("[data-countdown-seconds]") 368 }; 369 var timer; 370 371 var updateCountdown = function () { 372 var remaining = Math.max(0, target - Date.now()); 373 var totalSeconds = Math.floor(remaining / 1000); 374 var values = { 375 days: Math.floor(totalSeconds / 86400), 376 hours: Math.floor((totalSeconds % 86400) / 3600), 377 minutes: Math.floor((totalSeconds % 3600) / 60), 378 seconds: totalSeconds % 60 379 }; 380 381 Object.keys(fields).forEach(function (key) { 382 if (fields[key]) { 383 fields[key].textContent = String(values[key]).padStart(2, "0"); 384 } 385 }); 386 387 if (remaining === 0 && timer) { 388 window.clearInterval(timer); 389 } 390 }; 391 392 timer = window.setInterval(updateCountdown, 1000); 393 updateCountdown(); 394 }); 395 396 if (backToTop) { 397 var updateBackToTop = function () { 398 backToTop.hidden = window.scrollY < 650; 399 }; 400 401 window.addEventListener("scroll", updateBackToTop, { passive: true }); 402 updateBackToTop(); 403 404 backToTop.addEventListener("click", function () { 405 window.scrollTo({ top: 0, behavior: "smooth" }); 406 }); 407 } 408 409 document.querySelectorAll("[data-ad-format]").forEach(function (slot) { 410 var format = slot.getAttribute("data-ad-format"); 411 412 if (window.sas && window.sas.cmd && format) { 413 window.sas.cmd.push(function () { 414 window.sas.render(format); 415 }); 416 } else { 417 var wrapper = slot.closest(".ad-banner"); 418 if (wrapper) { 419 wrapper.hidden = true; 420 } 421 } 422 }); 423}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.