Skip to content
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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,21 @@ impl Step for Std {
t!(fs::create_dir_all(&out));
t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));

t!(fs::copy(
builder.src.join("src/doc/version-switcher.js"),
out.join("version-switcher.js")
));

let index_page = builder.src.join("src/doc/index.md").into_os_string();
let switcher_script = builder.src.join("src/doc/switcher.inc").into_os_string();
let mut extra_args = vec![
OsStr::new("--markdown-css"),
OsStr::new("rust.css"),
OsStr::new("--markdown-no-toc"),
OsStr::new("--index-page"),
&index_page,
OsStr::new("--html-in-header"),
&switcher_script,
];

if !builder.config.docs_minification {
Expand Down
1 change: 1 addition & 0 deletions src/doc/switcher.inc
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>
269 changes: 269 additions & 0 deletions src/doc/version-switcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
(function() {

let CURRENT_VERSION = -1;
Copy link
Member

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.


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
Copy link
Member

Choose a reason for hiding this comment

The 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 https://blog.rust-lang.org/releases.json and extract the number from the title or URL.

}

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:&nbsp;";
}

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>&nbsp;`;
return warning_img + "You are seeing an outdated version of this documentation. " +
"Click on the dropdown to go to the latest stable version:&nbsp;";
Copy link
Member

Choose a reason for hiding this comment

The 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());

}());