1
0
mirror of synced 2025-12-23 03:44:00 -05:00
Files
docs/middleware/contextualizers/current-product-tree.js
2023-07-11 11:44:52 +00:00

140 lines
4.7 KiB
JavaScript

import path from 'path'
import { liquid } from '#src/content-render/index.js'
import findPageInSiteTree from '../../lib/find-page-in-site-tree.js'
import removeFPTFromPath from '../../lib/remove-fpt-from-path.js'
import { executeWithFallback } from '../../lib/render-with-fallback.js'
// This module adds currentProductTree to the context object for use in layouts.
export default async function currentProductTree(req, res, next) {
if (!req.context.page) return next()
if (req.context.page.documentType === 'homepage') return next()
// We need this so we can fall back to English if localized pages are out of sync.
req.context.currentEnglishTree = req.context.siteTree.en[req.context.currentVersion]
const currentRootTree =
req.context.siteTree[req.context.currentLanguage][req.context.currentVersion]
const currentProductPath = removeFPTFromPath(
path.posix.join(
'/',
req.context.currentLanguage,
req.context.currentVersion,
req.context.currentProduct,
),
)
req.context.currentProductTree = findPageInSiteTree(
currentRootTree,
req.context.currentEnglishTree,
currentProductPath,
)
// First make a slim tree of just the 'href', 'title', 'shortTitle'
// 'documentType' and 'childPages' (which is recursive).
// This gets used for map topic and category pages.
req.context.currentProductTreeTitles = await getCurrentProductTreeTitles(
req.context.currentProductTree,
req.context,
)
// Now make an even slimmer version that excludes all hidden pages.
// This is i used for sidebars.
req.context.currentProductTreeTitlesExcludeHidden = excludeHidden(
req.context.currentProductTreeTitles,
)
// Some pages, like hidden pages, don't have a tree. For example,
// the search page. That one uses the same items as the homepage
// for its sidebar.
if (req.context.currentProductTreeTitlesExcludeHidden) {
req.context.sidebarTree = sidebarTree(req.context.currentProductTreeTitlesExcludeHidden)
}
return next()
}
// Return a nested object that contains the bits and pieces we need
// for the tree which is used for sidebars and listing
async function getCurrentProductTreeTitles(input, context) {
const { page, href } = input
const childPages = await Promise.all(
(input.childPages || []).map((child) => getCurrentProductTreeTitles(child, context)),
)
// If the current page is a translation we're going to need the English
// equivalent for multiple things later in this function.
const enPage =
page.languageCode !== 'en' ? context.pages[href.replace(`/${page.languageCode}`, '/en')] : null
let rawShortTitle = page.rawShortTitle // might change our minds about this
// A lot of translations have a short title that is identical to the
// English equivalent. E.g.
//
// content/foo.md:
//
// title: Something Something Bla
// shortTitle: Something
//
// translations/docs-internal.se-sv/content/foo.md:
//
// title: Nånting Nånting Blä
// shortTitle: Something
//
// I.e. the translations `shortTitle` hasn't been translated.
// If this is the case, use the long title instead.
if (page.languageCode !== 'en' && page.rawShortTitle) {
if (page.rawShortTitle === enPage.shortTitle) {
rawShortTitle = page.rawTitle
}
}
const renderedFullTitle = await executeWithFallback(
context,
() => liquid.parseAndRender(page.rawTitle, context),
(enContext) => liquid.parseAndRender(enPage.rawTitle, enContext),
)
let renderedShortTitle = ''
if (rawShortTitle) {
renderedShortTitle = await executeWithFallback(
context,
() => liquid.parseAndRender(page.rawShortTitle, context),
(enContext) => liquid.parseAndRender(enPage.rawShortTitle, enContext),
)
}
// If the short title was present but "useless" (same as the title),
// force it to be an empty string to not waste space.
const shortTitle =
renderedShortTitle && (renderedShortTitle || '') !== renderedFullTitle ? renderedShortTitle : ''
const node = {
href: input.href,
title: renderedFullTitle,
shortTitle,
documentType: page.documentType,
childPages: childPages.filter(Boolean),
}
if (page.hidden) node.hidden = true
return node
}
function excludeHidden(tree) {
if (tree.hidden) return null
const newTree = {
href: tree.href,
title: tree.title,
shortTitle: tree.shortTitle,
documentType: tree.documentType,
childPages: tree.childPages.map(excludeHidden).filter(Boolean),
}
return newTree
}
function sidebarTree(tree) {
const { href, title, shortTitle, childPages } = tree
const childChildPages = childPages.map(sidebarTree)
const newTree = {
href,
title: shortTitle || title,
childPages: childChildPages,
}
return newTree
}