feat: ✨ handle video on slider
This commit is contained in:
parent
12f22bf593
commit
55e51ca304
1 changed files with 104 additions and 18 deletions
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue