From 84fece051f79868b413578a36640d0583472bd2e Mon Sep 17 00:00:00 2001
From: ouidade <ouidade@figureslibres.io>
Date: Mon, 3 Mar 2025 12:23:37 +0100
Subject: [PATCH] ajustement js longueru texte actus

---
 .../quartiers_de_demain/dist/assets/bundle.js |  2 +-
 .../src/assets/js/quartiers_de_demain.js      | 35 ++++++++++++++-----
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/web/themes/custom/quartiers_de_demain/dist/assets/bundle.js b/web/themes/custom/quartiers_de_demain/dist/assets/bundle.js
index 11daa9c..248f81b 100644
--- a/web/themes/custom/quartiers_de_demain/dist/assets/bundle.js
+++ b/web/themes/custom/quartiers_de_demain/dist/assets/bundle.js
@@ -36,7 +36,7 @@ eval("document.addEventListener('scroll', function() {\n    const scrolled = win
   \**********************************************/
 /***/ (function() {
 
-eval("/**\n * @file\n * quartiers_de_demain behaviors.\n */\n (function (Drupal) {\n\n    'use strict';\n  \n    Drupal.behaviors.quartiers_de_demain = {\n      attach: function (context, settings) {\n        console.log('It works!');\n      }\n    };\n  } (Drupal));\n\n\n  //////// start header ////////////\n  document.addEventListener('DOMContentLoaded', function() {\n\n    const header = document.querySelector('header');\n    const logo = document.querySelector('#block-quartiers-de-demain-logoquartiersdedemain > div:nth-child(1) > div:nth-child(1) > a:nth-child(1) > svg:nth-child(1)');\n    const headerNavContainer = document.querySelector('.header_nav_container');\n    const isFirstLoad = !performance.getEntriesByType(\"navigation\")[0].type.includes('back_forward');\n    const isTargetPath = window.location.pathname === '/';\n\n    // Fonction pour démarrer l'animation du logo SVG\n    function startLogoAnimation() {\n      logo.classList.add('animated');\n    }\n  \n    // Fonction pour arrêter l'animation du logo SVG\n    function stopLogoAnimation() {\n      logo.classList.remove('animated');\n    }\n  \n    // Vérifier si le header a la classe header--collapse\n    function checkHeaderCollapse() {\n      if (header.classList.contains('header--collapsed')) {\n        stopLogoAnimation();\n      } else if (header.classList.contains('header--collapsed-already'))  {\n          stopLogoAnimation();\n        } else {\n        startLogoAnimation();\n      }\n\n    }\n  \n    // Appeler la fonction au chargement initial\n    checkHeaderCollapse();\n  \n    // Observer les changements de classe sur le header\n    const observer = new MutationObserver(function(mutations) {\n      mutations.forEach(function(mutation) {\n        if (mutation.attributeName === 'class') {\n          checkHeaderCollapse();\n        }\n      });\n    });\n    observer.observe(header, { attributes: true });\n \n\n    // Si ce n'est pas la première charge ou si le chemin n'est pas le chemin cible, ajouter la classe immédiatement\n    if (!isFirstLoad || !isTargetPath) {\n      header.classList.add('header--collapsed-already');\n      // logo.classList.remove('animated');\n      stopLogoAnimation();\n    } else {\n      // Sinon, appliquer la transition après un délai\n      setTimeout(() => {\n          header.classList.add('header--collapsed');\n      }, 5000);\n    }\n\n    //////////////////////////////////////\n\n    let lastScrollTop = 0;\n    let threshold = 100; // Change this value as needed\n    let isHidden = false;\n  \n    function slideOut() {\n      headerNavContainer.animate([\n        { transform: 'translateX(0)' },\n        { transform: 'translateX(-100%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = true;\n    }\n  \n    function slideIn() {\n      headerNavContainer.animate([\n        { transform: 'translateX(-100%)' },\n        { transform: 'translateX(0)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = false;\n    }\n    \n    function slideDown() {\n      // headerNavContainer.style.display = 'block';\n      headerNavContainer.animate([\n        { transform: 'translateY(0%)' },\n        { transform: 'translateY(+100%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = false;\n    }\n  \n    function slideUp() {\n      headerNavContainer.animate([\n        { transform: 'translateY(100%)' },\n        { transform: 'translateY(0%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      }).onfinish = function() {\n        // headerNavContainer.style.display = 'none';\n      };\n      isHidden = true;\n    }\n      // Fonction pour ajuster la hauteur du header lors du défilement\n      function adjustHeaderHeight() {\n        if (window.scrollY > 0) {\n          header.classList.add('shrink');\n        } else {\n          header.classList.remove('shrink');\n        }\n      }\n\n    function handleScroll() {\n      let scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n      const isMobile = window.innerWidth < 811;\n\n      if (scrollTop > threshold && !isHidden) {\n        if (isMobile) {\n          slideUp();\n        } else {\n          slideOut();\n        }\n      } else if (scrollTop <= threshold && isHidden) {\n        if (isMobile) {\n          slideDown();\n        } else {\n          slideIn();\n        }\n      }\n  \n  \n      lastScrollTop = scrollTop <= 0 ? 0 : scrollTop; // For Mobile or negative scrolling\n    }\n  \n    function handleTouchAndMouseEnter() {\n      if (isHidden) {\n        if (window.innerWidth < 811) {\n          slideDown();\n        } else {\n          slideIn();\n        }\n      }\n    }\n  \n    function handleTouchAndMouseLeave() {\n      if (lastScrollTop > threshold && !isHidden) {\n        if (window.innerWidth < 811) {\n          slideUp();\n        } else {\n          slideOut();\n        }\n      }\n    }\n  \n    window.addEventListener('scroll', handleScroll);\n    window.addEventListener('scroll', adjustHeaderHeight);\n  \n    // Mouse events for desktop\n    header.addEventListener('mouseenter', handleTouchAndMouseEnter);\n    header.addEventListener('mouseleave', handleTouchAndMouseLeave);\n  \n    // Touch events for tablets and mobile devices\n    header.addEventListener('touchstart', handleTouchAndMouseEnter);\n    header.addEventListener('touchend', handleTouchAndMouseLeave);\n  \n    // Initial check to see if we're at the top of the page\n    if (window.pageYOffset <= threshold) {\n      if (window.innerWidth < 811) {\n        slideDown();\n      } else { \n        slideIn();\n      } \n    } else {\n      if (window.innerWidth < 811) {\n        slideUp();\n      } else {\n        slideIn();\n      }\n    }\n  \n  });\n\n//////// end header ////////////\n  \n\n\n//// ancre dans texte au click paragraphe correspondant arrive en dessous du header \n\n\n(function($, window) {\n  var adjustAnchor = function() {\n      var $anchor = $('.sidebar_first_container'),\n              fixedElementHeight = 500;\n      if ($anchor.length > 0) {\n          $('html, body').stop().animate({scrollTop: $anchor.offset().top - fixedElementHeight }, 0);\n      }\n  };\n\n  $(window).on('hashchange', function() {\n      adjustAnchor();\n  });\n\n\n  ////////////////////////  start script smooth apparition des textes /////////////////\n\n  function scrollReaveal(){\n\n    const nodes = {\n      logo : document.querySelectorAll('#logo-animated-container'),\n      chapeau :  document.querySelectorAll('.field_body'),\n      paragraph: document.querySelectorAll('.field_field_textes .paragraph--type--static-parts'),\n      enjeux : document.querySelectorAll('.field_field_textes .paragraph--type--static-parts .enjeux'),\n      // mapHome : document.querySelectorAll('.field_field_map_block #block-sitesmapblock'),\n      // mapSite : document.querySelectorAll('#sites-map-container'),\n      lienDoc : document.querySelectorAll('.field_field_documents'),\n      lienURL : document.querySelectorAll('.field_field_liens_site'),\n    }\n\n    const showUp = {\n        origin: 'bottom',\n        delay: 100,\n        duration: 1000,\n        distance: '50px',\n        easing: 'cubic-bezier(0.5, 0, 0, 1)'\n    }\n\n    const Show = {\n      delay: 100,\n      duration: 600,\n      easing: 'cubic-bezier(0.5, 0, 0, 1)'\n    }\n\n    console.log(nodes);\n\n    ScrollReveal().reveal(nodes.logo, Show);\n    ScrollReveal().reveal(nodes.chapeau, showUp);\n    ScrollReveal().reveal(nodes.paragraph, showUp);\n    ScrollReveal().reveal(nodes.enjeux, showUp);\n    // ScrollReveal().reveal(nodes.mapHome, showUp);\n    // ScrollReveal().reveal(nodes.mapSite, showUp);\n    ScrollReveal().reveal(nodes.lienDoc, showUp);\n    ScrollReveal().reveal(nodes.lienURL, showUp);\n\n  }\n\n\n  $( document ).ready(function() {\n    scrollReaveal();\n  });\n\n  ////////////////////////  end script smooth apparition des textes /////////////////\n\n  // //////////////////// start Timeline script ///////////////////////\n\n    // Update month field to only show the first 3 letters\n    document.querySelectorAll('.paragraph--type--phase-deroulement').forEach(function(paragraph) {\n      const monthField = paragraph.querySelector('.field_field_date_de_moi div:nth-of-type(2)');\n      if (monthField) {\n        const monthText = monthField.textContent.trim();\n        if (monthText === \"juillet\") {\n          monthField.textContent = monthText.slice(0, 4);\n          monthField.classList.add('after');\n        } else if (monthText === \"juin\") {\n          monthField.textContent = monthText.slice(0, 4);\n        } else if (monthText.length > 3) {\n          monthField.textContent = monthText.slice(0, 3);\n          monthField.classList.add('after');\n        }\n      }\n    });\n  \n    // Fonction pour ajouter ou retirer la classe .only\n    function updateDateClasses() {\n      document.querySelectorAll('.paragraph--type--phase-deroulement .date').forEach(function(dateElement) {\n        const date2Element = dateElement.querySelector('.date2');\n        const yearElement = dateElement.querySelector('.field_field_date_de_annee');\n  \n        if (date2Element && !date2Element.textContent.trim()) {\n          if (yearElement) {\n            yearElement.classList.add('only');\n          }\n        } else {\n          if (yearElement) {\n            yearElement.classList.remove('only');\n          }\n        }\n      });\n    }\n  \n    // Exécuter la fonction une première fois pour le contenu déjà présent\n    updateDateClasses();\n  \n    // MutationObserver pour surveiller les changements dans le DOM\n    const observer = new MutationObserver(function(mutationsList, observer) {\n      for(let mutation of mutationsList) {\n        if (mutation.type === 'childList') {\n          updateDateClasses();\n        }\n      }\n    });\n\n\n  //   ////////////////////// start  calendrier home   /////////////////////////////////\n    $(document).ready(function(){\n      $('.__timeline-content').slick({\n        slidesToShow: 3,\n        slidesToScroll: 1,\n        dots: false,\n        arrows: true,\n        centerMode: false,\n        draggable: true,\n        infinite: false,\n        responsive: [\n          {\n            breakpoint: 810,\n            settings: {\n              slidesToShow: 1,\n              adaptiveHeight: false,\n              arrows: true,\n              draggable: true,\n              centerMode: false,\n              infinite: false,\n            }\n          }]\n      });\n      console.log('salut slick calendrier');\n    \n      });\n    \n  //////////////////////// end   calendrier home   /////////////////////////////////\n  \n  \n\n  //////////////////////// end Timeline script /////////////////////////////////////////////\n\n  ///////////////////  caracteres  body actus/////////////////////////\n\n  document.addEventListener('DOMContentLoaded', function() {\n    // Maximum number of characters to display\n    const maxChars = 140; // Adjust this value as needed\n  \n    document.querySelectorAll('#actus-caroussel .node-type-actualite .field_body p').forEach(function(paragraph) {\n      let text = paragraph.textContent.trim();\n      if (text.length > maxChars) {\n        let truncatedText = text.slice(0, maxChars) + '...';\n        paragraph.textContent = truncatedText;\n      }\n    });\n  });\n  \n\n //////////// start slideshow home  ////////////////////////// \n\n\n\n  $(document).ready(function(){\n      let actuview = $('.content-actus .view ')\n      if (actuview) {\n        actuview.slick({\n          slidesToShow: 3,\n          // slidesToScroll: 1,\n          dots: false,\n          arrows: true,\n          // centerMode: true,\n          adaptiveHeight: false,\n          autoplay: false,\n          // autoplaySpeed: 1500,\n          // infinite: true,\n          // centerPadding: '100px',\n          responsive: [\n            {\n              breakpoint: 810,\n              settings: {\n                slidesToShow: 1,\n                // slidesToScroll: 1,\n                adaptiveHeight: false,\n                arrows: true,\n                draggable: true,\n                // centerMode: true,\n                // centerPadding: '100px',\n                autoplay: false,\n                // autoplaySpeed: 2000,\n              }\n            }]\n        });\n        console.log('salut slick home');\n        \n      }\n      $('.slick-carousel').slick({\n        lazyLoad: 'progressive', // Option 'ondemand' ou 'progressive'\n      });\n\n  });\n\n\n\n\n  $(document).ready(function () {\n    let diapohome = $('.config_pages--type--diaporama-home .diaporama');\n\n    if (diapohome.length) {\n        // Initialisation de Slick\n        diapohome.slick({\n            slidesToShow: 1,\n            dots: false,\n            arrows: false,\n            // centerMode: true,\n            adaptiveHeight: false,\n            autoplay: true,  // Activer l'autoplay\n            autoplaySpeed: 4000,  // Changement de slide toutes les 4 secondes\n            // infinite: true,\n            pauseOnHover: false,  // Ne pas arrêter l'autoplay lors du survol\n            pauseOnFocus: false,\n            responsive: [\n                {\n                    breakpoint: 810,\n                    settings: {\n                        slidesToShow: 1,\n                        adaptiveHeight: false,\n                        arrows: false,\n                        draggable: true,\n                        centerMode: false,\n                    }\n                }]\n        });\n\n  }\n});\n\n ////////////  end slideshow home  ////////////////////////// \n\n//////////////// start lightbox galerie image page site////////////////////////\n\n// Sélection des images et de leurs légendes dans la galerie\nlet images = document.querySelectorAll('.paragraph--type--site-diapo .lightbox-trigger');\nlet currentIndex;\n\n// Création de la lightbox et de ses éléments\nconst lightbox = document.createElement('div');\nlightbox.id = 'lightbox';\nlightbox.classList.add('lightbox');\ndocument.body.appendChild(lightbox);\n\nconst img = document.createElement('img');\nlightbox.appendChild(img);\n\n// Élément pour afficher la légende\nconst caption = document.createElement('p');\ncaption.classList.add('caption');\nlightbox.appendChild(caption);\n\nconst closeBtn = document.createElement('span');\ncloseBtn.classList.add('close');\ncloseBtn.innerHTML = '&times;';\nlightbox.appendChild(closeBtn);\n\nconst prevBtn = document.createElement('a');\nprevBtn.classList.add('prev');\nprevBtn.innerHTML = '&#10094;';\nlightbox.appendChild(prevBtn);\n\nconst nextBtn = document.createElement('a');\nnextBtn.classList.add('next');\nnextBtn.innerHTML = '&#10095;';\nlightbox.appendChild(nextBtn);\n\n// Fonction pour afficher l'image et la légende à l'index donné\nfunction showImage(index) {\n  if (index < 0) index = images.length - 1;\n  if (index >= images.length) index = 0;\n  currentIndex = index;\n\n  // Mettre à jour l'image\n  img.src = images[currentIndex].getAttribute('src');\n\n  // Récupérer la légende associée (le paragraphe dans blockquote suivant l'image)\n  const captionText = images[currentIndex]\n    .closest('.cadre-img-zoom')\n    .nextElementSibling.querySelector('.image-field-caption p')\n    .textContent;\n    \n  caption.textContent = captionText || ''; // Affiche la légende ou une chaîne vide si elle est absente\n  lightbox.style.display = 'flex';\n}\n\n// Événements de clic sur chaque image pour ouvrir le lightbox avec la légende\nimages.forEach((image, index) => {\n  image.addEventListener('click', () => {\n    showImage(index);\n  });\n});\n\n// Fermer le lightbox\ncloseBtn.addEventListener('click', () => {\n  lightbox.style.display = 'none';\n});\n\n// Navigation pour images précédente et suivante\nprevBtn.addEventListener('click', (e) => {\n  e.stopPropagation();\n  showImage(currentIndex - 1);\n});\n\nnextBtn.addEventListener('click', (e) => {\n  e.stopPropagation();\n  showImage(currentIndex + 1);\n});\n\n// Fermer le lightbox en cliquant en dehors de l'image\nlightbox.addEventListener('click', (e) => {\n  if (e.target === lightbox) {\n    lightbox.style.display = 'none';\n  }\n});\n\n// Ajout des contrôles clavier (Échap, flèches gauche/droite)\ndocument.addEventListener('keydown', (e) => {\n  if (lightbox.style.display === 'flex') {\n    if (e.key === 'Escape') {\n      lightbox.style.display = 'none';\n    } else if (e.key === 'ArrowLeft') {\n      showImage(currentIndex - 1);\n    } else if (e.key === 'ArrowRight') {\n      showImage(currentIndex + 1);\n    }\n  }\n});\n\n\n//////////////// end lightbox galerie image page site////////////////////////\n\n  \n\n//////////////////// start wrapper views-row  lessites /////////////////////////\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionne le conteneur principal avec l'ID 'lessites'\n  const container = document.getElementById(\"lessites\");\n\n  // Vérifie si le conteneur existe pour éviter toute erreur sur d'autres pages\n  if (container) {\n    // Sélectionne l'élément 'view' à l'intérieur de '.views-element-container'\n    const viewContainer = container.querySelector(\".views-element-container .view\");\n\n    // Vérifie si 'viewContainer' existe pour éviter les erreurs\n    if (viewContainer) {\n      // Crée une div englobante pour tous les éléments 'views-row'\n      const wrapperDiv = document.createElement(\"div\");\n      wrapperDiv.classList.add(\"views-row-wrapper\"); // ajoute une classe pour faciliter le style CSS\n\n      // Déplace tous les éléments 'views-row' dans la nouvelle div\n      const viewsRows = viewContainer.querySelectorAll(\".views-row\");\n      viewsRows.forEach(row => wrapperDiv.appendChild(row));\n\n      // Ajoute la div englobante dans le 'viewContainer'\n      viewContainer.appendChild(wrapperDiv);\n    }\n  }\n});\n\n\n//////////////////// end wrapper views-row  lessites /////////////////////////\n\n\n\n////////////////////  start div infos site  ////////////////////////\n\n// Vérifie si la page a la classe 'node-type-site' dans le <body>\nif (document.body.classList.contains('node-type-site')) {\n  // Sélectionne le conteneur principal\n  const blockRegion = document.querySelector('.block-region-second');\n\n  // Liste des classes spécifiques à cibler\n  const fieldClasses = [\n      '.field_field_region',\n      '.field_field_nom_du_qpv_nb_d_hab',\n      '.field_field_departement_s',\n      '.field_field_programme_de_l_etat',\n      '.field_field_porteur_s_de_site',\n      '.field_field_nom_de_la_commune_nb_d_hab'\n  ];\n\n  // Sélectionne les div parents de chacun des champs listés\n  const elementsToWrap = [];\n  fieldClasses.forEach(className => {\n      const fieldElement = blockRegion.querySelector(className);\n      if (fieldElement) {\n          // Ajoute le parent du champ au tableau si trouvé\n          elementsToWrap.push(fieldElement.parentElement);\n      }\n  });\n\n  // Vérifie que des éléments ont été trouvés\n  if (elementsToWrap.length > 0) {\n      // Crée le conteneur avec la classe 'infos'\n      const infosContainer = document.createElement('div');\n      infosContainer.className = 'infos';\n\n      // Insère le conteneur `.infos` avant le premier élément ciblé\n      const firstElement = elementsToWrap[0];\n      blockRegion.insertBefore(infosContainer, firstElement);\n\n      // Déplace chaque élément dans le conteneur `.infos`\n      elementsToWrap.forEach(element => infosContainer.appendChild(element));\n  }\n}\n////////////////////  end div infos site  ////////////////////////\n\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionner les éléments à déplacer\n  const documentsField = document.querySelector(\".field_field_documents\");\n  const liensSiteField = document.querySelector(\".field_field_liens_site\");\n  \n  // Sélectionner la destination\n  const thirdRegion = document.querySelector(\".block-region-third > div\");\n\n  // Créer une nouvelle div pour englober les éléments déplacés\n  const wrapperDiv = document.createElement(\"div\");\n  wrapperDiv.classList.add(\"documents-liens-wrapper\");\n\n  // Déplacer les éléments dans la nouvelle div\n  if (documentsField && liensSiteField && thirdRegion) {\n      wrapperDiv.appendChild(documentsField);\n      wrapperDiv.appendChild(liensSiteField);\n\n      // Ajouter la nouvelle div dans la destination\n      thirdRegion.appendChild(wrapperDiv);\n  }\n});\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionner les éléments pertinents\n  const documentsLiensWrapper = document.querySelector(\".documents-liens-wrapper\");\n  const blockRegionThird = document.querySelector(\".block-region-third\");\n\n  // Vérifier que les éléments existent avant de les manipuler\n  if (documentsLiensWrapper && blockRegionThird) {\n      // Déplacer .documents-liens-wrapper en dehors du div contenant les boutons prev/next\n      blockRegionThird.appendChild(documentsLiensWrapper);\n  }\n});\n\n\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n  // Fonction pour déplacer le bloc en fonction de la taille de l'écran\n  function moveLanguageSwitcher() {\n    const languageSwitcher = document.getElementById(\"block-quartiers-de-demain-selecteurdelangue\");\n    const navContainer = document.querySelector(\".header_nav_container\");\n\n    if (window.innerWidth <= 810) { // Si écran téléphone\n      if (languageSwitcher && navContainer && !navContainer.contains(languageSwitcher)) {\n        navContainer.appendChild(languageSwitcher); // Déplace le bloc dans header_nav_container\n      }\n    } else { // Si écran non téléphone\n      const headerRightContainer = document.querySelector(\".header_right_container\");\n      if (languageSwitcher && headerRightContainer && !headerRightContainer.contains(languageSwitcher)) {\n        headerRightContainer.appendChild(languageSwitcher); // Remet le bloc dans sa position initiale\n      }\n    }\n  }\n\n  // Déclencher au chargement et au redimensionnement\n  moveLanguageSwitcher();\n  window.addEventListener(\"resize\", moveLanguageSwitcher);\n});\n\n\n})(jQuery, window);\n\n\n\n\n//# sourceURL=webpack://quartiers_de_demain/./src/assets/js/quartiers_de_demain.js?");
+eval("/**\n * @file\n * quartiers_de_demain behaviors.\n */\n (function (Drupal) {\n\n    'use strict';\n  \n    Drupal.behaviors.quartiers_de_demain = {\n      attach: function (context, settings) {\n        console.log('It works!');\n      }\n    };\n  } (Drupal));\n\n\n  //////// start header ////////////\n  document.addEventListener('DOMContentLoaded', function() {\n\n    const header = document.querySelector('header');\n    const logo = document.querySelector('#block-quartiers-de-demain-logoquartiersdedemain > div:nth-child(1) > div:nth-child(1) > a:nth-child(1) > svg:nth-child(1)');\n    const headerNavContainer = document.querySelector('.header_nav_container');\n    const isFirstLoad = !performance.getEntriesByType(\"navigation\")[0].type.includes('back_forward');\n    const isTargetPath = window.location.pathname === '/';\n\n    // Fonction pour démarrer l'animation du logo SVG\n    function startLogoAnimation() {\n      logo.classList.add('animated');\n    }\n  \n    // Fonction pour arrêter l'animation du logo SVG\n    function stopLogoAnimation() {\n      logo.classList.remove('animated');\n    }\n  \n    // Vérifier si le header a la classe header--collapse\n    function checkHeaderCollapse() {\n      if (header.classList.contains('header--collapsed')) {\n        stopLogoAnimation();\n      } else if (header.classList.contains('header--collapsed-already'))  {\n          stopLogoAnimation();\n        } else {\n        startLogoAnimation();\n      }\n\n    }\n  \n    // Appeler la fonction au chargement initial\n    checkHeaderCollapse();\n  \n    // Observer les changements de classe sur le header\n    const observer = new MutationObserver(function(mutations) {\n      mutations.forEach(function(mutation) {\n        if (mutation.attributeName === 'class') {\n          checkHeaderCollapse();\n        }\n      });\n    });\n    observer.observe(header, { attributes: true });\n \n\n    // Si ce n'est pas la première charge ou si le chemin n'est pas le chemin cible, ajouter la classe immédiatement\n    if (!isFirstLoad || !isTargetPath) {\n      header.classList.add('header--collapsed-already');\n      // logo.classList.remove('animated');\n      stopLogoAnimation();\n    } else {\n      // Sinon, appliquer la transition après un délai\n      setTimeout(() => {\n          header.classList.add('header--collapsed');\n      }, 5000);\n    }\n\n    //////////////////////////////////////\n\n    let lastScrollTop = 0;\n    let threshold = 100; // Change this value as needed\n    let isHidden = false;\n  \n    function slideOut() {\n      headerNavContainer.animate([\n        { transform: 'translateX(0)' },\n        { transform: 'translateX(-100%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = true;\n    }\n  \n    function slideIn() {\n      headerNavContainer.animate([\n        { transform: 'translateX(-100%)' },\n        { transform: 'translateX(0)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = false;\n    }\n    \n    function slideDown() {\n      // headerNavContainer.style.display = 'block';\n      headerNavContainer.animate([\n        { transform: 'translateY(0%)' },\n        { transform: 'translateY(+100%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      });\n      isHidden = false;\n    }\n  \n    function slideUp() {\n      headerNavContainer.animate([\n        { transform: 'translateY(100%)' },\n        { transform: 'translateY(0%)' }\n      ], {\n        duration: 300,\n        fill: 'forwards'\n      }).onfinish = function() {\n        // headerNavContainer.style.display = 'none';\n      };\n      isHidden = true;\n    }\n      // Fonction pour ajuster la hauteur du header lors du défilement\n      function adjustHeaderHeight() {\n        if (window.scrollY > 0) {\n          header.classList.add('shrink');\n        } else {\n          header.classList.remove('shrink');\n        }\n      }\n\n    function handleScroll() {\n      let scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n      const isMobile = window.innerWidth < 811;\n\n      if (scrollTop > threshold && !isHidden) {\n        if (isMobile) {\n          slideUp();\n        } else {\n          slideOut();\n        }\n      } else if (scrollTop <= threshold && isHidden) {\n        if (isMobile) {\n          slideDown();\n        } else {\n          slideIn();\n        }\n      }\n  \n  \n      lastScrollTop = scrollTop <= 0 ? 0 : scrollTop; // For Mobile or negative scrolling\n    }\n  \n    function handleTouchAndMouseEnter() {\n      if (isHidden) {\n        if (window.innerWidth < 811) {\n          slideDown();\n        } else {\n          slideIn();\n        }\n      }\n    }\n  \n    function handleTouchAndMouseLeave() {\n      if (lastScrollTop > threshold && !isHidden) {\n        if (window.innerWidth < 811) {\n          slideUp();\n        } else {\n          slideOut();\n        }\n      }\n    }\n  \n    window.addEventListener('scroll', handleScroll);\n    window.addEventListener('scroll', adjustHeaderHeight);\n  \n    // Mouse events for desktop\n    header.addEventListener('mouseenter', handleTouchAndMouseEnter);\n    header.addEventListener('mouseleave', handleTouchAndMouseLeave);\n  \n    // Touch events for tablets and mobile devices\n    header.addEventListener('touchstart', handleTouchAndMouseEnter);\n    header.addEventListener('touchend', handleTouchAndMouseLeave);\n  \n    // Initial check to see if we're at the top of the page\n    if (window.pageYOffset <= threshold) {\n      if (window.innerWidth < 811) {\n        slideDown();\n      } else { \n        slideIn();\n      } \n    } else {\n      if (window.innerWidth < 811) {\n        slideUp();\n      } else {\n        slideIn();\n      }\n    }\n  \n  });\n\n//////// end header ////////////\n  \n\n\n//// ancre dans texte au click paragraphe correspondant arrive en dessous du header \n\n\n(function($, window) {\n  var adjustAnchor = function() {\n      var $anchor = $('.sidebar_first_container'),\n              fixedElementHeight = 500;\n      if ($anchor.length > 0) {\n          $('html, body').stop().animate({scrollTop: $anchor.offset().top - fixedElementHeight }, 0);\n      }\n  };\n\n  $(window).on('hashchange', function() {\n      adjustAnchor();\n  });\n\n\n  ////////////////////////  start script smooth apparition des textes /////////////////\n\n  function scrollReaveal(){\n\n    const nodes = {\n      logo : document.querySelectorAll('#logo-animated-container'),\n      chapeau :  document.querySelectorAll('.field_body'),\n      paragraph: document.querySelectorAll('.field_field_textes .paragraph--type--static-parts'),\n      enjeux : document.querySelectorAll('.field_field_textes .paragraph--type--static-parts .enjeux'),\n      // mapHome : document.querySelectorAll('.field_field_map_block #block-sitesmapblock'),\n      // mapSite : document.querySelectorAll('#sites-map-container'),\n      lienDoc : document.querySelectorAll('.field_field_documents'),\n      lienURL : document.querySelectorAll('.field_field_liens_site'),\n    }\n\n    const showUp = {\n        origin: 'bottom',\n        delay: 100,\n        duration: 1000,\n        distance: '50px',\n        easing: 'cubic-bezier(0.5, 0, 0, 1)'\n    }\n\n    const Show = {\n      delay: 100,\n      duration: 600,\n      easing: 'cubic-bezier(0.5, 0, 0, 1)'\n    }\n\n    console.log(nodes);\n\n    ScrollReveal().reveal(nodes.logo, Show);\n    ScrollReveal().reveal(nodes.chapeau, showUp);\n    ScrollReveal().reveal(nodes.paragraph, showUp);\n    ScrollReveal().reveal(nodes.enjeux, showUp);\n    // ScrollReveal().reveal(nodes.mapHome, showUp);\n    // ScrollReveal().reveal(nodes.mapSite, showUp);\n    ScrollReveal().reveal(nodes.lienDoc, showUp);\n    ScrollReveal().reveal(nodes.lienURL, showUp);\n\n  }\n\n\n  $( document ).ready(function() {\n    scrollReaveal();\n  });\n\n  ////////////////////////  end script smooth apparition des textes /////////////////\n\n  // //////////////////// start Timeline script ///////////////////////\n\n    // Update month field to only show the first 3 letters\n    document.querySelectorAll('.paragraph--type--phase-deroulement').forEach(function(paragraph) {\n      const monthField = paragraph.querySelector('.field_field_date_de_moi div:nth-of-type(2)');\n      if (monthField) {\n        const monthText = monthField.textContent.trim();\n        if (monthText === \"juillet\") {\n          monthField.textContent = monthText.slice(0, 4);\n          monthField.classList.add('after');\n        } else if (monthText === \"juin\") {\n          monthField.textContent = monthText.slice(0, 4);\n        } else if (monthText.length > 3) {\n          monthField.textContent = monthText.slice(0, 3);\n          monthField.classList.add('after');\n        }\n      }\n    });\n  \n    // Fonction pour ajouter ou retirer la classe .only\n    function updateDateClasses() {\n      document.querySelectorAll('.paragraph--type--phase-deroulement .date').forEach(function(dateElement) {\n        const date2Element = dateElement.querySelector('.date2');\n        const yearElement = dateElement.querySelector('.field_field_date_de_annee');\n  \n        if (date2Element && !date2Element.textContent.trim()) {\n          if (yearElement) {\n            yearElement.classList.add('only');\n          }\n        } else {\n          if (yearElement) {\n            yearElement.classList.remove('only');\n          }\n        }\n      });\n    }\n  \n    // Exécuter la fonction une première fois pour le contenu déjà présent\n    updateDateClasses();\n  \n    // MutationObserver pour surveiller les changements dans le DOM\n    const observer = new MutationObserver(function(mutationsList, observer) {\n      for(let mutation of mutationsList) {\n        if (mutation.type === 'childList') {\n          updateDateClasses();\n        }\n      }\n    });\n\n\n  //   ////////////////////// start  calendrier home   /////////////////////////////////\n    $(document).ready(function(){\n      $('.__timeline-content').slick({\n        slidesToShow: 3,\n        slidesToScroll: 1,\n        dots: false,\n        arrows: true,\n        centerMode: false,\n        draggable: true,\n        infinite: false,\n        responsive: [\n          {\n            breakpoint: 810,\n            settings: {\n              slidesToShow: 1,\n              adaptiveHeight: false,\n              arrows: true,\n              draggable: true,\n              centerMode: false,\n              infinite: false,\n            }\n          }]\n      });\n      console.log('salut slick calendrier');\n    \n      });\n    \n  //////////////////////// end   calendrier home   /////////////////////////////////\n  \n  \n\n  //////////////////////// end Timeline script /////////////////////////////////////////////\n\n  ///////////////////  caracteres  body actus/////////////////////////\n\n  document.addEventListener('DOMContentLoaded', function() {\n    // Nombre maximum de caractères à afficher\n    const maxChars = 140; // Ajustez cette valeur selon vos besoins\n\n    document.querySelectorAll('#actus-caroussel .node-type-actualite').forEach(function(node) {\n        let paragraphs = node.querySelectorAll('.field_body p');\n        let fullText = \"\";\n        \n        // Concaténer tous les paragraphes\n        paragraphs.forEach(p => fullText += p.textContent.trim() + \" \");\n        fullText = fullText.trim();\n\n        // Vérifier si le texte dépasse la limite\n        if (fullText.length > maxChars) {\n            let truncatedText = fullText.slice(0, maxChars) + '...';\n\n            // Vider tout le contenu et insérer seulement le texte tronqué\n            let firstParagraph = paragraphs[0];\n            firstParagraph.textContent = truncatedText;\n\n            // Masquer les autres paragraphes\n            for (let i = 1; i < paragraphs.length; i++) {\n                paragraphs[i].style.display = \"none\";\n            }\n        }\n    });\n  });\n\n\n  \n\n //////////// start slideshow home  ////////////////////////// \n\n\n\n  $(document).ready(function(){\n      let actuview = $('.content-actus .view ')\n      if (actuview) {\n        actuview.slick({\n          slidesToShow: 3,\n          // slidesToScroll: 1,\n          dots: false,\n          arrows: true,\n          // centerMode: true,\n          adaptiveHeight: false,\n          autoplay: false,\n          // autoplaySpeed: 1500,\n          // infinite: true,\n          // centerPadding: '100px',\n          responsive: [\n            {\n              breakpoint: 810,\n              settings: {\n                slidesToShow: 1,\n                // slidesToScroll: 1,\n                adaptiveHeight: false,\n                arrows: true,\n                draggable: true,\n                // centerMode: true,\n                // centerPadding: '100px',\n                autoplay: false,\n                // autoplaySpeed: 2000,\n              }\n            }]\n        });\n        console.log('salut slick home');\n        \n      }\n      $('.slick-carousel').slick({\n        lazyLoad: 'progressive', // Option 'ondemand' ou 'progressive'\n      });\n\n  });\n\n\n\n\n  $(document).ready(function () {\n    let diapohome = $('.config_pages--type--diaporama-home .diaporama');\n\n    if (diapohome.length) {\n        // Initialisation de Slick\n        diapohome.slick({\n            slidesToShow: 1,\n            dots: false,\n            arrows: false,\n            // centerMode: true,\n            adaptiveHeight: false,\n            autoplay: true,  // Activer l'autoplay\n            autoplaySpeed: 4000,  // Changement de slide toutes les 4 secondes\n            // infinite: true,\n            pauseOnHover: false,  // Ne pas arrêter l'autoplay lors du survol\n            pauseOnFocus: false,\n            responsive: [\n                {\n                    breakpoint: 810,\n                    settings: {\n                        slidesToShow: 1,\n                        adaptiveHeight: false,\n                        arrows: false,\n                        draggable: true,\n                        centerMode: false,\n                    }\n                }]\n        });\n\n  }\n});\n\n ////////////  end slideshow home  ////////////////////////// \n\n//////////////// start lightbox galerie image page site////////////////////////\n\n// Sélection des images et de leurs légendes dans la galerie\nlet images = document.querySelectorAll('.paragraph--type--site-diapo .lightbox-trigger');\nlet currentIndex;\n\n// Création de la lightbox et de ses éléments\nconst lightbox = document.createElement('div');\nlightbox.id = 'lightbox';\nlightbox.classList.add('lightbox');\ndocument.body.appendChild(lightbox);\n\nconst img = document.createElement('img');\nlightbox.appendChild(img);\n\n// Élément pour afficher la légende\nconst caption = document.createElement('p');\ncaption.classList.add('caption');\nlightbox.appendChild(caption);\n\nconst closeBtn = document.createElement('span');\ncloseBtn.classList.add('close');\ncloseBtn.innerHTML = '&times;';\nlightbox.appendChild(closeBtn);\n\nconst prevBtn = document.createElement('a');\nprevBtn.classList.add('prev');\nprevBtn.innerHTML = '&#10094;';\nlightbox.appendChild(prevBtn);\n\nconst nextBtn = document.createElement('a');\nnextBtn.classList.add('next');\nnextBtn.innerHTML = '&#10095;';\nlightbox.appendChild(nextBtn);\n\n// Fonction pour afficher l'image et la légende à l'index donné\nfunction showImage(index) {\n  if (index < 0) index = images.length - 1;\n  if (index >= images.length) index = 0;\n  currentIndex = index;\n\n  // Mettre à jour l'image\n  img.src = images[currentIndex].getAttribute('src');\n\n  // Récupérer la légende associée (le paragraphe dans blockquote suivant l'image)\n  const captionText = images[currentIndex]\n    .closest('.cadre-img-zoom')\n    .nextElementSibling.querySelector('.image-field-caption p')\n    .textContent;\n    \n  caption.textContent = captionText || ''; // Affiche la légende ou une chaîne vide si elle est absente\n  lightbox.style.display = 'flex';\n}\n\n// Événements de clic sur chaque image pour ouvrir le lightbox avec la légende\nimages.forEach((image, index) => {\n  image.addEventListener('click', () => {\n    showImage(index);\n  });\n});\n\n// Fermer le lightbox\ncloseBtn.addEventListener('click', () => {\n  lightbox.style.display = 'none';\n});\n\n// Navigation pour images précédente et suivante\nprevBtn.addEventListener('click', (e) => {\n  e.stopPropagation();\n  showImage(currentIndex - 1);\n});\n\nnextBtn.addEventListener('click', (e) => {\n  e.stopPropagation();\n  showImage(currentIndex + 1);\n});\n\n// Fermer le lightbox en cliquant en dehors de l'image\nlightbox.addEventListener('click', (e) => {\n  if (e.target === lightbox) {\n    lightbox.style.display = 'none';\n  }\n});\n\n// Ajout des contrôles clavier (Échap, flèches gauche/droite)\ndocument.addEventListener('keydown', (e) => {\n  if (lightbox.style.display === 'flex') {\n    if (e.key === 'Escape') {\n      lightbox.style.display = 'none';\n    } else if (e.key === 'ArrowLeft') {\n      showImage(currentIndex - 1);\n    } else if (e.key === 'ArrowRight') {\n      showImage(currentIndex + 1);\n    }\n  }\n});\n\n\n//////////////// end lightbox galerie image page site////////////////////////\n\n  \n\n//////////////////// start wrapper views-row  lessites /////////////////////////\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionne le conteneur principal avec l'ID 'lessites'\n  const container = document.getElementById(\"lessites\");\n\n  // Vérifie si le conteneur existe pour éviter toute erreur sur d'autres pages\n  if (container) {\n    // Sélectionne l'élément 'view' à l'intérieur de '.views-element-container'\n    const viewContainer = container.querySelector(\".views-element-container .view\");\n\n    // Vérifie si 'viewContainer' existe pour éviter les erreurs\n    if (viewContainer) {\n      // Crée une div englobante pour tous les éléments 'views-row'\n      const wrapperDiv = document.createElement(\"div\");\n      wrapperDiv.classList.add(\"views-row-wrapper\"); // ajoute une classe pour faciliter le style CSS\n\n      // Déplace tous les éléments 'views-row' dans la nouvelle div\n      const viewsRows = viewContainer.querySelectorAll(\".views-row\");\n      viewsRows.forEach(row => wrapperDiv.appendChild(row));\n\n      // Ajoute la div englobante dans le 'viewContainer'\n      viewContainer.appendChild(wrapperDiv);\n    }\n  }\n});\n\n\n//////////////////// end wrapper views-row  lessites /////////////////////////\n\n\n\n////////////////////  start div infos site  ////////////////////////\n\n// Vérifie si la page a la classe 'node-type-site' dans le <body>\nif (document.body.classList.contains('node-type-site')) {\n  // Sélectionne le conteneur principal\n  const blockRegion = document.querySelector('.block-region-second');\n\n  // Liste des classes spécifiques à cibler\n  const fieldClasses = [\n      '.field_field_region',\n      '.field_field_nom_du_qpv_nb_d_hab',\n      '.field_field_departement_s',\n      '.field_field_programme_de_l_etat',\n      '.field_field_porteur_s_de_site',\n      '.field_field_nom_de_la_commune_nb_d_hab'\n  ];\n\n  // Sélectionne les div parents de chacun des champs listés\n  const elementsToWrap = [];\n  fieldClasses.forEach(className => {\n      const fieldElement = blockRegion.querySelector(className);\n      if (fieldElement) {\n          // Ajoute le parent du champ au tableau si trouvé\n          elementsToWrap.push(fieldElement.parentElement);\n      }\n  });\n\n  // Vérifie que des éléments ont été trouvés\n  if (elementsToWrap.length > 0) {\n      // Crée le conteneur avec la classe 'infos'\n      const infosContainer = document.createElement('div');\n      infosContainer.className = 'infos';\n\n      // Insère le conteneur `.infos` avant le premier élément ciblé\n      const firstElement = elementsToWrap[0];\n      blockRegion.insertBefore(infosContainer, firstElement);\n\n      // Déplace chaque élément dans le conteneur `.infos`\n      elementsToWrap.forEach(element => infosContainer.appendChild(element));\n  }\n}\n////////////////////  end div infos site  ////////////////////////\n\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionner les éléments à déplacer\n  const documentsField = document.querySelector(\".field_field_documents\");\n  const liensSiteField = document.querySelector(\".field_field_liens_site\");\n  \n  // Sélectionner la destination\n  const thirdRegion = document.querySelector(\".block-region-third > div\");\n\n  // Créer une nouvelle div pour englober les éléments déplacés\n  const wrapperDiv = document.createElement(\"div\");\n  wrapperDiv.classList.add(\"documents-liens-wrapper\");\n\n  // Déplacer les éléments dans la nouvelle div\n  if (documentsField && liensSiteField && thirdRegion) {\n      wrapperDiv.appendChild(documentsField);\n      wrapperDiv.appendChild(liensSiteField);\n\n      // Ajouter la nouvelle div dans la destination\n      thirdRegion.appendChild(wrapperDiv);\n  }\n});\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n  // Sélectionner les éléments pertinents\n  const documentsLiensWrapper = document.querySelector(\".documents-liens-wrapper\");\n  const blockRegionThird = document.querySelector(\".block-region-third\");\n\n  // Vérifier que les éléments existent avant de les manipuler\n  if (documentsLiensWrapper && blockRegionThird) {\n      // Déplacer .documents-liens-wrapper en dehors du div contenant les boutons prev/next\n      blockRegionThird.appendChild(documentsLiensWrapper);\n  }\n});\n\n\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n  // Fonction pour déplacer le bloc en fonction de la taille de l'écran\n  function moveLanguageSwitcher() {\n    const languageSwitcher = document.getElementById(\"block-quartiers-de-demain-selecteurdelangue\");\n    const navContainer = document.querySelector(\".header_nav_container\");\n\n    if (window.innerWidth <= 810) { // Si écran téléphone\n      if (languageSwitcher && navContainer && !navContainer.contains(languageSwitcher)) {\n        navContainer.appendChild(languageSwitcher); // Déplace le bloc dans header_nav_container\n      }\n    } else { // Si écran non téléphone\n      const headerRightContainer = document.querySelector(\".header_right_container\");\n      if (languageSwitcher && headerRightContainer && !headerRightContainer.contains(languageSwitcher)) {\n        headerRightContainer.appendChild(languageSwitcher); // Remet le bloc dans sa position initiale\n      }\n    }\n  }\n\n  // Déclencher au chargement et au redimensionnement\n  moveLanguageSwitcher();\n  window.addEventListener(\"resize\", moveLanguageSwitcher);\n});\n\n\n})(jQuery, window);\n\n\n\n\n//# sourceURL=webpack://quartiers_de_demain/./src/assets/js/quartiers_de_demain.js?");
 
 /***/ })
 
diff --git a/web/themes/custom/quartiers_de_demain/src/assets/js/quartiers_de_demain.js b/web/themes/custom/quartiers_de_demain/src/assets/js/quartiers_de_demain.js
index 8e7c646..aea2721 100644
--- a/web/themes/custom/quartiers_de_demain/src/assets/js/quartiers_de_demain.js
+++ b/web/themes/custom/quartiers_de_demain/src/assets/js/quartiers_de_demain.js
@@ -358,17 +358,34 @@
   ///////////////////  caracteres  body actus/////////////////////////
 
   document.addEventListener('DOMContentLoaded', function() {
-    // Maximum number of characters to display
-    const maxChars = 140; // Adjust this value as needed
-  
-    document.querySelectorAll('#actus-caroussel .node-type-actualite .field_body p').forEach(function(paragraph) {
-      let text = paragraph.textContent.trim();
-      if (text.length > maxChars) {
-        let truncatedText = text.slice(0, maxChars) + '...';
-        paragraph.textContent = truncatedText;
-      }
+    // Nombre maximum de caractères à afficher
+    const maxChars = 140; // Ajustez cette valeur selon vos besoins
+
+    document.querySelectorAll('#actus-caroussel .node-type-actualite').forEach(function(node) {
+        let paragraphs = node.querySelectorAll('.field_body p');
+        let fullText = "";
+        
+        // Concaténer tous les paragraphes
+        paragraphs.forEach(p => fullText += p.textContent.trim() + " ");
+        fullText = fullText.trim();
+
+        // Vérifier si le texte dépasse la limite
+        if (fullText.length > maxChars) {
+            let truncatedText = fullText.slice(0, maxChars) + '...';
+
+            // Vider tout le contenu et insérer seulement le texte tronqué
+            let firstParagraph = paragraphs[0];
+            firstParagraph.textContent = truncatedText;
+
+            // Masquer les autres paragraphes
+            for (let i = 1; i < paragraphs.length; i++) {
+                paragraphs[i].style.display = "none";
+            }
+        }
     });
   });
+
+
   
 
  //////////// start slideshow home  //////////////////////////