Skip to content
5 changes: 1 addition & 4 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,6 @@ function preLoadCss(cssUrl) {
});
}());

// @ts-expect-error
window.rustdoc_add_line_numbers_to_examples = () => {
// @ts-expect-error
function generateLine(nb) {
Expand All @@ -1123,7 +1122,6 @@ function preLoadCss(cssUrl) {
});
};

// @ts-expect-error
window.rustdoc_remove_line_numbers_from_examples = () => {
onEachLazy(
document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"),
Expand All @@ -1132,7 +1130,6 @@ function preLoadCss(cssUrl) {
};

if (getSettingValue("line-numbers") === "true") {
// @ts-expect-error
window.rustdoc_add_line_numbers_to_examples();
}

Expand Down Expand Up @@ -1596,7 +1593,7 @@ function preLoadCss(cssUrl) {
/**
* Hide popover menus, clickable tooltips, and the sidebar (if applicable).
*
* Pass "true" to reset focus for tooltip popovers.
* Pass `true` to reset focus for tooltip popovers.
*/
window.hideAllModals = switchFocus => {
hideSidebar();
Expand Down
14 changes: 14 additions & 0 deletions src/librustdoc/html/static/js/rustdoc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ declare global {
currentCrate: string|null;
/**
* Hide popovers, tooltips, or the mobile sidebar.
*
* Pass `true` to reset focus for tooltip popovers.
*/
hideAllModals: function(boolean),
/**
Expand Down Expand Up @@ -78,6 +80,8 @@ declare global {
pending_implementors?: rustdoc.Implementors,
register_type_impls?: function(rustdoc.TypeImpls): void,
pending_type_impls?: rustdoc.TypeImpls,
rustdoc_add_line_numbers_to_examples?: function(),
rustdoc_remove_line_numbers_from_examples?: function(),
}
interface HTMLElement {
/** Used by the popover tooltip code. */
Expand Down Expand Up @@ -477,4 +481,14 @@ declare namespace rustdoc {
* is a tuple of (filename, subdirs, filenames).
*/
type Dir = [string, rustdoc.Dir[], string[]]

/**
* Indivitual setting object, used in `settings.js`
*/
interface Setting {
js_name: string,
name: string,
options?: string[],
default: string | boolean,
}
}
127 changes: 85 additions & 42 deletions src/librustdoc/html/static/js/settings.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
// Local js definitions:
/* global getSettingValue, updateLocalStorage, updateTheme */
/* global addClass, removeClass, onEach, onEachLazy */
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */

// Eventually fix this.
// @ts-nocheck
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton, nonnull */

"use strict";

(function() {
const isSettingsPage = window.location.pathname.endsWith("/settings.html");

/**
* @param {Element} elem
* @param {EventTarget|null} target
*/
function elemContainsTarget(elem, target) {
if (target instanceof Node) {
return elem.contains(target);
} else {
return false;
}
}

/**
* @overload {"theme"|"preferred-dark-theme"|"preferred-light-theme"}
* @param {string} settingName
* @param {string} value
* @returns
* @param {string} settingName
* @param {string|boolean} value
*/
function changeSetting(settingName, value) {
if (settingName === "theme") {
const useSystem = value === "system preference" ? "true" : "false";
updateLocalStorage("use-system-theme", useSystem);
}
updateLocalStorage(settingName, value);
updateLocalStorage(settingName, "" + value);

switch (settingName) {
case "theme":
Expand All @@ -27,9 +44,15 @@
break;
case "line-numbers":
if (value === true) {
window.rustdoc_add_line_numbers_to_examples();
const f = window.rustdoc_add_line_numbers_to_examples;
if (f !== undefined) {
f();
}
} else {
window.rustdoc_remove_line_numbers_from_examples();
const f = window.rustdoc_remove_line_numbers_from_examples;
if (f !== undefined) {
f();
}
}
break;
case "hide-sidebar":
Expand Down Expand Up @@ -89,6 +112,9 @@
}
}

/**
* @param {HTMLElement} settingsElement
*/
function setEvents(settingsElement) {
updateLightAndDark();
onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"), toggle => {
Expand All @@ -101,43 +127,42 @@
changeSetting(toggle.id, toggle.checked);
};
});
onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
const settingId = elem.name;
let settingValue = getSettingValue(settingId);
if (settingId === "theme") {
const useSystem = getSettingValue("use-system-theme");
if (useSystem === "true" || settingValue === null) {
// "light" is the default theme
settingValue = useSystem === "false" ? "light" : "system preference";
onEachLazy(
settingsElement.querySelectorAll("input[type=\"radio\"]"),
/** @param {HTMLInputElement} elem */
elem => {
const settingId = elem.name;
let settingValue = getSettingValue(settingId);
if (settingId === "theme") {
const useSystem = getSettingValue("use-system-theme");
if (useSystem === "true" || settingValue === null) {
// "light" is the default theme
settingValue = useSystem === "false" ? "light" : "system preference";
}
}
}
if (settingValue !== null && settingValue !== "null") {
elem.checked = settingValue === elem.value;
}
elem.addEventListener("change", ev => {
changeSetting(ev.target.name, ev.target.value);
});
});
if (settingValue !== null && settingValue !== "null") {
elem.checked = settingValue === elem.value;
}
elem.addEventListener("change", () => {
changeSetting(elem.name, elem.value);
});
},
);
}

/**
* This function builds the sections inside the "settings page". It takes a `settings` list
* as argument which describes each setting and how to render it. It returns a string
* representing the raw HTML.
*
* @param {Array<Object>} settings
* @param {Array<rustdoc.Setting>} settings
*
* @return {string}
*/
function buildSettingsPageSections(settings) {
let output = "";

for (const setting of settings) {
if (setting === "hr") {
output += "<hr>";
continue;
}

const js_data_name = setting["js_name"];
const setting_name = setting["name"];

Expand Down Expand Up @@ -182,7 +207,9 @@
* @return {HTMLElement}
*/
function buildSettingsPage() {
const theme_names = getVar("themes").split(",").filter(t => t);
const theme_list = getVar("themes");
const theme_names = (theme_list === null ? "" : theme_list)
.split(",").filter(t => t);
theme_names.push("light", "dark", "ayu");

const settings = [
Expand Down Expand Up @@ -272,10 +299,16 @@
el.innerHTML = innerHTML;

if (isSettingsPage) {
document.getElementById(MAIN_ID).appendChild(el);
const mainElem = document.getElementById(MAIN_ID);
if (mainElem !== null) {
mainElem.appendChild(el);
}
} else {
el.setAttribute("tabindex", "-1");
getSettingsButton().appendChild(el);
const settingsBtn = getSettingsButton();
if (settingsBtn !== null) {
settingsBtn.appendChild(el);
}
}
return el;
}
Expand All @@ -293,34 +326,44 @@
});
}

/**
* @param {FocusEvent} event
*/
function settingsBlurHandler(event) {
if (!getHelpButton().contains(document.activeElement) &&
!getHelpButton().contains(event.relatedTarget) &&
!getSettingsButton().contains(document.activeElement) &&
!getSettingsButton().contains(event.relatedTarget)
) {
const helpBtn = getHelpButton();
const settingsBtn = getSettingsButton();
const helpUnfocused = helpBtn === null ||
(!helpBtn.contains(document.activeElement) &&
!elemContainsTarget(helpBtn, event.relatedTarget));
const settingsUnfocused = settingsBtn === null ||
(!settingsBtn.contains(document.activeElement) &&
!elemContainsTarget(settingsBtn, event.relatedTarget));
if (helpUnfocused && settingsUnfocused) {
window.hidePopoverMenus();
}
}

if (!isSettingsPage) {
// We replace the existing "onclick" callback.
const settingsButton = getSettingsButton();
const settingsMenu = document.getElementById("settings");
// These elements must exist, as (outside of the settings page)
// `settings.js` is only loaded after the settings button is clicked.
const settingsButton = nonnull(getSettingsButton());
const settingsMenu = nonnull(document.getElementById("settings"));
settingsButton.onclick = event => {
if (settingsMenu.contains(event.target)) {
if (elemContainsTarget(settingsMenu, event.target)) {
return;
}
event.preventDefault();
const shouldDisplaySettings = settingsMenu.style.display === "none";

window.hideAllModals();
window.hideAllModals(false);
if (shouldDisplaySettings) {
displaySettings();
}
};
settingsButton.onblur = settingsBlurHandler;
settingsButton.querySelector("a").onblur = settingsBlurHandler;
// the settings button should always have a link in it
nonnull(settingsButton.querySelector("a")).onblur = settingsBlurHandler;
onEachLazy(settingsMenu.querySelectorAll("input"), el => {
el.onblur = settingsBlurHandler;
});
Expand Down
Loading