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

Adding support for first localnav menu being a dropdown #3693

Merged
merged 10 commits into from
Mar 3, 2025
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
30 changes: 25 additions & 5 deletions libs/blocks/global-navigation/global-navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ const convertToPascalCase = (str) => str
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
.join(' ');

const removeLocalNav = () => {
lanaLog({ message: 'Gnav Localnav was removed, potential CLS', tags: 'gnav-localnav' });
document.querySelector('.feds-localnav')?.remove();
};

class Gnav {
constructor({ content, block, newMobileNav } = {}) {
this.content = content;
Expand Down Expand Up @@ -428,9 +433,12 @@ class Gnav {
};

decorateLocalNav = async () => {
if (!this.isLocalNav()) return;
if (!this.isLocalNav()) {
removeLocalNav();
return;
}
const localNavItems = this.elements.navWrapper.querySelector('.feds-nav').querySelectorAll('.feds-navItem:not(.feds-navItem--section, .feds-navItem--mobile-only)');
const firstElem = localNavItems[0]?.querySelector('a');
const firstElem = localNavItems[0]?.querySelector('a') || localNavItems[0]?.querySelector('button');
if (!firstElem) {
lanaLog({ message: 'GNAV: Incorrect authoring of localnav found.', tags: 'gnav', errorType: 'info' });
return;
Expand All @@ -454,7 +462,11 @@ class Gnav {

localNavItems.forEach((elem, idx) => {
const clonedItem = elem.cloneNode(true);
const link = clonedItem.querySelector('a');
const link = clonedItem.querySelector('a, button');

if (link) {
link.dataset.title = link.textContent;
}

if (idx === 0) {
localNav.querySelector('.feds-localnav-title').innerText = title.trim();
Expand All @@ -477,7 +489,7 @@ class Gnav {
const promo = document.querySelector('.feds-promo-aside-wrapper');
if (promo) localNav.classList.add('has-promo');
this.elements.localNav = localNav;
localNavItems[0].querySelector('a').textContent = title.trim();
firstElem.textContent = title.trim();
const isAtTop = () => {
const rect = this.elements.localNav.getBoundingClientRect();
// note: ios safari changes between -0.34375, 0, and 0.328125
Expand Down Expand Up @@ -1115,10 +1127,18 @@ class Gnav {
// Copying dropdown contents to localNav items
const decorateLocalNavItems = (navItem, template) => {
const elements = [...document.querySelectorAll('.feds-localnav .feds-navItem')].find(
(el) => el.textContent.trim() === navItem.textContent,
(el) => {
const link = el.querySelector('a, button');
return link.dataset.title?.trim() === navItem.textContent;
},
);
if (elements) {
const dropdownBtn = elements.querySelector('button');
elements.innerHTML = template.innerHTML;
// To override the textcontent of button of first item of localnav
if (dropdownBtn) {
elements.querySelector('button').textContent = dropdownBtn.textContent;
}
// Reattach click events & mutation observers, as cloned elem don't retain event listeners
elements.querySelector('.feds-localnav-items button')?.addEventListener('click', (e) => {
trigger({ element: e.currentTarget, event: e, type: 'localNavItem' });
Expand Down
3 changes: 3 additions & 0 deletions test/navigation/bootstrapper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import fetchedFooter from '../blocks/global-footer/mocks/fetched-footer.js';
import placeholders from '../blocks/global-navigation/mocks/placeholders.js';
import { setConfig } from '../../libs/utils/utils.js';
import { mockRes } from '../blocks/global-navigation/test-utilities.js';
import gnavLocalNav from './mocks/gnav-with-localnav.plain.js';

const blockConfig = {
footer: {
Expand Down Expand Up @@ -36,6 +37,7 @@ describe('Bootstrapper', async () => {
),
});
}
if (url.includes('/localnav/gnav.plain.html')) return mockRes({ payload: gnavLocalNav });
if (url.includes('/placeholders')) return mockRes({ payload: placeholders });
if (url.includes('/footer.plain.html')) return mockRes({ payload: await readFile({ path: '../blocks/region-nav/mocks/regions.html' }) });
if (url.includes('/gnav.plain.html')) return mockRes({ payload: await readFile({ path: './mocks/gnav.html' }) });
Expand Down Expand Up @@ -95,6 +97,7 @@ describe('Bootstrapper', async () => {
it('Renders the localnav', async () => {
blockConfig.header.isLocalNav = true;
blockConfig.header.mobileGnavV2 = true;
setConfig({ contentRoot: '/federal/localnav' });
const { default: init } = await import('../../libs/blocks/global-navigation/global-navigation.js');
await loadBlock(init, blockConfig.header);
const el = document.querySelector('header');
Expand Down
70 changes: 70 additions & 0 deletions test/navigation/mocks/gnav-with-localnav.plain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
export default `
<div>
<div class="gnav-brand logo brand-image-only">
<div>
<div><a href="/federal/assets/svgs/adobe-logo.svg">https://main--federal--adobecom.hlx.page/federal/assets/svgs/adobe-logo.svg|Adobe, Inc.</a> <a href="https://www.adobe.com/">Adobe</a></div>
</div>
</div>
<div class="large-menu section">
<div>
<div>
<h2 id="creativity--design"><a href="/federal/dev/mock-megamenu">Creativity &#x26; Design</a></h2>
</div>
</div>
</div>
</div>
<div>
<h2 id="adobe-express"><a href="https://www.adobe.com/express">Adobe Express</a></h2>
</div>
<div>
<div class="large-menu">
<div>
<div>
<h2 id="create"><a href="/federal/dev/mock-megamenu">Create</a></h2>
</div>
</div>
</div>
</div>
<div>
<h2 id="education">Education</h2>
<h5 id="k-12-schools">K-12 Schools</h5>
<ul>
<li><a href="https://google.com">Educators</a></li>
<li><a href="https://google.com">Administrators</a></li>
<li><a href="https://google.com">Educators and Administrators</a></li>
</ul>
<h5 id="higher-ed">Higher Ed</h5>
<ul>
<li><a href="https://google.com">Students</a></li>
<li><a href="https://google.com">Educators and Administrators</a></li>
</ul>
<div class="gnav-image dark test">
<div>
<div>
<p>
<picture>
<source type="image/webp" srcset="./media_15a432afa417d0d701bb2fa01ba27f17c7fd8385d.png?width=2000&#x26;format=webply&#x26;optimize=medium" media="(min-width: 600px)">
<source type="image/webp" srcset="./media_15a432afa417d0d701bb2fa01ba27f17c7fd8385d.png?width=750&#x26;format=webply&#x26;optimize=medium">
<source type="image/png" srcset="./media_15a432afa417d0d701bb2fa01ba27f17c7fd8385d.png?width=2000&#x26;format=png&#x26;optimize=medium" media="(min-width: 600px)">
<img loading="lazy" alt="Hello I am alt text" src="./media_15a432afa417d0d701bb2fa01ba27f17c7fd8385d.png?width=750&#x26;format=png&#x26;optimize=medium" width="496" height="396">
</picture>
</p>
<p><a href="https://www.adobe.com">www.adobe.com</a></p>
</div>
</div>
</div>
</div>
<div>
<p><a href="https://www.adobe.com/creativecloud/photography/compare-plans.html">Compare Plans</a></p>
</div>
<div>
<p><a href="/cc-shared/fragments/trial-modals/photography#modal-twp-photography">Free trial</a></p>
</div>
<div>
<p><em><a href="https://commerce.adobe.com/store/segmentation?cli=adobe_com&#x26;co=US&#x26;ctx=fp&#x26;lang=en&#x26;ms=COM&#x26;ot=BASE&#x26;pa=PA-126">Free trial</a></em></p>
</div>
<div>
<p><strong><a href="https://milo.adobe.com/tools/ost?osi=jWh-iooSLW82QkvJ1ZIWqU1jF4UAlKttsWFGBPTmcmo&#x26;type=checkoutUrl&#x26;text=buy-now&#x26;workflowStep=commitment">CTA {{buy-now}}</a></strong></p>
</div>
<div></div>
`;
Loading