64 lines
3.1 KiB
TypeScript
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)
|
|
})
|