1(function(){var W=document.getElementById('fchat');if(!W)return;W.hidden=false; 2/* polices : si le site n'en déclare pas dans le Customizer, on prend celles calculées du body et des titres */ 3try{var cs=getComputedStyle(W);var fb=cs.getPropertyValue('--fc-fb').trim(),ft=cs.getPropertyValue('--fc-ft').trim();if(!fb||fb==='inherit'){W.style.setProperty('--fc-fb',getComputedStyle(document.body).fontFamily);}if(!ft||ft==='inherit'){var h=document.querySelector('h1,h2');W.style.setProperty('--fc-ft',h?getComputedStyle(h).fontFamily:getComputedStyle(document.body).fontFamily);}}catch(e){} 4var relais=W.getAttribute('data-relais')+'/chat',sitekey=W.getAttribute('data-turnstile'),agent=W.getAttribute('data-agent');function banque(sel){try{return JSON.parse(W.querySelector(sel).textContent);}catch(e){return [];}}var B1=banque('[data-fchat-m1]'),B2=banque('[data-fchat-m2]');function tirer(b){return b[Math.floor(Math.random()*b.length)]||'';} 5var fen=W.querySelector('[data-fchat-fen]'),fil=W.querySelector('[data-fchat-fil]'),form=W.querySelector('[data-fchat-form]'),ta=form.querySelector('textarea'),btn=form.querySelector('button'),tsBox=W.querySelector('[data-fchat-ts]'),notifs=W.querySelector('[data-fchat-notifs]'),badge=W.querySelector('[data-fchat-badge]'); 6var hist=[],sid='',widget=null,tsPret=null,nonLus=0,ouvert=false,etat={}; 7var persona='';/* interlocuteur choisi (sites à plusieurs intervenants) â vide = l'agent du site */ 8function lire(k,d){try{var v=sessionStorage.getItem(k);return v===null?d:JSON.parse(v);}catch(e){return d;}}function ecrire(k,v){try{sessionStorage.setItem(k,JSON.stringify(v));}catch(e){}} 9sid=lire('fchat_sid','');hist=lire('fchat_h',[]);etat=lire('fchat_e',{}); 10if(!sid){sid=Array.from(crypto.getRandomValues(new Uint8Array(12)),function(b){return b.toString(16).padStart(2,'0');}).join('');ecrire('fchat_sid',sid);} 11function esc(s){return s.replace(/[&<>"']/g,function(c){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];});} 12function lier(s){var h=location.origin;return esc(s).replace(new RegExp('('+h.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'[^\\s<]*)','g'),function(u){var f=u.replace(/[.,;:!?)]+$/,'');return '<a href="'+f+'">'+f+'</a>'+u.slice(f.length);});} 13function bulle(role,txt){var d=document.createElement('div');d.className='fchat-m '+(role==='user'?'fchat-m--moi':'fchat-m--bot');if(role==='user')d.textContent=txt;else d.innerHTML=lier(txt);fil.appendChild(d);fil.scrollTop=fil.scrollHeight;return d;} 14function ecrit(mode){var e=fil.querySelector('.fchat-ecrit');if(!mode){if(e)e.remove();return;}if(!e){e=document.createElement('div');e.className='fchat-ecrit';fil.appendChild(e);}e.innerHTML=mode==='attente'?'<i class="fchat-att"><span></span></i>En attente de réponseâ¦':'<i><span></span><span></span><span></span></i>'+esc(agent)+' écritâ¦';fil.scrollTop=fil.scrollHeight;} 15function sauver(){if(hist.length>16)hist=hist.slice(-16);ecrire('fchat_h',hist);} 16function aEcrit(){return hist.some(function(m){return m.role==='user';});} 17function accueil(txt){hist.push({role:'assistant',content:txt,accueil:true});sauver();if(ouvert){bulle('assistant',txt);}else{nonLus++;badge.textContent=nonLus;badge.hidden=false;notif(txt);}} 18var photo=W.getAttribute('data-photo')||'';function av(){return photo?'<img class="fchat-av" src="'+esc(photo)+'" alt="">':'<span class="fchat-av">'+esc(agent.charAt(0))+'</span>';} 19function notif(txt){var n=document.createElement('div');n.className='fchat-notif';n.innerHTML=av()+'<div><b>'+esc(agent)+'</b><p>'+esc(txt)+'</p></div>';n.addEventListener('click',ouvrir);notifs.appendChild(n);requestAnimationFrame(function(){n.classList.add('est-visible');});setTimeout(function(){n.classList.add('disparait');setTimeout(function(){n.remove();},950);},mobile()?4200:3200);} 20function mobile(){return window.matchMedia('(max-width:600px)').matches;} 21var scrollSauv=0,verrouille=false;function verrou(on){if(on&&mobile()){if(verrouille)return;verrouille=true;scrollSauv=window.scrollY||0;document.documentElement.classList.add('fchat-lock');document.body.classList.add('fchat-lock');document.body.style.top=(-scrollSauv)+'px';}else if(verrouille){verrouille=false;document.documentElement.classList.remove('fchat-lock');document.body.classList.remove('fchat-lock');document.body.style.top='';window.scrollTo(0,scrollSauv);}} 22/* mobile : la fenêtre épouse EXACTEMENT la zone visible (clavier compris) via visualVie
22wport : en-tête en haut, saisie au-dessus du clavier, seul le fil défile */ 23function ajusterVV(){if(!ouvert||!mobile()||!window.visualViewport){return;}var vv=window.visualViewport;fen.style.top=Math.max(0,vv.offsetTop)+'px';fen.style.height=Math.round(vv.height)+'px';fen.style.bottom='auto';window.scrollTo(0,0);fil.scrollTop=fil.scrollHeight;} 24if(window.visualViewport){window.visualViewport.addEventListener('resize',ajusterVV);window.visualViewport.addEventListener('scroll',ajusterVV);} 25ta.addEventListener('focus',function(){setTimeout(ajusterVV,50);setTimeout(ajusterVV,350);});ta.addEventListener('blur',function(){setTimeout(ajusterVV,50);}); 26function ouvrir(){ouvert=true;etat.vu=1;etat.ouvert=1;ecrire('fchat_e',etat);if(!etat.m1&&!etat.hl){clearTimeout(tm1);direM1();}W.classList.add('est-ouvert');verrou(true);fen.hidden=false;ajusterVV();nonLus=0;badge.hidden=true;notifs.innerHTML='';fil.innerHTML='';hist.forEach(function(m){bulle(m.role,m.content);});ta.focus();chargerTurnstile();verifierEtat();} 27function horsLigne(portee){etat.hl=portee;ecrire('fchat_e',etat);var d=W.querySelector('.fchat-dot'),t=W.querySelector('.fchat-tete-t span');if(d)d.style.background='#9a9a9a';if(t)t.innerHTML=t.innerHTML.replace('en ligne','hors ligne');ta.disabled=true;ta.placeholder=portee==='session'?'Conversation terminée â écrivez-nous via la page contact.':'Hors ligne pour aujourdâhui â écrivez-nous via la page contact.';btn.disabled=true;} 28function fermer(){ouvert=false;etat.ouvert=0;ecrire('fchat_e',etat);W.classList.remove('est-ouvert');verrou(false);fen.hidden=true;fen.style.top='';fen.style.height='';fen.style.bottom='';} 29/* Clic sur un lien proposé dans la conversation : on REPLIE le chat avant de naviguer. 30 Sans ça, l'état ouvert est mémorisé en session et la page d'arrivée se charge avec la 31 fenêtre de chat par-dessus le contenu qu'on venait justement consulter (07/09/2026). */ 32fil.addEventListener('click',function(e){var a=e.target.closest&&e.target.closest('a[href]');if(!a)return;etat.ouvert=0;ecrire('fchat_e',etat);}); 33window.addEventListener('resize',function(){verrou(ouvert);}); 34if(etat.ouvert){fen.style.animation='none';ouvrir();fen.style.animation='';} 35// /etat seulement à l'ouverture, une fois par page, en text/plain (pas de pré-requête OPTIONS) : quota Workers 100k/jour (30/09/2026) 36var etatVerifie;function verifierEtat(){if(etatVerifie||etat.hl)return;etatVerifie=true;fetch(W.getAttribute('data-relais')+'/etat',{method:'POST',headers:{'Content-Type':'text/plain'},body:JSON.stringify({sid:sid})}).then(function(r){return r.json();}).then(function(d){if(d&&d.enligne===false){horsLigne(d.portee);}}).catch(function(){});} 37if(etat.hl){horsLigne(etat.hl);} 38/* les deux messages d'accueil : une fois par session â 2 s après l'arrivée, puis 10 s plus tard si le visiteur n'a rien écrit */ 39var tm1=null,tm2=null;function direM1(){if(etat.m1||etat.hl)return;etat.m1=1;ecrire('fchat_e',etat);accueil(tirer(B1));tm2=setTimeout(function(){if(etat.m2||aEcrit()||etat.hl||ouvert)return;etat.m2=1;ecrire('fchat_e',etat);accueil(tirer(B2));},25000);} 40if(!etat.m1&&!etat.hl){tm1=setTimeout(direM1,6000);} 41else if(!etat.vu&&hist.length&&!aEcrit()){nonLus=hist.length;badge.textContent=nonLus;badge.hidden=false;} 42function chargerTurnstile(){if(tsPret)return tsPret;tsPret=new Promise(function(res){var s=document.createElement('script');s.src='https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';s.async=true;s.onload=function(){widget=turnstile.render(tsBox,{sitekey:sitekey,execution:'execute',appearance:'execute',callback:function(){}});res();};document.head.appendChild(s);});return tsPret;} 43var dejaExecute=false;function jeton(){return new Promise(function(res,rej){var fini=false,fin=function(v,ok){if(fini)return;fini=true;clearTimeout(tm);ok?res(v):rej();},tm=setTimeout(function(){fin(null,false);},12000);try{if(dejaExecute)turnstile.reset(widget);dejaExecute=true;turnstile.execute(widget,{callback:function(v){fin(v,true);},'error-callback':function(){fin(null,false);},'expired-callback':function(){fin(null,false);}});}catch(e){fin(null,false);}});} 44var bouton=W.querySelector('[data-fchat-ouvrir]');if(photo){var mini=document.createElement('img');mini.className='fchat-mini';mini.src=photo;mini.alt='';mini.width=26;mini.height=26;bouton.appendChild(mini);} 45bouton.addEventListener('click',ouvrir); 46/* API du site : window.factoryChat.ouvrir({persona,nom,avatar}) â ouvre le chat AVEC cette personne.
47 Changer d'interlocuteur repart sur un fil neuf (nouveau sid) : une conversation qui change de 48 personne au milieu serait illisible dans l'archive. Sans argument, comportement d'origine. */ 49function neufFil(){hist=[];clearTimeout(tm1);clearTimeout(tm2); 50 /* m1/m2 marqués comme déjà dits : les accueils génériques du site ne doivent pas s'intercaler 51 au milieu d'une conversation ouverte avec quelqu'un en particulier. */ 52 etat={m1:1,m2:1,vu:1,ouvert:1};ecrire('fchat_h',hist);ecrire('fchat_e',etat); 53 sid=Array.from(crypto.getRandomValues(new Uint8Array(12)),function(b){return b.toString(16).padStart(2,'0');}).join('');ecrire('fchat_sid',sid); 54 fil.innerHTML='';nonLus=0;badge.hidden=true;notifs.innerHTML='';clearTimeout(tm1);clearTimeout(tm2);} 55window.factoryChat={ouvrir:function(o){o=o||{}; 56 var cle=(o.persona||'').toString(); 57 if(cle!==persona){neufFil();persona=cle; 58 if(o.nom){agent=o.nom.split(' ')[0];W.setAttribute('data-agent',agent); 59 var tb=W.querySelector('.fchat-tete-t b');if(tb)tb.textContent=o.nom; 60 var ts2=W.querySelector('.fchat-tete-t span');if(ts2&&o.role)ts2.innerHTML=esc(o.role)+' · <i class="fchat-dot"></i> en ligne';} 61 if(o.avatar){photo=o.avatar;W.setAttribute('data-photo',photo); 62 W.querySelectorAll('img.fchat-av,img.fchat-mini,.fchat-tete img').forEach(function(i){i.src=photo;});} 63 if(cle){accueil('Bonjour, '+agent+'. Dites-moi ce qui vous amène â je vous dirai tout de suite si câest de mon ressort et ce quâil faut regarder en premier.');}} 64 ouvrir();},persona:function(){return persona;}}; 65W.querySelectorAll('[data-fchat-fermer]').forEach(function(b){b.addEventListener('click',fermer);}); 66ta.addEventListener('keydown',function(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();form.requestSubmit();}}); 67form.addEventListener('submit',async function(e){e.preventDefault();var q=ta.value.trim().slice(0,500);if(!q||btn.disabled)return;ta.value='';btn.disabled=true;bulle('user',q);hist.push({role:'user',content:q});sauver();etat.m2=1;clearTimeout(tm2);ecrire('fchat_e',etat);var t0=Date.now(),attente=2000+Math.random()*4000;ecrit('attente');var minuteur=setTimeout(function(){ecrit('ecrit');},attente); 68 try{await chargerTurnstile();var t;try{t=await jeton();}catch(x){t='';} 69 var r=await fetch(relais,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sid:sid,turnstile:t,persona:persona,messages:hist.filter(function(m){return !m.accueil;}).slice(-13)})});var d={};try{d=await r.json();}catch(x){} 70 if(r.ok&&d.silence){clearTimeout(minuteur);await new Promise(function(res){setTimeout(res,Math.max(0,1200-(Date.now()-t0)));});ecrit(false);btn.disabled=false;ta.focus();return;} 71 var rep=d.reponse||'Je nâarrive pas à répondre pour le moment. Réessayez dans quelques minutes, ou écrivez-nous par la page contact.'; 72 var reste=Math.max(0,attente+900+Math.min(2500,rep.length*6)-(Date.now()-t0));await new Promise(function(res){setTimeout(res,reste);});clearTimeout(minuteur);ecrit(false);bulle('assistant',rep); 73 if(r.ok){hist.push({role:'assistant',content:rep});sauver();}else{hist.pop();sauver();} 74 if(d.erreur==='quota'){horsLigne(d.portee||'session');btn.disabled=true;ta.focus=function(){};} 75 }catch(x){clearTimeout(minuteur);ecrit(false);bulle('assistant','Impossible de joindre le site. Vérifiez votre connexion et réessayez.');hist.pop();sauver();} 76 if(!etat.hl){btn.disabled=false;ta.focus();}}); 77})();
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.