aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/templates/assets/javascripts/integrations/version
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2023-10-07 06:48:07 +0800
committer简律纯 <i@jyunko.cn>2023-10-07 06:48:07 +0800
commit991fd7a6d67ee017c57beaaa21fc31c4bee7944d (patch)
treee895202203fcaa50b0052f60ef6fc7d6d2928cf9 /src/templates/assets/javascripts/integrations/version
parentd62900046bb6f754a8e6e7e670a66a90134055d9 (diff)
downloadinfini-991fd7a6d67ee017c57beaaa21fc31c4bee7944d.tar.gz
infini-991fd7a6d67ee017c57beaaa21fc31c4bee7944d.zip
feat(version): versions
Diffstat (limited to 'src/templates/assets/javascripts/integrations/version')
-rw-r--r--src/templates/assets/javascripts/integrations/version/.eslintrc5
-rw-r--r--src/templates/assets/javascripts/integrations/version/index.ts186
2 files changed, 191 insertions, 0 deletions
diff --git a/src/templates/assets/javascripts/integrations/version/.eslintrc b/src/templates/assets/javascripts/integrations/version/.eslintrc
new file mode 100644
index 00000000..38a5714d
--- /dev/null
+++ b/src/templates/assets/javascripts/integrations/version/.eslintrc
@@ -0,0 +1,5 @@
+{
+ "rules": {
+ "no-null/no-null": "off"
+ }
+}
diff --git a/src/templates/assets/javascripts/integrations/version/index.ts b/src/templates/assets/javascripts/integrations/version/index.ts
new file mode 100644
index 00000000..38d78f17
--- /dev/null
+++ b/src/templates/assets/javascripts/integrations/version/index.ts
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+import {
+ EMPTY,
+ Subject,
+ catchError,
+ combineLatest,
+ filter,
+ fromEvent,
+ map,
+ of,
+ switchMap,
+ withLatestFrom
+} from "rxjs"
+
+import { configuration } from "~/_"
+import {
+ getElement,
+ getLocation,
+ requestJSON,
+ setLocation
+} from "~/browser"
+import { getComponentElements } from "~/components"
+import {
+ Version,
+ renderVersionSelector
+} from "~/templates"
+
+import { fetchSitemap } from "../sitemap"
+
+/* ----------------------------------------------------------------------------
+ * Helper types
+ * ------------------------------------------------------------------------- */
+
+/**
+ * Setup options
+ */
+interface SetupOptions {
+ document$: Subject<Document> /* Document subject */
+}
+
+/* ----------------------------------------------------------------------------
+ * Functions
+ * ------------------------------------------------------------------------- */
+
+/**
+ * Set up version selector
+ *
+ * @param options - Options
+ */
+export function setupVersionSelector(
+ { document$ }: SetupOptions
+): void {
+ const config = configuration()
+ const versions$ = requestJSON<Version[]>(
+ new URL("../versions.json", config.base)
+ )
+ .pipe(
+ catchError(() => EMPTY) // @todo refactor instant loading
+ )
+
+ /* Determine current version */
+ const current$ = versions$
+ .pipe(
+ map(versions => {
+ const [, current] = config.base.match(/([^/]+)\/?$/)!
+ return versions.find(({ version, aliases }) => (
+ version === current || aliases.includes(current)
+ )) || versions[0]
+ })
+ )
+
+ /* Intercept inter-version navigation */
+ versions$
+ .pipe(
+ map(versions => new Map(versions.map(version => [
+ `${new URL(`../${version.version}/`, config.base)}`,
+ version
+ ]))),
+ switchMap(urls => fromEvent<MouseEvent>(document.body, "click")
+ .pipe(
+ filter(ev => !ev.metaKey && !ev.ctrlKey),
+ withLatestFrom(current$),
+ switchMap(([ev, current]) => {
+ if (ev.target instanceof Element) {
+ const el = ev.target.closest("a")
+ if (el && !el.target && urls.has(el.href)) {
+ const url = el.href
+ // This is a temporary hack to detect if a version inside the
+ // version selector or on another part of the site was clicked.
+ // If we're inside the version selector, we definitely want to
+ // find the same page, as we might have different deployments
+ // due to aliases. However, if we're outside the version
+ // selector, we must abort here, because we might otherwise
+ // interfere with instant navigation. We need to refactor this
+ // at some point together with instant navigation.
+ //
+ // See https://github.com/squidfunk/mkdocs-material/issues/4012
+ if (!ev.target.closest(".md-version")) {
+ const version = urls.get(url)!
+ if (version === current)
+ return EMPTY
+ }
+ ev.preventDefault()
+ return of(url)
+ }
+ }
+ return EMPTY
+ }),
+ switchMap(url => {
+ const { version } = urls.get(url)!
+ return fetchSitemap(new URL(url))
+ .pipe(
+ map(sitemap => {
+ const location = getLocation()
+ const path = location.href.replace(config.base, "")
+ return sitemap.includes(path.split("#")[0])
+ ? new URL(`../${version}/${path}`, config.base)
+ : new URL(url)
+ })
+ )
+ })
+ )
+ )
+ )
+ .subscribe(url => setLocation(url, true))
+
+ /* Render version selector and warning */
+ combineLatest([versions$, current$])
+ .subscribe(([versions, current]) => {
+ const topic = getElement(".md-header__topic")
+ topic.appendChild(renderVersionSelector(versions, current))
+ })
+
+ /* Integrate outdated version banner with instant navigation */
+ document$.pipe(switchMap(() => current$))
+ .subscribe(current => {
+
+ /* Check if version state was already determined */
+ let outdated = __md_get("__outdated", sessionStorage)
+ if (outdated === null) {
+ outdated = true
+
+ /* Obtain and normalize default versions */
+ let ignored = config.version?.default || "latest"
+ if (!Array.isArray(ignored))
+ ignored = [ignored]
+
+ /* Check if version is considered a default */
+ main: for (const ignore of ignored)
+ for (const alias of current.aliases)
+ if (new RegExp(ignore, "i").test(alias)) {
+ outdated = false
+ break main
+ }
+
+ /* Persist version state in session storage */
+ __md_set("__outdated", outdated, sessionStorage)
+ }
+
+ /* Unhide outdated version banner */
+ if (outdated)
+ for (const warning of getComponentElements("outdated"))
+ warning.hidden = false
+ })
+}