From fce4ae6a799b5673d9bc7c3a28b435bd851b7560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9drix?= Date: Tue, 19 May 2026 22:39:21 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20visitors.json=20cl=C3=A9s=20perdues,=20b?= =?UTF-8?q?outon=20AS=20inaccessible,=20graphique=20visiteurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix array_merge → + pour préserver clés 7/14/30 dans visitors.json - Bouton ✕ exclusion AS sorti du div 9rem + stopPropagation - Handler délégué unique (removeEventListener avant de rajouter) - Graphique trend : visiteurs uniques/jour depuis ip_data (top 200) Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 12 ++++++++++ public/assets/js/admin-stats.js | 39 +++++++++++++++++++-------------- public/index.php | 2 +- public/version.txt | 2 +- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 738df10..4801e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag --- +## [1.6.35] - 2026-05-19 + +### Corrigé +- `visitors.json` : utilisation de `+` au lieu de `array_merge` pour préserver les clés entières 7/14/30 (array_merge les renumérote en 0/1/2) +- Admin stats / Visiteurs par pays : bouton ✕ déplacé hors du div 9rem (il était écrasé par le nom de l'AS) ; `e.stopPropagation()` ajouté pour ne pas déclencher l'accordéon +- Admin stats / Visiteurs par pays : listener délégué stocké et retiré avant réajout (évite l'accumulation de handlers après chaque `renderCountry()`) + +### Modifié +- Graphique "Trafic total" → "Visiteurs uniques / jour" calculé depuis les IPs du top 200 (approximation) + +--- + ## [1.6.34] - 2026-05-19 ### Ajouté diff --git a/public/assets/js/admin-stats.js b/public/assets/js/admin-stats.js index aec83be..257b94f 100644 --- a/public/assets/js/admin-stats.js +++ b/public/assets/js/admin-stats.js @@ -75,6 +75,7 @@ var _csrf = (typeof FOLIO_CSRF !== 'undefined') ? FOLIO_CSRF : ''; var ipData = (typeof FOLIO_IP_DATA !== 'undefined') ? FOLIO_IP_DATA : {}; if (!el || !asList.length) { return; } + var _countryClickHandler = null; var dispNames = null; try { dispNames = new Intl.DisplayNames(['fr'], { type: 'region' }); } catch (e) {} function countryName(code) { @@ -277,17 +278,17 @@ var _csrf = (typeof FOLIO_CSRF !== 'undefined') ? FOLIO_CSRF : ''; var toggleAttrs = hasIps ? ' data-bs-toggle="collapse" data-bs-target="#' + asId + '" role="button"' : ''; var chevron = hasIps ? '' : ''; var excludeBtn = n.asn - ? '' + ? '' : ''; return '
' - + '
' - + '
' - + esc(n.name || '?') - + (n.asn ? ' AS' + esc(n.asn) + '' : '') + + '
' + + '
' + + '' + esc(n.name || '?') + '' + + (n.asn ? ' AS' + esc(n.asn) + '' : '') + chevron - + excludeBtn + '
' + + excludeBtn + '
' + '
' + '
' @@ -336,13 +337,15 @@ var _csrf = (typeof FOLIO_CSRF !== 'undefined') ? FOLIO_CSRF : ''; el.innerHTML = html; - // Délégation : boutons exclure / inclure - el.addEventListener('click', function (e) { + // Délégation : boutons exclure / inclure (handler unique pour éviter les doublons) + if (_countryClickHandler) { el.removeEventListener('click', _countryClickHandler); } + _countryClickHandler = function (e) { var btn = e.target.closest('.exclude-as-btn'); - if (btn) { excludeAs(btn.getAttribute('data-asn'), btn.getAttribute('data-name')); return; } + if (btn) { e.stopPropagation(); excludeAs(btn.getAttribute('data-asn'), btn.getAttribute('data-name')); return; } btn = e.target.closest('.include-as-btn'); - if (btn) { includeAs(btn.getAttribute('data-asn')); } - }, { once: true }); + if (btn) { e.stopPropagation(); includeAs(btn.getAttribute('data-asn')); } + }; + el.addEventListener('click', _countryClickHandler); } renderCountry(); @@ -543,14 +546,14 @@ var _csrf = (typeof FOLIO_CSRF !== 'undefined') ? FOLIO_CSRF : ''; var dots = pts.map(function (p) { return '' - + '' + esc(p.l) + ' : ' + p.v + ' vis.' + + '' + esc(p.l) + ' : ' + p.v + ' visiteur(s)' + '' + ''; }).join(''); trendEl.innerHTML = - '

Trafic total — 30 derniers jours

' + '

Visiteurs uniques / jour — 30 derniers jours (top 200 IPs)

' + '' + '' @@ -690,11 +693,13 @@ var _csrf = (typeof FOLIO_CSRF !== 'undefined') ? FOLIO_CSRF : ''; return { title: title, link: link, slug: slug, vis: vis, daily: daily }; }); var nDays = Object.values(pagesByDay)[0] ? Object.values(pagesByDay)[0].length : 30; - var totals = new Array(nDays).fill(0); - Object.values(pagesByDay).forEach(function (arr) { - arr.forEach(function (v, i) { if (i < nDays) { totals[i] += v; } }); + // Visiteurs uniques par jour — compté sur les IPs du top 200 (approximation) + var dailyVisitors = new Array(nDays).fill(0); + Object.keys(ipData).forEach(function (ip) { + var daily = ipData[ip].daily || []; + daily.forEach(function (v, i) { if (i < nDays && v > 0) { dailyVisitors[i]++; } }); }); - trendChart(totals); + trendChart(dailyVisitors); multiLineChart(pagesByDay, rows); var html = '
'; diff --git a/public/index.php b/public/index.php index 6cc9963..60d849f 100644 --- a/public/index.php +++ b/public/index.php @@ -2823,7 +2823,7 @@ switch ($action) { if ($_artUuid !== null && preg_match('/^[0-9a-f\-]{36}$/i', $_artUuid)) { @file_put_contents( DATA_PATH . '/' . $_artUuid . '/visitors.json', - json_encode(array_merge($_artCounts, ['updated' => time()]), JSON_UNESCAPED_UNICODE) + json_encode($_artCounts + ['updated' => time()], JSON_UNESCAPED_UNICODE) ); } } diff --git a/public/version.txt b/public/version.txt index d8462d4..e7b0418 100644 --- a/public/version.txt +++ b/public/version.txt @@ -1 +1 @@ -1.6.34 +1.6.35