* Add failing breadcrumb test for paths with partial match * Handle overlapping paths when creating breadcrumbs
104 lines
3.5 KiB
JavaScript
104 lines
3.5 KiB
JavaScript
export default async function breadcrumbs(req, res, next) {
|
|
if (!req.context.page) return next()
|
|
if (req.context.page.hidden) return next()
|
|
|
|
req.context.breadcrumbs = []
|
|
|
|
// Return an empty array on the landing page.
|
|
if (req.context.page.documentType === 'homepage') {
|
|
return next()
|
|
}
|
|
|
|
const currentSiteTree =
|
|
req.context.siteTree[req.context.currentLanguage][req.context.currentVersion]
|
|
const fallbackSiteTree = req.context.siteTree.en[req.context.currentVersion]
|
|
|
|
req.context.breadcrumbs = await getBreadcrumbs(
|
|
// Array of child pages on the root, i.e., the product level.
|
|
currentSiteTree.childPages,
|
|
fallbackSiteTree.childPages,
|
|
req.context.currentPath.slice(3),
|
|
req.context.currentLanguage
|
|
)
|
|
|
|
return next()
|
|
}
|
|
|
|
async function getBreadcrumbs(
|
|
pageArray,
|
|
fallbackPageArray,
|
|
currentPathWithoutLanguage,
|
|
intendedLanguage
|
|
) {
|
|
// Find the page that starts with the requested path
|
|
let childPage = findPageWithPath(currentPathWithoutLanguage, pageArray)
|
|
|
|
// Find the page in the fallback page array (likely the English sub-tree)
|
|
const fallbackChildPage =
|
|
findPageWithPath(currentPathWithoutLanguage, fallbackPageArray || []) || childPage
|
|
|
|
// No matches, we bail
|
|
if (!childPage && !fallbackChildPage) {
|
|
return []
|
|
}
|
|
|
|
// Didn't find the intended page, but found the fallback
|
|
if (!childPage) {
|
|
childPage = fallbackChildPage
|
|
}
|
|
|
|
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 && currentPathWithoutLanguage !== childPage.href.slice(3)) {
|
|
return [
|
|
breadcrumb,
|
|
...(await getBreadcrumbs(
|
|
childPage.childPages,
|
|
fallbackChildPage.childPages,
|
|
currentPathWithoutLanguage,
|
|
intendedLanguage
|
|
)),
|
|
]
|
|
} else {
|
|
return [breadcrumb]
|
|
}
|
|
}
|
|
|
|
// Finds the page that starts with or equals the requested path in the array of
|
|
// pages e.g. if the current page is /actions/learn-github-actions/understanding-github-actions,
|
|
// depending on the pages in the pageArray agrument, would find:
|
|
//
|
|
// * /actions
|
|
// * /actions/learn-github-actions
|
|
// * /actions/learn-github-actions/understanding-github-actions
|
|
function findPageWithPath(pageToFind, pageArray) {
|
|
return pageArray.find((page) => {
|
|
const pageWithoutLanguage = page.href.slice(3)
|
|
const numPathSegments = pageWithoutLanguage.split('/').length
|
|
const pageToFindNumPathSegments = pageToFind.split('/').length
|
|
|
|
if (pageToFindNumPathSegments > numPathSegments) {
|
|
// if the current page to find has more path segments, add a trailing
|
|
// slash to the page comparison to avoid an overlap like:
|
|
//
|
|
// * /github-cli/github-cli/about-github-cli with /github
|
|
return pageToFind.startsWith(`${pageWithoutLanguage}/`)
|
|
} else if (pageToFindNumPathSegments === numPathSegments) {
|
|
// if the current page has the same number of path segments, only match
|
|
// if the paths are the same to avoid an overlap like:
|
|
//
|
|
// * /get-started/using-github with /get-started/using-git
|
|
return pageToFind === pageWithoutLanguage
|
|
} else {
|
|
return false
|
|
}
|
|
})
|
|
}
|