Skip to content

Commit

Permalink
Play video on hover (#1106)
Browse files Browse the repository at this point in the history
Co-authored-by: Ruchika Sinha <tek10248@Ruchikas-MacBook-Pro.local>
Co-authored-by: Elaine Borges <62952234+elaineskpt@users.noreply.github.com>
Co-authored-by: Sunil Kamat <107644736+sukamat@users.noreply.github.com>
  • Loading branch information
4 people committed Aug 16, 2023
1 parent e661c8f commit e0e58a0
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 11 deletions.
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 () => {
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;
});
});

0 comments on commit e0e58a0

Please sign in to comment.