document.addEventListener('DOMContentLoaded', () => { const mql = window.matchMedia('(max-width: 479px) and (orientation: portrait)'); const isMobilePortrait = () => mql.matches; const galleries = Array.from(document.querySelectorAll('[data-gallery]')); const instances = []; function createGalleryInstance(rootEl, galleryIdx) { const prevBtn = rootEl.querySelector('.mixed-arrow-prev'); const nextBtn = rootEl.querySelector('.mixed-arrow-next'); const sliderEl = rootEl.querySelector('.mixed_slider-wrapper.swiper'); const slideEls = Array.from(rootEl.querySelectorAll('.mixed_slider-item.swiper-slide')); function resetSlideUI(slide) { const inner = slide?.querySelector('.slide-inner'); const video = slide?.querySelector('video'); const btn = slide?.querySelector('.video-play'); if (!video || !inner || !btn) return; inner.classList.remove('playing'); video.controls = false; btn.classList.remove('is-hidden'); btn.setAttribute('aria-hidden', 'false'); } function pauseAllExcept(index) { slideEls.forEach((s, i) => { const v = s.querySelector('video'); if (!v) return; if (typeof index === 'number' && index >= 0 && i === index) return; try { v.pause(); if (typeof index === 'number' && index >= 0) v.currentTime = 0; } catch(e) {} resetSlideUI(s); }); } function playVideo(slide, btnEl) { const inner = slide?.querySelector('.slide-inner'); const video = slide?.querySelector('video'); if (!video || !inner) return; const idx = slideEls.indexOf(slide); if (idx >= 0) pauseAllExcept(idx); inner.classList.add('playing'); video.controls = true; try { video.play(); } catch(e) {} const btn = btnEl || slide.querySelector('.video-play'); if (btn) { btn.classList.add('is-hidden'); btn.setAttribute('aria-hidden', 'true'); } video.focus?.({ preventScroll: true }); if (!video.dataset.uiHandlers) { const resetUI = () => resetSlideUI(slide); video.addEventListener('pause', resetUI); video.addEventListener('ended', resetUI); video.dataset.uiHandlers = '1'; } } // a11y wire-up per gallery with unique ids slideEls.forEach((s, i) => { const v = s.querySelector('video'); const b = s.querySelector('.video-play'); if (v && b) { if (!v.id) v.id = `video-g${galleryIdx + 1}-${i + 1}`; b.setAttribute('aria-controls', v.id); } }); function attachPlayHandlers() { rootEl.querySelectorAll('.video-play').forEach((btn) => { btn.addEventListener('click', (e) => { const slide = e.currentTarget.closest('.mixed_slider-item.swiper-slide'); playVideo(slide, btn); }); }); } let swiper; let currentMode = isMobilePortrait() ? 'mobile' : 'desktop'; function initSwiper(initialSlide = 0) { swiper = new Swiper(sliderEl, { loop: false, slidesPerView: 1, centeredSlides: true, effect: isMobilePortrait() ? 'slide' : 'cards', grabCursor: true, keyboard: { enabled: false, onlyInViewport: true }, initialSlide, breakpoints: { 0: { spaceBetween: 16 }, 480: { spaceBetween: 0 } }, cardsEffect: { perSlideOffset: 1, perSlideRotate: 1, rotate: true, slideShadows: false }, on: { setTranslate(sw) { sw.slides.forEach((slide) => { slide.style.transform = slide.style.transform.replace( /translate3d\(([^,]+),\s*([^,]+),\s*[^)]+\)/, 'translate3d($1, $2, 0px)' ); }); }, transitionStart() { pauseAllExcept(swiper.activeIndex); }, }, }); // Enable keyboard only when gallery is hovered or focused const setKb = (on) => { if (!swiper?.keyboard) return; on ? swiper.keyboard.enable() : swiper.keyboard.disable(); }; rootEl.addEventListener('mouseenter', () => setKb(true)); rootEl.addEventListener('mouseleave', () => setKb(false)); rootEl.addEventListener('focusin', () => setKb(true)); rootEl.addEventListener('focusout', () => setTimeout(() => { if (!rootEl.contains(document.activeElement)) setKb(false); }, 0)); return swiper; } function maybeReinitSwiper() { const desiredMode = isMobilePortrait() ? 'mobile' : 'desktop'; if (desiredMode !== currentMode) { const prevIndex = swiper?.activeIndex ?? 0; try { swiper?.destroy(true, true); } catch(e) {} swiper = undefined; currentMode = desiredMode; initSwiper(prevIndex); pauseAllExcept(swiper.activeIndex); } } function fallbackInit() { let active = 0; function render() { slideEls.forEach((s, i) => { if (i === active) s.classList.remove('is-hidden'); else s.classList.add('is-hidden'); }); pauseAllExcept(active); } prevBtn?.addEventListener('click', () => { active = (active - 1 + slideEls.length) % slideEls.length; render(); }); nextBtn?.addEventListener('click', () => { active = (active + 1) % slideEls.length; render(); }); attachPlayHandlers(); render(); } if (typeof window.Swiper !== 'function') { fallbackInit(); return { maybeReinit: () => {}, pauseAll: () => pauseAllExcept(-1) }; } initSwiper(); prevBtn?.addEventListener('click', () => swiper.slidePrev()); nextBtn?.addEventListener('click', () => swiper.slideNext()); attachPlayHandlers(); return { maybeReinit: () => maybeReinitSwiper(), pauseAll: () => pauseAllExcept(-1), }; } // create instances for all galleries galleries.forEach((g, i) => { instances.push(createGalleryInstance(g, i)); }); // global visibility pause document.addEventListener('visibilitychange', () => { if (document.hidden) instances.forEach(inst => inst.pauseAll()); }); // one media listener to re-init all when crossing threshold const onMedia = () => { instances.forEach(inst => inst.maybeReinit()); }; if (typeof mql.addEventListener === 'function') mql.addEventListener('change', onMedia); else if (typeof mql.addListener === 'function') mql.addListener(onMedia); });