Files
mathew/frontend/app/middleware/open-article.ts
2026-10-01 02:29:21 +02:00

64 lines
3.1 KiB
TypeScript

/* Before a reader route draws anything — /wiki/<lang>/<slug> for one language
version of an article, /wiki/<slug> for whichever version a bare slug speaks
— put the document it names on the library's shelf. On the server that is
what lets the page in view be written out in the first HTML; on the client it
is what the stack of open pages grows from, and the title the page is filed
under. A page that is already on the shelf comes straight off it and is
re-read in the background — so an edit made elsewhere still shows up when you
turn to it.
This is also the one place that knows where a version lives: an article's
identity is the canonical version's slug, and a version's address is that
identity with its own language in front. So a short /wiki/<slug> address — a
wiki link, an old bookmark, a graph node — and a versioned one written with a
translation's stored slug are both turned onto /wiki/<lang>/<identity> before
anything renders. An address naming no language is turned onto the reader's
own version when the article speaks it — English as the wiki's common tongue
failing that — so opening an article opens it in the language you read the
wiki in, and only then in whatever version the slug itself speaks. An address
that does name a language is honoured as asked: that is how the version
switcher keeps its promise. The address being left behind never reaches the
history: the navigation to it is abandoned, not committed, so Back still
leads out of the reader to the page the link was pressed on. The address that
stays put is the one naming nothing: the route says for itself that the wiki
has no such article, and offers to write it. */
export default defineNuxtRouteMiddleware(async (to) => {
const loc = parseReaderPath(to.path)
if (!loc) return
/* taken before any await, while the app context is certainly at hand */
const library = useArticleLibrary()
const tabs = useArticleTabs()
const { locale } = useAppLocale()
const onShelf = loc.lang
? library.getVersion(loc.identity, loc.lang)
: library.get(loc.identity)
const article =
onShelf ??
(loc.lang
? await library.loadVersion(loc.identity, loc.lang)
: await library.load(loc.identity))
// nothing at this address: the route speaks its own emptiness
if (!article) return
/* every version answers to one address, whatever form it was asked with;
a short address picks the reader's version among the ones the article
speaks, English failing that, before its own document speaks for it */
const identity = identityOf(article)
let lang = articleLanguage(article)
if (!loc.lang) {
const spoken = (article.versions ?? []).map((v) => v.language)
lang = preferredLanguage(spoken, locale.value) ?? lang
}
if (loc.lang !== lang || loc.identity !== identity)
return navigateTo(versionHref(identity, lang), { redirectCode: 302 })
/* a page already open turns to this version instead of another being added
beside it: the article keeps its place in the book */
tabs.openVersion(article)
if (onShelf) library.revalidate(identity, lang)
})