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-140096] Genfill Marquee images are blinking during auto play and on click as well in Firefox browser #144

Merged
merged 18 commits into from
Dec 14, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default async function init(el) {
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);
await decorateGenfill(el, { createTag });
break;
}
case el.classList.contains('firefly'): {
Expand Down
29 changes: 7 additions & 22 deletions creativecloud/features/genfill/genfill-interactive.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.genfill .tablet-only,
.genfill .mobile-only {
-webkit-tap-highlight-color: transparent;
-webkit-user-select: none;
user-select: none;
display: none;
}
Expand All @@ -12,11 +13,10 @@
}

.genfill .media a {
display: none;
}

.interactive-marquee.genfill .media a {
cursor: pointer;
position: absolute;
top: 0;
left: 0;
}

.enticement-arrow {
Expand All @@ -42,12 +42,7 @@
}

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

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

Expand All @@ -57,12 +52,7 @@
}

@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 {
.genfill .tablet-only {
display: block;
}

Expand All @@ -83,12 +73,7 @@
}

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

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

Expand Down
160 changes: 91 additions & 69 deletions creativecloud/features/genfill/genfill-interactive.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,90 @@
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';
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 viewports = ['tablet', 'desktop'];
viewports.forEach((v) => {
const mDiv = container.querySelector(`.media.${v}-only`);
mDiv.insertBefore(entcmtEl.cloneNode(true), mDiv.firstElementChild);
});
}

function generateDaaLL(hText, alt, v) {
const altTxt = alt
? `${alt}|Marquee|${hText}`
: `Image-${v}|Marquee|${hText}`;
return altTxt;
}

function setImgAttrs(img, src, attrs) {
img.src = src;
if (attrs.alt) img.alt = attrs.alt;
if (attrs.w) img.width = attrs.w;
if (attrs.h) img.height = attrs.h;
}

function handleClick(a, v, deviceConfig, hText) {
const img = a.querySelector('img');
const currIndex = deviceConfig[v].index;
const nextIndex = (currIndex + 1) % deviceConfig[v].srcList.length;
const src = deviceConfig[v].srcList[nextIndex];
const attrs = deviceConfig[v].attrList[nextIndex];
setImgAttrs(img, src, attrs);
a.setAttribute('daa-ll', generateDaaLL(hText, attrs.alt, v));
deviceConfig[v].index = nextIndex;
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);
function startAutocycle(a, autoCycleConfig, viewport, deviceConfig, interval, hText) {
if (autoCycleConfig.isImageClicked) return;
autoCycleConfig.autocycleInterval = setInterval(() => {
handleClick(a, viewport, deviceConfig, hText);
if (autoCycleConfig.isImageClicked
|| deviceConfig[viewport].index === deviceConfig[viewport].srcList.length - 1) {
clearInterval(autoCycleConfig.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);
});
function processMedia(ic, miloUtil, autoCycleConfig, deviceConfig, v, hText) {
const media = miloUtil.createTag('div', { class: `media ${v}-only` });
const a = miloUtil.createTag('a', { class: 'genfill-link' });
const img = miloUtil.createTag('img', { class: 'genfill-image' });
const src = deviceConfig[v].srcList[0];
const attrs = deviceConfig[v].attrList[0];
setImgAttrs(img, src, attrs);
a.setAttribute('daa-ll', generateDaaLL(hText, attrs.alt, v));
a.appendChild(img);
media.appendChild(a);
ic.appendChild(media);
a.addEventListener('click', () => {
autoCycleConfig.isImageClicked = true;
if (autoCycleConfig.autocycleInterval) clearInterval(autoCycleConfig.autocycleInterval);
handleClick(a, v, deviceConfig, hText);
});
}

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);
});
function getImgSrc(pic, viewport) {
let source = '';
if (viewport === 'mobile') source = pic.querySelector('source[type="image/webp"]:not([media])');
else source = pic.querySelector('source[type="image/webp"][media]');
return source.srcset;
}

