From 7f78493859c7932b8b689b16b3ed32bb287467dd Mon Sep 17 00:00:00 2001 From: Quentin Rouiller Date: Sun, 19 Apr 2026 12:00:00 +0200 Subject: [PATCH] =?UTF-8?q?Version=204.2.3=20=E2=80=94=20Grande=20popup=20?= =?UTF-8?q?timeline=20persistante=20(bindTimelinePopover)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- background.js | 44 +++++--- manifest.json | 4 +- viewer.css | 63 +++++++++++ viewer.html | 14 ++- viewer.js | 306 +++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 387 insertions(+), 44 deletions(-) diff --git a/background.js b/background.js index 11d5929..2822f88 100644 --- a/background.js +++ b/background.js @@ -211,23 +211,31 @@ async function fetchCurrentUser(origin, phpsessid) { const html = await resp.text(); if (looksLikeLoginPage(html)) return null; - // Essais de patterns (du plus spécifique au plus générique) + // v4.2.2 : patterns spécifiques à la structure EasyVista réelle du Canton + // de Vaud (identifiés à partir du HTML de la page d'accueil). L'user est + // affiché dans un dropdown ".ev-employee-dropdown" avec ces éléments : + // + // Nom, Prénom + // 3.3 DGNSI-ServiceDesk + // ... + // + // Le title du parent contient aussi "Nom, Prénom / Service / Société". const patterns = [ - // Attribut data-user-name (si EasyVista l'expose) + // 1) Le plus fiable : span class="h5" dans profile-info (structure EV 2026) + /]*>\s*]*title=["']([^"']{2,80})["']/i, + // 2) Fallback : span class="h5" avec title= même hors profile-info + /]*title=["']([^"']{2,80})["'][^>]*>\s*([^<]{2,80})<\/span>/i, + // 3) Fallback : title= de ev-employee-dropdown (format "Nom, Prénom / Service / Société") + /class=["'][^"']*ev-employee-dropdown[^"']*["'][^>]*title=["']([^"'\/]+?)(?:\s*\/\s*[^"']+)?["']/i, + // 4) Anciens patterns génériques (autres instances EasyVista éventuelles) /data-user-name\s*=\s*["']([^"']+)["']/i, /data-username\s*=\s*["']([^"']+)["']/i, /data-user-fullname\s*=\s*["']([^"']+)["']/i, - // Variable JS typique EasyVista /EV\.User\.name\s*=\s*["']([^"']+)["']/, /EV\.User\.fullname\s*=\s*["']([^"']+)["']/, /userFullName\s*[:=]\s*["']([^"']+)["']/, - /currentUser(?:Name)?\s*[:=]\s*["']([^"']+)["']/, - // Balises cachées ou spans avec classe "user" - /<(?:span|div)[^>]*class=["'][^"']*(?:user[_-]?(?:name|full|display))[^"']*["'][^>]*>([^<]{2,80})<\/(?:span|div)>/i, - // "Bienvenue" / "Welcome" - /(?:Bienvenue|Welcome)[,\s]+(?:M\.?\s+|Mme\s+)?([A-ZÀÁÂÄÇÉÈÊËÍÎÏÓÔÖÚÛÜÑ][\wÀ-ÿ'.\-]+(?:\s*,?\s+[A-ZÀÁÂÄÇÉÈÊËÍÎÏÓÔÖÚÛÜÑ][\wÀ-ÿ'.\-]+){0,3})/, - // Title de la page (souvent "EasyVista - Nom Prénom") - /([^<]*)<\/title>/i + // 5) "Bienvenue" / "Welcome" + /(?:Bienvenue|Welcome)[,\s]+(?:M\.?\s+|Mme\s+)?([A-ZÀÁÂÄÇÉÈÊËÍÎÏÓÔÖÚÛÜÑ][\wÀ-ÿ'.\-]+(?:\s*,?\s+[A-ZÀÁÂÄÇÉÈÊËÍÎÏÓÔÖÚÛÜÑ][\wÀ-ÿ'.\-]+){0,3})/ ]; let name = null; @@ -236,7 +244,6 @@ async function fetchCurrentUser(origin, phpsessid) { if (m && m[1]) { const candidate = m[1].trim() .replace(/\s+/g, " ") - // Enlever des éléments du <title> type "EasyVista" / "Planning" / etc. .replace(/^(?:EasyVista|EV|Accueil|Home|Planning|ITSMA)[\s\-|•]+/i, "") .replace(/[\s\-|•]+(?:EasyVista|EV|ITSMA)$/i, "") .trim(); @@ -249,7 +256,16 @@ async function fetchCurrentUser(origin, phpsessid) { } } - // Chercher aussi le login (ID court) — utile comme fallback secondaire + // v4.2.2 : on extrait aussi le service/unité si disponible (h6 à côté du h5) + let service = null; + const serviceMatch = html.match( + /<span\s+class=["']profile-info["'][^>]*>[\s\S]{0,500}?<span\s+class=["']h6["'][^>]*title=["']([^"']{2,80})["']/i + ); + if (serviceMatch && serviceMatch[1]) { + service = serviceMatch[1].trim(); + } + + // Login / identifiant court (optionnel) let login = null; const loginPatterns = [ /data-user-login\s*=\s*["']([^"']+)["']/i, @@ -265,8 +281,8 @@ async function fetchCurrentUser(origin, phpsessid) { } } - if (!name && !login) return null; - return { name, login }; + if (!name && !login && !service) return null; + return { name, login, service }; } // ============================================================================ diff --git a/manifest.json b/manifest.json index e0821c7..bf0791f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 3, "name": "Planning Techniciens — Vue claire", - "version": "4.2.1", - "description": "Vue claire du planning EasyVista (itsma.etat-de-vaud.ch et itsma.vd.ch). v4.2.1 : messages d'erreur clairs (session expirée vs EasyVista inaccessible) avec bouton Ouvrir EasyVista et Réessayer, vouvoiement uniformisé. Inclut v4.2.0 : contact + personne de contact sur site avec anomalie rouge, parser téléphone élargi (41XXX sans +), sélection texte dans la bulle sans épingler, utilisateur EV connecté en haut, suppression auto-refresh 12h/15h.", + "version": "4.2.3", + "description": "Vue claire du planning EasyVista (itsma.etat-de-vaud.ch et itsma.vd.ch). v4.2.3 : titre renommé 'Planification', pastille d'initiales utilisateur à gauche (clic = popup nom complet), timeline petite popup qui suit la souris, clic timeline = grande popup persistante sous la timeline, double-clic = ouvre fiche, Ctrl+clic = fiche en arrière-plan, 2 contacts séparés par 'et' affichés sur 2 lignes, numéros courts 5 chiffres commençant par 6/7/8 avec espaces reconnus.", "permissions": [ "activeTab", "scripting", diff --git a/viewer.css b/viewer.css index 6e88445..77e0c5a 100644 --- a/viewer.css +++ b/viewer.css @@ -1453,3 +1453,66 @@ html, body { .current-user.hidden { display: none; } + +/* ───────────────────────────────────────────────────────────────────────── + v4.2.3 : pastille utilisateur (initiales) dans la topbar gauche + ───────────────────────────────────────────────────────────────────────── */ +.user-badge { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + padding: 0; + margin-right: 10px; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.5px; + color: #fff; + background: var(--user-badge-color, #5b6372); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 50%; + cursor: pointer; + transition: transform 0.1s, box-shadow 0.12s; + flex-shrink: 0; + user-select: none; +} +.user-badge:hover { + transform: scale(1.06); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +} +.user-badge:active { + transform: scale(0.97); +} +.user-badge.hidden { + display: none; +} +.user-badge.open { + /* Indication visuelle quand la popup nom est ouverte */ + box-shadow: 0 0 0 2px var(--user-badge-color, #5b6372) inset, + 0 0 0 2px rgba(255, 255, 255, 0.15); +} + +/* Popup du nom complet, affichée juste sous la pastille au clic */ +.user-name-popup { + position: fixed; + z-index: 10050; + padding: 8px 14px; + background: var(--bg, #ffffff); + color: var(--text, #111); + border: 1px solid var(--border, rgba(128, 128, 128, 0.25)); + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18), + 0 2px 6px rgba(0, 0, 0, 0.12); + font-size: 13px; + font-weight: 500; + white-space: nowrap; + animation: user-popup-in 0.12s ease-out; +} +.user-name-popup.hidden { + display: none; +} +@keyframes user-popup-in { + from { opacity: 0; transform: translateY(-4px); } + to { opacity: 1; transform: translateY(0); } +} diff --git a/viewer.html b/viewer.html index 92c4d02..7ee753b 100644 --- a/viewer.html +++ b/viewer.html @@ -2,13 +2,18 @@ <html lang="fr"> <head> <meta charset="utf-8"> - <title>Planning techniciens + Planification
-

Planning techniciens

+ + +

Planification

@@ -19,7 +24,6 @@
-