I recently restructured a Sphinx documentation project by moving around a lot of files and arranging them into associated folders. This process changed the location urls of the existing documentation causing the old links to return 404s.
I used the sphinx-reredirects extension to handle redirects to the new location of the documentation pages. This works fine for most of the URLs. However, URLs that contain fragments/anchors, for example: an old URL, https://example.com/docs#example1, would redirect to https://example.com/new-location/docs, losing the #example1 in the process. These fragments are very important as a lot of links to the docs scattered accross the internet contain fragments and removing them would cause the links to lose important context.
I have tried intercepting the redirect using JavaScript, but I can't seem to capture the URL that causes the redirect in my code before it happens.
// Function to capture and log the current URL
function logOldUrl() {
const oldUrl = window.location.href;
const hash = window.location.hash;
console.log("Old URL before redirect:", oldUrl, hash);
}
// Add an event listener to capture the URL before unloading the page
window.addEventListener("beforeunload", logOldUrl);
window.onload = logOldUrl;
// Optionally, listen for visibility changes to detect potential navigation changes
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
logOldUrl();
}
});
logOldUrl();
It keeps logging the new URL. Are there any events that Sphinx-reredirects
emits before a redirect happens or are there any other ways to tackle this issue?
In case anyone runs into this issue. A viable workaround would be writing a custom HTML redirect file for sphinx-reredirects and including a script that captures the fragment and appends it to url.
For example:
<!DOCTYPE html>
<html>
<head>
<noscript>
<meta http-equiv="refresh" content="0; url=${to_uri}" />
</noscript>
<script>
var target = "${to_uri}";
// If there's a URL hash, append it to the target URL
if (window.location.hash) {
window.location.replace(target + window.location.hash);
} else {
window.location.replace(target);
}
</script>
</head>
</html>
Note that you have to register your custom redirect template in your conf.py
.
UPDATE: Since my PR got merged, the HTML template above is sphinx-reredirects' default HTML template. Thus, fragments are now preserved out of the box.