Skip to content

Commit cadc60e

Browse files
committed
Fixes to "staying on the same page functionality"
This is squidfunk#7350 with the tests removed, as requested in squidfunk#7350 (comment) . I do urge you to reconsider and merge something like squidfunk#7350 (including the tests I wrote) instead. Without tests, I suspect this code will break like its [previous version did]( squidfunk@ceacfe5) . Once the code does break, it might be difficult to fix without tests. Even if other parts of the theme work without tests, and even if you aren't in love with how I set up the infrastructure in squidfunk#7350 or squidfunk#7338, I think this logic is complex enough to need tests to be maintainable. Again, I wouldn't be able to check this code's correctness without the tests that aren't included in this PR. Of course, this is your project to maintain, so do what works best for you. I just hope this bugfix helps. --------------------- Fixes squidfunk#7226 Additionally, this allows using the version switcher even if the website is published at a different URL than the `site_url`. In particular, the version switcher should now work locally when serving the site with `mike serve`.
1 parent af08110 commit cadc60e

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

docs/setup/setting-up-versioning.md

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ MkDocs implements this behavior by default, but there are a few caveats:
6464
- the [`site_url`][mkdocs.site_url] must be set correctly in `mkdocs.yml`.
6565
See the ["Publishing a new version"](#publishing-a-new-version) section for
6666
an example.
67-
- you must be viewing the site at that URL (and not locally, for example).
6867
- the redirect happens via JavaScript and there is no way to know which page you
6968
will be redirected to ahead of time.
7069

src/templates/assets/javascripts/integrations/version/correspondingPage.ts

+75-7
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,79 @@ export function selectedVersionCorrespondingURL(
2424
currentLocation,
2525
currentBaseURL}: CorrespondingURLParams
2626
): URL | undefined {
27-
const result = currentLocation.href.replace(
28-
currentBaseURL,
29-
selectedVersionBaseURL.href,
30-
)
31-
return selectedVersionSitemap.has(result.split("#")[0])
32-
? new URL(result)
33-
: undefined
27+
const current_path = (new URL(currentBaseURL)).pathname
28+
const currentRelativePath = stripPrefix(currentLocation.pathname, current_path)
29+
if (currentRelativePath === undefined) {
30+
return
31+
}
32+
const sitemapCommonPrefix = shortestCommonPrefix(selectedVersionSitemap.keys())
33+
if (!selectedVersionSitemap.has(sitemapCommonPrefix)) {
34+
// We could also check that `commonSitemapPrefix` ends in the canonical version,
35+
// similarly to https://github.com/squidfunk/mkdocs-material/pull/7227. However,
36+
// I don't believe that Mike/MkDocs ever generate sitemaps where it would matter
37+
return
38+
}
39+
40+
const potentialSitemapURL = new URL(currentRelativePath, sitemapCommonPrefix)
41+
if (!selectedVersionSitemap.has(potentialSitemapURL.href)) {
42+
return
43+
}
44+
45+
const result = new URL(currentRelativePath, selectedVersionBaseURL)
46+
result.hash = currentLocation.hash
47+
result.search = currentLocation.search
48+
return result
49+
}
50+
51+
// Basic string manipulation
52+
53+
/**
54+
*
55+
* @param s - string
56+
* @param prefix - prefix to strip
57+
*
58+
* @returns either the string with the prefix stripped or undefined if the
59+
* string did not begin with the prefix.
60+
*/
61+
export function stripPrefix(s: string, prefix: string): string | undefined {
62+
if (s.startsWith(prefix)) {
63+
return s.slice(prefix.length)
64+
}
65+
return undefined
66+
}
67+
68+
/**
69+
*
70+
* @param s1 - first string
71+
* @param s2 - second string
72+
*
73+
* @returns - the length of the longest common prefix of the two strings.
74+
*/
75+
function commonPrefixLen(s1: string, s2: string): number {
76+
const max = Math.min(s1.length, s2.length)
77+
let result
78+
for (result = 0; result < max; ++result) {
79+
if (s1[result] !== s2[result]) {
80+
break
81+
}
82+
}
83+
return result
84+
}
85+
86+
/**
87+
*
88+
* @param strs - an iterable of strings
89+
*
90+
* @returns the longest common prefix of all the strings
91+
*/
92+
export function shortestCommonPrefix(strs: Iterable<string>): string {
93+
let result // Undefined if no iterations happened
94+
for (const s of strs) {
95+
if (result === undefined) {
96+
result = s
97+
} else {
98+
result = result.slice(0, commonPrefixLen(result, s))
99+
}
100+
}
101+
return result ?? ""
34102
}

0 commit comments

Comments
 (0)