1102 lines
45 KiB
JavaScript
1102 lines
45 KiB
JavaScript
/**
|
||
* @file
|
||
* erabletheme behaviors.
|
||
*/
|
||
(function ($, Drupal) {
|
||
|
||
'use strict';
|
||
|
||
Drupal.behaviors.erabletheme = {
|
||
attach: function (context, settings) {
|
||
|
||
//
|
||
// Bloc en-tête hors colonne (.page-header-outside) : positionné en
|
||
// absolute dans <main>, donc on mesure sa hauteur et on l'expose via
|
||
// une CSS variable pour que <main> réserve la bonne place en padding-top.
|
||
//
|
||
const header_outside = document.querySelector('.page-header-outside');
|
||
const main_el = header_outside ? header_outside.closest('main') : null;
|
||
if (header_outside && main_el && !main_el.dataset.headerOutsideMeasured) {
|
||
const updateHeaderOutsideHeight = () => {
|
||
const h = header_outside.getBoundingClientRect().height;
|
||
main_el.style.setProperty('--page-header-outside-h', h + 'px');
|
||
};
|
||
updateHeaderOutsideHeight();
|
||
window.addEventListener('resize', updateHeaderOutsideHeight);
|
||
main_el.dataset.headerOutsideMeasured = 'true';
|
||
}
|
||
|
||
//
|
||
// Sidebar projets : marquer .is-active sur le lien de la page courante
|
||
// (la vue ne pose pas cette classe automatiquement, contrairement aux
|
||
// blocs menus Drupal).
|
||
//
|
||
const projetsSidebar = document.querySelector('#block-erabletheme-views-block-projets-block-1');
|
||
if (projetsSidebar && !projetsSidebar.dataset.activeMarked) {
|
||
const currentPath = window.location.pathname.replace(/\/$/, '');
|
||
projetsSidebar.querySelectorAll('a[href]').forEach(a => {
|
||
if (a.getAttribute('href').replace(/\/$/, '') === currentPath) {
|
||
a.classList.add('is-active');
|
||
}
|
||
});
|
||
projetsSidebar.dataset.activeMarked = 'true';
|
||
}
|
||
|
||
//
|
||
// Pages taxonomy (filtres par tag de projet) : on rend les sous-titres
|
||
// des cards cliquables (le titre est déjà lié via le Twig).
|
||
//
|
||
document.querySelectorAll('.taxonomy_page').forEach(card => {
|
||
if (card.dataset.subtitleLinked) return;
|
||
const titleLink = card.querySelector('.projet_label a');
|
||
const subtitle = card.querySelector('.sous_titre');
|
||
if (titleLink && subtitle && !subtitle.querySelector('a')) {
|
||
const href = titleLink.getAttribute('href');
|
||
// On enveloppe les enfants du sous-titre dans un <a>.
|
||
const a = document.createElement('a');
|
||
a.setAttribute('href', href);
|
||
while (subtitle.firstChild) a.appendChild(subtitle.firstChild);
|
||
subtitle.appendChild(a);
|
||
}
|
||
card.dataset.subtitleLinked = 'true';
|
||
});
|
||
|
||
//
|
||
// Home intro : sortir le .more-link (rendu profond par smart_trim)
|
||
// de .intro_body pour le placer directement sous .intro_main.
|
||
// Ainsi le séparateur vertical s'arrête en bas du texte, pas du bouton,
|
||
// et le bouton est centré par rapport à .home_introduction.
|
||
//
|
||
const intro = document.querySelector('.home_introduction');
|
||
if (intro && !intro.dataset.moreLinkMoved) {
|
||
const moreLink = intro.querySelector('.intro_body .more-link');
|
||
if (moreLink) {
|
||
intro.appendChild(moreLink);
|
||
intro.dataset.moreLinkMoved = 'true';
|
||
}
|
||
}
|
||
|
||
//
|
||
// Carrousel
|
||
//
|
||
const isTaxonomyPage = document.querySelector('.taxonomy_page') ? true : false;
|
||
|
||
if ($('.slick-container') && !isTaxonomyPage) {
|
||
let slickEl = $('.slick-container').find('div').eq(3);
|
||
$(slickEl).slick({
|
||
centerMode: true,
|
||
slidesToShow: 3,
|
||
dots: true,
|
||
appendDots: $('#carousel_dots'),
|
||
responsive: [
|
||
{
|
||
breakpoint: 760,
|
||
settings: {
|
||
slidesToShow: 1
|
||
}
|
||
},
|
||
],
|
||
});
|
||
}
|
||
|
||
if ($('.diapo') && !isTaxonomyPage) {
|
||
let slickEl = $('.diapo > div > div');$(slickEl).slick({
|
||
dots: true,
|
||
appendDots: $('#carousel_dots'),
|
||
});
|
||
}
|
||
|
||
//
|
||
// Toggle du menu
|
||
//
|
||
const hamburgerBtn = document.getElementById("hamburger");
|
||
const hamburgerIcon = document.querySelector(".burger-icon");
|
||
const menu = hamburgerBtn.nextElementSibling;
|
||
const menuItems = menu.children;
|
||
const opacityDelay = 50;
|
||
let inTransition = false;
|
||
|
||
function toggleMenuItems(action) {
|
||
let delay = opacityDelay;
|
||
for (let i = 0; i < menuItems.length; i++) {
|
||
setTimeout(() => {
|
||
if (action === 'show') {
|
||
menuItems[i].classList.add('visible');
|
||
} else if (action === 'hide') {
|
||
menuItems[menuItems.length - i - 1].classList.remove('visible');
|
||
}
|
||
}, delay);
|
||
delay += opacityDelay;
|
||
}
|
||
}
|
||
|
||
// Toggle menu visibility on hamburger click
|
||
hamburgerBtn.addEventListener("click", function(event) {
|
||
event.stopPropagation();
|
||
if (!inTransition) {
|
||
inTransition = true;
|
||
hamburgerIcon.classList.toggle('open');
|
||
if(menu.classList.contains('active')) {
|
||
setTimeout(() => {
|
||
menu.style.display = "none";
|
||
}, 700);
|
||
toggleMenuItems('hide');
|
||
} else {
|
||
menu.style.display = "flex";
|
||
toggleMenuItems('show');
|
||
}
|
||
setTimeout(() => {
|
||
menu.classList.toggle("active");
|
||
}, 1);
|
||
setTimeout(() => {
|
||
inTransition = false;
|
||
}, 700);
|
||
}
|
||
|
||
|
||
});
|
||
|
||
// Close menu when clicking outside of the menu
|
||
document.addEventListener("click", function(event) {
|
||
const isHamburgerClicked = event.target === hamburgerBtn;
|
||
const isMenuClicked = event.target === menu || event.target.parentElement === menu;
|
||
if (!isMenuClicked && !isHamburgerClicked && !inTransition) {
|
||
inTransition = true;
|
||
hamburgerIcon.classList.remove('open');
|
||
menu.classList.remove("active");
|
||
toggleMenuItems('hide');
|
||
setTimeout(() => {
|
||
menu.style.display = "none";
|
||
inTransition = false;
|
||
}, 700);
|
||
}
|
||
});
|
||
|
||
//
|
||
// Programme page text fade in when it enters viewport
|
||
//
|
||
const url = window.location.pathname;
|
||
if (url.endsWith("le-programme-erable") || url.endsWith("le-programme-erable/")) {
|
||
const textElements = document.querySelectorAll('.fullpage_content p, .fullpage_content h3');
|
||
for (let element of textElements) element.classList.add('faded');
|
||
const fadeInOnScroll = (entries, observer) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add('fade-in'); // Add your fade-in class
|
||
observer.unobserve(entry.target); // Stop observing once it's visible
|
||
}
|
||
});
|
||
};
|
||
|
||
// Create an Intersection Observer
|
||
const observer = new IntersectionObserver(fadeInOnScroll, {
|
||
threshold: 0.1 // Adjust as needed (0.1 means 10% of the element is visible)
|
||
});
|
||
|
||
// Attach the observer to each element
|
||
textElements.forEach(element => {
|
||
observer.observe(element);
|
||
});
|
||
}
|
||
|
||
|
||
//
|
||
// Fixed links
|
||
//
|
||
let fluoButtons;
|
||
if (document.querySelector('.actu_full')) {
|
||
fluoButtons = document.querySelectorAll('.liens_fixed > div > div:nth-of-type(2):not(.visually-hidden) > div, .file_fixed > div > .visually-hidden + div > div');
|
||
} else if (document.querySelector('.offre-content')) {
|
||
fluoButtons = document.querySelectorAll('.liens_fixed > div, .file_fixed > div > div');
|
||
} else if (document.querySelector('.projets')) {
|
||
fluoButtons = document.querySelectorAll('.file_fixed > div > div, .liens > div > div > div');
|
||
} else {
|
||
fluoButtons = document.querySelectorAll('.liens_fixed > div > div:not(.visually-hidden), .file_fixed > div > div, .liens > div > div');
|
||
}
|
||
|
||
let footer = document.querySelector('footer');
|
||
|
||
function positionFluoLinks(scrollTop) {
|
||
for (let i = fluoButtons.length; i > 0 ; i--) {
|
||
if (window.innerWidth > 1080) {
|
||
const layoutContainerEl = document.querySelector('.layout-container');
|
||
let pageScrollableHeight = layoutContainerEl.offsetHeight;
|
||
let prevButtonBottom = fluoButtons[i] ? parseInt(fluoButtons[i].style.bottom) : 0;
|
||
let prevButtonHeight = fluoButtons[i] ? fluoButtons[i].offsetHeight : 0;
|
||
fluoButtons[i - 1].style.position = 'fixed';
|
||
fluoButtons[i - 1].style.left = document.querySelector('.projets') ? '76vw' : '75vw';
|
||
/* console.log(`
|
||
pageScrollableHeight: ${pageScrollableHeight},
|
||
footer.offsetHeight: ${footer.offsetHeight},
|
||
window.innerHeight: ${window.innerHeight},
|
||
scrollTop: ${scrollTop}
|
||
`); */
|
||
|
||
if (pageScrollableHeight - footer.offsetHeight < window.innerHeight + scrollTop && i === fluoButtons.length) {
|
||
let margin = document.querySelector('.projets') ? 15 : 30;
|
||
fluoButtons[i - 1].style.bottom = `${window.innerHeight - footer.offsetTop + scrollTop + margin}px`;
|
||
} else {
|
||
let margin = document.querySelector('.projets') ? 0 : 15;
|
||
fluoButtons[i - 1].style.bottom = i === fluoButtons.length ? '30px' : `${prevButtonBottom + prevButtonHeight + margin}px`;
|
||
}
|
||
} else {
|
||
fluoButtons[i - 1].style.position = 'relative';
|
||
fluoButtons[i - 1].style.left = '0';
|
||
fluoButtons[i - 1].style.bottom = '0';
|
||
}
|
||
}
|
||
}
|
||
if (document.querySelector('.fullpage')) {
|
||
let liens = document.querySelectorAll('.liens_fixed a, .file_fixed a, .content_partenaires a');
|
||
for (let lien of liens) {
|
||
lien.setAttribute('target', '_blank');
|
||
}
|
||
|
||
positionFluoLinks();
|
||
document.body.addEventListener('scroll', (e) => {
|
||
positionFluoLinks(e.target.scrollTop);
|
||
});
|
||
window.addEventListener('resize', () => {
|
||
positionFluoLinks();
|
||
});
|
||
}
|
||
|
||
// Changer le texte des liens des ressources
|
||
if (document.querySelector('.ressources')) {
|
||
let liens = document.querySelectorAll('.file a');
|
||
for (let lien of liens) {
|
||
lien.innerHTML = 'Télécharger le document';
|
||
lien.setAttribute('href', lien.getAttribute('href').replace('/index.php', ''));
|
||
lien.setAttribute('target', '_blank');
|
||
}
|
||
// si la ressource n'a pas de date afficher le lien plus haute
|
||
// et la ressource en premier
|
||
let ressources = document.querySelectorAll('.views-row');
|
||
let container = document.querySelector('.views-row:first-of-type').parentElement;
|
||
|
||
for (let ressource of ressources) {
|
||
if (!ressource.querySelector('time')) {
|
||
let link = ressource.querySelector('.file');
|
||
let linkContainer = link.parentElement.parentElement;
|
||
linkContainer.style.gridRow = '2';
|
||
linkContainer.style.marginTop = '30px';
|
||
}
|
||
|
||
const rows = Array.from(container.querySelectorAll('.views-row'));
|
||
|
||
const undated = [];
|
||
const dated = [];
|
||
|
||
rows.forEach(row => {
|
||
if (row.querySelector('time')) {
|
||
dated.push(row);
|
||
} else {
|
||
undated.push(row);
|
||
}
|
||
});
|
||
|
||
// Clear container
|
||
container.innerHTML = '';
|
||
|
||
// Append undated rows first, then dated
|
||
[...undated, ...dated].forEach(row => {
|
||
container.appendChild(row);
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Ajouter les logos réseaux sociaux dans le menu togglable
|
||
//
|
||
let socials = document.querySelector('.social-media-links--platforms');
|
||
let socialsClone = socials.cloneNode(true);
|
||
socialsClone.id = 'socials-in-menu-wrapper';
|
||
let menuContainer = document.querySelector('#hamburger + ul');
|
||
let socialsContainer = document.createElement('li');
|
||
socialsContainer?.append(socialsClone);
|
||
menuContainer?.append(socialsContainer);
|
||
|
||
//
|
||
// Retirer paragraphes vides fullpage
|
||
// et ajouter de la marge pour les images en portrait
|
||
//
|
||
let currentPage;
|
||
if (document.querySelector('.fullpage:not(.actus)')) currentPage = 'fullpage';
|
||
else if (document.querySelector('.carousel_container')) currentPage = 'home';
|
||
|
||
if (currentPage === 'fullpage') {
|
||
let paragraphs = document.querySelectorAll('p');
|
||
for (let paragraph of paragraphs) {
|
||
if (!/[a-zA-Z]/.test(paragraph.innerText)) {
|
||
paragraph.remove();
|
||
}
|
||
}
|
||
|
||
let imgs = document.querySelectorAll('.fullpage img');
|
||
let isActus = document.querySelector('.retour_actus');
|
||
if (isActus) {
|
||
for (let img of imgs) {
|
||
if (img.height > img.width) {
|
||
img.parentElement.style.padding = '0 12vw';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// all meetup card is a link
|
||
//
|
||
|
||
let meetup = document.querySelector('.meetup_list');
|
||
if (meetup) {
|
||
let meetupCards= document.querySelectorAll('.meetup_list > .views-row');
|
||
for (let card of meetupCards) {
|
||
let meetupLink = card.querySelector('.offre-title');
|
||
meetupLink = meetupLink.getAttribute('href');
|
||
let ficheLink = document.createElement('a');
|
||
ficheLink.setAttribute('href', meetupLink);
|
||
let cardArticle = card.querySelector('article');
|
||
ficheLink.append(cardArticle);
|
||
card.append(ficheLink);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Aside menu toggle
|
||
//
|
||
|
||
const sideMenuTitle =
|
||
document.querySelector('#block-erabletheme-leprogramme-2 h2') ||
|
||
document.querySelector('#block-erabletheme-views-block-projets-block-1 h2');
|
||
|
||
if (sideMenuTitle) {
|
||
sideMenuTitle.addEventListener('click', () => {
|
||
const sideMenu = document.querySelector('#block-erabletheme-leprogramme-2 > ul') ||
|
||
document.querySelector('#block-erabletheme-views-block-projets-block-1 .projets_list');
|
||
const titleArrow = sideMenuTitle.querySelector('div');
|
||
if (!sideMenu.classList.contains('closed')) {
|
||
sideMenu.classList.add('closed');
|
||
titleArrow.classList.add('closed');
|
||
} else {
|
||
sideMenu.classList.remove('closed');
|
||
titleArrow.classList.remove('closed');
|
||
}
|
||
});
|
||
}
|
||
|
||
//
|
||
// set active project in aside project menu
|
||
//
|
||
|
||
const asideProjectMenu = document.querySelector('#block-erabletheme-views-block-projets-block-1 .projets_list');
|
||
if (asideProjectMenu) {
|
||
// Le titre du projet n'est plus rendu dans .projet_full depuis la
|
||
// refonte (il a été remonté dans .page-header-outside, hors colonne
|
||
// blanche). On va chercher le titre courant à sa nouvelle place.
|
||
// Garde sur null + chaîne vide pour éviter l'exception qui plantait
|
||
// tout le behavior attach (et donc Rellax) sur /projets/<slug>.
|
||
const headerOutside = document.querySelector('.layout-content .page-header-outside h2');
|
||
const contentPageTitle = (headerOutside?.innerText || '').trim().toLowerCase();
|
||
if (contentPageTitle) {
|
||
for (let item of asideProjectMenu.children) {
|
||
const itemTitle = (item.innerText || '').trim().toLowerCase();
|
||
if (itemTitle === contentPageTitle) {
|
||
item.querySelector('a')?.classList.add('is-active');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// set non breaking spaces
|
||
//
|
||
|
||
document.querySelectorAll('p, li, h1, h2, h3, h4, h5, h6').forEach((content) => {
|
||
content.innerHTML = content.innerHTML.replaceAll(' ;', ' ;');
|
||
content.innerHTML = content.innerHTML.replaceAll(' :', ' :');
|
||
content.innerHTML = content.innerHTML.replaceAll(' ?', ' ?');
|
||
content.innerHTML = content.innerHTML.replaceAll(' !', ' !');
|
||
content.innerHTML = content.innerHTML.replaceAll('« ', '« ');
|
||
content.innerHTML = content.innerHTML.replaceAll(' »', ' »');
|
||
content.innerHTML = content.innerHTML.replaceAll('(« ', '(« ');
|
||
content.innerHTML = content.innerHTML.replaceAll(' »)', ' »)');
|
||
});
|
||
|
||
//
|
||
// index projets random shape
|
||
//
|
||
|
||
if (document.querySelector('.projets_list')) {
|
||
const projets = document.querySelectorAll('.projets_list > .views-row');
|
||
const shapesAmount = 6;
|
||
for (let i = 0; i < projets.length; i++) {
|
||
const randomShape = Math.floor(Math.random() * shapesAmount) + 1;
|
||
if (projets[i].querySelector('img')) {
|
||
const img = projets[i].querySelector('a');
|
||
img.style.maskImage = `url('/themes/erabletheme/assets/shapes/shape_${randomShape}.svg')`;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Décors mid-left (col-decor) : PNG empilés au pied gauche
|
||
// extérieur d'une colonne. Position absolue dans .layout-container,
|
||
// bord droit du PNG calé sur bord gauche colonne via
|
||
// translateX(-100%). Tailles + gaps proportionnels à colH (bornés
|
||
// min/max). Affichage conditionnel : seuils 50%/30% colH.
|
||
// - .fullpage:not(.large-container) : pile de 2 (mid-left-1+2).
|
||
// - .map-projets (home) : 1 seul (mid-left-1) via singleOnly.
|
||
// Parallax custom (sans Rellax) plus bas.
|
||
// Visibilité responsive : _background.scss.
|
||
//
|
||
const layoutContainer = document.querySelector('.layout-container');
|
||
const colDecorState = []; // { img1, img2, col }
|
||
|
||
function clamp(min, val, max) { return Math.max(min, Math.min(val, max)); }
|
||
|
||
// Coefficient appliqué aux décors home (oiseaux + fleurs) hors
|
||
// desktop : on grossit les images pour qu'elles restent lisibles
|
||
// sur écrans étroits (le viewport rétrécit mais les éléments
|
||
// décoratifs en vw deviennent visuellement trop petits).
|
||
function decorWidthScale() {
|
||
const w = window.innerWidth;
|
||
if (w < 760) return 1.8; // mobile
|
||
if (w < 1080) return 1.5; // tablette
|
||
return 1; // desktop
|
||
}
|
||
|
||
function colDecorMetrics(colH) {
|
||
return {
|
||
gapBottom: clamp(120, 0.08 * colH, 320),
|
||
gapBetween: clamp(60, 0.03 * colH, 180),
|
||
h2: clamp(180, 0.14 * colH, 480),
|
||
h1: clamp(220, 0.17 * colH, 580),
|
||
};
|
||
}
|
||
|
||
function createColDecorImg(idx) {
|
||
const img = document.createElement('img');
|
||
img.className = `col-decor col-decor-${idx}`;
|
||
img.setAttribute('aria-hidden', 'true');
|
||
img.setAttribute('alt', '');
|
||
img.src = `/themes/erabletheme/assets/new-bg-shapes/mid-left-${idx}.png`;
|
||
img.style.cssText = 'position:absolute;width:auto;pointer-events:none;z-index:0;transform:translateX(-100%);';
|
||
return img;
|
||
}
|
||
|
||
function setupColDecor() {
|
||
if (!layoutContainer) return;
|
||
layoutContainer.querySelectorAll('.col-decor').forEach(n => n.remove());
|
||
colDecorState.length = 0;
|
||
// Colonnes .fullpage internes : pile de 2 PNG (mid-left-1 et -2).
|
||
document.querySelectorAll('.fullpage:not(.large-container)').forEach(col => {
|
||
const img1 = createColDecorImg(1);
|
||
const img2 = createColDecorImg(2);
|
||
layoutContainer.appendChild(img1);
|
||
layoutContainer.appendChild(img2);
|
||
colDecorState.push({ img1, img2, col });
|
||
});
|
||
// Bloc .map-projets (home) : un seul PNG via singleOnly.
|
||
document.querySelectorAll('.map-projets').forEach(col => {
|
||
const img1 = createColDecorImg(1);
|
||
const img2 = createColDecorImg(2);
|
||
layoutContainer.appendChild(img1);
|
||
layoutContainer.appendChild(img2);
|
||
colDecorState.push({ img1, img2, col, singleOnly: true });
|
||
});
|
||
positionColDecor();
|
||
}
|
||
|
||
function positionColDecor() {
|
||
if (!colDecorState.length) return;
|
||
const lcRect = layoutContainer.getBoundingClientRect();
|
||
const lcTopAbs = lcRect.top + window.scrollY;
|
||
const lcLeftAbs = lcRect.left + window.scrollX;
|
||
for (const entry of colDecorState) {
|
||
const { img1, img2, col, singleOnly } = entry;
|
||
const r = col.getBoundingClientRect();
|
||
const colH = r.height;
|
||
const m = colDecorMetrics(colH);
|
||
const stack1H = m.gapBottom + m.h2 + m.gapBetween + m.h1;
|
||
// singleOnly : un seul motif (img1) si la place le permet
|
||
// (= gapBottom + h1 sous 50% colH).
|
||
const showBoth = !singleOnly && stack1H <= colH * 0.5;
|
||
const showOne = !showBoth && (m.gapBottom + m.h2) <= colH * 0.3;
|
||
const showSingle = singleOnly && (m.gapBottom + m.h1) <= colH * 0.5;
|
||
entry.visible1 = showBoth || showSingle;
|
||
entry.visible2 = !singleOnly && (showBoth || showOne);
|
||
img1.style.display = entry.visible1 ? 'block' : 'none';
|
||
img2.style.display = entry.visible2 ? 'block' : 'none';
|
||
if (!entry.visible1 && !entry.visible2) continue;
|
||
const colBottomAbs = r.bottom + window.scrollY;
|
||
const leftRel = (r.left + window.scrollX) - lcLeftAbs;
|
||
if (singleOnly) {
|
||
const top1 = colBottomAbs - m.gapBottom - m.h1;
|
||
img1.style.top = (top1 - lcTopAbs) + 'px';
|
||
img1.style.left = leftRel + 'px';
|
||
img1.style.height = m.h1 + 'px';
|
||
entry.scrollRef1 = top1 + m.h1 / 2 - window.innerHeight / 2;
|
||
} else {
|
||
const top2 = colBottomAbs - m.gapBottom - m.h2;
|
||
img2.style.top = (top2 - lcTopAbs) + 'px';
|
||
img2.style.left = leftRel + 'px';
|
||
img2.style.height = m.h2 + 'px';
|
||
entry.scrollRef2 = top2 + m.h2 / 2 - window.innerHeight / 2;
|
||
if (showBoth) {
|
||
const top1 = top2 - m.gapBetween - m.h1;
|
||
img1.style.top = (top1 - lcTopAbs) + 'px';
|
||
img1.style.left = leftRel + 'px';
|
||
img1.style.height = m.h1 + 'px';
|
||
entry.scrollRef1 = top1 + m.h1 / 2 - window.innerHeight / 2;
|
||
}
|
||
}
|
||
}
|
||
applyColDecorParallax();
|
||
}
|
||
|
||
// Parallax custom (sans Rellax) : remontée subtile, amplitude bornée,
|
||
// proportionnelle au scroll relatif à la position d'ancrage. À 0.15
|
||
// de vitesse, pour 100px de scroll au-delà de la référence, le motif
|
||
// monte de 15px ; clamp à ±30px évite tout débordement.
|
||
const COL_DECOR_PARALLAX_SPEED = 0.15;
|
||
const COL_DECOR_PARALLAX_AMP = 30;
|
||
let colDecorRafPending = false;
|
||
|
||
function applyColDecorParallax() {
|
||
const scrollY = window.scrollY || document.body.scrollTop || 0;
|
||
for (const { img1, img2, visible1, visible2, scrollRef1, scrollRef2 } of colDecorState) {
|
||
if (visible2 && scrollRef2 != null) {
|
||
const dY = clamp(-COL_DECOR_PARALLAX_AMP,
|
||
-(scrollY - scrollRef2) * COL_DECOR_PARALLAX_SPEED,
|
||
COL_DECOR_PARALLAX_AMP);
|
||
img2.style.transform = `translate3d(0, ${dY}px, 0) translateX(-100%)`;
|
||
}
|
||
if (visible1 && scrollRef1 != null) {
|
||
const dY = clamp(-COL_DECOR_PARALLAX_AMP,
|
||
-(scrollY - scrollRef1) * COL_DECOR_PARALLAX_SPEED,
|
||
COL_DECOR_PARALLAX_AMP);
|
||
img1.style.transform = `translate3d(0, ${dY}px, 0) translateX(-100%)`;
|
||
}
|
||
}
|
||
}
|
||
|
||
function onColDecorScroll() {
|
||
if (colDecorRafPending) return;
|
||
colDecorRafPending = true;
|
||
requestAnimationFrame(() => {
|
||
colDecorRafPending = false;
|
||
applyColDecorParallax();
|
||
applyHomeDiapoParallax();
|
||
});
|
||
}
|
||
if (!document.body.dataset.colDecorScrollWired) {
|
||
document.body.addEventListener('scroll', onColDecorScroll, { passive: true });
|
||
document.body.dataset.colDecorScrollWired = 'true';
|
||
}
|
||
|
||
//
|
||
// Décor aléatoire en haut à droite de chaque .fullpage. Tirage
|
||
// parmi drawings/ (excluant flower-2 + bird-3 déjà au footer).
|
||
// Bas de l'image overlap le haut de l'ancre (20%, sauf flower-3
|
||
// à 40% car tige fine). Mobile : ancre = .page-header-outside.
|
||
// Largeur par breakpoint.
|
||
//
|
||
const PAGE_DECOR_POOL = ['bird-1.png', 'bird-2.png', 'flower-1.png', 'flower-3.png'];
|
||
const pageDecorState = [];
|
||
|
||
function pageDecorWidthVw() {
|
||
const w = window.innerWidth;
|
||
if (w < 1080) return 22; // mobile + tablette
|
||
return 10; // desktop
|
||
}
|
||
|
||
function setupPageDecor() {
|
||
if (!layoutContainer) return;
|
||
layoutContainer.querySelectorAll('.page-decor').forEach(n => n.remove());
|
||
pageDecorState.length = 0;
|
||
document.querySelectorAll('.fullpage').forEach(col => {
|
||
// Exclure les .fullpage situées dans une sidebar (vue projets
|
||
// imbriquée). On ne décore que les colonnes de contenu.
|
||
if (col.closest('aside')) return;
|
||
// Tirage déterministe par colonne : on stocke l'index sur le
|
||
// dataset pour qu'un resize ne change pas l'image affichée.
|
||
let idx = col.dataset.pageDecorIdx;
|
||
if (idx == null) {
|
||
idx = Math.floor(Math.random() * PAGE_DECOR_POOL.length);
|
||
col.dataset.pageDecorIdx = String(idx);
|
||
} else {
|
||
idx = parseInt(idx, 10);
|
||
}
|
||
const img = document.createElement('img');
|
||
img.className = 'page-decor';
|
||
img.setAttribute('aria-hidden', 'true');
|
||
img.setAttribute('alt', '');
|
||
img.src = `/themes/erabletheme/assets/drawings/${PAGE_DECOR_POOL[idx]}`;
|
||
img.style.cssText = 'position:absolute;width:auto;height:auto;pointer-events:none;z-index:0;';
|
||
layoutContainer.appendChild(img);
|
||
pageDecorState.push({ img, col });
|
||
});
|
||
positionPageDecor();
|
||
}
|
||
|
||
function positionPageDecor() {
|
||
if (!pageDecorState.length) return;
|
||
const lcRect = layoutContainer.getBoundingClientRect();
|
||
const lcTopAbs = lcRect.top + window.scrollY;
|
||
const lcLeftAbs = lcRect.left + window.scrollX;
|
||
const widthVw = pageDecorWidthVw();
|
||
const widthPx = (widthVw / 100) * window.innerWidth;
|
||
const isMobile = window.innerWidth < 760;
|
||
for (const entry of pageDecorState) {
|
||
const img = entry.img;
|
||
if (!img.naturalWidth) {
|
||
img.addEventListener('load', positionPageDecor, { once: true });
|
||
continue;
|
||
}
|
||
const heightPx = widthPx * (img.naturalHeight / img.naturalWidth);
|
||
// Mobile : ancre = .page-header-outside (titre/retour) si présent,
|
||
// sinon la colonne elle-même.
|
||
let anchorEl = entry.col;
|
||
if (isMobile) {
|
||
const layoutContent = entry.col.closest('.layout-content');
|
||
const phOutside = layoutContent && layoutContent.querySelector('.page-header-outside');
|
||
if (phOutside) anchorEl = phOutside;
|
||
}
|
||
const r = anchorEl.getBoundingClientRect();
|
||
const anchorTopAbs = r.top + window.scrollY;
|
||
const anchorRightAbs = r.right + window.scrollX;
|
||
// flower-3 a une tige fine en haut → on la pousse plus dans
|
||
// l'ancre (40%) pour qu'elle ne soit pas perdue dans la marge.
|
||
const overlapRatio = img.src.includes('flower-3') ? 0.4 : 0.2;
|
||
const top = anchorTopAbs + heightPx * overlapRatio - heightPx;
|
||
const left = anchorRightAbs - widthPx * 0.7; // 30% dépasse à droite
|
||
img.style.width = widthPx + 'px';
|
||
img.style.top = (top - lcTopAbs) + 'px';
|
||
img.style.left = (left - lcLeftAbs) + 'px';
|
||
}
|
||
}
|
||
|
||
//
|
||
// Décors home-diapo-{right,left} : ancrés aux bords droit/gauche
|
||
// du viewport, leur haut dépassant au-dessus du haut des cards
|
||
// du carousel home (overlapTop px). Parallax custom.
|
||
//
|
||
const HOME_DIAPO_CONFIGS = [
|
||
{ side: 'right', file: 'home-diapo-right.png', widthVw: 30, overlapTop: 160 },
|
||
{ side: 'left', file: 'home-diapo-left.png', widthVw: 28, overlapTop: 80 },
|
||
];
|
||
const homeDiapoState = [];
|
||
|
||
// Ancre cible : .slick-list (cards visibles), avec fallbacks.
|
||
// .carousel_container inclut les dots → bas trop bas, à éviter.
|
||
function getCarouselCardsBox() {
|
||
return document.querySelector('.carousel_container .slick-list')
|
||
|| document.querySelector('.carousel_container .slick-container')
|
||
|| document.querySelector('.carousel_container');
|
||
}
|
||
|
||
function setupHomeDiapoDecor() {
|
||
if (!layoutContainer) return;
|
||
layoutContainer.querySelectorAll('.home-diapo-decor').forEach(n => n.remove());
|
||
homeDiapoState.length = 0;
|
||
const cardsBox = getCarouselCardsBox();
|
||
if (!cardsBox) return;
|
||
for (const cfg of HOME_DIAPO_CONFIGS) {
|
||
const img = document.createElement('img');
|
||
img.className = `home-diapo-decor home-diapo-decor-${cfg.side}`;
|
||
img.setAttribute('aria-hidden', 'true');
|
||
img.setAttribute('alt', '');
|
||
img.src = `/themes/erabletheme/assets/new-bg-shapes/${cfg.file}`;
|
||
img.style.cssText = `position:absolute;${cfg.side}:0;width:auto;height:auto;pointer-events:none;z-index:0;`;
|
||
layoutContainer.appendChild(img);
|
||
homeDiapoState.push({ img, widthVw: cfg.widthVw, overlapTop: cfg.overlapTop, cardsBox });
|
||
}
|
||
positionHomeDiapoDecor();
|
||
}
|
||
|
||
function positionHomeDiapoDecor() {
|
||
if (!homeDiapoState.length) return;
|
||
const lcRect = layoutContainer.getBoundingClientRect();
|
||
const lcTopAbs = lcRect.top + window.scrollY;
|
||
const scale = decorWidthScale();
|
||
for (const entry of homeDiapoState) {
|
||
const widthPx = (entry.widthVw / 100) * window.innerWidth * scale;
|
||
const cRect = entry.cardsBox.getBoundingClientRect();
|
||
const cardsTopAbs = cRect.top + window.scrollY;
|
||
// Top = haut des cards - overlapTop : le haut de l'image
|
||
// dépasse de cette valeur au-dessus du haut des cards.
|
||
const top = cardsTopAbs - entry.overlapTop;
|
||
entry.img.style.width = widthPx + 'px';
|
||
entry.img.style.top = (top - lcTopAbs) + 'px';
|
||
entry.scrollRef = top - window.innerHeight / 2;
|
||
}
|
||
applyHomeDiapoParallax();
|
||
}
|
||
|
||
function applyHomeDiapoParallax() {
|
||
if (!homeDiapoState.length) return;
|
||
const scrollY = window.scrollY || document.body.scrollTop || 0;
|
||
for (const { img, scrollRef } of homeDiapoState) {
|
||
if (scrollRef == null) continue;
|
||
const dY = clamp(-COL_DECOR_PARALLAX_AMP,
|
||
-(scrollY - scrollRef) * COL_DECOR_PARALLAX_SPEED,
|
||
COL_DECOR_PARALLAX_AMP);
|
||
img.style.transform = `translate3d(0, ${dY}px, 0)`;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Décors home-above : flower-1 (gauche) et bird-1 (droite),
|
||
// au-dessus des cards, leur bas débordant de `overlap` px sur le
|
||
// haut des cards. offsetVw : décalage horizontal vers l'intérieur.
|
||
// Pas de parallax.
|
||
//
|
||
const HOME_ABOVE_CONFIGS = [
|
||
{ side: 'left', file: 'drawings/flower-1.png', widthVw: 15, overlap: 40, offsetVw: 8 },
|
||
{ side: 'right', file: 'drawings/bird-1.png', widthVw: 15, overlap: 40, offsetVw: 4 },
|
||
];
|
||
const homeAboveState = [];
|
||
|
||
function setupHomeAboveDecor() {
|
||
if (!layoutContainer) return;
|
||
layoutContainer.querySelectorAll('.home-above-decor').forEach(n => n.remove());
|
||
homeAboveState.length = 0;
|
||
const cardsBox = getCarouselCardsBox();
|
||
if (!cardsBox) return;
|
||
for (const cfg of HOME_ABOVE_CONFIGS) {
|
||
const img = document.createElement('img');
|
||
img.className = `home-above-decor home-above-decor-${cfg.side}`;
|
||
img.setAttribute('aria-hidden', 'true');
|
||
img.setAttribute('alt', '');
|
||
img.src = `/themes/erabletheme/assets/${cfg.file}`;
|
||
img.style.cssText = `position:absolute;${cfg.side}:${cfg.offsetVw}vw;width:auto;height:auto;pointer-events:none;z-index:0;`;
|
||
layoutContainer.appendChild(img);
|
||
homeAboveState.push({ img, widthVw: cfg.widthVw, overlap: cfg.overlap, cardsBox });
|
||
}
|
||
positionHomeAboveDecor();
|
||
}
|
||
|
||
function positionHomeAboveDecor() {
|
||
if (!homeAboveState.length) return;
|
||
const lcRect = layoutContainer.getBoundingClientRect();
|
||
const lcTopAbs = lcRect.top + window.scrollY;
|
||
const lcHeight = lcRect.height;
|
||
const scale = decorWidthScale();
|
||
for (const entry of homeAboveState) {
|
||
const widthPx = (entry.widthVw / 100) * window.innerWidth * scale;
|
||
const cRect = entry.cardsBox.getBoundingClientRect();
|
||
const cardsTopAbs = cRect.top + window.scrollY;
|
||
// Le BAS de l'image est à `overlap` px sous le haut des cards :
|
||
// l'image est essentiellement au-dessus du carousel, débord en bas.
|
||
const imgBottom = cardsTopAbs + entry.overlap;
|
||
const bottomFromLcBottom = (lcTopAbs + lcHeight) - imgBottom;
|
||
entry.img.style.width = widthPx + 'px';
|
||
entry.img.style.bottom = bottomFromLcBottom + 'px';
|
||
}
|
||
}
|
||
|
||
//
|
||
// Décors home-projet, ancrés au bloc .map-projets :
|
||
// - bird-2 en haut à gauche, débordant à gauche du bloc en
|
||
// desktop, ou collé à -3vw du viewport en mobile/tablette.
|
||
// - flower-3 collée au bord droit du viewport (tronquée), centre
|
||
// vertical à 1/3 depuis le haut du bloc.
|
||
// Pas de parallax.
|
||
//
|
||
const HOME_PROJET_CONFIGS = [
|
||
{ file: 'drawings/bird-2.png', widthVw: 15, anchor: 'block-left-top' },
|
||
{ file: 'drawings/flower-3.png', widthVw: 7, anchor: 'viewport-right' },
|
||
];
|
||
const homeProjetState = [];
|
||
|
||
function setupHomeProjetDecor() {
|
||
if (!layoutContainer) return;
|
||
layoutContainer.querySelectorAll('.home-projet-decor').forEach(n => n.remove());
|
||
homeProjetState.length = 0;
|
||
const block = document.querySelector('.map-projets');
|
||
if (!block) return;
|
||
for (const cfg of HOME_PROJET_CONFIGS) {
|
||
const img = document.createElement('img');
|
||
img.className = `home-projet-decor home-projet-decor-${cfg.anchor}`;
|
||
img.setAttribute('aria-hidden', 'true');
|
||
img.setAttribute('alt', '');
|
||
img.src = `/themes/erabletheme/assets/${cfg.file}`;
|
||
img.style.cssText = 'position:absolute;width:auto;height:auto;pointer-events:none;z-index:0;';
|
||
layoutContainer.appendChild(img);
|
||
homeProjetState.push({ img, anchor: cfg.anchor, widthVw: cfg.widthVw, block });
|
||
}
|
||
positionHomeProjetDecor();
|
||
}
|
||
|
||
function positionHomeProjetDecor() {
|
||
if (!homeProjetState.length) return;
|
||
const lcRect = layoutContainer.getBoundingClientRect();
|
||
const lcTopAbs = lcRect.top + window.scrollY;
|
||
const lcLeftAbs = lcRect.left + window.scrollX;
|
||
const scale = decorWidthScale();
|
||
for (const entry of homeProjetState) {
|
||
const img = entry.img;
|
||
if (!img.naturalWidth) {
|
||
img.addEventListener('load', positionHomeProjetDecor, { once: true });
|
||
continue;
|
||
}
|
||
const widthPx = (entry.widthVw / 100) * window.innerWidth * scale;
|
||
const heightPx = widthPx * (img.naturalHeight / img.naturalWidth);
|
||
const bRect = entry.block.getBoundingClientRect();
|
||
const blockTopAbs = bRect.top + window.scrollY;
|
||
const blockLeftAbs = bRect.left + window.scrollX;
|
||
const blockHeightPx = bRect.height;
|
||
img.style.width = widthPx + 'px';
|
||
if (entry.anchor === 'block-left-top') {
|
||
// bird-2 remontée de 0.6× sa hauteur au-dessus du bloc.
|
||
const top = blockTopAbs - heightPx * 0.6;
|
||
if (window.innerWidth < 1080) {
|
||
img.style.left = '-3vw';
|
||
} else {
|
||
img.style.left = (blockLeftAbs - widthPx * 0.5 - lcLeftAbs) + 'px';
|
||
}
|
||
img.style.top = (top - lcTopAbs) + 'px';
|
||
img.style.right = '';
|
||
} else if (entry.anchor === 'viewport-right') {
|
||
// flower-3 : tronquée par le bord droit du viewport.
|
||
const top = blockTopAbs + blockHeightPx / 3 - heightPx / 2;
|
||
img.style.right = '-20px';
|
||
img.style.left = '';
|
||
img.style.top = (top - lcTopAbs) + 'px';
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Décors latéraux parallax v2.
|
||
// Cloner le .decor-tile autant de fois que nécessaire pour couvrir
|
||
// la hauteur de .layout-container, puis instancier Rellax sur tous
|
||
// les .bgImg (originaux + clones). Au resize, on détruit/recompute.
|
||
//
|
||
const bgRoot = document.getElementById('background');
|
||
let rellax = null;
|
||
|
||
function setupBackgroundTiles() {
|
||
if (!bgRoot) return;
|
||
const original = bgRoot.querySelector('.decor-tile:not([data-tile-clone])');
|
||
if (!original) return;
|
||
|
||
// Nettoyage des clones précédents (cas resize).
|
||
bgRoot.querySelectorAll('.decor-tile[data-tile-clone]').forEach(n => n.remove());
|
||
|
||
const layout = document.querySelector('.layout-container');
|
||
const pageHeight = layout ? layout.offsetHeight : window.innerHeight;
|
||
const tileHeight = original.getBoundingClientRect().height;
|
||
if (tileHeight <= 0) return;
|
||
|
||
const tileCount = Math.max(1, Math.ceil(pageHeight / tileHeight));
|
||
for (let i = 1; i < tileCount; i++) {
|
||
const clone = original.cloneNode(true);
|
||
clone.dataset.tileClone = 'true';
|
||
clone.dataset.tileIndex = String(i);
|
||
// .decor-once : formes pensées pour le haut du 1er tile
|
||
// (coupées en haut) — on les enlève des clones.
|
||
clone.querySelectorAll('.decor-once').forEach(n => n.remove());
|
||
bgRoot.appendChild(clone);
|
||
}
|
||
}
|
||
|
||
function initRellax() {
|
||
if (rellax) { try { rellax.destroy(); } catch (e) { /* noop */ } }
|
||
rellax = new Rellax('.bgImg', { wrapper: 'body' });
|
||
}
|
||
|
||
// Init initial : frises latérales (basées sur layout-container,
|
||
// mesure stable même sans images chargées) + Rellax. Les col-decor
|
||
// sont injectés et positionnés UNIQUEMENT au window.load — leur
|
||
// position dépend de getBoundingClientRect() de .fullpage qui n'est
|
||
// fiable qu'une fois toutes les images du contenu chargées (sinon
|
||
// Rellax cache un blockTop périmé et le motif dérive vers le bas
|
||
// sur les pages longues).
|
||
setupBackgroundTiles();
|
||
initRellax();
|
||
|
||
window.addEventListener('load', () => {
|
||
setupBackgroundTiles();
|
||
setupColDecor();
|
||
setupHomeDiapoDecor();
|
||
setupHomeAboveDecor();
|
||
setupHomeProjetDecor();
|
||
setupPageDecor();
|
||
initRellax();
|
||
});
|
||
|
||
// Resize debouncé : recalcule le nombre de tiles + tous les décors,
|
||
// repart Rellax propre.
|
||
let bgResizeTimer = null;
|
||
window.addEventListener('resize', () => {
|
||
clearTimeout(bgResizeTimer);
|
||
bgResizeTimer = setTimeout(() => {
|
||
setupBackgroundTiles();
|
||
setupColDecor();
|
||
setupHomeDiapoDecor();
|
||
setupHomeAboveDecor();
|
||
setupHomeProjetDecor();
|
||
setupPageDecor();
|
||
initRellax();
|
||
}, 200);
|
||
});
|
||
|
||
// footnotes
|
||
if (document.querySelector('.retour_projets')) {
|
||
const textContent = document.querySelector('.text-content');
|
||
if (textContent) {
|
||
const paragraphs = textContent.querySelectorAll('p');
|
||
const footnotes = [];
|
||
let footnoteNumber = 1;
|
||
|
||
// Process each paragraph to find and replace [...] with superscripts
|
||
paragraphs.forEach(p => {
|
||
p.innerHTML = p.innerHTML.replace(/\[(.*?)\]/g, (match, content) => {
|
||
footnotes.push({
|
||
number: footnoteNumber,
|
||
text: content
|
||
});
|
||
return `<sup style="font-size: 0.7rem; vertical-align: top; font-weight: bold;">${footnoteNumber++}</sup>`;
|
||
});
|
||
});
|
||
|
||
// Create footnotes div if there are any footnotes
|
||
if (footnotes.length > 0) {
|
||
const fullpageContent = document.querySelector('.fullpage_content');
|
||
if (fullpageContent) {
|
||
const footnotesDiv = document.createElement('div');
|
||
footnotesDiv.className = 'footnotes';
|
||
|
||
footnotes.forEach(footnote => {
|
||
const footnoteItem = document.createElement('p');
|
||
footnoteItem.innerHTML = `<strong>${footnote.number}.</strong> ${footnote.text}`;
|
||
footnoteItem.style.fontSize = '0.8rem';
|
||
footnotesDiv.appendChild(footnoteItem);
|
||
});
|
||
|
||
fullpageContent.appendChild(footnotesDiv);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
let firstMap = null;
|
||
|
||
Drupal.behaviors.customLeafletInteraction = {
|
||
attach: function (context, settings) {
|
||
$(context).on('leafletMapInit', function (e, settings, map, mapid, markers) {
|
||
|
||
if (document.querySelector('.projet_full')) {
|
||
// map on the projects page
|
||
|
||
let customIcon = L.icon({
|
||
iconUrl: '/themes/erabletheme/assets/leaflet-point.svg',
|
||
iconSize: [18, 18],
|
||
iconAnchor: [9, 9],
|
||
popupAnchor: [0, -9]
|
||
});
|
||
|
||
let initiatedMap = document.querySelector(`#${mapid}`);
|
||
const currentLibelle = initiatedMap.parentElement.nextElementSibling?.innerText;
|
||
if (currentLibelle) {
|
||
initiatedMap.parentElement.nextElementSibling.remove();
|
||
}
|
||
|
||
if (document.querySelectorAll('.leaflet-container').length <= 1) {
|
||
firstMap = map;
|
||
let bounds = L.latLngBounds();
|
||
map.eachLayer(function (layer) {
|
||
if (layer instanceof L.Marker && !layer._popup) {
|
||
layer.bindPopup(currentLibelle, { closeButton: false, className: 'popup' })
|
||
.setIcon(customIcon)
|
||
.on('mouseover', function () {
|
||
this.openPopup();
|
||
})
|
||
.on('mouseout', function () {
|
||
this.closePopup();
|
||
});
|
||
|
||
bounds.extend(layer.getLatLng());
|
||
map.fitBounds(bounds, { padding: [30, 30], maxZoom: 18 });
|
||
}
|
||
});
|
||
} else {
|
||
// map on the projects index
|
||
|
||
document.querySelector(`#${mapid}`).parentElement.parentElement.parentElement.remove();
|
||
const firstMarker = Object.values(markers)[0];
|
||
let newMarker = L.marker([firstMarker._latlng.lat, firstMarker._latlng.lng], { icon: customIcon })
|
||
.addTo(firstMap)
|
||
.bindPopup(currentLibelle, { closeButton: false, className: 'popup' })
|
||
.on('mouseover', function () {
|
||
this.openPopup();
|
||
})
|
||
.on('mouseout', function () {
|
||
this.closePopup();
|
||
});
|
||
|
||
firstMap.fitBounds(
|
||
firstMap.getBounds().extend(newMarker.getLatLng()),
|
||
{ padding: [30, 30], maxZoom: 18 }
|
||
);
|
||
}
|
||
} else {
|
||
//
|
||
// on projects pages, replace leaflet icons with erable leafs
|
||
//
|
||
const currentMap = document.querySelector('.leaflet-container');
|
||
const leafletIcons = document.querySelectorAll('.leaflet-marker-pane img');
|
||
for (let icon of leafletIcons) {
|
||
icon.setAttribute('src', '/themes/erabletheme/assets/leaflet-point.svg');
|
||
}
|
||
|
||
//
|
||
// set hover on leaflet marker and zones
|
||
//
|
||
const leafletPlaces = document.querySelectorAll('.leaflet-marker-pane img, .leaflet-overlay-pane path');
|
||
const libelles = document.querySelectorAll('.libelles-carte > div > div > div');
|
||
|
||
for (let i = 0; i < leafletPlaces.length; i++) {
|
||
const carte = document.querySelector('.carte');
|
||
|
||
leafletPlaces[i].addEventListener('mouseenter', () => {
|
||
let div = document.createElement('div');
|
||
div.setAttribute('id', 'leaflet-popup');
|
||
div.style.zIndex = '100';
|
||
const x = leafletPlaces[i].getBoundingClientRect().left + leafletPlaces[i].getBoundingClientRect().width / 2;
|
||
const y = leafletPlaces[i].getBoundingClientRect().top;
|
||
setTimeout(() => {
|
||
div.style.opacity = 1;
|
||
const divHeight = div.getBoundingClientRect().height;
|
||
const divWidth = div.getBoundingClientRect().width;
|
||
setTimeout(() => {
|
||
div.style.left = `${x - divWidth / 2}px`;
|
||
div.style.top = `${y - divHeight}px`;
|
||
}, 10);
|
||
}, 10);
|
||
|
||
div.innerText = libelles[i].innerText;
|
||
|
||
carte.appendChild(div);
|
||
});
|
||
leafletPlaces[i].addEventListener('mouseleave', () => {
|
||
let divs = document.querySelectorAll('#leaflet-popup');
|
||
for (let div of divs) {
|
||
div.style.opacity = 0;
|
||
setTimeout(() => {
|
||
div.remove();
|
||
}, 300);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
} (jQuery, Drupal));
|