Skip to content

Commit d86b829

Browse files
Add version switcher script for std docs
1 parent 57ee5cf commit d86b829

File tree

3 files changed

+221
-0
lines changed

3 files changed

+221
-0
lines changed

src/bootstrap/doc.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,13 +430,23 @@ impl Step for Std {
430430
t!(fs::create_dir_all(&out));
431431
t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
432432

433+
let content = fs::read_to_string(builder.src.join("src/doc/version-switcher.js")).unwrap();
434+
fs::write(
435+
out.join("version-switcher.js"),
436+
content.replace("/* VERSION TO BE REPLACED */", &builder.version),
437+
)
438+
.unwrap();
439+
433440
let index_page = builder.src.join("src/doc/index.md").into_os_string();
441+
let switcher_script = builder.src.join("src/doc/switcher.inc").into_os_string();
434442
let mut extra_args = vec![
435443
OsStr::new("--markdown-css"),
436444
OsStr::new("rust.css"),
437445
OsStr::new("--markdown-no-toc"),
438446
OsStr::new("--index-page"),
439447
&index_page,
448+
OsStr::new("--html-in-header"),
449+
&switcher_script,
440450
];
441451

442452
if !builder.config.docs_minification {

src/doc/switcher.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<script defer src='https://doc.rust-lang.org/version-switcher.js'></script>

src/doc/version-switcher.js

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
const CURRENT_VERSION = "/* VERSION TO BE REPLACED */";
2+
3+
function checkIfIsOldVersion() {
4+
if (["http:", "https:"].indexOf(window.location.protocol) === -1) {
5+
return;
6+
}
7+
const parts = window.location.pathname.split("/");
8+
9+
return parts.length > 1 && parts[1].indexOf(".") !== -1 && parts[1] !== CURRENT_VERSION;
10+
}
11+
12+
function createOption(text, isDefault) {
13+
const option = document.createElement("option");
14+
option.value = text;
15+
option.innerText = text;
16+
if (isDefault) {
17+
option.selected = true;
18+
}
19+
return option;
20+
}
21+
22+
function addStyle(css) {
23+
const style = document.createElement("style");
24+
style.type = "text/css";
25+
style.appendChild(document.createTextNode(css));
26+
27+
document.head.appendChild(style);
28+
}
29+
30+
function setupStyleFor59(rustdoc_container) {
31+
// nothing to do in here!
32+
}
33+
34+
function setupStyleFor32(rustdoc_container, switcherEl, extraStyle) {
35+
document.body.style.padding = "0";
36+
rustdoc_container.style.position = "relative";
37+
rustdoc_container.style.padding = "0 15px 20px 15px";
38+
39+
addStyle(`@media (min-width: 701px) {
40+
.rustdoc {
41+
padding: 10px 15px 20px 15px !important;
42+
}
43+
#switch-version-filler {
44+
display: block !important;
45+
left: 0 !important;
46+
}
47+
}
48+
49+
.sidebar.mobile {
50+
top: 0 !important;
51+
}
52+
${extraStyle}`);
53+
54+
// We also need to create a "cosmetic" element to not have a weird empty space above the
55+
// sidebar.
56+
const filler = document.createElement("div");
57+
filler.style.position = "fixed";
58+
filler.style.top = "0";
59+
filler.style.bottom = "0";
60+
filler.style.zIndex = "-1";
61+
filler.style.display = "none";
62+
filler.id = "switch-version-filler";
63+
document.body.appendChild(filler);
64+
65+
function changeSidebarTop() {
66+
const height = switcherEl.getBoundingClientRect().height;
67+
const sidebar = document.querySelector(".sidebar");
68+
sidebar.style.top = height + 1 + "px";
69+
}
70+
setTimeout(() => {
71+
const sidebar = window.getComputedStyle(document.querySelector(".sidebar"));
72+
filler.style.width = sidebar.width;
73+
filler.style.backgroundColor = sidebar.backgroundColor;
74+
changeSidebarTop();
75+
}, 0); // it'll be computed once it's added in the DOM.
76+
window.addEventListener("resize", changeSidebarTop);
77+
}
78+
79+
function setupStyleFor22(rustdoc_container, switcherEl) {
80+
// It's mostly the same as `setupStyleFor32` so we call it and make the extra changes afterward.
81+
setupStyleFor32(rustdoc_container, switcherEl, `@media (max-width: 700px) {
82+
.sidebar {
83+
height: 45px;
84+
min-height: 40px;
85+
margin: 0;
86+
margin-left: -15px;
87+
padding: 0 15px;
88+
position: static;
89+
z-index: 1;
90+
}
91+
}`);
92+
}
93+
94+
function setupStyleFor21(rustdoc_container, switcherEl) {
95+
// It's mostly the same as `setupStyleFor22` so we call it and make the extra changes afterward.
96+
document.body.style.padding = "0";
97+
98+
const css = `.rustdoc {
99+
padding: 10px 15px 20px 15px !important;
100+
}`;
101+
addStyle(css);
102+
103+
function changeSidebarTop() {
104+
const height = switcherEl.getBoundingClientRect().height;
105+
const sidebar = document.querySelector(".sidebar");
106+
sidebar.style.top = height + 1 + "px";
107+
}
108+
setTimeout(() => {
109+
const sidebar = window.getComputedStyle(document.querySelector(".sidebar"));
110+
changeSidebarTop();
111+
}, 0); // it'll be computed once it's added in the DOM.
112+
window.addEventListener("resize", changeSidebarTop);
113+
}
114+
115+
function getHtmlForSwitcher(isOldVersion, switcher_container) {
116+
if (!isOldVersion) {
117+
switcher_container.style.color = "#eee";
118+
return "You can pick a different version with this dropdown:&nbsp;";
119+
}
120+
121+
switcher_container.style.color = "#e57300";
122+
123+
addStyle(`#doc-version-switcher svg {
124+
width: 1em;
125+
height: 1em;
126+
fill: currentColor;
127+
padding-top: 0.1em;
128+
}`);
129+
130+
const warning_img = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">\
131+
<path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 \
132+
0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 \
133+
416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 \
134+
46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 \
135+
11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-\
136+
11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>&nbsp;`;
137+
return warning_img + "You are seeing an outdated version of this documentation. " +
138+
"Click on the dropdown to go to the latest stable version:&nbsp;";
139+
}
140+
141+
function showSwitcher(isOldVersion) {
142+
const el = document.createElement("div");
143+
144+
el.style.borderBottom = "1px solid #bbb";
145+
el.style.fontSize = "1.1em";
146+
el.style.padding = "4px";
147+
el.style.background = "#111";
148+
el.style.width = "100%";
149+
el.id = "doc-version-switcher";
150+
151+
const parts = window.location.pathname.split("/");
152+
parts[1] = "stable";
153+
const url = parts.join("/");
154+
155+
const current_doc_version = window.location.pathname.split("/")[1];
156+
const version_picker = document.createElement("select");
157+
158+
version_picker.appendChild(createOption("stable", false));
159+
version_picker.appendChild(createOption("beta", false));
160+
version_picker.appendChild(createOption("nightly", false));
161+
162+
const version_parts = CURRENT_VERSION.split(".");
163+
for (let major = parseInt(version_parts[0]); major >= 1; --major) {
164+
for (let medium = parseInt(version_parts[1]); medium >= 0; --medium) {
165+
const version = `${major}.${medium}.0`;
166+
version_picker.appendChild(createOption(version, version === current_doc_version));
167+
}
168+
}
169+
170+
version_picker.style.color = "#000";
171+
version_picker.onchange = (event) => {
172+
const url_parts = window.location.pathname.split("/");
173+
url_parts[1] = event.target.value;
174+
window.location.href = url_parts.join("/");
175+
};
176+
177+
const span = document.createElement("span");
178+
span.innerHTML = getHtmlForSwitcher(isOldVersion, el);
179+
span.appendChild(version_picker);
180+
181+
el.appendChild(span);
182+
183+
const rustdoc_container = document.createElement("div");
184+
185+
let medium_version = current_doc_version.split(".").slice(1, 2);
186+
if (medium_version.length === 0) {
187+
medium_version = ["-1"];
188+
}
189+
medium_version = parseInt(medium_version[0]);
190+
if (medium_version < 0 || medium_version > 58) {
191+
setupStyleFor59(rustdoc_container, el);
192+
} else if (medium_version > 31) {
193+
setupStyleFor32(rustdoc_container, el, "");
194+
} else if (medium_version > 21) {
195+
setupStyleFor22(rustdoc_container, el);
196+
} else {
197+
setupStyleFor21(rustdoc_container, el);
198+
}
199+
200+
rustdoc_container.className = document.body.className;
201+
document.body.className = "";
202+
while (document.body.childNodes.length > 0) {
203+
rustdoc_container.appendChild(document.body.childNodes[0]);
204+
}
205+
206+
document.body.appendChild(el);
207+
document.body.appendChild(rustdoc_container);
208+
}
209+
210+
showSwitcher(checkIfIsOldVersion());

0 commit comments

Comments
 (0)