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-137345] Genfill Interactive Marquee #134

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ export default async function init(el) {
changeBg(el);
break;
}
case el.classList.contains('genfill'): {
loadStyle('/creativecloud/blocks/interactive-marquee/milo-marquee.css');
loadStyle('/creativecloud/features/genfill/genfill-interactive.css');
interactiveInit(el, decorateButtons, decorateBlockBg, createTag);
const { default: decorateGenfill } = await import('../../features/genfill/genfill-interactive.js');
await decorateGenfill(el);
break;
}
case el.classList.contains('firefly'): {
loadStyle('/creativecloud/blocks/interactive-marquee/milo-marquee.css');
loadStyle('/creativecloud/features/interactive-elements/interactive-elements.css');
Expand Down
5 changes: 5 additions & 0 deletions creativecloud/blocks/interactive-marquee/milo-marquee.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
position: relative;
top: 63px; /* mobile */
margin: 0 auto;
cursor: pointer;
}

.interactive-marquee .text {
Expand All @@ -38,6 +39,10 @@
order: 2;
}

[dir="rtl"] .interactive-marquee .text {
margin: 0 auto 0 0;
}

.interactive-marquee .text p:last-of-type {
margin-bottom: 0;
}
Expand Down
106 changes: 106 additions & 0 deletions creativecloud/features/genfill/genfill-interactive.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
.genfill .desktop-only,
.genfill .tablet-only,
.genfill .mobile-only {
-webkit-tap-highlight-color: transparent;
user-select: none;
display: none;
}

.genfill .enticement-detail,
.genfill .enticement-mode,
.genfill .timer {
display: none;
}

.genfill .media a {
display: none;
}

.enticement-arrow {
display: none;
width: 49px;
height: 73px;
position: absolute;
}

.enticement-text {
display: none;
max-width: 30ch;
position: absolute;
font-size: 28px;
line-height: 35px;
margin: 40px 0 16px -20px;
top: -90px;
color: var(--color-white);
}

.enticement-text.light {
color: var(--color-black);
}

@media screen and (max-width: 600px) {
.genfill .mobile-only a {
display: none;
}

.genfill .media.mobile-only,
.genfill .media.mobile-only a:first-of-type {
display: block;
}

.genfill .enticement {
display: none;
}
}

@media screen and (min-width: 600px) and (max-width: 1200px) {
.genfill .tablet-only a {
display: none;
}

.genfill .tablet-only,
.genfill .tablet-only a:first-of-type {
display: block;
}

.enticement-arrow {
right: 575px;
top: -30px;
display: block;
}

.enticement-text {
display: block;
}

[dir="rtl"] .enticement-text {
position: absolute;
left: var(--spacing-xxs);
}
}

@media screen and (min-width: 1200px) {
.genfill .desktop-only a {
display: none;
}

.genfill .desktop-only,
.genfill .desktop-only a:first-of-type {
display: block;
}

.enticement-arrow {
right: 575px;
top: -30px;
display: block;
}

.enticement-text {
display: block;
}

[dir="rtl"] .enticement-text {
position: absolute;
left: var(--spacing-xxs);
}
}
103 changes: 103 additions & 0 deletions creativecloud/features/genfill/genfill-interactive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { getLibs } from '../../scripts/utils.js';
import { createEnticement } from '../interactive-elements/interactive-elements.js';
import defineDeviceByScreenSize from '../../scripts/decorate.js';

function handleTransition(pics, index) {
pics[index].style.display = 'none';
const nextIndex = (index + 1) % pics.length;
pics[nextIndex].style.display = 'block';
return nextIndex;
}

function startAutocycle(interval, pics, clickConfig) {
if (clickConfig.isImageClicked) return;
clickConfig.autocycleInterval = setInterval(() => {
clickConfig.autocycleIndex = handleTransition(pics, clickConfig.autocycleIndex);
if (clickConfig.autocycleIndex === pics.length - 1) {
clearInterval(clickConfig.autocycleInterval);
}
}, interval);
}

function handleClick(aTags, clickConfig) {
aTags.forEach((a, i) => {
a.querySelector('img').removeAttribute('loading');
a.addEventListener('click', () => {
clickConfig.isImageClicked = true;
if (clickConfig.autocycleInterval) clearInterval(clickConfig.autocycleInterval);
handleTransition(aTags, i);
});
});
}

