Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWPW-129910-Play video on hover #1106

Merged
merged 15 commits into from
Aug 16, 2023
8 changes: 6 additions & 2 deletions libs/blocks/aside/aside.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Aside - v5.1
*/

import { decorateBlockBg, decorateBlockText } from '../../utils/decorate.js';
import { decorateBlockBg, decorateBlockText, applyHoverPlay } from '../../utils/decorate.js';
import { createTag } from '../../utils/utils.js';

// standard/default aside uses same text sizes as the split
Expand Down Expand Up @@ -54,7 +54,11 @@ function decorateLayout(el) {
const text = foreground.querySelector('h1, h2, h3, h4, h5, h6, p')?.closest('div');
text?.classList.add('text');
const media = foreground.querySelector(':scope > div:not([class])');
if (!el.classList.contains('notification')) media?.classList.add('image');
if (media && !el.classList.contains('notification')) {
media.classList.add('image');
const video = media.querySelector('video');
if (video) applyHoverPlay(video);
}
const picture = text?.querySelector('picture');
const iconArea = picture ? (picture.closest('p') || createTag('p', null, picture)) : null;
iconArea?.classList.add('icon-area');
Expand Down
1 change: 1 addition & 0 deletions libs/blocks/figure/figure.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function buildFigure(blockEl) {
}
const video = clone.querySelector('video');
if (video) {
import('../../utils/decorate.js').then(({ applyHoverPlay }) => applyHoverPlay(video));
figEl.prepend(video);
}
const caption = clone.querySelector('em');
Expand Down
5 changes: 3 additions & 2 deletions libs/blocks/marquee/marquee.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/*
* Marquee - v6.0
*/
import { decorateButtons, getBlockSize } from '../../utils/decorate.js';
import { decorateButtons, getBlockSize, applyHoverPlay } from '../../utils/decorate.js';
import { decorateBlockAnalytics, decorateLinkAnalytics } from '../../martech/attributes.js';
import { createTag } from '../../utils/utils.js';

Expand Down Expand Up @@ -135,7 +135,8 @@ export default function init(el) {

if (media) {
media.classList.add('media');

const video = media.querySelector('video');
if (video) applyHoverPlay(video);
if (media.querySelector('a[href$=".mp4"]')) {
decorateVideo(media);
} else {
Expand Down
4 changes: 3 additions & 1 deletion libs/blocks/media/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* media - consonant v5.1
*/

import { decorateBlockBg, decorateBlockText, getBlockSize, decorateTextOverrides } from '../../utils/decorate.js';
import { decorateBlockBg, decorateBlockText, getBlockSize, decorateTextOverrides, applyHoverPlay } from '../../utils/decorate.js';
import { decorateBlockAnalytics } from '../../martech/attributes.js';
import { createTag } from '../../utils/utils.js';

Expand Down Expand Up @@ -49,6 +49,8 @@ export default function init(el) {
if (image) image.classList.add('image');
const img = image.querySelector(':scope img');
if (header && img?.alt === '') img.alt = header.textContent;
const imageVideo = image.querySelector('video');
if (imageVideo) applyHoverPlay(imageVideo);

// lists
if (row.querySelector('ul')) {
Expand Down
26 changes: 21 additions & 5 deletions libs/blocks/video/video.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
export default function init(a) {
const { pathname, hash } = a;
import { applyHoverPlay } from '../../utils/decorate.js';

const isAutoplay = !!(hash?.includes('autoplay'));
const isNotLooped = !!(hash?.includes('autoplay1'));
function getAttrs(hash) {
const isAutoplay = hash?.includes('autoplay');
const isAutoplayOnce = hash?.includes('autoplay1');
const playOnHover = hash.includes('hoverplay');
if (isAutoplay && !isAutoplayOnce) {
return 'playsinline autoplay loop muted';
}
if (playOnHover && isAutoplayOnce) {
return 'playsinline autoplay muted data-hoverplay';
}
if (isAutoplayOnce) {
return 'playsinline autoplay muted';
}
return 'playsinline controls';
}

const attrs = isAutoplay ? `playsinline autoplay ${isNotLooped ? '' : 'loop'} muted` : 'playsinline controls';
export default function init(a) {
const { pathname, hash } = a;
const attrs = getAttrs(hash);
const video = `<video ${attrs}>
<source src=".${pathname}" type="video/mp4" />
</video>`;
a.insertAdjacentHTML('afterend', video);
const videoElem = document.body.querySelector(`source[src=".${pathname}"]`)?.parentElement;
applyHoverPlay(videoElem);
a.remove();
}
12 changes: 11 additions & 1 deletion libs/utils/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,20 @@ function applyTextOverrides(el, override) {
}

export function decorateTextOverrides(el, options = ['-heading', '-body', '-detail']) {
const overrides = [...el.classList].filter((elClass) => options.findIndex((ovClass) => elClass.endsWith(ovClass)) >= 0);
const overrides = [...el.classList].filter(
(elClass) => options.findIndex((ovClass) => elClass.endsWith(ovClass)) >= 0,
);
if (!overrides.length) return;
overrides.forEach((override) => {
applyTextOverrides(el, override);
el.classList.remove(override);
});
}

export function applyHoverPlay(video) {
if (video.hasAttribute('data-hoverplay') && !video.hasAttribute('data-mouseevent')) {
video.addEventListener('mouseenter', () => { video.play(); });
video.addEventListener('mouseleave', () => { video.pause(); });
video.setAttribute('data-mouseevent', true);
}
}
16 changes: 16 additions & 0 deletions test/blocks/video/mocks/body.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,20 @@
https://main--blog--adobecom.hlx.page/media_17927691d22fe4e1bd058e94762a224fdc57ebb7b.mp4#autoplay1
</a>
</div>
<div class="video autoplay no-loop hoverplay">
<a href="https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#autoplay1#_hoverplay">
https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#autoplay1#_hoverplay
</a>
</div>
<div class="video autoplay playonhover">
<a href="https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#autoplay#_hoverplay">
https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#autoplay#_hoverplay
</a>
</div>
<div class="video hoveronly">
<a href="https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#_hoverplay">
https://main--milo--adobecom.hlx.page/media_1e798d01c6ddc7e7eadc8f134d69e4f8d7193fdbb.mp4#_hoverplay
</a>
</div>
</div>
</main>
38 changes: 38 additions & 0 deletions test/blocks/video/video.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,42 @@ describe('video uploaded using franklin bot', () => {

expect(block.firstElementChild.hasAttribute('loop')).to.be.false;
});

it('decorates video with autoplay, no loop and hover play', async () => {
chrischrischris marked this conversation as resolved.
Show resolved Hide resolved
const block = document.querySelector('.video.no-loop.hoverplay');
const a = block.querySelector('a');
const { href } = a;
a.textContent = href;
block.append(a);

init(a);

expect(block.firstElementChild.hasAttribute('loop')).to.be.false;
expect(block.firstElementChild.hasAttribute('data-hoverplay')).to.be.true;
});

it('no hoverplay attribute added when with autoplay on loop', async () => {
const block = document.querySelector('.video.autoplay.playonhover');
const a = block.querySelector('a');
const { href } = a;
a.textContent = href;
block.append(a);

init(a);

expect(block.firstElementChild.hasAttribute('loop')).to.be.true;
expect(block.firstElementChild.hasAttribute('data-hoverplay')).to.be.false;
});

it('no hoverplay attribute added when only hoverplay is added to url', async () => {
const block = document.querySelector('.video.hoveronly');
const a = block.querySelector('a');
const { href } = a;
a.textContent = href;
block.append(a);

init(a);

expect(block.firstElementChild.hasAttribute('data-hoverplay')).to.be.false;
});
});