diff --git a/blocks/video/video.css b/blocks/video/video.css index da920429..7040658c 100644 --- a/blocks/video/video.css +++ b/blocks/video/video.css @@ -1,11 +1,10 @@ .video { - width: unset; text-align: center; max-width: 800px; margin: 32px auto; } -.video.lazy-loading { +.video[data-embed-is-loaded="false"]:not(.placeholder) { /* reserve an approximate space to avoid extensive layout shifts */ aspect-ratio: 16 / 9; } @@ -31,6 +30,11 @@ position: relative; } +.video[data-embed-is-loaded="true"] .video-placeholder { + visibility: hidden; + height: 0; +} + .video .video-placeholder > * { display: flex; align-items: center; diff --git a/blocks/video/video.js b/blocks/video/video.js index c9784d42..6fb36f48 100644 --- a/blocks/video/video.js +++ b/blocks/video/video.js @@ -4,17 +4,17 @@ * https://www.hlx.live/developer/block-collection/video */ -function embedYoutube(url, replacePlaceholder, autoplay) { +function embedYoutube(url, autoplay, background) { const usp = new URLSearchParams(url.search); let suffix = ''; - if (replacePlaceholder || autoplay) { + if (background || autoplay) { const suffixParams = { - autoplay: '1', - mute: autoplay ? '1' : '0', - controls: autoplay ? '0' : '1', - disablekb: autoplay ? '1' : '0', - loop: autoplay ? '1' : '0', - playsinline: autoplay ? '1' : '0', + autoplay: autoplay ? '1' : '0', + mute: background ? '1' : '0', + controls: background ? '0' : '1', + disablekb: background ? '1' : '0', + loop: background ? '1' : '0', + playsinline: background ? '1' : '0', }; suffix = `&${Object.entries(suffixParams).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')}`; } @@ -32,13 +32,13 @@ function embedYoutube(url, replacePlaceholder, autoplay) { return temp.children.item(0); } -function embedVimeo(url, replacePlaceholder, autoplay) { +function embedVimeo(url, autoplay, background) { const [, video] = url.pathname.split('/'); let suffix = ''; - if (replacePlaceholder || autoplay) { + if (background || autoplay) { const suffixParams = { - autoplay: '1', - background: autoplay ? '1' : '0', + autoplay: autoplay ? '1' : '0', + background: background ? '1' : '0', }; suffix = `?${Object.entries(suffixParams).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')}`; } @@ -52,14 +52,13 @@ function embedVimeo(url, replacePlaceholder, autoplay) { return temp.children.item(0); } -function getVideoElement(source, replacePlaceholder, autoplay) { +function getVideoElement(source, autoplay, background) { const video = document.createElement('video'); video.setAttribute('controls', ''); video.dataset.loading = 'true'; video.addEventListener('loadedmetadata', () => delete video.dataset.loading); - if (autoplay || replacePlaceholder) { - video.setAttribute('autoplay', ''); - if (autoplay) { + if (autoplay) video.setAttribute('autoplay', ''); + if (background) { video.setAttribute('loop', ''); video.setAttribute('playsinline', ''); video.removeAttribute('controls'); @@ -67,7 +66,6 @@ function getVideoElement(source, replacePlaceholder, autoplay) { video.muted = true; video.play(); }); - } } const sourceEl = document.createElement('source'); @@ -78,50 +76,59 @@ function getVideoElement(source, replacePlaceholder, autoplay) { return video; } -const loadVideoEmbed = (block, link, replacePlaceholder, autoplay) => { - if (block.dataset.embedIsLoaded) { + +const loadVideoEmbed = (block, link, autoplay, background) => { + if (block.dataset.embedIsLoaded === 'true') { return; } const url = new URL(link); const isYoutube = link.includes('youtube') || link.includes('youtu.be'); const isVimeo = link.includes('vimeo'); - const isMp4 = link.includes('.mp4'); - let embedEl; if (isYoutube) { - embedEl = embedYoutube(url, replacePlaceholder, autoplay); + block.append(embedYoutube(url, autoplay, background)); + block.dataset.embedIsLoaded = true; } else if (isVimeo) { - embedEl = embedVimeo(url, replacePlaceholder, autoplay); - } else if (isMp4) { - embedEl = getVideoElement(link, replacePlaceholder, autoplay); + block.append(embedVimeo(url, autoplay, background)); + block.dataset.embedIsLoaded = true; + } else { + const videoEl = getVideoElement(link, autoplay, background); + block.append(videoEl); + videoEl.addEventListener('canplay', () => { + block.dataset.embedIsLoaded = true; + }); } - block.replaceChildren(embedEl); - - block.dataset.embedIsLoaded = true; }; export default async function decorate(block) { const placeholder = block.querySelector('picture'); const link = block.querySelector('a').href; block.textContent = ''; + block.dataset.embedIsLoaded = false; - if (placeholder) { + const autoplay = block.classList.contains('autoplay'); + if (!!placeholder) { + block.classList.add('placeholder'); const wrapper = document.createElement('div'); wrapper.className = 'video-placeholder'; - wrapper.innerHTML = '
'; - wrapper.prepend(placeholder); - wrapper.addEventListener('click', () => { - loadVideoEmbed(block, link, true, false); - }); + wrapper.append(placeholder); + + if (!autoplay) { + wrapper.insertAdjacentHTML('beforeend', + '
'); + wrapper.addEventListener('click', () => { + loadVideoEmbed(block, link, true, false); + }); + } block.append(wrapper); - } else { - block.classList.add('lazy-loading'); + } + + if (!placeholder || (autoplay)) { const observer = new IntersectionObserver((entries) => { if (entries.some((e) => e.isIntersecting)) { observer.disconnect(); - loadVideoEmbed(block, link, false, block.classList.contains('autoplay')); - block.classList.remove('lazy-loading'); + loadVideoEmbed(block, link, !!placeholder || autoplay, autoplay); } }); observer.observe(block);