Move settings into full JS
This commit is contained in:
parent
76d4862fdd
commit
9625ed8be7
8 changed files with 344 additions and 197 deletions
|
@ -1440,6 +1440,10 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
|
|||
let mut map = FxHashMap::default();
|
||||
// This is the list of IDs used in Javascript.
|
||||
map.insert("help".into(), 1);
|
||||
map.insert("settings".into(), 1);
|
||||
map.insert("not-displayed".into(), 1);
|
||||
map.insert("alternative-display".into(), 1);
|
||||
map.insert("search".into(), 1);
|
||||
// This is the list of IDs used in HTML generated in Rust (including the ones
|
||||
// used in tera template files).
|
||||
map.insert("mainThemeStyle".into(), 1);
|
||||
|
@ -1449,7 +1453,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
|
|||
map.insert("settings-menu".into(), 1);
|
||||
map.insert("help-button".into(), 1);
|
||||
map.insert("main-content".into(), 1);
|
||||
map.insert("search".into(), 1);
|
||||
map.insert("crate-search".into(), 1);
|
||||
map.insert("render-detail".into(), 1);
|
||||
map.insert("toggle-all-docs".into(), 1);
|
||||
|
|
|
@ -17,8 +17,8 @@ use super::print_item::{full_path, item_path, print_item};
|
|||
use super::search_index::build_index;
|
||||
use super::write_shared::write_shared;
|
||||
use super::{
|
||||
collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
|
||||
LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
|
||||
collect_spans_and_sources, print_sidebar, scrape_examples_help, AllTypes, LinkFromSrc, NameDoc,
|
||||
StylePath, BASIC_KEYWORDS,
|
||||
};
|
||||
|
||||
use crate::clean::{self, types::ExternalLocation, ExternalCrate};
|
||||
|
@ -589,21 +589,18 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||
page.root_path = "./";
|
||||
|
||||
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
|
||||
let theme_names: Vec<String> = self
|
||||
.shared
|
||||
.style_files
|
||||
.iter()
|
||||
.map(StylePath::basename)
|
||||
.collect::<Result<_, Error>>()?;
|
||||
let v = layout::render(
|
||||
&self.shared.layout,
|
||||
&page,
|
||||
sidebar,
|
||||
settings(
|
||||
self.shared.static_root_path.as_deref().unwrap_or("./"),
|
||||
&self.shared.resource_suffix,
|
||||
theme_names,
|
||||
)?,
|
||||
|buf: &mut Buffer| {
|
||||
write!(
|
||||
buf,
|
||||
"<script defer src=\"{}settings{}.js\"></script>",
|
||||
page.static_root_path.unwrap_or(""),
|
||||
page.resource_suffix
|
||||
)
|
||||
},
|
||||
&self.shared.style_files,
|
||||
);
|
||||
self.shared.fs.write(settings_file, v)?;
|
||||
|
|
|
@ -334,134 +334,6 @@ impl AllTypes {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Setting {
|
||||
Section {
|
||||
description: &'static str,
|
||||
sub_settings: Vec<Setting>,
|
||||
},
|
||||
Toggle {
|
||||
js_data_name: &'static str,
|
||||
description: &'static str,
|
||||
default_value: bool,
|
||||
},
|
||||
Select {
|
||||
js_data_name: &'static str,
|
||||
description: &'static str,
|
||||
default_value: &'static str,
|
||||
options: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Setting {
|
||||
fn display(&self, root_path: &str, suffix: &str) -> String {
|
||||
match *self {
|
||||
Setting::Section { description, ref sub_settings } => format!(
|
||||
"<div class=\"setting-line\">\
|
||||
<div class=\"title\">{}</div>\
|
||||
<div class=\"sub-settings\">{}</div>
|
||||
</div>",
|
||||
description,
|
||||
sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
|
||||
),
|
||||
Setting::Toggle { js_data_name, description, default_value } => format!(
|
||||
"<div class=\"setting-line\">\
|
||||
<label class=\"toggle\">\
|
||||
<input type=\"checkbox\" id=\"{}\" {}>\
|
||||
<span class=\"slider\"></span>\
|
||||
</label>\
|
||||
<div>{}</div>\
|
||||
</div>",
|
||||
js_data_name,
|
||||
if default_value { " checked" } else { "" },
|
||||
description,
|
||||
),
|
||||
Setting::Select { js_data_name, description, default_value, ref options } => format!(
|
||||
"<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span><div class=\"choices\">{}</div></div></div>",
|
||||
js_data_name,
|
||||
description,
|
||||
options
|
||||
.iter()
|
||||
.map(|opt| format!(
|
||||
"<label for=\"{js_data_name}-{name}\" class=\"choice\">
|
||||
<input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\
|
||||
{name}\
|
||||
</label>",
|
||||
js_data_name = js_data_name,
|
||||
name = opt,
|
||||
checked = if opt == default_value { "checked" } else { "" },
|
||||
))
|
||||
.collect::<String>(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&'static str, &'static str, bool)> for Setting {
|
||||
fn from(values: (&'static str, &'static str, bool)) -> Setting {
|
||||
Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
|
||||
fn from(values: (&'static str, Vec<T>)) -> Setting {
|
||||
Setting::Section {
|
||||
description: values.0,
|
||||
sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
|
||||
// (id, explanation, default value)
|
||||
let settings: &[Setting] = &[
|
||||
Setting::from(("use-system-theme", "Use system theme", true)),
|
||||
Setting::Select {
|
||||
js_data_name: "theme",
|
||||
description: "Theme",
|
||||
default_value: "light",
|
||||
options: theme_names.clone(),
|
||||
},
|
||||
Setting::Select {
|
||||
js_data_name: "preferred-light-theme",
|
||||
description: "Preferred light theme",
|
||||
default_value: "light",
|
||||
options: theme_names.clone(),
|
||||
},
|
||||
Setting::Select {
|
||||
js_data_name: "preferred-dark-theme",
|
||||
description: "Preferred dark theme",
|
||||
default_value: "dark",
|
||||
options: theme_names,
|
||||
},
|
||||
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
|
||||
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
|
||||
("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
|
||||
.into(),
|
||||
("go-to-only-result", "Directly go to item in search if there is only one result", false)
|
||||
.into(),
|
||||
("line-numbers", "Show line numbers on code examples", false).into(),
|
||||
("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
|
||||
];
|
||||
|
||||
Ok(format!(
|
||||
"<div class=\"main-heading\">
|
||||
<h1 class=\"fqn\">\
|
||||
<span class=\"in-band\">Rustdoc settings</span>\
|
||||
</h1>\
|
||||
<span class=\"out-of-band\">\
|
||||
<a id=\"back\" href=\"javascript:void(0)\">Back</a>\
|
||||
</span>\
|
||||
</div>\
|
||||
<div class=\"settings\">{}</div>\
|
||||
<link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
|
||||
<script src=\"{root_path}settings{suffix}.js\"></script>",
|
||||
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
|
||||
root_path = root_path,
|
||||
suffix = suffix
|
||||
))
|
||||
}
|
||||
|
||||
fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
|
||||
let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
|
||||
content.push_str(&format!(
|
||||
|
|
|
@ -57,11 +57,20 @@ function resourcePath(basename, extension) {
|
|||
return getVar("root-path") + basename + getVar("resource-suffix") + extension;
|
||||
}
|
||||
|
||||
function hideMain() {
|
||||
addClass(document.getElementById(MAIN_ID), "hidden");
|
||||
}
|
||||
|
||||
function showMain() {
|
||||
removeClass(document.getElementById(MAIN_ID), "hidden");
|
||||
}
|
||||
|
||||
(function () {
|
||||
window.rootPath = getVar("root-path");
|
||||
window.currentCrate = getVar("current-crate");
|
||||
window.searchJS = resourcePath("search", ".js");
|
||||
window.searchIndexJS = resourcePath("search-index", ".js");
|
||||
window.settingsJS = resourcePath("settings", ".js");
|
||||
const sidebarVars = document.getElementById("sidebar-vars");
|
||||
if (sidebarVars) {
|
||||
window.sidebarCurrent = {
|
||||
|
@ -104,6 +113,9 @@ function getVirtualKey(ev) {
|
|||
const THEME_PICKER_ELEMENT_ID = "theme-picker";
|
||||
const THEMES_ELEMENT_ID = "theme-choices";
|
||||
const MAIN_ID = "main-content";
|
||||
const SETTINGS_BUTTON_ID = "settings-menu";
|
||||
const ALTERNATIVE_DISPLAY_ID = "alternative-display";
|
||||
const NOT_DISPLAYED_ID = "not-displayed";
|
||||
|
||||
function getThemesElement() {
|
||||
return document.getElementById(THEMES_ELEMENT_ID);
|
||||
|
@ -113,6 +125,10 @@ function getThemePickerElement() {
|
|||
return document.getElementById(THEME_PICKER_ELEMENT_ID);
|
||||
}
|
||||
|
||||
function getSettingsButton() {
|
||||
return document.getElementById(SETTINGS_BUTTON_ID);
|
||||
}
|
||||
|
||||
// Returns the current URL without any query parameter or hash.
|
||||
function getNakedUrl() {
|
||||
return window.location.href.split("?")[0].split("#")[0];
|
||||
|
@ -136,6 +152,10 @@ function hideThemeButtonState() {
|
|||
themePicker.style.borderBottomLeftRadius = "3px";
|
||||
}
|
||||
|
||||
window.hideSettings = function() {
|
||||
// Does nothing by default.
|
||||
};
|
||||
|
||||
// Set up the theme picker list.
|
||||
(function () {
|
||||
if (!document.location.href.startsWith("file:///")) {
|
||||
|
@ -182,14 +202,120 @@ function hideThemeButtonState() {
|
|||
});
|
||||
}());
|
||||
|
||||
/**
|
||||
* This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
|
||||
* doesn't have a parent node.
|
||||
*
|
||||
* @param {DOM} newNode
|
||||
* @param {DOM} referenceNode
|
||||
*/
|
||||
function insertAfter(newNode, referenceNode) {
|
||||
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates a new `<section>` with the given `id` and `classes` if it doesn't already
|
||||
* exist.
|
||||
*
|
||||
* More information about this in `switchDisplayedElement` documentation.
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string} classes
|
||||
*/
|
||||
function getOrCreateSection(id, classes) {
|
||||
let el = document.getElementById(id);
|
||||
|
||||
if (!el) {
|
||||
el = document.createElement("section");
|
||||
el.id = id;
|
||||
el.className = classes;
|
||||
insertAfter(el, document.getElementById(MAIN_ID));
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<section>` element which contains the displayed element.
|
||||
*
|
||||
* @return {DOM}
|
||||
*/
|
||||
function getAlternativeDisplayElem() {
|
||||
return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<section>` element which contains the not-displayed elements.
|
||||
*
|
||||
* @return {DOM}
|
||||
*/
|
||||
function getNotDisplayedElem() {
|
||||
return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* To nicely switch between displayed "extra" elements (such as search results or settings menu)
|
||||
* and to alternate between the displayed and not displayed elements, we hold them in two different
|
||||
* `<section>` elements. They work in pair: one hold the not displayed elements while the other
|
||||
* contains the displayed element (there can be only one at the same time!). So basically, we switch
|
||||
* elements between the two `<section>` elements.
|
||||
*
|
||||
* @param {DOM} elemToDisplay
|
||||
*/
|
||||
function switchDisplayedElement(elemToDisplay) {
|
||||
const el = getAlternativeDisplayElem();
|
||||
|
||||
if (el.children.length > 0) {
|
||||
getNotDisplayedElem().appendChild(el.firstElementChild);
|
||||
}
|
||||
if (elemToDisplay === null) {
|
||||
addClass(el, "hidden");
|
||||
showMain();
|
||||
return;
|
||||
}
|
||||
el.appendChild(elemToDisplay);
|
||||
hideMain();
|
||||
removeClass(el, "hidden");
|
||||
}
|
||||
|
||||
function browserSupportsHistoryApi() {
|
||||
return window.history && typeof window.history.pushState === "function";
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function loadCss(cssFileName) {
|
||||
const link = document.createElement("link");
|
||||
link.href = resourcePath(cssFileName, ".css");
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
}
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function loadScript(url) {
|
||||
const script = document.createElement('script');
|
||||
script.src = url;
|
||||
document.head.append(script);
|
||||
}
|
||||
|
||||
|
||||
getSettingsButton().onclick = function(event) {
|
||||
event.preventDefault();
|
||||
loadScript(window.settingsJS);
|
||||
};
|
||||
|
||||
window.searchState = {
|
||||
loadingText: "Loading search results...",
|
||||
input: document.getElementsByClassName("search-input")[0],
|
||||
outputElement: function() {
|
||||
return document.getElementById("search");
|
||||
let el = document.getElementById("search");
|
||||
if (!el) {
|
||||
el = document.createElement("section");
|
||||
el.id = "search";
|
||||
getNotDisplayedElem().appendChild(el);
|
||||
}
|
||||
return el;
|
||||
},
|
||||
title: document.title,
|
||||
titleBeforeSearch: document.title,
|
||||
|
@ -208,6 +334,9 @@ function hideThemeButtonState() {
|
|||
searchState.timeout = null;
|
||||
}
|
||||
},
|
||||
isDisplayed: function() {
|
||||
return searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID;
|
||||
},
|
||||
// Sets the focus on the search bar at the top of the page
|
||||
focus: function() {
|
||||
searchState.input.focus();
|
||||
|
@ -220,20 +349,15 @@ function hideThemeButtonState() {
|
|||
if (search === null || typeof search === 'undefined') {
|
||||
search = searchState.outputElement();
|
||||
}
|
||||
addClass(main, "hidden");
|
||||
removeClass(search, "hidden");
|
||||
switchDisplayedElement(search);
|
||||
searchState.mouseMovedAfterSearch = false;
|
||||
document.title = searchState.title;
|
||||
},
|
||||
hideResults: function(search) {
|
||||
if (search === null || typeof search === 'undefined') {
|
||||
search = searchState.outputElement();
|
||||
}
|
||||
addClass(search, "hidden");
|
||||
removeClass(main, "hidden");
|
||||
hideResults: function() {
|
||||
switchDisplayedElement(null);
|
||||
document.title = searchState.titleBeforeSearch;
|
||||
// We also remove the query parameter from the URL.
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
history.replaceState(null, window.currentCrate + " - Rust",
|
||||
getNakedUrl() + window.location.hash);
|
||||
}
|
||||
|
@ -248,20 +372,11 @@ function hideThemeButtonState() {
|
|||
});
|
||||
return params;
|
||||
},
|
||||
browserSupportsHistoryApi: function() {
|
||||
return window.history && typeof window.history.pushState === "function";
|
||||
},
|
||||
setup: function() {
|
||||
const search_input = searchState.input;
|
||||
if (!searchState.input) {
|
||||
return;
|
||||
}
|
||||
function loadScript(url) {
|
||||
const script = document.createElement('script');
|
||||
script.src = url;
|
||||
document.head.append(script);
|
||||
}
|
||||
|
||||
let searchLoaded = false;
|
||||
function loadSearch() {
|
||||
if (!searchLoaded) {
|
||||
|
@ -303,23 +418,20 @@ function hideThemeButtonState() {
|
|||
}
|
||||
|
||||
const toggleAllDocsId = "toggle-all-docs";
|
||||
const main = document.getElementById(MAIN_ID);
|
||||
let savedHash = "";
|
||||
|
||||
function handleHashes(ev) {
|
||||
let elem;
|
||||
const search = searchState.outputElement();
|
||||
if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
|
||||
if (ev !== null && searchState.isDisplayed() && ev.newURL) {
|
||||
// This block occurs when clicking on an element in the navbar while
|
||||
// in a search.
|
||||
searchState.hideResults(search);
|
||||
switchDisplayedElement(null);
|
||||
const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
// `window.location.search`` contains all the query parameters, not just `search`.
|
||||
history.replaceState(null, "",
|
||||
getNakedUrl() + window.location.search + "#" + hash);
|
||||
}
|
||||
elem = document.getElementById(hash);
|
||||
const elem = document.getElementById(hash);
|
||||
if (elem) {
|
||||
elem.scrollIntoView();
|
||||
}
|
||||
|
@ -389,14 +501,17 @@ function hideThemeButtonState() {
|
|||
}
|
||||
|
||||
function handleEscape(ev) {
|
||||
searchState.clearInputTimeout();
|
||||
const help = getHelpElement(false);
|
||||
const search = searchState.outputElement();
|
||||
if (help && !hasClass(help, "hidden")) {
|
||||
displayHelp(false, ev, help);
|
||||
} else if (search && !hasClass(search, "hidden")) {
|
||||
searchState.clearInputTimeout();
|
||||
} else {
|
||||
switchDisplayedElement(null);
|
||||
if (browserSupportsHistoryApi()) {
|
||||
history.replaceState(null, window.currentCrate + " - Rust",
|
||||
getNakedUrl() + window.location.hash);
|
||||
}
|
||||
ev.preventDefault();
|
||||
searchState.hideResults(search);
|
||||
}
|
||||
searchState.defocus();
|
||||
hideThemeButtonState();
|
||||
|
@ -733,10 +848,6 @@ function hideThemeButtonState() {
|
|||
innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
|
||||
}
|
||||
|
||||
function insertAfter(newNode, referenceNode) {
|
||||
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
|
||||
}
|
||||
|
||||
(function() {
|
||||
const toggles = document.getElementById(toggleAllDocsId);
|
||||
if (toggles) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* eslint no-var: "error" */
|
||||
/* eslint prefer-const: "error" */
|
||||
/* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
|
||||
/* global onEachLazy, removeClass, searchState, hasClass */
|
||||
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
|
||||
|
||||
(function() {
|
||||
// This mapping table should match the discriminants of
|
||||
|
@ -1786,8 +1786,9 @@ window.initSearch = function(rawSearchIndex) {
|
|||
|
||||
// Because searching is incremental by character, only the most
|
||||
// recent search query is added to the browser history.
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
const newURL = buildUrl(query.original, filterCrates);
|
||||
|
||||
if (!history.state && !params.search) {
|
||||
history.pushState(null, "", newURL);
|
||||
} else {
|
||||
|
@ -1965,10 +1966,9 @@ window.initSearch = function(rawSearchIndex) {
|
|||
if (!searchState.input) {
|
||||
return;
|
||||
}
|
||||
const search = searchState.outputElement();
|
||||
if (search_input.value !== "" && hasClass(search, "hidden")) {
|
||||
searchState.showResults(search);
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (search_input.value !== "" && !searchState.isDisplayed()) {
|
||||
searchState.showResults();
|
||||
if (browserSupportsHistoryApi()) {
|
||||
history.replaceState(null, "",
|
||||
buildUrl(search_input.value, getFilterCrates()));
|
||||
}
|
||||
|
@ -1980,7 +1980,7 @@ window.initSearch = function(rawSearchIndex) {
|
|||
const searchAfter500ms = function() {
|
||||
searchState.clearInputTimeout();
|
||||
if (searchState.input.value.length === 0) {
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
history.replaceState(null, window.currentCrate + " - Rust",
|
||||
getNakedUrl() + window.location.hash);
|
||||
}
|
||||
|
@ -2058,7 +2058,7 @@ window.initSearch = function(rawSearchIndex) {
|
|||
|
||||
// Push and pop states are used to add search results to the browser
|
||||
// history.
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
// Store the previous <title> so we can revert back to it later.
|
||||
const previousTitle = document.title;
|
||||
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
/* eslint no-var: "error" */
|
||||
/* eslint prefer-const: "error" */
|
||||
// Local js definitions:
|
||||
/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
|
||||
/* global addClass, removeClass */
|
||||
/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme, loadCss */
|
||||
/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */
|
||||
/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */
|
||||
|
||||
(function () {
|
||||
const isSettingsPage = window.location.pathname.endsWith("/settings.html");
|
||||
|
||||
function changeSetting(settingName, value) {
|
||||
updateLocalStorage(settingName, value);
|
||||
|
||||
|
@ -55,9 +58,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
function setEvents() {
|
||||
function setEvents(settingsElement) {
|
||||
updateLightAndDark();
|
||||
onEachLazy(document.getElementsByClassName("slider"), function(elem) {
|
||||
onEachLazy(settingsElement.getElementsByClassName("slider"), function(elem) {
|
||||
const toggle = elem.previousElementSibling;
|
||||
const settingId = toggle.id;
|
||||
const settingValue = getSettingValue(settingId);
|
||||
|
@ -70,7 +73,7 @@
|
|||
toggle.onkeyup = handleKey;
|
||||
toggle.onkeyrelease = handleKey;
|
||||
});
|
||||
onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
|
||||
onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), function(elem) {
|
||||
const select = elem.getElementsByTagName("select")[0];
|
||||
const settingId = select.id;
|
||||
const settingValue = getSettingValue(settingId);
|
||||
|
@ -81,7 +84,7 @@
|
|||
changeSetting(this.id, this.value);
|
||||
};
|
||||
});
|
||||
onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) {
|
||||
onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), function(elem) {
|
||||
const settingId = elem.name;
|
||||
const settingValue = getSettingValue(settingId);
|
||||
if (settingValue !== null && settingValue !== "null") {
|
||||
|
@ -91,10 +94,172 @@
|
|||
changeSetting(ev.target.name, ev.target.value);
|
||||
});
|
||||
});
|
||||
document.getElementById("back").addEventListener("click", function() {
|
||||
history.back();
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", setEvents);
|
||||
function buildSettings(settings) {
|
||||
let output = "";
|
||||
|
||||
onEach(settings, function(setting) {
|
||||
output += `<div class="setting-line">`;
|
||||
const js_data_name = setting["js_name"];
|
||||
const setting_name = setting["name"];
|
||||
|
||||
if (setting["options"] !== undefined) {
|
||||
// This is a select setting.
|
||||
output += `<div class="radio-line" id="${js_data_name}">\
|
||||
<span class="setting-name">${setting_name}</span>\
|
||||
<div class="choices">`;
|
||||
onEach(setting["options"], function(option) {
|
||||
const checked = option === setting["default"] ? " checked" : "";
|
||||
|
||||
output += `<label for="${js_data_name}-${option}" class="choice">\
|
||||
<input type="radio" name="${js_data_name}" \
|
||||
id="${js_data_name}-${option}" value="${option}"${checked}>\
|
||||
${option}\
|
||||
</label>`;
|
||||
});
|
||||
output += "</div></div>";
|
||||
} else {
|
||||
// This is a toggle.
|
||||
const checked = setting["default"] === true ? " checked" : "";
|
||||
output += `
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="${js_data_name}"${checked}>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<div>${setting_name}</div>`;
|
||||
}
|
||||
output += "</div>";
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
function buildSettingsPage(settings) {
|
||||
// First, we add the settings.css file.
|
||||
loadCss("settings");
|
||||
|
||||
// Then we build the DOM.
|
||||
const el = document.createElement("section");
|
||||
el.id = "settings";
|
||||
let innerHTML = `
|
||||
<div class="main-heading">
|
||||
<h1 class="fqn">
|
||||
<span class="in-band">Rustdoc settings</span>
|
||||
</h1>
|
||||
<span class="out-of-band">`;
|
||||
|
||||
if (isSettingsPage) {
|
||||
innerHTML +=
|
||||
`<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
|
||||
} else {
|
||||
innerHTML +=
|
||||
`<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
|
||||
Back</a>`;
|
||||
}
|
||||
innerHTML += `</span>
|
||||
</div>
|
||||
<div class="settings">${buildSettings(settings)}</div>`;
|
||||
|
||||
el.innerHTML = innerHTML;
|
||||
|
||||
if (isSettingsPage) {
|
||||
document.getElementById(MAIN_ID).appendChild(el);
|
||||
} else {
|
||||
getNotDisplayedElem().appendChild(el);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
function createSettingsPage() {
|
||||
const themes = getVar("themes").split(",");
|
||||
const settings = [
|
||||
{
|
||||
"name": "Use system theme",
|
||||
"js_name": "use-system-theme",
|
||||
"default": true,
|
||||
},
|
||||
{
|
||||
"name": "Theme",
|
||||
"js_name": "theme",
|
||||
"default": "light",
|
||||
"options": themes,
|
||||
},
|
||||
{
|
||||
"name": "Preferred dark theme",
|
||||
"js_name": "preferred-dark-theme",
|
||||
"default": "dark",
|
||||
"options": themes,
|
||||
},
|
||||
{
|
||||
"name": "Preferred light theme",
|
||||
"js_name": "preferred-light-theme",
|
||||
"default": "light",
|
||||
"options": themes,
|
||||
},
|
||||
{
|
||||
"name": "Auto-hide item contents for large items",
|
||||
"js_name": "auto-hide-large-items",
|
||||
"default": true,
|
||||
},
|
||||
{
|
||||
"name": "Auto-hide item methods' documentation",
|
||||
"js_name": "auto-hide-method-docs",
|
||||
"default": false,
|
||||
},
|
||||
{
|
||||
"name": "Auto-hide trait implementation documentation",
|
||||
"js_name": "auto-hide-trait-implementations",
|
||||
"default": false,
|
||||
},
|
||||
{
|
||||
"name": "Directly go to item in search if there is only one result",
|
||||
"js_name": "go-to-only-result",
|
||||
"default": false,
|
||||
},
|
||||
{
|
||||
"name": "Show line numbers on code examples",
|
||||
"js_name": "line-numbers",
|
||||
"default": false,
|
||||
},
|
||||
{
|
||||
"name": "Disable keyboard shortcuts",
|
||||
"js_name": "disable-shortcuts",
|
||||
"default": false,
|
||||
},
|
||||
];
|
||||
|
||||
return buildSettingsPage(settings);
|
||||
}
|
||||
|
||||
const settingsMenu = createSettingsPage();
|
||||
|
||||
if (isSettingsPage) {
|
||||
// We replace the existing "onclick" callback to do nothing if clicked.
|
||||
getSettingsButton().onclick = function(event) {
|
||||
event.preventDefault();
|
||||
};
|
||||
} else {
|
||||
// We replace the existing "onclick" callback.
|
||||
const settingsButton = getSettingsButton();
|
||||
settingsButton.onclick = function(event) {
|
||||
event.preventDefault();
|
||||
if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) {
|
||||
switchDisplayedElement(settingsMenu);
|
||||
} else {
|
||||
window.hideSettings();
|
||||
}
|
||||
};
|
||||
window.hideSettings = function() {
|
||||
switchDisplayedElement(null);
|
||||
};
|
||||
}
|
||||
|
||||
// We now wait a bit for the web browser to end re-computing the DOM...
|
||||
setTimeout(function() {
|
||||
setEvents(settingsMenu);
|
||||
// The setting menu is already displayed if we're on the settings page.
|
||||
if (!isSettingsPage) {
|
||||
switchDisplayedElement(settingsMenu);
|
||||
}
|
||||
}, 10);
|
||||
})();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/* global search, sourcesIndex */
|
||||
|
||||
// Local js definitions:
|
||||
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, searchState */
|
||||
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
|
||||
/* global updateLocalStorage */
|
||||
(function() {
|
||||
|
||||
|
@ -195,7 +195,7 @@ const handleSourceHighlight = (function() {
|
|||
const set_fragment = function(name) {
|
||||
const x = window.scrollX,
|
||||
y = window.scrollY;
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
if (browserSupportsHistoryApi()) {
|
||||
history.replaceState(null, null, "#" + name);
|
||||
highlightSourceLines();
|
||||
} else {
|
||||
|
|
|
@ -135,7 +135,6 @@
|
|||
</nav> {#- -#}
|
||||
</div> {#- -#}
|
||||
<section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
|
||||
<section id="search" class="content hidden"></section> {#- -#}
|
||||
</div> {#- -#}
|
||||
</main> {#- -#}
|
||||
{{- layout.external_html.after_content|safe -}}
|
||||
|
|
Loading…
Add table
Reference in a new issue