feat: ✨ handle video on slider

This commit is contained in:
Abdel LAMRANI 2026-10-13 16:11:26 +02:00
parent 12f22bf593
commit 55e51ca304

View file

@ -14,11 +14,38 @@ document.addEventListener("DOMContentLoaded", function () {
return;
}
// Add enablejsapi=1 to YouTube iframes (inserted later by the cookie script) so they can be paused
const storyRoot = document.querySelector("#story-historical-milestones") as HTMLElement;
storyRoot.querySelectorAll<HTMLIFrameElement>("iframe").forEach(enableYoutubeApi);
new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.target instanceof HTMLIFrameElement) {
enableYoutubeApi(mutation.target); // src changed
}
mutation.addedNodes.forEach(node => {
if (node instanceof HTMLIFrameElement) enableYoutubeApi(node);
else if (node instanceof Element) node.querySelectorAll("iframe").forEach(enableYoutubeApi);
});
});
}).observe(storyRoot, { childList: true, subtree: true, attributes: true, attributeFilter: ["src"] });
const swiperNodeMobile = document.querySelectorAll(".story-mobile-content-wrapper") as NodeListOf<HTMLDivElement>;
const swiperYearsNode = document.querySelector("#swiper-historicalmilestone-years") as unknown as SwiperType;
const swiperYearsBtns = document.querySelectorAll("#swiper-historicalmilestone-years .btn") as NodeListOf<HTMLButtonElement>;
let isChangingSlide = false; // Flag to avoid conflict between onClick and onScroll actions on mobile.
let isPausedByVideo = false; // Autoplay paused because the user started a video
// MOBILE: pause videos when they leave the screen
const videoObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio < 0.25) pauseVideos(entry.target);
});
}, { threshold: [0, 0.25] });
document.querySelectorAll("#story-mobile .video-inlaid").forEach(video => videoObserver.observe(video));
// MOBILE on click navigation (arrows)
setTimeout(() => {
if (swiperNodeMobile && swiperYearsNode) {
@ -70,12 +97,47 @@ document.addEventListener("DOMContentLoaded", function () {
// DESKTOP.
setTimeout(() => {
const swiperNodeDesktop = document.querySelector("#swiper-historicalmilestone-desktop") as unknown as SwiperType;
swiperNodeDesktop.swiper.on("slideChange", function () {
swiperYearsNode.swiper.slideTo(swiperNodeDesktop.swiper.activeIndex);
const swiper = swiperNodeDesktop.swiper;
swiper.on("slideChange", function () {
// Sync the years slider
swiperYearsNode.swiper.slideTo(swiper.activeIndex);
// Pause the video of the slide we are leaving
const previousSlide = swiper.slides[swiper.previousIndex];
if (previousSlide) pauseVideos(previousSlide);
// The video was the reason of the pause → resume the autoplay
if (isPausedByVideo) {
isPausedByVideo = false;
swiper.autoplay.resume();
}
updatePlayPauseIcon(swiper);
// Give the focus back to the page, so the next click in a video triggers "blur" again
const active = document.activeElement;
if (active instanceof HTMLIFrameElement) {
active.blur();
window.focus();
}
});
// The user starts a video → pause the autoplay so the slider doesn't move away
window.addEventListener("blur", () => {
const active = document.activeElement;
if (active?.tagName === "IFRAME" && swiper.el.contains(active) && !swiper.autoplay.paused) {
isPausedByVideo = true;
swiper.autoplay.pause();
updatePlayPauseIcon(swiper);
}
});
// Keep the play/pause icon in sync with the autoplay state
swiper.on("transitionEnd", function () {
updatePlayPauseIcon(swiper);
});
swiperYearsNode.swiper.on("slideChange", function () {
swiperNodeDesktop.swiper.slideTo(swiperYearsNode.swiper.activeIndex);
swiper.slideTo(swiperYearsNode.swiper.activeIndex);
});
swiperYearsBtns.forEach((swiperYearsBtn, swiperYearsIndex) => {
@ -86,24 +148,48 @@ document.addEventListener("DOMContentLoaded", function () {
const btnPlayPause = document.querySelector("#story-historical-milestones-years .swiper-pagination-playpause");
btnPlayPause?.addEventListener("click", function () {
eventBtnPlayPause(swiperNodeDesktop.swiper, document.querySelector("#story-historical-milestones-years .swiper-pagination-playpause"));
});
swiperNodeDesktop.swiper.on("transitionEnd", function() {
const svgs = document.querySelector("#story-historical-milestones-years .swiper-pagination-playpause")?.querySelectorAll("svg");
if (svgs) {
svgs[0].classList.remove("d-none");
svgs[1].classList.add("d-none");
}
eventBtnPlayPause(swiper);
});
}, 10);
function eventBtnPlayPause(swiper: Swiper, btnPlayPause: HTMLElement|null) {
const svgs = btnPlayPause?.querySelectorAll("svg");
svgs?.forEach(svg => {
svg.classList.toggle("d-none");
function eventBtnPlayPause(swiper: Swiper) {
isPausedByVideo = false;
if (swiper.autoplay.paused) swiper.autoplay.resume();
else swiper.autoplay.pause();
updatePlayPauseIcon(swiper);
}
//Shows the right icon on the play/pause button
function updatePlayPauseIcon(swiper: Swiper): void {
const svgs = document.querySelector("#story-historical-milestones-years .swiper-pagination-playpause")?.querySelectorAll("svg");
if (!svgs) return;
svgs[0].classList.toggle("d-none", swiper.autoplay.paused);
svgs[1].classList.toggle("d-none", !swiper.autoplay.paused);
}
// Pauses every YouTube/Vimeo video inside the given element
function pauseVideos(container: Element): void {
container.querySelectorAll<HTMLIFrameElement>("iframe").forEach(iframe => {
if (/youtube(-nocookie)?\.com/.test(iframe.src)) {
iframe.contentWindow?.postMessage(
JSON.stringify({ event: "command", func: "pauseVideo", args: [] }),
"*"
);
} else if (iframe.src.includes("vimeo.com")) {
iframe.contentWindow?.postMessage(JSON.stringify({ method: "pause" }), "*");
}
});
if (swiper?.autoplay.paused)
swiper?.autoplay.start();
else swiper?.autoplay.pause();
}
// Adds enablejsapi to a YouTube iframe so it accepts the pause command.
function enableYoutubeApi(iframe: HTMLIFrameElement): void {
if (!/youtube(-nocookie)?\.com/.test(iframe.src) || iframe.src.includes("enablejsapi=1")) return;
const url = new URL(iframe.src);
url.searchParams.set("enablejsapi", "1");
iframe.src = url.toString();
}
});