forked from FWS/TEMPLATE-Web-site-one-page
156 lines
3.4 KiB
JavaScript
156 lines
3.4 KiB
JavaScript
(() => {
|
|
"use strict";
|
|
|
|
const existingCleanup = window.__heroCarouselCleanup;
|
|
if (typeof existingCleanup === "function") {
|
|
existingCleanup();
|
|
}
|
|
|
|
const hero = document.querySelector(".hero-carousel");
|
|
if (!hero) {
|
|
return;
|
|
}
|
|
|
|
const slides = Array.from(hero.querySelectorAll("[data-hero-slide]"));
|
|
const prevButton = hero.querySelector("[data-hero-prev]");
|
|
const nextButton = hero.querySelector("[data-hero-next]");
|
|
const dotsContainer = hero.querySelector("[data-hero-dots]");
|
|
|
|
if (!slides.length || !prevButton || !nextButton || !dotsContainer) {
|
|
return;
|
|
}
|
|
|
|
let currentIndex = Math.max(
|
|
0,
|
|
slides.findIndex((slide) => slide.classList.contains("is-active"))
|
|
);
|
|
let autoRotateTimer = null;
|
|
const rotateDelay = 5500;
|
|
const abortController = new AbortController();
|
|
const { signal } = abortController;
|
|
|
|
const dots = slides.map((_, index) => {
|
|
const dot = document.createElement("button");
|
|
dot.type = "button";
|
|
dot.className = "hero-dot";
|
|
dot.setAttribute("role", "tab");
|
|
dot.setAttribute("aria-label", `Aller a l'image ${index + 1}`);
|
|
dot.dataset.index = index.toString();
|
|
dotsContainer.appendChild(dot);
|
|
return dot;
|
|
});
|
|
|
|
function updateUI() {
|
|
slides.forEach((slide, index) => {
|
|
const isActive = index === currentIndex;
|
|
slide.classList.toggle("is-active", isActive);
|
|
slide.setAttribute("aria-hidden", String(!isActive));
|
|
});
|
|
|
|
dots.forEach((dot, index) => {
|
|
const isActive = index === currentIndex;
|
|
dot.classList.toggle("is-active", isActive);
|
|
dot.setAttribute("aria-selected", String(isActive));
|
|
dot.tabIndex = isActive ? 0 : -1;
|
|
});
|
|
}
|
|
|
|
function goTo(index) {
|
|
if (index < 0) {
|
|
currentIndex = slides.length - 1;
|
|
} else if (index >= slides.length) {
|
|
currentIndex = 0;
|
|
} else {
|
|
currentIndex = index;
|
|
}
|
|
updateUI();
|
|
}
|
|
|
|
function stopAutoRotate() {
|
|
if (autoRotateTimer !== null) {
|
|
window.clearInterval(autoRotateTimer);
|
|
autoRotateTimer = null;
|
|
}
|
|
}
|
|
|
|
function startAutoRotate() {
|
|
stopAutoRotate();
|
|
autoRotateTimer = window.setInterval(() => {
|
|
goTo(currentIndex + 1);
|
|
}, rotateDelay);
|
|
}
|
|
|
|
prevButton.addEventListener(
|
|
"click",
|
|
() => {
|
|
goTo(currentIndex - 1);
|
|
startAutoRotate();
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
nextButton.addEventListener(
|
|
"click",
|
|
() => {
|
|
goTo(currentIndex + 1);
|
|
startAutoRotate();
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
dotsContainer.addEventListener(
|
|
"click",
|
|
(event) => {
|
|
const button = event.target.closest(".hero-dot");
|
|
if (!button) {
|
|
return;
|
|
}
|
|
|
|
const targetIndex = Number.parseInt(button.dataset.index || "0", 10);
|
|
goTo(targetIndex);
|
|
startAutoRotate();
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
hero.addEventListener(
|
|
"mouseenter",
|
|
() => {
|
|
stopAutoRotate();
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
hero.addEventListener(
|
|
"mouseleave",
|
|
() => {
|
|
startAutoRotate();
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
document.addEventListener(
|
|
"visibilitychange",
|
|
() => {
|
|
if (document.hidden) {
|
|
stopAutoRotate();
|
|
} else {
|
|
startAutoRotate();
|
|
}
|
|
},
|
|
{ signal }
|
|
);
|
|
|
|
updateUI();
|
|
startAutoRotate();
|
|
|
|
window.__heroCarouselCleanup = () => {
|
|
stopAutoRotate();
|
|
abortController.abort();
|
|
};
|
|
|
|
document.addEventListener("page:before-route-change", window.__heroCarouselCleanup, {
|
|
once: true,
|
|
});
|
|
})();
|