Skip to content

Commit 7fde595

Browse files
authored
Mwpw 174987 hero marquee order (adobecom#4475)
* MWPW-174987: Change DOM order of elements based on viewport * MWPW-174987: Add additional check * MWPW-174987: PR feedback * MWPW-174987: Fix no-order els bug * MWPW-174987: Fix no desktop bug * MWPW-174987: Update unit tests * MWPW-174987: Fix * MWPW-174987: Remove previous
1 parent 02b63cf commit 7fde595

6 files changed

Lines changed: 199 additions & 12 deletions

File tree

libs/blocks/hero-marquee/hero-marquee.css

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,6 @@ html[dir="rtl"] .hero-marquee li.icon-item span.icon {
379379
/* min height */
380380
.hero-marquee.s-min-height-tablet { min-height: var(--s-min-height);}
381381
.hero-marquee.l-min-height-tablet { min-height: var(--l-min-height);}
382-
383-
/* helper classes */
384-
.hero-marquee .order-0-tablet { order: 0; }
385-
.hero-marquee .order-1-tablet { order: 1; }
386-
.hero-marquee .order-2-tablet { order: 2; }
387-
.hero-marquee .order-3-tablet { order: 3; }
388382
}
389383

390384
@media screen and (min-width: 920px) {
@@ -474,10 +468,4 @@ html[dir="rtl"] .hero-marquee li.icon-item span.icon {
474468
/* min height */
475469
.hero-marquee.s-min-height-desktop { min-height: var(--s-min-height);}
476470
.hero-marquee.l-min-height-desktop { min-height: var(--l-min-height);}
477-
478-
/* helper classes */
479-
.hero-marquee .order-0-desktop { order: 0; }
480-
.hero-marquee .order-1-desktop { order: 1; }
481-
.hero-marquee .order-2-desktop { order: 2; }
482-
.hero-marquee .order-3-desktop { order: 3; }
483471
}

libs/blocks/hero-marquee/hero-marquee.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,66 @@ function loadBreakpointThemes() {
166166
loadStyle(`${base}/styles/breakpoint-theme.css`);
167167
}
168168

169+
export function getViewportOrder(viewport, content) {
170+
const els = [...content.children];
171+
const viewportObject = { 0: [] };
172+
els.forEach((el) => {
173+
const orderClass = {
174+
tablet: null,
175+
desktop: null,
176+
};
177+
el.classList.forEach((className) => {
178+
if (!className.startsWith('order-')
179+
|| (!className.endsWith('desktop') && !className.endsWith('tablet'))) return;
180+
orderClass.tablet = orderClass.tablet || (className.endsWith('tablet') ? className : null);
181+
orderClass.desktop = orderClass.desktop || (className.endsWith('desktop') ? className : null);
182+
});
183+
const viewportClass = orderClass[viewport] || orderClass.tablet;
184+
const order = parseInt(viewportClass?.split('-')[1], 10);
185+
if (Number.isInteger(order)) {
186+
if (!viewportObject[order]) viewportObject[order] = [];
187+
viewportObject[order].push(el);
188+
} else {
189+
viewportObject[0].push(el);
190+
}
191+
});
192+
193+
const viewportOrder = [];
194+
Object.keys(viewportObject).sort((a, b) => a - b).forEach((key) => {
195+
viewportOrder.push(...viewportObject[key]);
196+
});
197+
return viewportOrder;
198+
}
199+
200+
function handleViewportOrder(content) {
201+
const hasOrder = content.querySelector(':scope > div[class*="order-"]');
202+
if (!hasOrder) return;
203+
204+
const viewports = {
205+
mobile: {
206+
media: '(max-width: 599px)',
207+
elements: [...content.children],
208+
},
209+
tablet: {
210+
media: '(min-width: 600px) and (max-width: 1199px)',
211+
elements: getViewportOrder('tablet', content),
212+
},
213+
desktop: {
214+
media: '(min-width: 1200px)',
215+
elements: getViewportOrder('desktop', content),
216+
},
217+
};
218+
219+
Object.entries(viewports).forEach(([viewport, { media, elements }]) => {
220+
const mediaQuery = window.matchMedia(media);
221+
if (mediaQuery.matches && viewport !== 'mobile') content.replaceChildren(...elements);
222+
mediaQuery.addEventListener('change', (e) => {
223+
if (!e.matches) return;
224+
content.replaceChildren(...elements);
225+
});
226+
});
227+
}
228+
169229
export default async function init(el) {
170230
el.classList.add('con-block');
171231
let rows = el.querySelectorAll(':scope > div');
@@ -268,6 +328,7 @@ export default async function init(el) {
268328
}
269329
});
270330
decorateTextOverrides(el, ['-heading', '-body', '-detail'], mainCopy);
331+
handleViewportOrder(copy);
271332

272333
if (el.classList.contains('countdown-timer')) {
273334
promiseArr.push(loadCDT(copy, el.classList));

test/blocks/hero-marquee/hero-marquee.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { expect } from '@esm-bundle/chai';
33
import { stub } from 'sinon';
44
import { waitForElement } from '../../helpers/waitfor.js';
55
import { setConfig } from '../../../libs/utils/utils.js';
6+
import { getViewportOrder } from '../../../libs/blocks/hero-marquee/hero-marquee.js';
67

78
window.lana = { log: stub() };
89

@@ -35,4 +36,39 @@ describe('Hero Marquee', () => {
3536
const hr = await waitForElement('.has-divider');
3637
expect(hr).to.exist;
3738
});
39+
it('sorts con-block elements based on order class and viewport', async () => {
40+
const orderHero = await readFile({ path: './mocks/order-marquee.html' });
41+
const orderMarquee = document.querySelector('#order-hero');
42+
orderMarquee.innerHTML = orderHero;
43+
const orderCopy = orderMarquee.querySelector('.copy');
44+
const tabletOrder = getViewportOrder('tablet', orderCopy);
45+
const desktopOrder = getViewportOrder('desktop', orderCopy);
46+
47+
expect(tabletOrder[0].classList.contains('main-copy')).to.be.true;
48+
expect(desktopOrder[0].classList.contains('main-copy')).to.be.true;
49+
50+
expect(tabletOrder[1].classList.contains('order-0-tablet')).to.be.true;
51+
expect(desktopOrder[1].classList.contains('no-order-element')).to.be.true;
52+
53+
expect(tabletOrder[2].classList.contains('no-order-element')).to.be.true;
54+
expect(desktopOrder[2].classList.contains('order-0-desktop')).to.be.true;
55+
56+
expect(tabletOrder[3].classList.contains('order-1-tablet')).to.be.true;
57+
expect(desktopOrder[3].classList.contains('order-1-tablet')).to.be.true;
58+
59+
expect(tabletOrder[4].classList.contains('order-2-tablet')).to.be.true;
60+
expect(desktopOrder[4].classList.contains('order-1-desktop')).to.be.true;
61+
62+
expect(tabletOrder[5].classList.contains('order-3-tablet')).to.be.true;
63+
expect(desktopOrder[5].classList.contains('order-2-desktop')).to.be.true;
64+
});
65+
it('order of con-blocks is the same as mobile if there is no order class', async () => {
66+
const noOrderHero = await readFile({ path: './mocks/no-order-marquee.html' });
67+
const noOrderMarquee = document.querySelector('#no-order-hero');
68+
noOrderMarquee.innerHTML = noOrderHero;
69+
const noOrderCopy = noOrderMarquee.querySelector('.copy');
70+
const mobileOrder = [...noOrderCopy.children];
71+
const tabletOrder = getViewportOrder('tablet', noOrderCopy);
72+
for (const [index, el] of tabletOrder.entries()) expect(el === mobileOrder[index]).to.be.true;
73+
});
3874
});

