(function(){
const ORIGIN = location.origin;
// Patch origin param for YouTube embeds (it helps when enablejsapi=1)
document.querySelectorAll('.js-player[data-type="youtube"]').forEach(el=>{
try{
const u = new URL(el.dataset.src);
u.searchParams.set('origin', ORIGIN);
el.dataset.src = u.toString();
}catch(e){}
});
function postToYouTube(iframe, func, args){
if(!iframe || !iframe.contentWindow) return;
iframe.contentWindow.postMessage(JSON.stringify({event:'command',func:func,args:args||[]}), '*');
}
function postToVimeo(iframe, method, value){
if(!iframe || !iframe.contentWindow) return;
iframe.contentWindow.postMessage({method, value}, '*');
}
function ensureIframe(el){
const frame = el.querySelector('.frame');
if(!frame) return null;
let iframe = frame.querySelector('iframe');
if(iframe) return iframe;
iframe = document.createElement('iframe');
iframe.allow = 'autoplay; fullscreen; picture-in-picture';
iframe.setAttribute('allowfullscreen','');
iframe.setAttribute('playsinline','');
iframe.src = el.dataset.src || '';
iframe.id = 'scalePlayer';
frame.appendChild(iframe);
const poster = frame.querySelector('.poster');
if(poster) poster.style.display='none';
const ctp = frame.querySelector('.clickToPlay');
if(ctp) ctp.style.display='none';
// Make 16:9 iframe cover 2.35 container (uniform scale, then crop).
function cover(){
const r = frame.getBoundingClientRect();
// target a 16:9 box inside frame for scaling reference
const iw = r.width;
const ih = r.width * 9/16;
const scale = Math.max(1, r.height / ih);
iframe.style.width = iw + 'px';
iframe.style.height = ih + 'px';
iframe.style.transform = 'translate(-50%,-50%) scale(' + scale + ')';
}
cover();
window.addEventListener('resize', cover, {passive:true});
setTimeout(cover, 250);
iframe.addEventListener('load', ()=>{ iframe.classList.add('ready'); setTimeout(cover, 50); });
return iframe;
}
function currentType(el){ return (el && el.dataset && el.dataset.type) || 'none'; }
document.addEventListener('click', (e)=>{
const playClick = e.target.closest('.clickToPlay');
if(playClick){
const el = playClick.closest('.js-player');
if(!el) return;
const iframe = ensureIframe(el);
const t = currentType(el);
if(t === 'youtube') postToYouTube(iframe, 'playVideo');
if(t === 'vimeo') postToVimeo(iframe, 'play');
}
const btn = e.target.closest('.ctl');
if(!btn) return;
const el = btn.closest('.js-player');
if(!el) return;
const act = btn.getAttribute('data-act');
const iframe = ensureIframe(el);
const t = currentType(el);
if(act === 'toggle'){
const playing = el.getAttribute('data-playing') === '1';
if(t === 'youtube'){
postToYouTube(iframe, playing ? 'pauseVideo' : 'playVideo');
}
if(t === 'vimeo'){
postToVimeo(iframe, playing ? 'pause' : 'play');
}
el.setAttribute('data-playing', playing ? '0' : '1');
}
if(act === 'rew'){
if(t === 'youtube'){
const cur = (el.__yt && typeof el.__yt.currentTime === 'number') ? el.__yt.currentTime : 0;
postToYouTube(iframe,'seekTo',[Math.max(0, cur - 10), true]);
}
if(t === 'vimeo'){
postToVimeo(iframe,'getCurrentTime');
el.__vmSeekDir = -1;
}
}
if(act === 'ff'){
if(t === 'youtube'){
const cur = (el.__yt && typeof el.__yt.currentTime === 'number') ? el.__yt.currentTime : 0;
postToYouTube(iframe,'seekTo',[Math.max(0, cur + 10), true]);
}
if(t === 'vimeo'){
postToVimeo(iframe,'getCurrentTime');
el.__vmSeekDir = +1;
}
}
if(act === 'fs'){ if(act === 'fs'){
const f = el.querySelector('iframe');
if(f && f.requestFullscreen) f.requestFullscreen();
}
});
// Seek helpers: we request current time, then set.
window.addEventListener('message', (ev)=>{
const data = ev.data;
// YouTube infoDelivery messages arrive as strings (JSON)
if(typeof data === 'string' && data.indexOf('infoDelivery') !== -1){
try{
const obj = JSON.parse(data);
if(obj && obj.event === 'infoDelivery' && obj.info){
const iframe = document.getElementById('scalePlayer');
// best-effort: attach to the nearest player
const el = iframe ? iframe.closest('.js-player') : null;
if(el){
el.__yt = el.__yt || {};
if(typeof obj.info.currentTime === 'number') el.__yt.currentTime = obj.info.currentTime;
if(typeof obj.info.playerState === 'number') el.__yt.playerState = obj.info.playerState; // 1=playing
el.setAttribute('data-playing', (el.__yt.playerState === 1) ? '1' : (el.getAttribute('data-playing')||'0'));
}
}
}catch(e){}
}
// Vimeo responses are objects
if(data && typeof data === 'object' && data.method === 'getCurrentTime' && typeof data.value === 'number'){
const iframe = document.getElementById('scalePlayer');
const el = iframe ? iframe.closest('.js-player') : null;
if(el){
const dir = el.__vmSeekDir || 0;
const next = Math.max(0, data.value + dir * 10);
postToVimeo(iframe, 'setCurrentTime', next);
el.__vmSeekDir = 0;
el.setAttribute('data-playing','1');
}
}
});
// Volume
document.querySelectorAll('.volR').forEach(r=>{
r.addEventListener('input', ()=>{
const el = r.closest('.js-player');
const iframe = ensureIframe(el);
const t = currentType(el);
const v = parseInt(r.value || '0',10);
if(t === 'youtube') postToYouTube(iframe,'setVolume',[v]);
if(t === 'vimeo') postToVimeo(iframe,'setVolume', Math.max(0, Math.min(1, v/100)));
}, {passive:true});
});
// Share link (copy)
document.querySelectorAll('[data-act="share"]').forEach(a=>{
a.addEventListener('click', async (e)=>{
e.preventDefault();
try{
await navigator.clipboard.writeText(location.href);
a.style.opacity = '1';
}catch(err){
// fallback
prompt('Copy link:', location.href);
}
});
});
// Photo gallery lightbox (if present)
const masonry = document.getElementById('masonry');
const lb = document.getElementById('lb');
const lbImg = document.getElementById('lbImg');
const lbX = document.getElementById('lbX');
const lbPrev = document.getElementById('lbPrev');
const lbNext = document.getElementById('lbNext');
if (masonry && lb && lbImg) {
const buttons = Array.from(masonry.querySelectorAll('[data-idx]'));
const urls = buttons.map(b => (b.querySelector('img') ? b.querySelector('img').getAttribute('src') : '')).filter(Boolean);
let idx = 0;
function openAt(i){
idx = Math.max(0, Math.min(urls.length - 1, i));
lbImg.src = urls[idx] || '';
lb.classList.add('open');
lb.setAttribute('aria-hidden', 'false');
}
function closeLb(){
lb.classList.remove('open');
lb.setAttribute('aria-hidden', 'true');
}
function next(){ openAt((idx + 1) % urls.length); }
function prev(){ openAt((idx - 1 + urls.length) % urls.length); }
masonry.addEventListener('click', (e) => {
const b = e.target && e.target.closest ? e.target.closest('[data-idx]') : null;
if (!b) return;
const i = parseInt(b.getAttribute('data-idx') || '0', 10) || 0;
openAt(i);
});
lbX && (lbX.onclick = closeLb);
lbPrev && (lbPrev.onclick = prev);
lbNext && (lbNext.onclick = next);
lb.addEventListener('click', (e) => { if (e.target === lb) closeLb(); });
document.addEventListener('keydown', (e) => {
if (!urls.length) return;
const isOpen = lb.classList.contains('open');
if (e.key === ' ' || e.code === 'Space') {
e.preventDefault();
if (isOpen) closeLb(); else openAt(0);
return;
}
if (!isOpen) return;
if (e.key === 'Escape') { closeLb(); return; }
if (e.key === 'ArrowRight') { next(); return; }
if (e.key === 'ArrowLeft') { prev(); return; }
});
}
})();