Skip to content

Commit

Permalink
MWPW-137938 - Inline video image fallback (#1542)
Browse files Browse the repository at this point in the history
* Summarize changes in 50 characters or less

More detailed explanatory text. Wrap at 72 characters.

Resolves: MWPW-xxxx
See also: MWPW-xxxx, MWPW-xxxx

* Adding unit test. Addressing PR feedback.

---------

Co-authored-by: Ryan Clayton <rclayton@adobe.com>
Co-authored-by: Blaine Gunn <Blainegunn@gmail.com>
  • Loading branch information
3 people authored Jan 2, 2024
1 parent 45a3a38 commit b42c800
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 33 deletions.
55 changes: 36 additions & 19 deletions libs/blocks/figure/figure.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,47 @@ function buildCaption(pEl) {
return figCaptionEl;
}

function htmlToElement(html) {
const template = document.createElement('template');
const convertHtml = html.trim();
template.innerHTML = convertHtml;
return template.content.firstChild;
}

function decorateVideo(clone, figEl) {
let video = clone.querySelector('video');
const videoLink = clone.querySelector('a[href*=".mp4"]');
if (videoLink) {
const { href, hash, dataset } = videoLink;
const attrs = getVideoAttrs(hash, dataset);
const videoElem = `<video ${attrs}>
<source src="${href}" type="video/mp4" />
</video>`;

videoLink.insertAdjacentHTML('afterend', videoElem);
videoLink.remove();
video = clone.querySelector('video');
}
if (video) {
video.removeAttribute('data-mouseevent');
applyHoverPlay(video);
figEl.prepend(video);
}
}

export function buildFigure(blockEl) {
const figEl = document.createElement('figure');
figEl.classList.add('figure');
Array.from(blockEl.children).forEach((child) => {
const clone = child.cloneNode(true);
// picture, video, or embed link is NOT wrapped in P tag
if (clone.nodeName === 'PICTURE' || clone.nodeName === 'VIDEO' || clone.nodeName === 'A'
|| (clone.nodeName === 'SPAN' && clone.classList.contains('modal-img-link'))) {
const tags = ['PICTURE', 'VIDEO', 'A'];
if (tags.includes(clone.nodeName) || (clone.nodeName === 'SPAN' && clone.classList.contains('modal-img-link'))) {
if (clone.href?.includes('.mp4')) {
const videoPlaceholderLink = `<p>${clone.outerHTML}</p>`;
const videoLink = htmlToElement(videoPlaceholderLink);
decorateVideo(videoLink, figEl);
}
figEl.prepend(clone);
} else {
// content wrapped in P tag(s)
Expand All @@ -26,23 +59,7 @@ export function buildFigure(blockEl) {
if (picture) {
figEl.prepend(picture);
}
let video = clone.querySelector('video');
const videoLink = clone.querySelector('a[href*=".mp4"]');
if (videoLink) {
const { href, hash } = videoLink;
const attrs = getVideoAttrs(hash);
const videoElem = `<video ${attrs}>
<source src="${href}" type="video/mp4" />
</video>`;
videoLink.insertAdjacentHTML('afterend', videoElem);
videoLink.remove();
video = clone.querySelector('video');
}
if (video) {
video.removeAttribute('data-mouseevent');
applyHoverPlay(video);
figEl.prepend(video);
}
decorateVideo(clone, figEl);
const caption = clone.querySelector('em');
if (caption) {
const figElCaption = buildCaption(caption);
Expand Down
4 changes: 2 additions & 2 deletions libs/blocks/media/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ export default function init(el) {
}
const image = row.querySelector(':scope > div:not([class])');
if (image) image.classList.add('image');
const img = image.querySelector(':scope img');
const img = image?.querySelector(':scope img');
if (header && img?.alt === '') img.alt = header.textContent;
const imageVideo = image.querySelector('video');
const imageVideo = image?.querySelector('video');
if (imageVideo) applyHoverPlay(imageVideo);

// subcopy
Expand Down
4 changes: 2 additions & 2 deletions libs/blocks/video/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { applyHoverPlay, getVideoAttrs } from '../../utils/decorate.js';
const ROOT_MARGIN = 1000;

const loadVideo = (a) => {
const { pathname, hash } = a;
const { pathname, hash, dataset } = a;
let videoPath = `.${pathname}`;
if (pathname.match('media_.*.mp4')) {
const { codeRoot } = getConfig();
Expand All @@ -15,7 +15,7 @@ const loadVideo = (a) => {
videoPath = `${root}${mediaFilename}`;
}

const attrs = getVideoAttrs(hash);
const attrs = getVideoAttrs(hash, dataset);
const video = `<video ${attrs}>
<source src="${videoPath}" type="video/mp4" />
</video>`;
Expand Down
14 changes: 9 additions & 5 deletions libs/utils/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,20 +168,24 @@ export function decorateTextOverrides(el, options = ['-heading', '-body', '-deta
});
}

export function getVideoAttrs(hash) {
export function getVideoAttrs(hash, dataset) {
const isAutoplay = hash?.includes('autoplay');
const isAutoplayOnce = hash?.includes('autoplay1');
const playOnHover = hash?.includes('hoverplay');
const poster = dataset?.videoPoster ? `poster='${dataset.videoPoster}'` : '';
const globalAttrs = `playsinline ${poster}`;
const autoPlayAttrs = 'autoplay muted';

if (isAutoplay && !isAutoplayOnce) {
return 'playsinline autoplay loop muted';
return `${globalAttrs} ${autoPlayAttrs} loop`;
}
if (playOnHover && isAutoplayOnce) {
return 'playsinline autoplay muted data-hoverplay';
return `${globalAttrs} ${autoPlayAttrs} data-hoverplay`;
}
if (isAutoplayOnce) {
return 'playsinline autoplay muted';
return `${globalAttrs} ${autoPlayAttrs}`;
}
return 'playsinline controls';
return `${globalAttrs} controls`;
}

export function applyHoverPlay(video) {
Expand Down
16 changes: 11 additions & 5 deletions libs/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,12 +523,18 @@ export function decorateImageLinks(el) {
if (alt?.trim().length) img.alt = alt.trim();
const pic = img.closest('picture');
const picParent = pic.parentElement;
const aTag = createTag('a', { href, class: 'image-link' });
picParent.insertBefore(aTag, pic);
if (icon) {
import('./image-video-link.js').then((mod) => mod.default(picParent, aTag, icon));
if (href.includes('.mp4')) {
const a = createTag('a', { href: url, 'data-video-poster': img.src });
a.innerHTML = url;
pic.replaceWith(a);
} else {
aTag.append(pic);
const aTag = createTag('a', { href, class: 'image-link' });
picParent.insertBefore(aTag, pic);
if (icon) {
import('./image-video-link.js').then((mod) => mod.default(picParent, aTag, icon));
} else {
aTag.append(pic);
}
}
} catch (e) {
console.log('Error:', `${e.message} '${source.trim()}'`);
Expand Down
7 changes: 7 additions & 0 deletions test/blocks/figure/figure.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,11 @@ describe('init', () => {
init(blockEl);
expect(sections[4].querySelector('span.modal-img-link')).to.exist;
});

it('anchor tag should end in .mp4 and have videoPoster data attribute', () => {
const blockEl = sections[5].querySelector('.figure');
init(blockEl);
expect(sections[5].querySelector('.figure a[href*=".mp4"]')).to.exist;
expect(sections[5].querySelector('.figure a').hasAttribute('videoPoster')).to.exist;
});
});
11 changes: 11 additions & 0 deletions test/blocks/figure/mocks/body.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,15 @@
</div>
</div>
</div>
<!-- #5 -->
<div class="section">
<div class="figure">
<!-- video poster link -->
<div>
<div>
<a href="link-to-video.mp4" data-video-poster="link-to-poster-image" class="video link-block hide-video">https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4</a>
</div>
</div>
</div>
</div>
</main>

0 comments on commit b42c800

Please sign in to comment.