1/** 2 * Bandeau de reconsentement cookies â source unique desktop + mobile. 3 * 4 * Remplace le markup #r-cookies-wall qui était dupliqué dans les têtières, les 5 * pieds de page et les modèles mobiles, ainsi que la logique dupliquée entre 6 * design/js/commun.js et design/mob_js/scripts.js. Les libellés, le markup, le 7 * style et le comportement ne vivent plus qu'ici. 8 * 9 * Le bandeau s'affiche quand l'utilisateur a refusé les traceurs dans la CMP 10 * Didomi. Un seul niveau (plus de repli), un seul bouton qui renvoie vers la 11 * CMP (plus d'acceptation directe), et deux façons de le fermer : 12 * - la croix : masquage mémorisé 6 mois, durée de conservation du refus 13 * recommandée par la CNIL, alignée sur celle du choix Didomi ; 14 * - 20 s d'affichage sans action : masquage mémorisé 48 h seulement, une 15 * disparition automatique n'étant pas un choix du visiteur. 16 * Le défilement ne ferme pas le bandeau : en mobile, un simple geste le 17 * retirait avant qu'il soit lu. 18 * 19 * Un nouveau refus exprimé dans la CMP ré-arme le masquage en cours, avec sa 20 * durée, au lieu de réafficher le bandeau. 21 * 22 * Mise en conformité demandée par le comité RGPD (09/2026) : suppression du 23 * bandeau réduit, du bouton d'acceptation unique et des formulations 24 * incitatives assimilables à des dark patterns. 25 */ 26(function () { 27 'use strict'; 28 29 // La têtière et le pied de page chargent tous deux ce script : on ne garde 30 // que la première exécution. 31 if (window.MVI_CookieWall) { 32 return; 33 } 34 35 var TEXTES = { 36 titre: 'Pourquoi dire oui aux cookies ?', 37 message: 'Vous avez refusé les cookies. Ils nous permettent de vous proposer des contenus adaptés à votre lieu de vie, des publicités correspondant à vos centres dâintérêt et de mesurer lâaudience du site. Vous pouvez modifier votre choix à tout moment.', 38 bouton: 'Modifier mes choix cookies', 39 fermer: 'Fermer ce message' 40 }; 41 42 var FINALITE_DIDOMI = 'cookies'; 43 var NOM_COOKIE = 'mvi_cw_hide'; 44 var DELAI_AFFICHAGE = 20000; // avant disparition automatique, en ms 45 var DUREE_CROIX = 15768000; // masquage après la croix : 6 mois, en secondes 46 var DUREE_DELAI = 172800; // masquage après disparition automatique : 48 h, en secondes 47 48 // Valeur du cookie : la fermeture à l'origine du masquage. Le préfixe « 1 » 49 // fait lire ces valeurs comme un masquage par la version du 14/09/2026 (test 50 // indexOf('mvi_cw_hide=1')), qu'une page aux blocs encore en cache peut 51 // exécuter quelque temps après un déploiement. 52 var PAR_CROIX = '1-croix'; 53 var PAR_DELAI = '1-delai'; 54 // Valeur posée 6 mois par cette version quelle que soit la fermeture, le plus 55 // souvent le défilement : ramenée à un masquage court (voir plus bas). 56 var VALEUR_V1 = '1'; 57 58 var bandeau = null; 59 var minuteur = null; 60 61 /* -------------------------------------------------- mémorisation du choix */ 62 63 /** 64 * Domaine de dépôt du cookie : partagé entre les villes du réseau 65 * (rennes.maville.com, nantes.maville.comâ¦) pour ne pas redemander à chaque 66 * site. Ailleurs (préprod, local), cookie limité à l'hôte courant. 67 */ 68 function domaineCookie() { 69 return /(^|\.)maville\.com$/.test(location.hostname) ? '; domain=.maville.com' : ''; 70 } 71 72 function lisCookie() { 73 var trouve = document.cookie.match(new RegExp('(?:^|;\\s*)' + NOM_COOKIE + '=([^;]*)')); 74 return trouve ? trouve[1] : ''; 75 } 76 77 /** Fermeture à l'origine du masquage en cours (PAR_CROIX ou PAR_DELAI), '' sinon. */ 78 function masquage() { 79 var valeur = lisCookie(); 80 return PAR_CROIX === valeur || PAR_DELAI === valeur ? valeur : ''; 81 } 82 83 function estMasque() { 84 return '' !== masquage(); 85 } 86 87 /** Mémorise le masquage dû à la fermeture `par`, pour la durée qui lui correspond. */ 88 function memoriseMasquage(par) { 89 var duree = PAR_CROIX === par ? DUREE_CROIX : DUREE_DELAI; 90 var secure = 'https:' === location.protocol ? '; secure' : ''; 91 document.cookie = NOM_COOKIE + '=' + par + '; max-age=' + duree + '; path=/' 92 + domaineCookie() + '; samesite=lax' + secure; 93 } 94 95 /* ------------------------------------------------------------------ style */ 96 97 function injecteStyle() { 98 // Taille de base en px : le CSS mobile impose body{font-size:0}, et une 99 // base en em rendrait invisible le texte du bandeau (enfant de body). 100 var css = [ 101 '.mvi-cw{position:fixed;bottom:0;left:0;width:100%;z-index:100000;', 102 'background-color:#FF4200;color:#fff;font-size:16px;', 103 'box-shadow:0 -4px 8px rgba(0,0,0,.2);box-sizing:border-box}', 104 '.mvi-cw *{box-sizing:border-box}', 105 '.mvi-cw__grid{display:flex;align-items:center;justify-content:space-between;', 106 'gap:16px;max-width:1190px;margin:auto;padding:16px 48px 16px 16px}', 107 '.mvi-cw__title{margin:0 0 4px;font-size:1.2em;line-height:1.3;color:#fff}', 108 '.mvi-cw__message{margin:0;font-size:.85em;line-height:1.4}', 109 '.mvi-cw__btn{flex:0 0 auto;display:inline-block;padding:10px 16px;', 110 'border:1px solid #fff;border-radius:8px;background-color:#fff;color:#FF4200;', 111 'font-size:.9em;font-weight:700;text-align:center;text-decoration:none;cursor:pointer}', 112 '.mvi-cw__btn:hover,.mvi-cw__btn:focus{background-color:#f2f2f2;color:#FF4200;text-decoration:none}', 113 '.mvi-cw__close{position:absolute;top:8px;right:8px;width:32px;height:32px;', 114 'padding:0;border:none;border-radius:50%;background-color:transparent;color:#fff;', 115 'font-size:24px;line-height:32px;
115cursor:pointer}', 116 '.mvi-cw__close:hover,.mvi-cw__close:focus{background-color:rgba(255,255,255,.2)}', 117 '@media (max-width:767px){', 118 '.mvi-cw{font-size:17px}', 119 '.mvi-cw__grid{flex-direction:column;align-items:stretch;gap:10px;padding:14px 16px 18px}', 120 '.mvi-cw__title{padding-right:32px}', 121 '.mvi-cw__message{font-size:.82em}', 122 '.mvi-cw__btn{width:100%}}' 123 ].join(''); 124 125 var style = document.createElement('style'); 126 style.setAttribute('type', 'text/css'); 127 style.appendChild(document.createTextNode(css)); 128 document.getElementsByTagName('head')[0].appendChild(style); 129 } 130 131 /* ---------------------------------------------------------------- markup */ 132 133 function construit() { 134 var el = document.createElement('aside'); 135 el.className = 'mvi-cw'; 136 el.id = 'mvi-cw'; 137 el.setAttribute('role', 'complementary'); 138 el.setAttribute('aria-label', 'Information sur les cookies'); 139 140 var grille = document.createElement('div'); 141 grille.className = 'mvi-cw__grid'; 142 143 var texte = document.createElement('div'); 144 texte.className = 'mvi-cw__content'; 145 146 var titre = document.createElement('h2'); 147 titre.className = 'mvi-cw__title'; 148 titre.appendChild(document.createTextNode(TEXTES.titre)); 149 150 var message = document.createElement('p'); 151 message.className = 'mvi-cw__message'; 152 message.appendChild(document.createTextNode(TEXTES.message)); 153 154 texte.appendChild(titre); 155 texte.appendChild(message); 156 157 var bouton = document.createElement('button'); 158 bouton.className = 'mvi-cw__btn'; 159 bouton.setAttribute('type', 'button'); 160 bouton.appendChild(document.createTextNode(TEXTES.bouton)); 161 bouton.onclick = function () { 162 if (window.Didomi && window.Didomi.preferences) { 163 window.Didomi.preferences.show(); 164 } 165 return false; 166 }; 167 168 var croix = document.createElement('button'); 169 croix.className = 'mvi-cw__close'; 170 croix.setAttribute('type', 'button'); 171 croix.setAttribute('aria-label', TEXTES.fermer); 172 croix.setAttribute('title', TEXTES.fermer); 173 croix.innerHTML = '×'; 174 croix.onclick = function () { 175 ferme(); 176 return false; 177 }; 178 179 grille.appendChild(texte); 180 grille.appendChild(bouton); 181 el.appendChild(grille); 182 el.appendChild(croix); 183 184 return el; 185 } 186 187 /* ------------------------------------------------------------ affichage */ 188 189 function affiche() { 190 if (bandeau || estMasque()) { 191 return; 192 } 193 194 injecteStyle(); 195 bandeau = construit(); 196 document.body.appendChild(bandeau); 197 198 minuteur = window.setTimeout(disparait, DELAI_AFFICHAGE); 199 } 200 201 /** Fermeture par la croix : choix explicite du visiteur, mémorisé 6 mois. */ 202 function ferme() { 203 masqueSansMemoriser(); 204 memoriseMasquage(PAR_CROIX); 205 } 206 207 /** 208 * Disparition automatique : masquage court, le visiteur n'ayant rien choisi. 209 * Sans mémorisation, le bandeau reviendrait à chaque page, ce que les 210 * recommandations du comité RGPD visent précisément à supprimer. Une croix 211 * cliquée entre-temps dans un autre onglet garde ses 6 mois. 212 */ 213 function disparait() { 214 masqueSansMemoriser(); 215 if (PAR_CROIX !== masquage()) { 216 memoriseMasquage(PAR_DELAI); 217 } 218 } 219 220 function masqueSansMemoriser() { 221 window.clearTimeout(minuteur); 222 223 if (bandeau && bandeau.parentNode) { 224 bandeau.parentNode.removeChild(bandeau); 225 } 226 bandeau = null; 227 } 228 229 /* --------------------------------------------------------------- Didomi */ 230 231 // Cookie de la version du 14/09/2026 (voir VALEUR_V1) : sa fermeture est 232 // inconnue, il est traité comme une disparition automatique. 233 if (VALEUR_V1 === lisCookie()) { 234 memoriseMasquage(PAR_DELAI); 235 } 236 237 // Masquage lu dès le chargement, par sécurité. Au retrait du consentement, un 238 // tag GTM (GTM-M55VGXP, tag 117) supprime les cookies hors de sa liste 239 // blanche avant l'appel des listeners Didomi : si ce cookie en sortait, 240 // masquage() y lirait un cookie déjà effacé. 241 var masqueAuChargement = masquage(); 242 243 function refuse() { 244 return window.Didomi && false === window.Didomi.getUserConsentStatusForPurpose(FINALITE_DIDOMI); 245 } 246 247 window.didomiOnReady = window.didomiOnReady || []; 248 window.didomiOnReady.push(function () { 249 if (refuse()) { 250 affiche(); 251 } 252 }); 253 254 window.didomiEventListeners = window.didomiEventListeners || []; 255 window.didomiEventListeners.push({ 256 event: 'consent.changed', 257 listener: function () { 258 if (refuse()) { 259 // Refus exprimé depuis la CMP. Bandeau déjà masqué : on ré-arme ce 260 // masquage, avec sa durée, sans le réafficher. Cela recrée aussi
261 // le cookie s'il a été purgé par GTM (voir masqueAuChargement). 262 var par = masquage() || masqueAuChargement; 263 if (par) { 264 memoriseMasquage(par); 265 return; 266 } 267 268 // Sinon le bandeau a lieu d'être ; affiche ne fait rien s'il 269 // est encore à l'écran. 270 affiche(); 271 return; 272 } 273 274 // Consentement donné : le bandeau n'a plus lieu d'être. 275 masqueSansMemoriser(); 276 } 277 }); 278 279 window.MVI_CookieWall = { 280 affiche: affiche, 281 ferme: ferme, 282 estMasque: estMasque 283 }; 284}());
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.