-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add version switcher script for std docs #101855
Changes from all commits
d86b829
810dc9b
96c2982
b174ed1
74af1af
7e37ea1
d8aff43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<script defer src='https://dev-doc.rust-lang.org/nightly/version-switcher.js'></script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
(function() { | ||
|
||
let CURRENT_VERSION = -1; | ||
|
||
function get_current_version() { | ||
if (CURRENT_VERSION !== -1) { | ||
return CURRENT_VERSION; | ||
} | ||
const now = Date.now(); | ||
// Month is 0-indexed. | ||
// First release of Rust, 15 may 2015. | ||
const first_release = new Date(2015, 4, 15); | ||
const diff_time = Math.abs(now - first_release); | ||
const nb_days = Math.ceil(diff_time / (1000 * 60 * 60 * 24)); | ||
const nb_weeks = nb_days / 7; | ||
CURRENT_VERSION = Math.floor(nb_weeks / 6); | ||
return CURRENT_VERSION; | ||
Comment on lines
+6
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't account for patch versions. Also, it seems fragile to compute the version from the date. E.g., what if for some reason Rust had to skip or delay a release? I think a decent solution would be to use |
||
} | ||
|
||
function checkIfIsOldVersion() { | ||
if (["http:", "https:"].indexOf(window.location.protocol) === -1) { | ||
return false; | ||
} | ||
const parts = window.location.pathname.split("/"); | ||
|
||
return parts.length > 1 && parts[1].indexOf(".") !== -1 && parts[1] !== CURRENT_VERSION; | ||
} | ||
|
||
function createOption(text, isDefault) { | ||
const option = document.createElement("option"); | ||
option.value = text; | ||
option.innerText = text; | ||
if (isDefault) { | ||
option.selected = true; | ||
} | ||
return option; | ||
} | ||
|
||
function addStyle(css) { | ||
const style = document.createElement("style"); | ||
style.type = "text/css"; | ||
style.appendChild(document.createTextNode(css)); | ||
|
||
document.head.appendChild(style); | ||
} | ||
|
||
function setupStyleFor60(rustdoc_container, switcherEl) { | ||
function changeSidebarTop() { | ||
const height = switcherEl.getBoundingClientRect().height; | ||
const sidebarTopbar = document.querySelector(".mobile-topbar"); | ||
const sidebarTopbarHeight = sidebarTopbar.getBoundingClientRect().height; | ||
const sidebar = document.querySelector(".sidebar"); | ||
sidebar.style.top = height + sidebarTopbarHeight + 1 + "px"; | ||
} | ||
setTimeout(() => { | ||
changeSidebarTop(); | ||
}, 0); // it'll be computed once it's added in the DOM. | ||
window.addEventListener("resize", changeSidebarTop); | ||
} | ||
|
||
function setupStyleFor59(rustdoc_container, switcherEl) { | ||
function changeSidebarTop() { | ||
const height = switcherEl.getBoundingClientRect().height; | ||
document.body.marginTop = height + 1 + "px"; | ||
const sidebarButton = document.querySelector(".sidebar-menu"); | ||
const val = sidebarButton.getAttribute("old-top"); | ||
if (val === null) { | ||
// We update the position directly. | ||
sidebarButton.style.top = height + 1 + "px"; | ||
} else { | ||
// We update the attribute value. | ||
sidebarButton.setAttribute("old-top", height + 1 + "px"); | ||
} | ||
} | ||
setTimeout(() => { | ||
changeSidebarTop(); | ||
}, 0); // it'll be computed once it's added in the DOM. | ||
window.addEventListener("resize", changeSidebarTop); | ||
document.querySelector(".sidebar-menu").addEventListener("click", () => { | ||
const sidebarButton = document.querySelector(".sidebar-menu"); | ||
const val = sidebarButton.getAttribute("old-top"); | ||
if (val === null) { | ||
const height = switcherEl.getBoundingClientRect().height; | ||
sidebarButton.setAttribute("old-top", sidebarButton.style.top); | ||
sidebarButton.style.top = "0"; | ||
} else { | ||
sidebarButton.style.top = val; | ||
sidebarButton.removeAttribute("old-top"); | ||
} | ||
}); | ||
} | ||
|
||
function setupStyleFor32(rustdoc_container, switcherEl, extraStyle) { | ||
document.body.style.padding = "0"; | ||
rustdoc_container.style.position = "relative"; | ||
rustdoc_container.style.padding = "0 15px 20px 15px"; | ||
|
||
addStyle(`@media (min-width: 701px) { | ||
.rustdoc { | ||
padding: 10px 15px 20px 15px !important; | ||
} | ||
#switch-version-filler { | ||
display: block !important; | ||
left: 0 !important; | ||
} | ||
} | ||
|
||
.sidebar.mobile { | ||
top: 0 !important; | ||
} | ||
${extraStyle}`); | ||
|
||
// We also need to create a "cosmetic" element to not have a weird empty space above the | ||
// sidebar. | ||
const filler = document.createElement("div"); | ||
filler.style.position = "fixed"; | ||
filler.style.top = "0"; | ||
filler.style.bottom = "0"; | ||
filler.style.zIndex = "-1"; | ||
filler.style.display = "none"; | ||
filler.id = "switch-version-filler"; | ||
document.body.appendChild(filler); | ||
|
||
function changeSidebarTop() { | ||
const height = switcherEl.getBoundingClientRect().height; | ||
const sidebar = document.querySelector(".sidebar"); | ||
sidebar.style.top = height + 1 + "px"; | ||
} | ||
setTimeout(() => { | ||
const sidebar = window.getComputedStyle(document.querySelector(".sidebar")); | ||
filler.style.width = sidebar.width; | ||
filler.style.backgroundColor = sidebar.backgroundColor; | ||
changeSidebarTop(); | ||
}, 0); // it'll be computed once it's added in the DOM. | ||
window.addEventListener("resize", changeSidebarTop); | ||
} | ||
|
||
function setupStyleFor22(rustdoc_container, switcherEl) { | ||
// It's mostly the same as `setupStyleFor32` so we call it and make the extra changes afterward. | ||
setupStyleFor32(rustdoc_container, switcherEl, `@media (max-width: 700px) { | ||
.sidebar { | ||
height: 45px; | ||
min-height: 40px; | ||
margin: 0; | ||
margin-left: -15px; | ||
padding: 0 15px; | ||
position: static; | ||
z-index: 1; | ||
} | ||
}`); | ||
} | ||
|
||
function setupStyleFor21(rustdoc_container, switcherEl) { | ||
// It's mostly the same as `setupStyleFor22` so we call it and make the extra changes afterward. | ||
document.body.style.padding = "0"; | ||
|
||
const css = `.rustdoc { | ||
padding: 10px 15px 20px 15px !important; | ||
}`; | ||
addStyle(css); | ||
|
||
function changeSidebarTop() { | ||
const height = switcherEl.getBoundingClientRect().height; | ||
const sidebar = document.querySelector(".sidebar"); | ||
sidebar.style.top = height + 1 + "px"; | ||
} | ||
setTimeout(() => { | ||
changeSidebarTop(); | ||
}, 0); // it'll be computed once it's added in the DOM. | ||
window.addEventListener("resize", changeSidebarTop); | ||
} | ||
|
||
function getHtmlForSwitcher(isOldVersion, switcher_container) { | ||
if (!isOldVersion) { | ||
switcher_container.style.color = "#eee"; | ||
return "You can pick a different version with this dropdown: "; | ||
} | ||
|
||
switcher_container.style.color = "#e57300"; | ||
|
||
addStyle(`#doc-version-switcher svg { | ||
width: 1em; | ||
height: 1em; | ||
fill: currentColor; | ||
padding-top: 0.1em; | ||
}`); | ||
|
||
const warning_img = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">\ | ||
<path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 \ | ||
0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 \ | ||
416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 \ | ||
46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 \ | ||
11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-\ | ||
11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg> `; | ||
return warning_img + "You are seeing an outdated version of this documentation. " + | ||
"Click on the dropdown to go to the latest stable version: "; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a screenshot of what this warning looks like? I can't get it to show with the dev-doc since it's only for old versions. |
||
} | ||
|
||
function showSwitcher(isOldVersion) { | ||
const el = document.createElement("div"); | ||
|
||
el.style.borderBottom = "1px solid #bbb"; | ||
el.style.fontSize = "1.1em"; | ||
el.style.padding = "4px"; | ||
el.style.background = "#111"; | ||
el.style.width = "100%"; | ||
el.id = "doc-version-switcher"; | ||
|
||
const parts = window.location.pathname.split("/"); | ||
parts[1] = "stable"; | ||
const url = parts.join("/"); | ||
|
||
const current_doc_version = window.location.pathname.split("/")[1]; | ||
const version_picker = document.createElement("select"); | ||
|
||
version_picker.appendChild(createOption("nightly", current_doc_version === "nightly")); | ||
version_picker.appendChild(createOption("beta", current_doc_version === "beta")); | ||
version_picker.appendChild(createOption("stable", current_doc_version === "stable")); | ||
|
||
for (let medium = get_current_version(); medium >= 0; --medium) { | ||
const version = `1.${medium}.0`; | ||
version_picker.appendChild(createOption(version, version === current_doc_version)); | ||
} | ||
|
||
version_picker.style.color = "#000"; | ||
version_picker.onchange = (event) => { | ||
const url_parts = window.location.pathname.split("/"); | ||
url_parts[1] = event.target.value; | ||
window.location.href = url_parts.join("/"); | ||
}; | ||
|
||
const span = document.createElement("span"); | ||
span.innerHTML = getHtmlForSwitcher(isOldVersion, el); | ||
span.appendChild(version_picker); | ||
|
||
el.appendChild(span); | ||
|
||
const rustdoc_container = document.createElement("div"); | ||
|
||
let medium_version = current_doc_version.split(".").slice(1, 2); | ||
if (medium_version.length === 0) { | ||
medium_version = ["-1"]; | ||
} | ||
medium_version = parseInt(medium_version[0]); | ||
if (medium_version < 0 || medium_version > 59) { | ||
setupStyleFor60(rustdoc_container, el); | ||
} else if (medium_version > 58) { | ||
setupStyleFor59(rustdoc_container, el); | ||
} else if (medium_version > 31) { | ||
setupStyleFor32(rustdoc_container, el, ""); | ||
} else if (medium_version > 21) { | ||
setupStyleFor22(rustdoc_container, el); | ||
} else { | ||
setupStyleFor21(rustdoc_container, el); | ||
} | ||
|
||
rustdoc_container.className = document.body.className; | ||
document.body.className = ""; | ||
while (document.body.childNodes.length > 0) { | ||
rustdoc_container.appendChild(document.body.childNodes[0]); | ||
} | ||
|
||
document.body.appendChild(el); | ||
document.body.appendChild(rustdoc_container); | ||
} | ||
|
||
showSwitcher(checkIfIsOldVersion()); | ||
|
||
}()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like this should be null to be a better indication that it's a sentinel value.