PageSourceSearch

https://www.centresante-squaremutualite.fr/assets/js/global.js

js centresante-squaremutualite.fr collected 2026-10-05 07:00:26 UTC 48,766 bytes, 1,462 lines download raw bytes

1function debounce(func, wait, immediate) {
2  var timeout;
3
4  return function executedFunction() {
5    var context = this;
6    var args = arguments;
7
8    var later = function () {
9      timeout = null;
10      if (!immediate) func.apply(context, args);
11    };
12
13    var callNow = immediate && !timeout;
14
15    clearTimeout(timeout);
16
17    timeout = setTimeout(later, wait);
18
19    if (callNow) func.apply(context, args);
20  };
21}
22
23function createCookie(name, value, nbDays) {
24  var today = new Date(),
25    expires = new Date();
26  expires.setTime(today.getTime() + nbDays * 24 * 60 * 60 * 1000);
27  document.cookie =
28    name +
29    "=" +
30    encodeURIComponent(value) +
31    ";expires=" +
32    expires.toGMTString();
33}
34function readCookie(name) {
35  var oRegex = new RegExp("(?:; )?" + name + "=([^;]*);?");
36  if (oRegex.test(document.cookie)) {
37    return decodeURIComponent(RegExp["$1"]);
38  } else {
39    return null;
40  }
41}
42var target_href;
43function RecupParam(name) {
44  name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
45  var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
46    results = regex.exec(location.search);
47  return results === null
48    ? ""
49    : decodeURIComponent(results[1].replace(/\+/g, " "));
50}
51
52/* Affichage des cookies */
53function readCookie(name) {
54  var nameEQ = name + "=";
55  var ca = document.cookie.split(";");
56  for (var i = 0; i < ca.length; i++) {
57    var c = ca[i];
58    while (c.charAt(0) == " ") c = c.substring(1, c.length);
59    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
60  }
61  return null;
62}
63
64function createCookieValidation() {
65  var dateJour = new Date();
66  var date1an = new Date(
67    Date.UTC(
68      dateJour.getFullYear() + 1,
69      dateJour.getMonth(),
70      dateJour.getDate(),
71      0,
72      0,
73      0
74    )
75  );
76  document.cookie = "cookie=ok; expires=" + date1an + "; path=/";
77  $("#cookieChoice").slideUp();
78}
79
80function stopResponsiveTransition() {
81  var timer = null;
82  var viewportWidth = window.innerWidth;
83  window.addEventListener("resize", function () {
84    if (timer) {
85      clearTimeout(timer);
86      timer = null;
87    } else {
88      $(".navigationNiv3").addClass("stop-transition");
89      $(".navigationNiv2 > .BigMenu").addClass("stop-transition");
90    }
91    timer = setTimeout(function () {
92      $(".navigationNiv3").removeClass("stop-transition");
93      $(".navigationNiv2 > .BigMenu").removeClass("stop-transition");
94      timer = null;
95    }, 50);
96
97    // ACS 350 - Mutualisation header mobile et desktop
98    var header = document.querySelector("header");
99    if (
100      header &&
101      ((viewportWidth < 1240 && window.innerWidth >= 1240) ||
102        (viewportWidth >= 1240 && window.innerWidth < 1240))
103    ) {
104      viewportWidth = window.innerWidth;
105      var overlay = document.querySelector("#overlay");
106      if (header.classList && header.classList.contains("actif")) {
107        header.classList.add("inactif");
108        header.classList.remove("actif");
109        document.body.classList.remove("lockscroll");
110        if (overlay) overlay.style.display = "none";
111      }
112      var opennedMenu = document.querySelector(
113        "header nav#menuhamb .navigationNiv2 ul.actif"
114      );
115      if (opennedMenu) {
116        opennedMenu.classList.remove("actif");
117        if (overlay) overlay.style.display = "none";
118      }
119    }
120  });
121}
122
123/**
124 * ACCESSIBILITÉ : Ferme un sous-menu proprement (focus d'abord, puis aria-hidden)
125 */
126
127/**
128 * Vérifie si un élément est visible (fonctionne avec position:fixed)
129 */
130function isElementVisible(el) {
131  if (!el) return false;
132  
133  var style = window.getComputedStyle(el);
134  if (style.display === 'none' || 
135      style.visibility === 'hidden' || 
136      style.opacity === '0') {
137    return false;
138  }
139  
140  var rect = el.getBoundingClientRect();
141  if (rect.width === 0 && rect.height === 0) {
142    return false;
143  }
144  
145  var parent = el.parentElement;
146  while (parent) {
147    var parentStyle = window.getComputedStyle(parent);
148    if (parentStyle.display === 'none' || 
149        parentStyle.visibility === 'hidden') {
150      return false;
151    }
152    parent = parent.parentElement;
153  }
154  
155  return true;
156}
157
158/**
159 * Force le retrait du focus de tous les éléments d'un conteneur
160 * en déplaçant le focus sur un élément cible AVANT de cacher le conteneur
161 */
162function forceFocusOut($container, $focusTarget) {
163  // Créer un élément temporaire invisible pour capturer le focus
164  var tempFocusTrap = document.createElement('span');
165  tempFocusTrap.setAttribute('tabindex', '-1');
166  tempFocusTrap.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none;';
167  document.body.appendChild(tempFocusTrap);
168  tempFocusTrap.focus();
169  
170  // Nettoyer immédiatement
171  setTimeout(function() {
172    if (tempFocusTrap.parentNode) {
173      tempFocusTrap.parentNode.removeChild(tempFocusTrap);
174    }
175    if ($focusTarget && $focusTarget.length) {
176      $focusTarget.focus();
177    }
178  }, 0);
179}
180
181function closeSubmenuAccessible($submenu, $parentButton) {
182  // 1. D'abord déplacer le focus HORS du sous-menu
183  if ($parentButton && $parentButton.length) {
184    $parentButton.focus();
185  } else {
186    // Fallback : focus sur le body
187    document.body.focus();
188  }
189  
190  // 2. Ensuite seulement mettre aria-hidden (après un petit délai pour laisser le focus se déplacer)
191  setTimeout(function() {
192    $submenu.attr("aria-hidden", "true");
193  }, 50);
194}
195
196function inactiveBigMenu(element) {
197  // ACCESSIBILITÉ : Trouver le bouton parent AVANT de fermer
198  var $navigationNiv3 = $(element).closest(".navigationNiv3");
199  var menuId = $navigationNiv3.attr("id");
200  var $parentButton = $("a[aria-controls='" + menuId + "']");
201  
202  $(element).parent().parent().removeClass("actif");
203  $("body .navigationHeader > a").removeClass("actif");
204  $("header").removeClass("bigMenuActif");
205  $(".sousmenu").find(".actif").removeClass("actif");
206  
207  // ACCESSIBILITÉ : Mettre à jour aria-expanded sur tous les boutons BigMenu
208  $("a.BigMenu[role='button']").attr("aria-expanded", "false");
209  $(".navigationHeader > a[role='button']").attr("aria-expanded", "false");
210  
211  // ACCESSIBILITÉ : Fermer proprement avec gestion du focus
212  if ($parentButton.length) {
213    $parentButton.focus();
214  }
215  
216  // FIX menu mobile et overlay
217  var header = document.querySelector("header");
218  if (!(header && header.classList && header.classList.contains("actif"))) {
219    var overlay = document.querySelector("#overlay");
220    if (overlay) overlay.style.display = "none";
221  }
222}
223
224$(document).ready(function () {
225  
226  // ============================================
227  // ACCESSIBILITÉ NAVIGATION - RGAA 7.1
228  // ============================================
229  initAccessibleNavigation();
230  
231  // MOBILE : Gestion des sous-menus
232  $("nav#menuhamb > ul > li > a[href='#']").on("click", function (e) {
233    e.preventDefault();
234    e.stopPropagation();
235    
236    var $this = $(this);
237    var $parent = $this.parent();
238    var wasSelected = $parent.hasClass("selected");
239    
240    // Fermer tous les autres sous-menus d'abord
241    var $otherItems = $("nav#menuhamb > ul > li").not($parent);
242    
243    // ACCESSIBILITÉ : Forcer le focus hors des sous-menus AVANT de les fermer
244    $otherItems.find(".sousmenu").each(function() {
245      if ($.contains(this, document.activeElement)) {
246        forceFocusOut($(this), $this);
247      }
248    });
249    
250    $otherItems.removeClass("selected");
251    $("nav#menuhamb > ul > li > a[href='#']").not(this).attr("aria-expanded", "false");
252    
253    // Fermer les sous-menus des autres items - avec délai pour que forceFocusOut ait le temps
254    setTimeout(function() {
255      $otherItems.find(".sousmenu").attr("aria-hidden", "true");
256      $otherItems.find(".sousmenu").find('a[href], button:not([disabled])').attr('tabindex', '-1');
257      $otherItems.find(".navigationNiv3").removeClass("actif").attr("aria-hidden", "true");
258    }, 10);
259    
260    if (!wasSelected) {
261      // Ouvrir ce sous-menu
262      $parent.addClass("selected");
263      $this.attr("aria-expanded", "true");
264      
265      // ACCESSIBILITÉ : Mettre aria-hidden="false" sur le sous-menu ouvert
266      var submenuId = $this.attr("aria-controls");
267      if (submenuId) {
268        $("#" + submenuId).attr("aria-hidden", "false");
269        // ACCESSIBILITÉ : Initialiser les BigMenu du sous-menu qui vient de s'ouvrir
270        initBigMenuButtons(document.getElementById(submenuId));
271        
272        // ACCESSIBILITÉ : Mettre à jour le tabindex de TOUS les liens et focus le premier
273        setTimeout(function() {
274          var submenu = document.getElementById(submenuId);
275          if (submenu) {
276            // Rendre TOUS les liens/boutons du sous-menu focusables
277            submenu.querySelectorAll('a[href], button:not([disabled])').forEach(function(el) {
278              if (el.getAttribute('tabindex') === '-1') {
279                el.setAttribute('tabindex', '0');
280              }
281            });
282            
283            var firstFocusable = submenu.querySelector('a[href]:not(.fermerSousMenu), a.BigMenu');
284            if (firstFocusable) {
285              firstFocusable.focus();
286            }
287          }
288        }, 150);
289      }
290    } else {
291      // Fermer ce sous-menu
292      $parent.removeClass("selected");
293      $this.attr("aria-expanded", "false");
294      
295      // ACCESSIBILITÉ : Mettre aria-hidden="true" sur le sous-menu fermé
296      var submenuId = $this.attr("aria-controls");
297      if (submenuId) {
298        var submenuEl = document.getElementById(submenuId);
299        if (submenuEl && $.contains(submenuEl, document.activeElement)) {
300          forceFocusOut($(submenuEl), $this);
301        }
302        setTimeout(function() {
303          $("#" + submenuId).attr("aria-hidden", "true");
304          $("#" + submenuId).find('a[href], button:not([disabled])').attr('tabindex', '-1');
305        }, 10);
306      }
307    }
308    
309    return false;
310  });
311
312  /* TODO : Gestion collapse footer à mutualiser dans JS base du GUI */
313  (function () {
314    var collapsesFooter = document.querySelectorAll(".footer-collapse-trigger");
315    collapsesFooter.forEach(function (button) {
316      button.addEventListener("click", function (event) {
317        event.preventDefault();
318        var element = document.querySelector(
319          '[data-id="' + $(this).attr("data-triggerid") + '"]'
320        );
321        var collapse = button.parentNode;
322
323        if (collapse && collapse.classList.contains("fieldsetPlus")) {
324          collapse.classList.remove("fieldsetPlus");
325          collapse.classList.add("fieldsetMoins");
326          button.setAttribute("aria-expanded", true);
327          button.setAttribute("title", button.dataset.tooltipless);
328          button.innerHTML = button.dataset.labeldisplayless;
329        } else {
330          collapse.classList.remove("fieldsetMoins");
331          collapse.classList.add("fieldsetPlus");
332          button.setAttribute("aria-expanded", false);
333          button.setAttribute("title", button.dataset.tooltipmore);
334          button.innerHTML = button.dataset.labeldisplaymore;
335        }
336      });
337    });
338  })();
339
340  /* Big Menu */
341  // Permet d'activer le scroll du BigMenu en mobile si celui-ci est trop grand.
342  $(".navigationNiv3, .navigationNiv2 > .BigMenu").css(
343    "max-height",
344    $("body").height() -
345      $("#menuheader").height() -
346      $("#conteneurlogo").height()
347  );
348
349  $("a.BigMenu").on("mouseover", function () {
350    if ($(window).width() > 1239) {
351      changeBigMenu($(this));
352    }
353  });
354  $("a.BigMenu").on("click", function (e) {
355    e.preventDefault();
356    changeBigMenu($(this));
357    return false;
358  });
359
360  $(
361    "#overlay, body:not(.theme6) #menuheader, ul#sousmenu_auto > li > a:not('.BigMenu'), ul#sousmenu_santeprev > li > a:not('.BigMenu'), ul#sousmenu_habitation > li > a:not('.BigMenu')"
362  ).on("mouseover", function () {
363    if ($(".navigationHeader.focus").length) {
364      return;
365    }
366    $("a.BigMenu").next().removeClass("actif");
367    $("header").removeClass("bigMenuActif");
368    $(".navigationNiv3").attr("aria-hidden", true);
369    $(".sousmenu").find("li").removeClass("actif");
370    
371    // ACCESSIBILITÉ : Mettre à jour aria-expanded
372    $("a.BigMenu[role='button']").attr("aria-expanded", "false");
373    
374    if (!$("header.actif #menuhamb").length) $("#overlay").hide();
375  });
376
377  
378
379  $("main").on("mouseenter", function () {
380    $("header").find(".actif").removeClass("actif");
381    // ACCESSIBILITÉ : Mettre à jour aria-expanded
382    $("a.BigMenu[role='button']").attr("aria-expanded", "false");
383    $(".navigationHeader > a[role='button']").attr("aria-expanded", "false");
384    return false;
385  });
386
387  $(".fermerMenu").off("click").on("click", function (e) {
388    e.preventDefault();
389    e.stopImmediatePropagation();
390    
391    var $navigationNiv3 = $(this).closest(".navigationNiv3");
392    var menuId = $navigationNiv3.attr("id");
393    var $parentButton = $("a[aria-controls='" + menuId + "']");
394    
395    // Mettre à jour aria-expanded
396    if ($parentButton.length) {
397      $parentButton.attr("aria-expanded", "false");
398    }
399    
400    // Fermer UNIQUEMENT le niveau 3
401    $navigationNiv3.removeClass("actif");
402    $navigationNiv3.attr("aria-hidden", "true");
403    $("header").removeClass("bigMenuActif");
404    
405    // Focus direct sur le BigMenu parent (sans forceFocusOut)
406    if ($parentButton.length) {
407      $parentButton.attr("tabindex", "0");
408      $parentButton[0].focus();
409    }
410    
411    return false;
412});
413
414  $("#menuhamb .fermerSousMenu").on("click", function (e) {
415    e.preventDefault();
416    
417    var $item = $(this).closest(".navigationNiv2-item");
418    var $sousmenu = $(this).closest(".sousmenu");
419    var $parentButton = $item.find("> a[href='#']");
420    
421    // ACCESSIBILITÉ : Forcer le focus hors du sous-menu
422    if ($parentButton.length) {
423      $parentButton.attr("aria-expanded", "false");
424      forceFocusOut($sousmenu, $parentButton);
425    }
426    
427    setTimeout(function() {
428      $item.removeClass("selected");
429      $sousmenu.attr("aria-hidden", "true");
430      $sousmenu.find('a[href], button:not([disabled])').attr('tabindex', '-1');
431    }, 10);
432    
433    return false;
434  });
435
436  $("body:not(.theme6) .navigationHeader > a[href='#']").on(
437    "click",
438    function () {
439      var $this = $(this);
440      var attr = $this.attr("id");
441      var test = $this.hasClass("actif");
442      
443      $(".navigationHeader a, .navigationNiv2 ul").removeClass("actif");
444      
445      // ACCESSIBILITÉ : Réinitialiser tous les aria-expanded du header
446      $(".navigationHeader > a[role='button']").attr("aria-expanded", "false");
447      
448      function sousmenu() {
449        $(".navigationNiv2 ul").removeClass("actif");
450        $("#sousmenu_" + attr).addClass("actif");
451      }
452      
453      if (!test) {
454        $this.addClass("actif");
455        // ACCESSIBILITÉ : Mettre à jour aria-expanded
456        $this.attr("aria-expanded", "true");
457        setTimeout(sousmenu, 300);
458      }
459      
460      $(".navigationNiv2 ul")
461        .attr("aria-hidden", true)
462        .find(".BigMenu")
463        .attr("tabindex", "-1");
464
465      $("#sousmenu_" + attr)
466        .attr("aria-hidden", false)
467        .find(".BigMenu")
468        .attr("tabindex", "0");
469      
470      // ACCESSIBILITÉ : Initialiser les BigMenu du sous-menu qui vient de s'ouvrir
471      var submenuIdDesktop = "sousmenu_" + attr;
472      initBigMenuButtons(document.getElementById(submenuIdDesktop));
473      
474      // ACCESSIBILITÉ : Focus automatique sur le premier élément du sous-menu
475      if (!test) {
476        (function(menuId) {
477          setTimeout(function() {
478            var submenu = document.getElementById(menuId);
479            if (submenu) {
480              var firstFocusable = submenu.querySelector('a.BigMenu[tabindex="0"], a.BigMenu, a[href]:not(.fermerSousMenu)');
481              if (firstFocusable) {
482                firstFocusable.setAttribute('tabindex', '0');
483                firstFocusable.focus();
484              }
485            }
486          }, 400);
487        })(submenuIdDesktop);
488      }
489        
490      return false;
491    }
492  );
493
494  $("body.theme6 .navigationHeader > a").on("mouseover", function () {
495    var $this = $(this);
496    var attr = $this.attr("id");
497    $("body.theme6 .navigationHeader > a").removeClass("actif");
498    $("body.theme6 .navigationNiv2 .BigMenu + .navigationNiv3").removeClass(
499      "actif"
500    );
501    
502    // ACCESSIBILITÉ : Réinitialiser tous les aria-expanded
503    $("body.theme6 .navigationHeader > a[role='button']").attr("aria-expanded", "false");
504    
505    $this.addClass("actif");
506    
507    // ACCESSIBILITÉ : Mettre à jour aria-expanded si c'est un bouton
508    if ($this.attr("role") === "button") {
509      $this.attr("aria-expanded", "true");
510    }
511    
512    $("header").addClass("bigMenuActif");
513    if ($this.parents(".navigationHeader").length) {
514      $("#sousmenu_" + attr)
515        .addClass("actif")
516        .attr("aria-hidden", false)
517        .siblings()
518        .attr("aria-hidden", true);
519      
520      // ACCESSIBILITÉ : Initialiser les BigMenu du sous-menu qui vient de s'ouvrir
521      initBigMenuButtons(document.getElementById("sousmenu_" + attr));
522    }
523    $("#overlay").show();
524    return false;
525  });
526
527  stopResponsiveTransition();
528
529  /* Fin Big Menu */
530  $("body header").addClass("inactif");
531  $("header a#btnmenu").on("click", function () {
532    $("body header").removeClass("inactif").addClass("actif");
533    $("body").addClass("lockscroll");
534    $("#overlay").show();
535
536    // Desactivate selected header button
537    var selectedTab = document.querySelector(
538      "#menuheader .navigationHeader a.actif"
539    );
540    if (selectedTab) selectedTab.click();
541
542    return false;
543  });
544  $("header a#closemenu").on("click", function () {
545    $("body header").removeClass("actif");
546    $("nav > div").removeClass("selected");
547    $("#overlay").hide();
548    
549    // ACCESSIBILITÉ : Réinitialiser tous les aria-expanded
550    $("a[role='button']").attr("aria-expanded", "false");
551    
552    // ACCESSIBILITÉ : Fermer tous les sous-menus mobile
553    $("nav#menuhamb > ul > li").removeClass("selected");
554    
555    // ACCESSIBILITÉ : Forcer le focus hors des sous-menus avant aria-hidden
556    $("nav#menuhamb .sousmenu").each(function() {
557      if ($.contains(this, document.activeElement)) {
558        forceFocusOut($(this), $("header a#btnmenu"));
559      }
560    });
561    setTimeout(function() {
562      $("nav#menuhamb .sousmenu").attr("aria-hidden", "true");
563      $("nav#menuhamb .sousmenu").find('a[href], button:not([disabled])').attr('tabindex', '-1');
564    }, 10);
565
566    setTimeout(function () {
567      $("body header").addClass("inactif");
568      $("body").removeClass("lockscroll");
569
570      // On ferme le bigMenu encore actif pour le pro
571      $("body.theme6 .navigationNiv2 .BigMenu + .navigationNiv3")
572        .addClass("stop-transition")
573        .removeClass("actif");
574      $("body.theme6 header").removeClass("bigMenuActif");
575      setTimeout(function () {
576        $("body.theme6 .navigationNiv2 .BigMenu + .navigationNiv3").removeClass(
577          "stop-transition"
578        );
579      }, 50);
580    }, 300);
581    return false;
582  });
583
584  $("button.closeBandeauInfo").on("click", function () {
585    $(this).parents(".gm").hide();
586  });
587});
588
589function changeBigMenu($element) {
590  $(".sousmenu").find("li").removeClass("actif");
591  $("a.BigMenu").next().removeClass("actif");
592  $("header").removeClass("bigMenuActif");
593  
594  // ACCESSIBILITÉ : Réinitialiser tous les aria-expanded des BigMenu
595  $("a.BigMenu[role='button']").attr("aria-expanded", "false");
596  
597  $element.next().addClass("actif");
598  $("header").addClass("bigMenuActif");
599  $("#overlay").show();
600  
601  // ACCESSIBILITÉ : Mettre à jour aria-expanded sur l'élément actif
602  if ($element.attr("role") === "button") {
603    $element.attr("aria-expanded", "true");
604  }
605  
606  if ($(".navigationNiv3").length) {
607    $($element).parent().addClass("actif").siblings().removeClass("actif");
608    $(".navigationNiv3").attr("aria-hidden", true);
609    $("#" + $element.attr("aria-controls"))
610      .attr("aria-hidden", false);
611      
612    // ACCESSIBILITÉ : Mettre à jour tabindex des items du sous-menu ouvert
613    updateSubmenuTabindex($("#" + $element.attr("aria-controls")), true);
614  }
615  return false;
616}
617
618/**
619 * ============================================
620 * ACCESSIBILITÉ NAVIGATION - RGAA 7.1
621 * ============================================
622 */
623
624function initAccessibleNavigation() {
625  // Initialiser les boutons du menu desktop
626  document.querySelectorAll('.navigationHeader > a[aria-controls]').forEach(function(btn) {
627    setupMenuButton(btn);
628  });
629  
630  // Initialiser les boutons du menu mobile
631  document.querySelectorAll('#menuhamb .navigationNiv2-item > a[href="#"]').forEach(function(btn) {
632    setupMenuButton(btn);
633  });
634  
635  // Initialiser les boutons BigMenu (niveau 3)
636  document.querySelectorAll('a.BigMenu[aria-controls]').forEach(function(btn) {
637    setupMenuButton(btn);
638  });
639  
640  // Gestion globale de la touche Escape
641  document.addEventListener('keydown', handleGlobalEscape);
642  
643  // Navigation au clavier dans les sous-menus
644  document.addEventListener('keydown', handleSubmenuKeyboardNavigation);
645  
646  // Marquer la page courante avec aria-current
647  setAriaCurrentPage();
648  
649  // Tracking de aria-current sur l'élément actif
650  setupAriaCurrentTracking();
651}
652
653/**
654 * Configure un bouton de menu avec les événements clavier
655 */
656function setupMenuButton(button) {
657  // Éviter de rebind plusieurs fois
658  if (button.dataset.a11yInitialized) return;
659  button.dataset.a11yInitialized = 'true';
660  
661  // Gestion clavier pour les boutons de menu
662  button.addEventListener('keydown', function(e) {
663    // Space : ouvrir et focus premier élément (les liens ne réagissent pas à Space par défaut)
664    if (e.key === ' ' || e.key === 'Spacebar') {
665      e.preventDefault();
666      e.stopPropagation();
667      openSubmenuAndFocus(button, 'first');
668    }
669    
670    // Entrée : laisser le click natif se produire, puis gérer le focus
671    if (e.key === 'Enter') {
672      // Ne PAS faire preventDefault ni stopPropagation
673      // Le click natif va ouvrir le menu, on gère juste le focus après
674      setTimeout(function() {
675        var submenuId = button.getAttribute('aria-controls');
676        if (submenuId) {
677          var submenu = document.getElementById(submenuId);
678          if (submenu) {
679            var firstFocusable = submenu.querySelector('a[href]:not(.fermerSousMenu):not(.fermerMenu), a.BigMenu');
680            if (firstFocusable) {
681              if (firstFocusable.getAttribute('tabindex') === '-1') {
682                firstFocusable.setAttribute('tabindex', '0');
683              }
684              firstFocusable.focus();
685            }
686          }
687        }
688      }, 400);
689    }
690    
691    // Flèche bas : ouvrir et focus premier élément
692    if (e.key === 'ArrowDown') {
693      e.preventDefault();
694      e.stopPropagation();
695      openSubmenuAndFocus(button, 'first');
696    }
697    
698    // Flèche haut : ouvrir et focus dernier élément
699    if (e.key === 'ArrowUp') {
700      e.preventDefault();
701      e.stopPropagation();
702      openSubmenuAndFocus(button, 'last');
703    }
704  });
705}
706
707/**
708 * Initialise les boutons BigMenu dans un sous-menu qui vient de s'ouvrir
709 */
710function initBigMenuButtons(container) {
711  if (!container) return;
712  container.querySelectorAll('a.BigMenu[aria-controls]').forEach(function(btn
712) {
713    setupMenuButton(btn);
714  });
715}
716
717/**
718 * Ouvre le sous-menu et met le focus sur le premier ou dernier élément
719 */
720function openSubmenuAndFocus(button, position) {
721  var submenuId = button.getAttribute('aria-controls');
722  if (!submenuId) return;
723  
724  var submenu = document.getElementById(submenuId);
725  if (!submenu) return;
726  
727  // Déclencher l'ouverture
728  if (window.innerWidth >= 1240) {
729    // Desktop : simuler mouseover pour le BigMenu
730    var event = new MouseEvent('mouseover', { bubbles: true, cancelable: true });
731    button.dispatchEvent(event);
732  } else {
733    // Mobile : simuler un clic
734    button.click();
735  }
736  
737  // Attendre que le menu soit ouvert puis focus
738  setTimeout(function() {
739    // Vérifier que le sous-menu est maintenant visible
740    var isVisible = submenu.classList.contains('actif') || 
741                    submenu.getAttribute('aria-hidden') === 'false' ||
742                    submenu.closest('.selected');
743    
744    if (!isVisible) return;
745    
746    // Trouver tous les éléments focusables (exclure ceux avec tabindex="-1" sauf si le menu est ouvert)
747    var focusables = submenu.querySelectorAll('a[href], button:not([disabled])');
748    if (focusables.length === 0) return;
749    
750    // Rendre tous les éléments focusables
751    focusables.forEach(function(el) {
752      if (el.getAttribute('tabindex') === '-1') {
753        el.setAttribute('tabindex', '0');
754      }
755    });
756    
757    var targetElement;
758    if (position === 'first') {
759      // Premier élément focusable (pas le bouton fermer)
760      for (var i = 0; i < focusables.length; i++) {
761        if (!focusables[i].classList.contains('fermerSousMenu') && 
762            !focusables[i].classList.contains('fermerMenu')) {
763          targetElement = focusables[i];
764          break;
765        }
766      }
767      // Fallback sur le premier si tous sont des boutons fermer
768      if (!targetElement) targetElement = focusables[0];
769    } else {
770      targetElement = focusables[focusables.length - 1];
771    }
772    
773    if (targetElement) {
774      targetElement.focus();
775    }
776  }, 200);
777}
778
779/**
780 * Gestion globale de la touche Escape
781 */
782function handleGlobalEscape(e) {
783  if (e.key !== 'Escape' && e.key !== 'Esc') return;
784  
785  // Chercher le sous-menu niveau 3 actif en premier
786  var activeNiv3 = document.querySelector('.navigationNiv3.actif');
787  if (activeNiv3) {
788    e.preventDefault();
789    var closeBtn = activeNiv3.querySelector('.fermerMenu');
790    if (closeBtn) {
791      closeBtn.click();
792    }
793    return;
794  }
795  // Sinon chercher un menu mobile ouvert (item avec classe "selected")
796  var selectedMobileItem = document.querySelector('#menuhamb .navigationNiv2-item.selected');
797  if (selectedMobileItem) {
798    e.preventDefault();
799    var closeBtn = selectedMobileItem.querySelector('.fermerSousMenu');
800    if (closeBtn) {
801      closeBtn.click();
802    }
803    return;
804  }
805  
806  // Sinon chercher le sous-menu niveau 2 actif (desktop)
807  var activeSousmenu = document.querySelector('.navigationNiv2 .sousmenu.actif');
808  if (activeSousmenu) {
809    e.preventDefault();
810    // Trouver le bouton parent dans le header
811    var parentButton = document.querySelector('.navigationHeader > a.actif[aria-controls]');
812    if (parentButton) {
813      // Simuler un clic pour fermer (toggle)
814      parentButton.click();
815      parentButton.focus();
816    }
817    return;
818  }
819  
820  // Sinon fermer le menu hamburger si ouvert
821  var header = document.querySelector('header.actif');
822  if (header) {
823    e.preventDefault();
824    var closeMenuBtn = document.querySelector('#closemenu');
825    if (closeMenuBtn) {
826      closeMenuBtn.click();
827    }
828  }
829}
830
831/**
832 * Navigation au clavier dans les sous-menus (flèches haut/bas/gauche/droite + Tab amélioré)
833 */
834function handleSubmenuKeyboardNavigation(e) {
835  if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'ArrowLeft' && e.key !== 'ArrowRight' && e.key !== 'Tab') return;
836  
837  var activeElement = document.activeElement;
838  if (!activeElement) return;
839  
840  // Vérifier si on est dans un sous-menu
841  var parentSubmenu = activeElement.closest('.sousmenu, .navigationNiv3');
842  if (!parentSubmenu) return;
843  
844  // Vérifier que le sous-menu est actif/visible
845  var isVisible = parentSubmenu.classList.contains('actif') || 
846                  parentSubmenu.getAttribute('aria-hidden') === 'false' ||
847                  parentSubmenu.closest('.selected');
848  if (!isVisible) return;
849  
850  // Pour Tab, gestion spéciale pour navigation circulaire
851  if (e.key === 'Tab') {
852    var allFocusables = parentSubmenu.querySelectorAll('a[href], button:not([disabled])');
853    allFocusables.forEach(function(item) {
854      if (item.getAttribute('tabindex') === '-1') {
855        item.setAttribute('tabindex', '0');
856      }
857    });
858    
859    // Si on est dans un navigationNiv3 (sous-sous-menu)
860    var currentNiv3 = activeElement.closest('.navigationNiv3.actif');
861    
862    if (currentNiv3) {
863      var focusablesInNiv3 = Array.prototype.slice.call(
864        currentNiv3.querySelectorAll('a[href]:not(.fermerMenu):not(.fermerSousMenu), button:not([disabled]):not(.fermerMenu):not(.fermerSousMenu)')
865      ).filter(function(el) {
866        return isElementVisible(el);
867      });
868      
869      var currentIndex = focusablesInNiv3.indexOf(activeElement);
870      var isLastElement = currentIndex === focusablesInNiv3.length - 1;
871      var isFirstElement = currentIndex === 0;
872      
873      if (!e.shiftKey && isLastElement) {
874        e.preventDefault();
875        focusablesInNiv3[0].focus();
876        return;
877      }
878      
879      if (e.shiftKey && isFirstElement) {
880        e.preventDefault();
881        focusablesInNiv3[focusablesInNiv3.length - 1].focus();
882        return;
883      }
884    }
885    
886    // Si on est dans un sous-menu niveau 2 SANS BigMenu
887    var currentSousmenu = activeElement.closest('.sousmenu:not(.BigMenuContainer)');
888    
889    if (currentSousmenu && !currentNiv3) {
890      var isSousmenuVisible = currentSousmenu.classList.contains('actif') || 
891                               currentSousmenu.getAttribute('aria-hidden') === 'false' ||
892                               currentSousmenu.closest('.selected') ||
893                               currentSousmenu.closest('.navigationNiv2-item.selected');
894      
895      if (!isSousmenuVisible) {
896        return;
897      }
898      
899      var focusablesInSousmenu = Array.prototype.slice.call(
900        currentSousmenu.querySelectorAll('a[href]:not(.fermerSousMenu), button:not(.fermerSousMenu)')
901      ).filter(function(el) {
902        return isElementVisible(el) && !el.classList.contains('fermerSousMenu');
903      });
904      
905      if (focusablesInSousmenu.length === 0) return;
906      
907      var currentIndex = focusablesInSousmenu.indexOf(activeElement);
908      
909      // Si l'élément actif n'est pas dans la liste (ex: bouton fermer), trouver le plus proche
910      if (currentIndex === -1) {
911        e.preventDefault();
912        focusablesInSousmenu[0].focus();
913        return;
914      }
915      
916      var isLastElement = currentIndex === focusablesInSousmenu.length - 1;
917      var isFirstElement = currentIndex === 0;
918      
919      if (!e.shiftKey && isLastElement) {
920        e.preventDefault();
921        focusablesInSousmenu[0].focus();
922        return;
923      }
924      
925      if (e.shiftKey && isFirstElement) {
926        e.preventDefault();
927        focusablesInSousmenu[focusablesInSousmenu.length - 1].focus();
928        return;
929      }
930      
931      // Empêcher le Tab de sortir du sous-menu dans tous les cas
932      e.preventDefault();
933      var nextIndex = e.shiftKey ? currentIndex - 1 : currentIndex + 1;
934      focusablesInSousmenu[nextIndex].focus();
935      return;
936    }
937    
938    // Si on est dans un BigMenuContainer mais PAS dans un niveau 3
939    var currentBigMenuContainer = activeElement.closest('.sousmenu.BigMenuContainer');
940    
941    if (currentBigMenuContainer && !currentNiv3) {
942      var allBigMenus = Array.prototype.slice.call(
943        currentBigMenuContainer.querySelectorAll('a.BigMenu')
944      );
945      var bigMenuIndex = allBigMenus.indexOf(activeElement);
946      
947      if (!e.shiftKey && bigMenuIndex === allBigMenus.length - 1) {
948        e.preventDefault();
949        allBigMenus[0].focus();
950        return;
951      }
952      
953      if (e.shiftKey && bigMenuIndex === 0) {
954        e.preventDefault();
955        allBigMenus[allBigMenus.length - 1].focus();
956        return;
957      }
958    }
959    
960    // Laisser le comportement Tab par défaut dans les autres cas
961    return;
962  }
963  
964  // FLÈCHE GAUCHE : Fermer le sous-menu actuel et revenir au parent
965if (e.key === 'ArrowLeft') {
966  e.preventDefault();
967  
968  // Si on est dans un navigationNiv3, fermer et revenir au BigMenu parent
969  var currentNiv3 = activeElement.closest('.navigationNiv3.actif');
970  if (currentNiv3) {
971    var menuId = currentNiv3.getAttribute('id');
972    var $parentButton = $("a[aria-controls='" + menuId + "']");
973    
974    // Fermer le niveau 3
975    $(currentNiv3).removeClass("actif");
976    $(currentNiv3).attr("aria-hidden", "true");
977    $("header").removeClass("bigMenuActif");
978    
979    // Mettre à jour aria-expanded
980    if ($parentButton.length) {
981      $parentButton.attr("aria-expanded", "false");
982      
983      // En mobile, s'assurer que le BigMenu parent est focusable
984      $parentButton.attr("tabindex", "0");
985      $parentButton.focus();
986    }
987    return;
988  }
989  
990  // Si on est dans un sousmenu mobile (selected), fermer et revenir au menu principal
991  var selectedItem = activeElement.closest('.navigationNiv2-item.selected');
992  if (selectedItem) {
993    var closeBtn = selectedItem.querySelector('.fermerSousMenu');
994    if (closeBtn) {
995      closeBtn.click();
996    }
997    return;
998  }
999  
1000  // Si on est dans un sousmenu desktop, fermer via le bouton header
1001  var currentSousmenu = activeElement.closest('.sousmenu.actif, .sousmenu[aria-hidden="false"]');
1002  if (currentSousmenu) {
1003    var parentButton = document.querySelector('.navigationHeader > a.actif[aria-controls]');
1004    if (parentButton) {
1005      parentButton.click();
1006      parentButton.focus();
1007    }
1008  }
1009  return;
1010}
1011  
1012  // FLÈCHE DROITE : Ouvrir le sous-menu de l'élément actif (si c'est un BigMenu)
1013  if (e.key === 'ArrowRight') {
1014    e.preventDefault();
1015    
1016    // Si l'élément actif est un BigMenu, l'ouvrir
1017    if (activeElement.classList.contains('BigMenu') && activeElement.hasAttribute('aria-controls')) {
1018      activeElement.click();
1019      
1020      // Focus sur le premier élément du sous-menu ouvert
1021      setTimeout(function() {
1022        var submenuId = activeElement.getAttribute('aria-controls');
1023        var submenu = document.getElementById(submenuId);
1024        if (submenu) {
1025          var firstLink = submenu.querySelector('a[href]:not(.fermerMenu):not(.fermerSousMenu)');
1026          if (firstLink) {
1027            if (firstLink.getAttribute('tabindex') === '-1') {
1028              firstLink.setAttribute('tabindex', '0');
1029            }
1030            firstLink.focus();
1031          }
1032        }
1033      }, 150);
1034      return;
1035    }
1036    
1037    // Si on est dans le header sur un bouton avec sous-menu, l'ouvrir
1038    if (activeElement.hasAttribute('aria-controls') && activeElement.closest('.navigationHeader')) {
1039      activeElement.click();
1040      setTimeout(function() {
1041        var submenuId = activeElement.getAttribute('aria-controls');
1042        var submenu = document.getElementById(submenuId);
1043        if (submenu) {
1044          var firstLink = submenu.querySelector('a[href], a.BigMenu');
1045          if (firstLink) {
1046            if (firstLink.getAttribute('tabindex') === '-1') {
1047              firstLink.setAttribute('tabindex', '0');
1048            }
1049            firstLink.focus();
1050          }
1051        }
1052      }, 150);
1053      return;
1054    }
1055    return;
1056  }
1057  
1058  // Pour les flèches HAUT/BAS, navigation circulaire dans les items
1059  var focusables = Array.prototype.slice.call(
1060    parentSubmenu.querySelectorAll('a[href], button:not([disabled])')
1061  ).filter(function(el) {
1062    // Exclure les éléments cachés
1063    return isElementVisible(el);
1064  });
1065  
1066  if (focusables.length === 0) return;
1067  
1068  var currentIndex = focusables.indexOf(activeElement);
1069  if (currentIndex === -1) return;
1070  
1071  e.preventDefault();
1072  
1073  var nextIndex;
1074  if (e.key === 'ArrowDown') {
1075    nextIndex = (currentIndex + 1) % focusables.length;
1076  } else { // ArrowUp
1077    nextIndex = currentIndex - 1 < 0 ? focusables.length - 1 : currentIndex - 1;
1078  }
1079  
1080  focusables[nextIndex].focus();
1081}
1082
1083/**
1084 * Met à jour le tabindex des éléments du sous-menu
1085 */
1086function updateSubmenuTabindex($submenu, isOpen) {
1087  if (!$submenu || !$submenu.length) return;
1088  
1089  var tabindexValue = isOpen ? '0' : '-1';
1090  $submenu.find('a[href], button:not(.fermerSousMenu):not(.fermerMenu)').attr('tabindex', tabindexValue);
1091}
1092
1093/**
1094 * Ferme le sous-menu et va au bouton header suivant
1095 */
1096function goToNextHeaderButton(currentSousmenu) {
1097  // Trouver le bouton header actif
1098  var currentHeaderButton = document.querySelector('.navigationHeader > a.actif[aria-controls]');
1099  
1100  if (currentHeaderButton) {
1101    // Trouver tous les boutons/liens du header
1102    var allHeaderItems = Array.prototype.slice.call(
1103      document.querySelectorAll('.navigationHeader > a')
1104    );
1105    var currentIndex = allHeaderItems.indexOf(currentHeaderButton);
1106    
1107    // Fermer le sous-menu actuel
1108    currentHeaderButton.click(); // Toggle pour fermer
1109    
1110    // Focus sur le bouton suivant
1111    if (currentIndex < allHeaderItems.length - 1) {
1112      var nextButton = allHeaderItems[currentIndex + 1];
1113      setTimeout(function() {
1114        nextButton.focus();
1115      }, 100);
1116    } else {
1117      // C'est le dernier, laisser le focus sortir du menu naturellement
1118      setTimeout(function() {
1119        currentHeaderButton.focus();
1120      }, 100);
1121    }
1122  }
1123}
1124
1125/**
1126 * Ferme le sous-menu et va au bouton header précédent
1127 */
1128function goToPreviousHeaderButton(currentSousmenu) {
1129  // Trouver le bouton header actif
1130  var currentHeaderButton = document.querySelector('.navigationHeader > a.actif[aria-controls]');
1131  
1132  if (currentHeaderButton) {
1133    // Trouver tous les boutons/liens du header
1134    var allHeaderItems = Array.prototype.slice.call(
1135      document.querySelectorAll('.navigationHeader > a')
1136    );
1137    var currentIndex = allHeaderItems.indexOf(currentHeaderButton);
1138    
1139    // Fermer le sous-menu actuel
1140    currentHeaderButton.click(); // Toggle pour fermer
1141    
1142    // Focus sur le bouton précédent
1143    if (currentIndex > 0) {
1144      var prevButton = allHeaderItems[currentIndex - 1];
1145      setTimeout(function() {
1146        prevButton.focus();
1147      }, 100);
1148    } else {
1149      // C'est le premier, focus sur lui-même
1150      setTimeout(function() {
1151        currentHeaderButton.focus();
1152      }, 100);
1153    }
1154  }
1155}
1156
1157/**
1158 * Marque la page courante avec aria-current="page"
1159 */
1160function setAriaCurrentPage() {
1161  var currentPath = window.location.pathname;
1162  
1163  // Nettoyer le path (enlever le slash final si présent)
1164  if (currentPath.length > 1 && currentPath.endsWith('/')) {
1165    currentPath = currentPath.slice(0, -1);
1166  }
1167  
1168  // Chercher dans tous les liens de navigation
1169  var allNavLinks = document.querySelectorAll(
1170    '.navigationHeader a[href], #menuhamb a[href], .sousmenu a[href], .navigationNiv3 a[href]'
1171  );
1172  
1173  allNavLinks.forEach(function(link) {
1174    var href = link.getAttribute('href');
1175    if (!href || href === '#') return;
1176    
1177    // Nettoyer le href
1178    var linkPath = href;
1179    if (linkPath.length > 1 && linkPath.endsWith('/')) {
1180      linkPath = linkPath.slice(0, -1);
1181    }
1182    
1183    // Vérifier si c'est la page courante ou une page parente
1184    if (currentPath === linkPath || (linkPath !== '/' && currentPath.startsWith(l
1184inkPath + '/'))) {
1185      link.setAttribute('aria-current', 'page');
1186    }
1187  });
1188}
1189
1190/**
1191 * Met à jour aria-current="true" sur l'élément actuellement focus dans le menu
1192 */
1193function setupAriaCurrentTracking() {
1194  // Écouter les focus dans les menus
1195  document.addEventListener('focusin', function(e) {
1196    var target = e.target;
1197    
1198    // Vérifier si on est dans un menu
1199    var isInMenu = target.closest('.sousmenu, .navigationNiv3, .navigationHeader, #menuhamb');
1200    if (!isInMenu) return;
1201    
1202    // Retirer aria-current="true" des autres éléments du même menu (pas aria-current="page")
1203    var parentMenu = target.closest('.sousmenu, .navigationNiv3, .navigationHeader, #menuhamb');
1204    if (parentMenu) {
1205      parentMenu.querySelectorAll('[aria-current="true"]').forEach(function(el) {
1206        el.removeAttribute('aria-current');
1207      });
1208    }
1209    
1210    // Ajouter aria-current="true" sur l'élément actif (sauf s'il a déjà aria-current="page")
1211    if (target.tagName === 'A' || target.tagName === 'BUTTON') {
1212      if (target.getAttribute('aria-current') !== 'page') {
1213        target.setAttribute('aria-current', 'true');
1214      }
1215    }
1216  });
1217  
1218  // Retirer aria-current="true" quand on quitte le menu
1219  document.addEventListener('focusout', function(e) {
1220    var target = e.target;
1221    
1222    // Si l'élément avait aria-current="true" (pas "page"), le retirer
1223    if (target.getAttribute('aria-current') === 'true') {
1224      // Petit délai pour vérifier si le nouveau focus est toujours dans le même menu
1225      setTimeout(function() {
1226        var newFocus = document.activeElement;
1227        var sameMenu = target.closest('.sousmenu, .navigationNiv3, .navigationHeader, #menuhamb');
1228        var newFocusInSameMenu = sameMenu && sameMenu.contains(newFocus);
1229        
1230        if (!newFocusInSameMenu) {
1231          target.removeAttribute('aria-current');
1232        }
1233      }, 10);
1234    }
1235  });
1236}
1237
1238function consentAAUserToken() {
1239  if (typeof aa === "undefined") {
1240    window.caReady = window.caReady || [];
1241    window.cact = function () {
1242      window.caReady.push(arguments);
1243    };
1244
1245    cact("consent.get", function (result) {
1246      if (result.consent.categories["200"].status === "on") {
1247        initAAUserToken();
1248      } else {
1249        document.cookie = "userTokenAlgolia = null; Max-Age = 0;";
1250      }
1251    });
1252    cact("consent.onUpdate", function (result) {
1253      if (result.consent.categories["200"].status === "on") {
1254        initAAUserToken();
1255      } else {
1256        document.cookie = "userTokenAlgolia = null; Max-Age = 0;";
1257      }
1258    });
1259  }
1260}
1261
1262initSliders();
1263
1264/******** SLIDERS  ********/
1265
1266function initSliders() {
1267  window.addEventListener(
1268    "resize",
1269    debounce(function () {
1270      refreshTnsSliders();
1271    }, 50)
1272  );
1273  window.dispatchEvent(new Event("resize"));
1274
1275  let $tnsOuters = document.querySelectorAll(".tns-outer");
1276  let indexTnsOuters = $tnsOuters.length;
1277  if (indexTnsOuters < 1) {
1278    return;
1279  }
1280  while (indexTnsOuters) {
1281    addEventSlide($tnsOuters[indexTnsOuters - 1]);
1282    indexTnsOuters--;
1283  }
1284
1285  let $tnsBtnControls = document.querySelectorAll(".tns-controls-button");
1286  let indexTnsBtnControls = $tnsBtnControls.length;
1287  if (indexTnsBtnControls < 1) {
1288    return;
1289  }
1290  while (indexTnsBtnControls) {
1291    let $btnControl = $tnsBtnControls[indexTnsBtnControls - 1];
1292
1293    /* Au clic sur les boutons de contrôle, mise à jour de l'item actif */
1294    $btnControl.addEventListener("click", () => {
1295      $btnControl.setAttribute("disabled", "disabled");
1296      setTimeout(() => {
1297        $btnControl.removeAttribute("disabled");
1298      }, 200);
1299      let $currentSlider = $btnControl.closest(".tns-outer");
1300      doScrollSlider($currentSlider, $btnControl);
1301
1302      $currentSlider = null;
1303    });
1304    indexTnsBtnControls--;
1305  }
1306  $tnsOuters = indexTnsBtnControls = null;
1307}
1308
1309/**
1310 * Anime le scroll du slider vers la gauche ou la droite
1311 * @$currentSlider Le slider sur lequel appliquer l'animation
1312 * @$btnControl Le bouton cliqué
1313 */
1314function doScrollSlider($currentSlider, $btnControl) {
1315  let $slider = $currentSlider.querySelector(".tns-slider");
1316  let newPosition = $slider.scrollLeft;
1317  let isForward = true;
1318  if ("prec" === $btnControl.getAttribute("data-controls")) {
1319    newPosition -= $currentSlider.querySelector(
1320      ".tns-item:first-child"
1321    ).offsetWidth;
1322    isForward = false;
1323  } else {
1324    newPosition += $currentSlider.querySelector(
1325      ".tns-item:first-child"
1326    ).offsetWidth;
1327  }
1328  $slider.scroll({
1329    left: newPosition,
1330    behavior: "smooth",
1331    duration: 500,
1332  });
1333  if ($currentSlider.closest("#offre-de-soins")) {
1334    let div = document.createElement("div");
1335    if (isForward) {
1336      let $firstItem = $currentSlider.querySelector(".slide:first-child");
1337      div.innerHTML = $firstItem.outerHTML.trim();
1338      $currentSlider.querySelector(".slides").appendChild(div.firstChild);
1339      $firstItem.remove();
1340      $firstItem = null;
1341    } else {
1342      let $lastItem = $currentSlider.querySelector(".slide:last-child");
1343      div.innerHTML = $lastItem.outerHTML.trim();
1344      $currentSlider.querySelector(".slides").prepend(div.firstChild);
1345      $lastItem.remove();
1346      $lastItem = null;
1347    }
1348    div = null;
1349  }
1350
1351  $slider = null;
1352  newPosition = null;
1353}
1354
1355/**
1356 * Détermine s'il existe des sliders dans la page et affiche ou non les contrôles en fonction de la taille de la fenêtre et de la quantité d'items
1357 */
1358function refreshTnsSliders() {
1359  let $tnsOuters = document.querySelectorAll(".tns-outer");
1360  let indexTnsOuters = $tnsOuters.length;
1361  if (indexTnsOuters < 1) {
1362    return;
1363  }
1364  while (indexTnsOuters) {
1365    let $tnsOuter = $tnsOuters[indexTnsOuters - 1];
1366    let totalItemsWidth = updateTnsControls(
1367      $tnsOuter,
1368      getTnsCurrentDisplayedItemIndex($tnsOuter)
1369    );
1370    if ($tnsOuter.offsetWidth > totalItemsWidth) {
1371      $tnsOuter.querySelector(".tns-controls").style.display = "none";
1372    } else {
1373      $tnsOuter.querySelector(".tns-controls").style.display = "block";
1374    }
1375
1376    totalItemsWidth = $tnsOuter = null;
1377    indexTnsOuters--;
1378  }
1379  $tnsOuters = indexTnsOuters = null;
1380}
1381
1382/**
1383 * Retrouve l'index de l'item actuellement affiché dans un slider
1384 * @param {any} $currentSlider Le conteneur du slider ayant la classe "tns-outer"
1385 */
1386function getTnsCurrentDisplayedItemIndex($currentSlider) {
1387  if (!$currentSlider) {
1388    return;
1389  }
1390  let value;
1391  let $tnsItems = $currentSlider.querySelectorAll(".tns-item");
1392  [].slice.call($tnsItems).forEach(function ($element, index) {
1393    if (
1394      Math.abs(
1395        $element.getBoundingClientRect().left -
1396          $currentSlider.getBoundingClientRect().left
1397      ) < $tnsItems[0].offsetWidth
1398    ) {
1399      value = index;
1400      return;
1401    }
1402  });
1403  return value;
1404}
1405
1406/**
1407 * Mets à jour l'affichage des boutons de contrôle du slider
1408 * @param {any} $currentSlider l'élément ayant la classe "tns-outer"
1409 * @param {any} nextIndex l'index de l'item que l'on veut afficher
1410 * @return {number} la largeur totale du slider en ajoutant tous ses éléments
1411 */
1412function updateTnsControls($currentSlider, nextIndex) {
1413  let currentTotalItems = $currentSlider.querySelectorAll(".tns-item").length;
1414  const totalItemsWidth =
1415    currentTotalItems *
1416    $currentSlider.querySelector(".tns-item:first-child").offsetWidth;
1417  if ($currentSlider.offsetWidth < totalItemsWidth) {
1418    if (nextIndex < 1) {
1419      $currentSlider.querySelector(
1420        '.tns-controls-button[data-controls="prec"]'
1421      ).style.display = "none";
1422      nextIndex = 0;
1423    } else {
1424      $currentSlider.querySelector(
1425        '.tns-controls-button[data-controls="prec"]'
1426      ).style.display = "block";
1427    }
1428    if (nextIndex >= currentTotalItems - 1) {
1429      nextIndex = currentTotalItems - 1;
1430      $currentSlider.querySelector(
1431        '.tns-controls-button[data-controls="suiv"]'
1432      ).style.display = "none";
1433    } else {
1434      $currentSlider.querySelector(
1435        '.tns-controls-button[data-controls="suiv"]'
1436      ).style.display = "block";
1437    }
1438  }
1439
1440  currentTotalItem = null;
1441  return totalItemsWidth;
1442}
1443
1444/**
1445 * Ajoute le listeners scroll sur le slider
1446 * @param {any} $currentSlider l'élément ayant la classe "tns-outer"
1447 */
1448function addEventSlide($currentSlider) {
1449  $currentSlider.querySelector(".tns-slider").addEventListener(
1450    "scroll",
1451    debounce(function () {
1452      setTimeout(() => {
1453        updateTnsControls(
1454          $currentSlider,
1455          getTnsCurrentDisplayedItemIndex($currentSlider)
1456        );
1457      }, 100);
1458    }, 50)
1459  );
1460}
1461
1462/******** FIN SLIDERS  ********/

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.