(function () { 'use strict'; var overlay = null; var content = null; var closeBtn = null; var lastFocus = null; var isOpen = false; var currentMedia = null; function dispatch(name) { document.dispatchEvent(new CustomEvent(name, { bubbles: true })); } function ensureDom() { if (overlay) return; overlay = document.createElement('div'); overlay.className = 'lb'; overlay.setAttribute('role', 'dialog'); overlay.setAttribute('aria-modal', 'true'); overlay.setAttribute('aria-label', 'プレビュー'); overlay.hidden = true; closeBtn = document.createElement('button'); closeBtn.type = 'button'; closeBtn.className = 'lb__close'; closeBtn.setAttribute('aria-label', '閉じる'); closeBtn.innerHTML = '×'; content = document.createElement('div'); content.className = 'lb__content'; overlay.appendChild(closeBtn); overlay.appendChild(content); document.body.appendChild(overlay); overlay.addEventListener('click', function (e) { if (e.target === overlay || e.target === content) { close(); } }); closeBtn.addEventListener('click', close); } function lockScroll(lock) { document.documentElement.classList.toggle('lb-open', lock); document.body.style.overflow = lock ? 'hidden' : ''; } function clearMedia() { if (!content) return; content.innerHTML = ''; currentMedia = null; } function isImageUrl(url) { return /\.(jpe?g|png|gif|webp|avif|svg)(\?|#|$)/i.test(url); } function toYoutubeEmbed(url) { try { var u = new URL(url, location.href); var host = u.hostname.replace(/^www\./, ''); var id = null; if (host === 'youtu.be') { id = u.pathname.replace(/^\//, '').split('/')[0]; } else if (host === 'youtube.com' || host === 'm.youtube.com' || host === 'youtube-nocookie.com') { if (u.pathname.indexOf('/embed/') === 0) { id = u.pathname.split('/')[2]; } else if (u.searchParams.get('v')) { id = u.searchParams.get('v'); } } if (!id) return null; var params = new URLSearchParams(); // 既存クエリから主要パラメータを引き継ぎ ['autoplay', 'mute', 'controls', 'rel', 'playsinline'].forEach(function (key) { if (u.searchParams.has(key)) params.set(key, u.searchParams.get(key)); }); if (!params.has('autoplay')) params.set('autoplay', '1'); if (!params.has('rel')) params.set('rel', '0'); return 'https://www.youtube.com/embed/' + id + '?' + params.toString(); } catch (err) { return null; } } function openImage(src, alt) { var img = document.createElement('img'); img.className = 'lb__img'; img.alt = alt || ''; img.addEventListener('load', function () { img.classList.add('is-ready'); }); img.addEventListener('error', function () { img.classList.add('is-ready'); }); content.appendChild(img); currentMedia = img; requestAnimationFrame(function () { img.src = src; }); } function openIframe(src) { var wrap = document.createElement('div'); wrap.className = 'lb__iframe-wrap'; var iframe = document.createElement('iframe'); iframe.className = 'lb__iframe'; iframe.src = src; iframe.title = '埋め込みコンテンツ'; iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute( 'allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' ); wrap.appendChild(iframe); content.appendChild(wrap); currentMedia = iframe; } function open(src, alt) { ensureDom(); lastFocus = document.activeElement; isOpen = true; clearMedia(); var yt = toYoutubeEmbed(src); if (yt) { content.classList.add('lb__content--video'); openIframe(yt); } else if (isImageUrl(src)) { content.classList.remove('lb__content--video'); openImage(src, alt); } else if (/^https?:/i.test(src)) { content.classList.add('lb__content--video'); openIframe(src); } else { content.classList.remove('lb__content--video'); openImage(src, alt); } overlay.hidden = false; lockScroll(true); closeBtn.focus({ preventScroll: true }); dispatch('lightbox:open'); } function close() { if (!isOpen || !overlay) return; isOpen = false; overlay.hidden = true; clearMedia(); content.classList.remove('lb__content--video'); lockScroll(false); dispatch('lightbox:close'); if (lastFocus && typeof lastFocus.focus === 'function') { lastFocus.focus({ preventScroll: true }); } lastFocus = null; } function onKeydown(e) { if (!isOpen) return; if (e.key === 'Escape') { e.preventDefault(); close(); } } function onClick(e) { var a = e.target.closest('a[data-lightbox], a[data-lity]'); if (!a) return; var href = a.getAttribute('href'); if (!href || href === '#') return; e.preventDefault(); var thumb = a.querySelector('img'); var alt = (thumb && thumb.getAttribute('alt')) || ''; open(href, alt); } document.addEventListener('click', onClick); document.addEventListener('keydown', onKeydown); window.GuririLightbox = { open: open, close: close, isOpen: function () { return isOpen; } }; })();