export default async function decorateGenfill(el) {
const clickConfig = {
autocycleIndex: 0,
export default async function decorateGenfill(el, miloUtil) {
const autoCycleConfig = {
autocycleInterval: null,
isImageClicked: false,
};
const interactiveContainer = el.querySelector('.interactive-container');
const allP = interactiveContainer.querySelectorAll('.media:first-child p');
const ic = el.querySelector('.interactive-container');
const heading = ic.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 allP = ic.querySelectorAll('.media:first-child p');
const pMetadata = [...allP].filter((p) => !p.querySelector('picture'));
const [enticement, timer = null] = [...pMetadata];
enticement.classList.add('enticement-detail');
Expand All @@ -79,24 +94,31 @@ export default async function decorateGenfill(el) {
const [intervalTime = 2000, delayTime = 1000] = (timerValues && timerValues.length > 1)
? timerValues : [2000];
[enticement, timer].forEach((i) => i?.remove());
const currentDom = ic.cloneNode(true);
ic.innerHTML = '';
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);
});
const deviceConfig = {
mobile: { srcList: [], attrList: [], index: 0 },
tablet: { srcList: [], attrList: [], index: 0 },
desktop: { srcList: [], attrList: [], index: 0 },
};
const mediaElements = currentDom.querySelectorAll('.media');
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);
}
: currentDom.lastElementChild;
[...media.querySelectorAll('picture')].forEach((pic, index) => {
const src = getImgSrc(pic, v);
deviceConfig[v].srcList.push(src);
const img = pic.querySelector('img');
deviceConfig[v].attrList.push({ alt: img.alt, w: img.width, h: img.height });
if (index === 0) processMedia(ic, miloUtil, autoCycleConfig, deviceConfig, v, hText);
});
});
addEnticement(interactiveContainer, enticement, mode);
const currentVP = defineDeviceByScreenSize().toLocaleLowerCase();
setTimeout(() => {
const aTag = ic.querySelector(`.${currentVP}-only a`);
startAutocycle(aTag, autoCycleConfig, currentVP, deviceConfig, intervalTime, hText);
}, delayTime);
addEnticement(ic, enticement, mode);
}
6 changes: 6 additions & 0 deletions test/features/genfill/genfill-interactive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@ describe('genfill variant of interactive marquee', () => {
expect(ent.querySelector('.enticement-text')).to.exist;
expect(ent.querySelector('.enticement-arrow')).to.exist;
});
it('should implement click functionality and analytics', () => {
const a = im.querySelector('.desktop-only a');
expect(a.getAttribute('daa-ll').includes('Generate Jungle')).to.true;
a.click();
expect(a.getAttribute('daa-ll').includes('Generate Pond')).to.true;
});
});
74 changes: 21 additions & 53 deletions test/features/genfill/mocks/genfill.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<div class="interactive-marquee light genfill">
<div class="interactive-marquee genfill">
<div>
<div data-valign="middle">
<picture>
<source type="image/webp" srcset="" media="(min-width: 600px)">
<source type="image/webp" srcset="">
<source type="image/png" srcset="" media="(min-width: 600px)">
<img loading="lazy" alt="" src="" width="1600" height="750">
</picture>
</div>
Expand All @@ -10,76 +13,41 @@
<div data-valign="middle">
<p>
<picture>
<img loading="lazy" alt="" src="" width="154" height="150">
<source type="image/webp" srcset="" media="(min-width: 600px)">
<source type="image/webp" srcset="">
<source type="image/png" srcset="" media="(min-width: 600px)">
<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">
<p><a href="/drafts/ruchika/svg/enticement-arrow.svg">See it in action</a></p>
<p><a href="">See it in action</a></p>
<p>2000|0</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
<source type="image/webp" srcset="" media="(min-width: 600px)">
<source type="image/webp" srcset="">
<source type="image/jpeg" srcset="" media="(min-width: 600px)">
<img loading="lazy" alt="Generate Jungle" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
<source type="image/webp" srcset="" media="(min-width: 600px)">
<source type="image/webp" srcset="">
<source type="image/jpeg" srcset="" media="(min-width: 600px)">
<img loading="lazy" alt="Generate Pond" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
</div>
<div data-valign="middle">
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
</picture>
</p>
<p>
<picture>
<img loading="lazy" alt="" src="" width="1000" height="1000">
<source type="image/webp" srcset="" media="(min-width: 600px)">
<source type="image/webp" srcset="">
<source type="image/jpeg" srcset="" media="(min-width: 600px)">
<img loading="lazy" alt="Generate Jaguar" src="" width="1000" height="1000">
</picture>
</p>
</div>
Expand Down
Loading