PageSourceSearch

https://gabonmatin.com/squelettes/gmatin.js

js gabonmatin.com collected 2026-10-02 23:36:13 UTC 13,002 bytes, 423 lines download raw bytes

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&current=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.