async function addEnticement(container, enticement, mode) {
const svgUrl = enticement.querySelector('a').href;
const enticementText = enticement.innerText;
const entcmtEl = await createEnticement(`${enticementText}|${svgUrl}`, mode);
entcmtEl.classList.add('enticement');
const n = container.children.length;
const desktopMedia = container.querySelector('.desktop-only');
const tabletMedia = (n > 2) ? container.querySelector('.tablet-only') : null;
desktopMedia.insertBefore(entcmtEl, desktopMedia.firstElementChild);
tabletMedia?.insertBefore(entcmtEl.cloneNode(true), tabletMedia.firstElementChild);
}

async function removePTags(media, vi) {
const heading = media.closest('.foreground').querySelector('h1, h2, h3, h4, h5, h6');
const hText = heading.id
.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');
const miloLibs = getLibs();
const { createTag } = await import(`${miloLibs}/utils/utils.js`);
const pics = media.querySelectorAll('picture');
pics.forEach((pic, index) => {
if (pic.closest('p')) pic.closest('p').remove();
const a = createTag('a', { class: 'genfill-link' });
const img = pic.querySelector('img');
const altTxt = img.alt
? `${img.alt}|Marquee|${hText}`
: `Image-${vi}-${index}|Marquee|${hText}`;
a.setAttribute('daa-ll', altTxt);
a.appendChild(pic);
media.appendChild(a);
});
}