test/blocks/hero-marquee/mocks/body.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,6 @@ <h1 id="row-cell---text-right-2">Hero w/ Adobe.tv link</h1>
121121
<div><a href="https://video.tv.adobe.com/v/3427744">https://video.tv.adobe.com/v/3427744</a></div>
122122
</div>
123123
</div>
124+
<div id="no-order-hero"></div>
125+
<div id="order-hero"></div>
126+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<div id="no-order-hero" class="hero-marquee con-block has-bg" style="background: rgb(250, 250, 250);">
2+
<div class="background">
3+
<div class="mobile-only"><picture>
4+
<img loading="lazy" alt="" src="./" width="100" height="100">
5+
</picture></div>
6+
<div class="tablet-only"><picture>
7+
<img loading="lazy" alt="" src="./" width="100" height="100">
8+
</picture></div>
9+
<div class="desktop-only"><picture>
10+
<img loading="lazy" alt="" src="./" width="100" height="100">
11+
</picture></div>
12+
</div>
13+
<div class="foreground cols-1">
14+
<div class="copy"><div class="prepend row-lockup con-block xl-icon-size l-lockup">
15+
<div class="row-wrapper lockup-area"><picture><img loading="lazy" src="./"></picture> <strong>XL Icon Size</strong></div>
16+
</div><div class="prepend row-lockup con-block xl-lockup">
17+
<div class="row-wrapper lockup-area"><picture><img loading="lazy" src="./"></picture> <strong>XL Icon Size</strong></div>
18+
</div><div class="main-copy l-lockup l-button">
19+
<p class="body-m lockup-area"><picture><img loading="lazy" src="./"></picture><span class="lockup-label"> After Effects</span></p>
20+
<p class="detail-l">DETAIL TEXT</p>
21+
<h2 id="this-hero-has-all-row-types" class="heading-xxxl">This Hero has all row types</h2>
22+
<p class="body-m">lockup, list, qrcode, text, background</p>
23+
<p class="body-m action-area"><a href="#the-bg-image-is-on-top-for-mobiletablet" class="icon-area con-button outline button-xl button-justified-mobile"><span class="icon icon-checkmark-circle"></span>See more</a> <a href="#bg-mobile" class="con-button blue button-xl button-justified-mobile">Other options you say?</a></p>
24+
</div><div class="row-list con-block max-width-6-tablet body-l">
25+
<div class="row-wrapper foreground">
26+
<ul class="icon-list">
27+
<li class="icon-item"><span class="icon icon-checkmark"></span>Small</li>
28+
<li class="icon-item"><span class="icon icon-checkmark"></span>Medium length text</li>
29+
<li class="icon-item"><span class="icon icon-checkmark"></span>Long length text that may break onto a new line, what will happen, keep it going so this is even longer and really wraps?</li>
30+
<li class="icon-item"><span class="icon icon-checkmark"></span>Another list</li>
31+
</ul>
32+
</div>
33+
</div><div class="norm has-divider">
34+
<div><hr style="background: white;"></div>
35+
</div><div class="row-qrcode con-block">
36+
<div class="row-wrapper">
37+
<p class="qr-code-img"><a href="/drafts/rparrish/assets/qr-adobe-com.svg">https://main--milo--adobecom.hlx.page/drafts/rparrish/assets/qr-adobe-com.svg</a></p>
38+
<p class="google-play"><a href="https://www.adobe.com/">Google play</a></p>
39+
<p class="app-store"><a href="https://www.adobe.com/">Apple store</a></p>
40+
</div>
41+
</div><div class="row-qrcode con-block">
42+
43+
<!-- intentionally left empty for test case-->
44+
<div class="row-wrapper"></div>
45+
</div><div class="row-text con-block norm">
46+
47+
<div class="row-wrapper"><p class="body-xs">See plans for <a href="#teach">students and teachers</a> or <a href="#biz">small and medium business.</a></p></div>
48+
</div><div class="row-text con-block body-m norm">
49+
50+
<div class="row-wrapper"><p class="body-m">Text with no button class</p></div>
51+
</div><div class="row-supplemental con-block norm">
52+
53+
<div class="row-wrapper">sup text</div>
54+
</div></div>
55+
</div>
56+
</div>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<div id="hero-order" class="hero-marquee con-block has-bg">
2+
<div class="background">
3+
<div class="mobile-only"><picture>
4+
<img loading="lazy" alt="" src="./" width="100" height="100">
5+
</picture></div>
6+
<div class="tablet-only"><picture>
7+
<img loading="lazy" alt="" src="./" width="100" height="100">
8+
</picture></div>
9+
<div class="desktop-only"><picture>
10+
<img loading="lazy" alt="" src="./" width="100" height="100">
11+
</picture></div>
12+
</div>
13+
<div class="foreground cols-1">
14+
<div class="copy"><div class="prepend row-lockup con-block xl-icon-size order-3-tablet order-2-desktop l-lockup">
15+
<div class="row-wrapper lockup-area"><picture><img loading="lazy" src="./"></picture> <strong>XL Icon Size</strong></div>
16+
</div><div class="prepend row-lockup con-block order-1-tablet xl-lockup">
17+
<div class="row-wrapper lockup-area"><picture><img loading="lazy" src="./"></picture> <strong>XL Icon Size</strong></div>
18+
</div><div class="main-copy l-lockup l-button">
19+
<p class="body-m lockup-area"><picture><img loading="lazy" src="./"></picture><span class="lockup-label"> After Effects</span></p>
20+
<p class="detail-l">DETAIL TEXT</p>
21+
<h2 id="this-hero-has-all-row-types" class="heading-xxxl">This Hero has all row types</h2>
22+
<p class="body-m">lockup, list, qrcode, text, background</p>
23+
<p class="body-m action-area"><a href="#the-bg-image-is-on-top-for-mobiletablet" class="icon-area con-button outline button-xl button-justified-mobile"><span class="icon icon-checkmark-circle"></span>See more</a> <a href="#bg-mobile" class="con-button blue button-xl button-justified-mobile">Other options you say?</a></p>
24+
</div><div class="row-list con-block max-width-6-tablet order-0-tablet order-1-desktop body-l">
25+
<div class="row-wrapper foreground">
26+
<ul class="icon-list">
27+
<li class="icon-item"><span class="icon icon-checkmark"></span>Small</li>
28+
<li class="icon-item"><span class="icon icon-checkmark"></span>Medium length text</li>
29+
<li class="icon-item"><span class="icon icon-checkmark"></span>Long length text that may break onto a new line, what will happen, keep it going so this is even longer and really wraps?</li>
30+
<li class="icon-item"><span class="icon icon-checkmark"></span>Another list</li>
31+
</ul>
32+
</div>
33+
</div><div class="no-order-element row-lockup con-block xl-icon-size l-lockup">
34+
<div class="row-wrapper lockup-area"><picture><img loading="lazy" src="./"></picture> <strong>XL Icon Size</strong></div>
35+
</div><div class="row-qrcode con-block order-2-tablet order-0-desktop">
36+
<div class="row-wrapper">
37+
<p class="qr-code-img"><a href="/drafts/rparrish/assets/qr-adobe-com.svg">https://main--milo--adobecom.hlx.page/drafts/rparrish/assets/qr-adobe-com.svg</a></p>
38+
<p class="google-play"><a href="https://www.adobe.com/">Google play</a></p>
39+
<p class="app-store"><a href="https://www.adobe.com/">Apple store</a></p>
40+
</div>
41+
</div></div>
42+
</div>
43+
</div>

0 commit comments

Comments
 (0)