diff --git a/components/lib/events.ts b/components/lib/events.ts index 751fdaf94f..03d0236b37 100644 --- a/components/lib/events.ts +++ b/components/lib/events.ts @@ -172,9 +172,13 @@ function trackScroll() { if (scrollPosition > maxScrollY) maxScrollY = scrollPosition } +function sendPage() { + const pageEvent = sendEvent({ type: EventType.page }) + pageEventId = pageEvent?.context?.event_id +} + function sendExit() { if (sentExit) return - if (document.visibilityState !== 'hidden') return sentExit = true const { render, firstContentfulPaint, domInteractive, domComplete } = getPerformance() return sendEvent({ @@ -188,9 +192,27 @@ function sendExit() { }) } -function initPageEvent() { - const pageEvent = sendEvent({ type: EventType.page }) - pageEventId = pageEvent?.context?.event_id +function initPageAndExitEvent() { + sendPage() // Initial page hit + + // Regular page exits + window.addEventListener('scroll', trackScroll) + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + sendExit() + } + }) + + // Client-side routing + const pushState = history.pushState + history.pushState = function (...args) { + sendExit() + const result = pushState.call(history, ...args) + sendPage() + sentExit = false + maxScrollY = 0 + return result + } } function initClipboardEvent() { @@ -213,11 +235,6 @@ function initLinkEvent() { }) } -function initExitEvent() { - window.addEventListener('scroll', trackScroll) - document.addEventListener('visibilitychange', sendExit) -} - function initPrintEvent() { window.addEventListener('beforeprint', () => { sendEvent({ type: EventType.print }) @@ -225,8 +242,7 @@ function initPrintEvent() { } export default function initializeEvents() { - initPageEvent() // must come first - initExitEvent() + initPageAndExitEvent() // must come first initLinkEvent() initClipboardEvent() initPrintEvent() diff --git a/middleware/contextualizers/breadcrumbs.js b/middleware/contextualizers/breadcrumbs.js index 1b1870564b..35a69d487f 100644 --- a/middleware/contextualizers/breadcrumbs.js +++ b/middleware/contextualizers/breadcrumbs.js @@ -11,37 +11,66 @@ export default async function breadcrumbs(req, res, next) { const currentSiteTree = req.context.siteTree[req.context.currentLanguage][req.context.currentVersion] + const fallbackSiteTree = req.context.siteTree.en[req.context.currentVersion] - await createBreadcrumb( + req.context.breadcrumbs = await getBreadcrumbs( // Array of child pages on the root, i.e., the product level. currentSiteTree.childPages, - req.context + fallbackSiteTree.childPages, + req.context.currentPath.slice(3), + req.context.currentLanguage ) return next() } -async function createBreadcrumb(pageArray, context) { - // Find each page in the siteTree's array of child pages that starts with the requested path. - let childPage = pageArray.find((page) => context.currentPath.startsWith(page.href)) +async function getBreadcrumbs( + pageArray, + fallbackPageArray, + currentPathWithoutLanguage, + intendedLanguage +) { + // Find the page that starts with the requested path + let childPage = pageArray.find((page) => + currentPathWithoutLanguage.startsWith(page.href.slice(3)) + ) - // Fall back to English if needed - if (!childPage) { - childPage = pageArray.find((page) => - context.currentPath.startsWith(page.href.replace(`/${context.currentLanguage}`, '/en')) - ) - if (!childPage) return + // Find the page in the fallback page array (likely the English sub-tree) + const fallbackChildPage = + (fallbackPageArray || []).find((page) => { + return currentPathWithoutLanguage.startsWith(page.href.slice(3)) + }) || childPage + + // No matches, we bail + if (!childPage && !fallbackChildPage) { + return [] } - context.breadcrumbs.push({ - documentType: childPage.page.documentType, - href: childPage.href, - title: childPage.renderedShortTitle || childPage.renderedFullTitle, - }) + // Didn't find the intended page, but found the fallback + if (!childPage) { + childPage = fallbackChildPage + } - // Recursively loop through the siteTree and create each breadcrumb, until we reach the + const breadcrumb = { + documentType: childPage.page.documentType, + // give the breadcrumb the intendedLanguage, so nav through breadcrumbs doesn't inadvertantly change the user's selected language + href: `/${intendedLanguage}/${childPage.href.slice(4)}`, + title: childPage.renderedShortTitle || childPage.renderedFullTitle, + } + + // Recursively loop through the childPages and create each breadcrumb, until we reach the // point where the current siteTree page is the same as the requested page. Then stop. - if (childPage.childPages && context.currentPath !== childPage.href) { - createBreadcrumb(childPage.childPages, context) + if (childPage.childPages && currentPathWithoutLanguage !== childPage.href.slice(3)) { + return [ + breadcrumb, + ...(await getBreadcrumbs( + childPage.childPages, + fallbackChildPage.childPages, + currentPathWithoutLanguage, + intendedLanguage + )), + ] + } else { + return [breadcrumb] } }