export default async function decorateGenfill(el) {
const clickConfig = {
autocycleIndex: 0,
autocycleInterval: null,
isImageClicked: false,
};
const interactiveContainer = el.querySelector('.interactive-container');
const allP = interactiveContainer.querySelectorAll('.media:first-child p');
const pMetadata = [...allP].filter((p) => !p.querySelector('picture'));
const [enticementMode, enticement, timer = null] = [...pMetadata];
enticementMode.classList.add('enticement-mode');
enticement.classList.add('enticement-detail');
timer?.classList.add('timer');
const mode = enticementMode.innerText.includes('light') ? 'light' : 'dark';
const timerValues = timer ? timer.innerText.split('|') : null;
const [intervalTime = 2000, delayTime = 1000] = (timerValues && timerValues.length > 1)
? timerValues : [2000];
[enticementMode, enticement, timer].forEach((i) => i?.remove());
const viewports = ['mobile', 'tablet', 'desktop'];
const mediaElements = interactiveContainer.querySelectorAll('.media');
mediaElements.forEach(async (mediaEl, index) => {
await removePTags(mediaEl, index);
const aTags = mediaEl.querySelectorAll('a');
handleClick(aTags, clickConfig);
});
viewports.forEach((v, vi) => {
const media = mediaElements[vi]
? mediaElements[vi]
: interactiveContainer.lastElementChild;
media.classList.add(`${v}-only`);
if (defineDeviceByScreenSize() === v.toUpperCase()) {
setTimeout(() => {
const aTags = media.querySelectorAll('a');
startAutocycle(intervalTime, aTags, clickConfig);
}, delayTime);
}
});
addEnticement(interactiveContainer, enticement, mode);
}
29 changes: 17 additions & 12 deletions creativecloud/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,23 @@ const eagerLoad = (img) => {

(async function loadLCPImage() {
const firstDiv = document.querySelector('body > main > div:nth-child(1) > div');
if (firstDiv?.classList.contains('marquee')) {
firstDiv.querySelectorAll('img').forEach(eagerLoad);
} else if (firstDiv?.classList.contains('changebg')) {
firstDiv.querySelector(':scope > div:nth-child(1)').querySelectorAll('img').forEach(eagerLoad);
import(`${CONFIG.codeRoot}/deps/interactive-marquee-changebg/changeBgMarquee.js`);
} else if (firstDiv?.classList.contains('interactive-marquee')) {
firstDiv.querySelector(':scope > div:nth-child(1)').querySelectorAll('img').forEach(eagerLoad);
if (firstDiv?.classList.contains('firefly')) {
firstDiv.querySelector(':scope > div:nth-child(2)').querySelectorAll('img').forEach(async (img) => eagerLoad(img));
}
} else {
eagerLoad(document.querySelector('img'));
let fgDivs = null;
switch (true) {
case firstDiv?.classList.contains('changebg'):
firstDiv.querySelector(':scope > div:nth-child(1)').querySelectorAll('img').forEach(eagerLoad);
import(`${CONFIG.codeRoot}/deps/interactive-marquee-changebg/changeBgMarquee.js`);
break;
case firstDiv?.classList.contains('marquee'):
firstDiv.querySelectorAll('img').forEach(eagerLoad);
break;
case firstDiv?.classList.contains('interactive-marquee'):
firstDiv.querySelector(':scope > div:nth-child(1)').querySelectorAll('img').forEach(eagerLoad);
fgDivs = firstDiv.querySelector(':scope > div:nth-child(2)').querySelectorAll('div:not(:first-child)');
fgDivs.forEach((d) => eagerLoad(d.querySelector('img')));
break;
default:
eagerLoad(document.querySelector('img'));
break;
}
}());

Expand Down
39 changes: 39 additions & 0 deletions test/blocks/interactive-marquee/interactive-marquee.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { readFile } from '@web/test-runner-commands';
import { expect } from '@esm-bundle/chai';

document.body.innerHTML = await readFile({ path: './mocks/container.html' });
const { setLibs } = await import('../../../creativecloud/scripts/utils.js');
const { default: init } = await import('../../../creativecloud/blocks/interactive-marquee/interactive-marquee.js');

describe('interactive marquee', () => {
const im = document.querySelector('.interactive-marquee');
before(async () => {
setLibs('https://milo.adobe.com/libs');
await init(im);
});
it('interactive marquee light variant should exist', () => {
const light = im.classList.contains('light');
expect(light).to.true;
});

it('has the interactive-area', () => {
const container = im.querySelector('.foreground .interactive-container');
expect(container).to.exist;
});

it('has a heading-xxl', () => {
const heading = im.querySelector('.heading-xxl');
expect(heading).to.exist;
});

it('has an icon area', () => {
const iconArea = im.querySelector('.icon-area');
expect(iconArea).to.exist;
});

it('should have icon text', () => {
const iconText = im.querySelector('.icon-text');
expect(iconText).to.exist;
expect(iconText.classList.contains('heading-xs')).to.be.true;
});
});
26 changes: 26 additions & 0 deletions test/blocks/interactive-marquee/mocks/container.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div class="interactive-marquee light">
<div>
<div data-valign="middle">
<picture>
<img loading="lazy" alt="" src="" width="1600" height="750">
</picture>
</div>
</div>
<div>
<div data-valign="middle">
<p>
<picture>
<img loading="lazy" alt="" src="" width="154" height="150">
</picture>Photoshop
</p>
<h2 id="edit-photos-online-with-adobe-photoshop">Edit photos online with Adobe Photoshop</h2>
<p>Add, remove, or expand content in images right in your browser with Photoshop on the web. Included in every Photoshop plan.</p>
<p><strong><a href="https://www.adobe.com/">Free Trial</a></strong> <em><a href="http://www.adobe.com/">Explore Photoshop online</a></em></p>
</div>
<div data-valign="middle">
<picture>
<img loading="lazy" alt="Jungle" data-title="JungleD" src="" width="1000" height="1000">
</picture>
</div>
</div>
</div>
32 changes: 32 additions & 0 deletions test/features/genfill/genfill-interactive.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { readFile } from '@web/test-runner-commands';
import { expect } from '@esm-bundle/chai';

document.body.innerHTML = await readFile({ path: './mocks/genfill.html' });
const { setLibs } = await import('../../../creativecloud/scripts/utils.js');
const { default: init } = await import('../../../creativecloud/blocks/interactive-marquee/interactive-marquee.js');

describe('genfill variant of interactive marquee', () => {
const im = document.querySelector('.interactive-marquee');
before(async () => {
setLibs('https://milo.adobe.com/libs');
await init(im);
});
it('desktop media should exist', () => {
const desktop = im.querySelector('.desktop-only');
expect(desktop).to.exist;
});
it('tablet media should exist', () => {
const tablet = im.querySelector('.tablet-only');
expect(tablet).to.exist;
});
it('mobile media should exist', () => {
const mobile = im.querySelector('.mobile-only');
expect(mobile).to.exist;
});
it('should have proper enticement', () => {
const ent = im.querySelector('.enticement');
expect(ent).to.exist;
expect(ent.querySelector('.enticement-text')).to.exist;
expect(ent.querySelector('.enticement-arrow')).to.exist;
});
});
Loading
Loading