1 // Local js definitions:
2 /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
3 /* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
4 /* global MAIN_ID, getVar, getSettingsButton */
9 const isSettingsPage = window.location.pathname.endsWith("/settings.html");
11 function changeSetting(settingName, value) {
12 updateLocalStorage(settingName, value);
14 switch (settingName) {
16 case "preferred-dark-theme":
17 case "preferred-light-theme":
18 case "use-system-theme":
24 window.rustdoc_add_line_numbers_to_examples();
26 window.rustdoc_remove_line_numbers_from_examples();
32 function handleKey(ev) {
33 // Don't interfere with browser shortcuts
34 if (ev.ctrlKey || ev.altKey || ev.metaKey) {
37 switch (getVirtualKey(ev)) {
41 ev.target.checked = !ev.target.checked;
47 function showLightAndDark() {
48 addClass(document.getElementById("theme").parentElement, "hidden");
49 removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
50 removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
53 function hideLightAndDark() {
54 addClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
55 addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
56 removeClass(document.getElementById("theme").parentElement, "hidden");
59 function updateLightAndDark() {
60 if (getSettingValue("use-system-theme") !== "false") {
67 function setEvents(settingsElement) {
69 onEachLazy(settingsElement.getElementsByClassName("slider"), elem => {
70 const toggle = elem.previousElementSibling;
71 const settingId = toggle.id;
72 const settingValue = getSettingValue(settingId);
73 if (settingValue !== null) {
74 toggle.checked = settingValue === "true";
76 toggle.onchange = function() {
77 changeSetting(this.id, this.checked);
79 toggle.onkeyup = handleKey;
80 toggle.onkeyrelease = handleKey;
82 onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => {
83 const select = elem.getElementsByTagName("select")[0];
84 const settingId = select.id;
85 const settingValue = getSettingValue(settingId);
86 if (settingValue !== null) {
87 select.value = settingValue;
89 select.onchange = function() {
90 changeSetting(this.id, this.value);
93 onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
94 const settingId = elem.name;
95 const settingValue = getSettingValue(settingId);
96 if (settingValue !== null && settingValue !== "null") {
97 elem.checked = settingValue === elem.value;
99 elem.addEventListener("change", ev => {
100 changeSetting(ev.target.name, ev.target.value);
106 * This function builds the sections inside the "settings page". It takes a `settings` list
107 * as argument which describes each setting and how to render it. It returns a string
108 * representing the raw HTML.
110 * @param {Array<Object>} settings
114 function buildSettingsPageSections(settings) {
117 for (const setting of settings) {
118 output += "<div class=\"setting-line\">";
119 const js_data_name = setting["js_name"];
120 const setting_name = setting["name"];
122 if (setting["options"] !== undefined) {
123 // This is a select setting.
124 output += `<div class="radio-line" id="${js_data_name}">\
125 <span class="setting-name">${setting_name}</span>\
126 <div class="choices">`;
127 onEach(setting["options"], option => {
128 const checked = option === setting["default"] ? " checked" : "";
130 output += `<label for="${js_data_name}-${option}" class="choice">\
131 <input type="radio" name="${js_data_name}" \
132 id="${js_data_name}-${option}" value="${option}"${checked}>\
133 <span>${option}</span>\
136 output += "</div></div>";
139 const checked = setting["default"] === true ? " checked" : "";
140 output += `<label class="toggle">\
141 <input type="checkbox" id="${js_data_name}"${checked}>\
142 <span class="slider"></span>\
143 <span class="label">${setting_name}</span>\
152 * This function builds the "settings page" and returns the generated HTML element.
154 * @return {HTMLElement}
156 function buildSettingsPage() {
157 const themes = getVar("themes").split(",");
160 "name": "Use system theme",
161 "js_name": "use-system-theme",
171 "name": "Preferred light theme",
172 "js_name": "preferred-light-theme",
177 "name": "Preferred dark theme",
178 "js_name": "preferred-dark-theme",
183 "name": "Auto-hide item contents for large items",
184 "js_name": "auto-hide-large-items",
188 "name": "Auto-hide item methods' documentation",
189 "js_name": "auto-hide-method-docs",
193 "name": "Auto-hide trait implementation documentation",
194 "js_name": "auto-hide-trait-implementations",
198 "name": "Directly go to item in search if there is only one result",
199 "js_name": "go-to-only-result",
203 "name": "Show line numbers on code examples",
204 "js_name": "line-numbers",
208 "name": "Disable keyboard shortcuts",
209 "js_name": "disable-shortcuts",
214 // Then we build the DOM.
215 const elementKind = isSettingsPage ? "section" : "div";
216 const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
217 const el = document.createElement(elementKind);
219 if (!isSettingsPage) {
220 el.className = "popover";
222 el.innerHTML = innerHTML;
224 if (isSettingsPage) {
225 document.getElementById(MAIN_ID).appendChild(el);
227 el.setAttribute("tabindex", "-1");
228 getSettingsButton().appendChild(el);
233 const settingsMenu = buildSettingsPage();
235 function displaySettings() {
236 settingsMenu.style.display = "";
239 function settingsBlurHandler(event) {
240 blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
243 if (isSettingsPage) {
244 // We replace the existing "onclick" callback to do nothing if clicked.
245 getSettingsButton().onclick = function(event) {
246 event.preventDefault();
249 // We replace the existing "onclick" callback.
250 const settingsButton = getSettingsButton();
251 const settingsMenu = document.getElementById("settings");
252 settingsButton.onclick = function(event) {
253 if (elemIsInParent(event.target, settingsMenu)) {
256 event.preventDefault();
257 const shouldDisplaySettings = settingsMenu.style.display === "none";
259 window.hidePopoverMenus();
260 if (shouldDisplaySettings) {
264 settingsButton.onblur = settingsBlurHandler;
265 settingsButton.querySelector("a").onblur = settingsBlurHandler;
266 onEachLazy(settingsMenu.querySelectorAll("input"), el => {
267 el.onblur = settingsBlurHandler;
269 settingsMenu.onblur = settingsBlurHandler;
272 // We now wait a bit for the web browser to end re-computing the DOM...
274 setEvents(settingsMenu);
275 // The setting menu is already displayed if we're on the settings page.
276 if (!isSettingsPage) {
279 removeClass(getSettingsButton(), "rotate");