|
1 | 1 | // Local js definitions:
|
2 | 2 | /* global getSettingValue, updateLocalStorage, updateTheme */
|
3 | 3 | /* global addClass, removeClass, onEach, onEachLazy */
|
4 |
| -/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */ |
5 |
| - |
6 |
| -// Eventually fix this. |
7 |
| -// @ts-nocheck |
| 4 | +/* global MAIN_ID, getVar, getSettingsButton, getHelpButton, nonnull */ |
8 | 5 |
|
9 | 6 | "use strict";
|
10 | 7 |
|
11 | 8 | (function() {
|
12 | 9 | const isSettingsPage = window.location.pathname.endsWith("/settings.html");
|
13 | 10 |
|
| 11 | + /** |
| 12 | + * @param {Element} elem |
| 13 | + * @param {EventTarget|null} target |
| 14 | + */ |
| 15 | + function elemContainsTarget(elem, target) { |
| 16 | + if (target instanceof Node) { |
| 17 | + return elem.contains(target); |
| 18 | + } else { |
| 19 | + return false; |
| 20 | + } |
| 21 | + } |
| 22 | + |
| 23 | + /** |
| 24 | + * @overload {"theme"|"preferred-dark-theme"|"preferred-light-theme"} |
| 25 | + * @param {string} settingName |
| 26 | + * @param {string} value |
| 27 | + * @returns |
| 28 | + * @param {string} settingName |
| 29 | + * @param {string|boolean} value |
| 30 | + */ |
14 | 31 | function changeSetting(settingName, value) {
|
15 | 32 | if (settingName === "theme") {
|
16 | 33 | const useSystem = value === "system preference" ? "true" : "false";
|
17 | 34 | updateLocalStorage("use-system-theme", useSystem);
|
18 | 35 | }
|
19 |
| - updateLocalStorage(settingName, value); |
| 36 | + updateLocalStorage(settingName, "" + value); |
20 | 37 |
|
21 | 38 | switch (settingName) {
|
22 | 39 | case "theme":
|
|
27 | 44 | break;
|
28 | 45 | case "line-numbers":
|
29 | 46 | if (value === true) {
|
30 |
| - window.rustdoc_add_line_numbers_to_examples(); |
| 47 | + const f = window.rustdoc_add_line_numbers_to_examples; |
| 48 | + if (f !== undefined) { |
| 49 | + f(); |
| 50 | + } |
31 | 51 | } else {
|
32 |
| - window.rustdoc_remove_line_numbers_from_examples(); |
| 52 | + const f = window.rustdoc_remove_line_numbers_from_examples; |
| 53 | + if (f !== undefined) { |
| 54 | + f(); |
| 55 | + } |
33 | 56 | }
|
34 | 57 | break;
|
35 | 58 | case "hide-sidebar":
|
|
89 | 112 | }
|
90 | 113 | }
|
91 | 114 |
|
| 115 | + /** |
| 116 | + * @param {HTMLElement} settingsElement |
| 117 | + */ |
92 | 118 | function setEvents(settingsElement) {
|
93 | 119 | updateLightAndDark();
|
94 | 120 | onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"), toggle => {
|
|
101 | 127 | changeSetting(toggle.id, toggle.checked);
|
102 | 128 | };
|
103 | 129 | });
|
104 |
| - onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => { |
105 |
| - const settingId = elem.name; |
106 |
| - let settingValue = getSettingValue(settingId); |
107 |
| - if (settingId === "theme") { |
108 |
| - const useSystem = getSettingValue("use-system-theme"); |
109 |
| - if (useSystem === "true" || settingValue === null) { |
110 |
| - // "light" is the default theme |
111 |
| - settingValue = useSystem === "false" ? "light" : "system preference"; |
| 130 | + onEachLazy( |
| 131 | + settingsElement.querySelectorAll("input[type=\"radio\"]"), |
| 132 | + /** @param {HTMLInputElement} elem */ |
| 133 | + elem => { |
| 134 | + const settingId = elem.name; |
| 135 | + let settingValue = getSettingValue(settingId); |
| 136 | + if (settingId === "theme") { |
| 137 | + const useSystem = getSettingValue("use-system-theme"); |
| 138 | + if (useSystem === "true" || settingValue === null) { |
| 139 | + // "light" is the default theme |
| 140 | + settingValue = useSystem === "false" ? "light" : "system preference"; |
| 141 | + } |
112 | 142 | }
|
113 |
| - } |
114 |
| - if (settingValue !== null && settingValue !== "null") { |
115 |
| - elem.checked = settingValue === elem.value; |
116 |
| - } |
117 |
| - elem.addEventListener("change", ev => { |
118 |
| - changeSetting(ev.target.name, ev.target.value); |
119 |
| - }); |
120 |
| - }); |
| 143 | + if (settingValue !== null && settingValue !== "null") { |
| 144 | + elem.checked = settingValue === elem.value; |
| 145 | + } |
| 146 | + elem.addEventListener("change", () => { |
| 147 | + changeSetting(elem.name, elem.value); |
| 148 | + }); |
| 149 | + }, |
| 150 | + ); |
121 | 151 | }
|
122 | 152 |
|
123 | 153 | /**
|
124 | 154 | * This function builds the sections inside the "settings page". It takes a `settings` list
|
125 | 155 | * as argument which describes each setting and how to render it. It returns a string
|
126 | 156 | * representing the raw HTML.
|
127 | 157 | *
|
128 |
| - * @param {Array<Object>} settings |
| 158 | + * @param {Array<rustdoc.Setting>} settings |
129 | 159 | *
|
130 | 160 | * @return {string}
|
131 | 161 | */
|
132 | 162 | function buildSettingsPageSections(settings) {
|
133 | 163 | let output = "";
|
134 | 164 |
|
135 | 165 | for (const setting of settings) {
|
136 |
| - if (setting === "hr") { |
137 |
| - output += "<hr>"; |
138 |
| - continue; |
139 |
| - } |
140 |
| - |
141 | 166 | const js_data_name = setting["js_name"];
|
142 | 167 | const setting_name = setting["name"];
|
143 | 168 |
|
|
182 | 207 | * @return {HTMLElement}
|
183 | 208 | */
|
184 | 209 | function buildSettingsPage() {
|
185 |
| - const theme_names = getVar("themes").split(",").filter(t => t); |
| 210 | + const theme_list = getVar("themes"); |
| 211 | + const theme_names = (theme_list === null ? "" : theme_list) |
| 212 | + .split(",").filter(t => t); |
186 | 213 | theme_names.push("light", "dark", "ayu");
|
187 | 214 |
|
188 | 215 | const settings = [
|
|
272 | 299 | el.innerHTML = innerHTML;
|
273 | 300 |
|
274 | 301 | if (isSettingsPage) {
|
275 |
| - document.getElementById(MAIN_ID).appendChild(el); |
| 302 | + const mainElem = document.getElementById(MAIN_ID); |
| 303 | + if (mainElem !== null) { |
| 304 | + mainElem.appendChild(el); |
| 305 | + } |
276 | 306 | } else {
|
277 | 307 | el.setAttribute("tabindex", "-1");
|
278 |
| - getSettingsButton().appendChild(el); |
| 308 | + const settingsBtn = getSettingsButton(); |
| 309 | + if (settingsBtn !== null) { |
| 310 | + settingsBtn.appendChild(el); |
| 311 | + } |
279 | 312 | }
|
280 | 313 | return el;
|
281 | 314 | }
|
|
293 | 326 | });
|
294 | 327 | }
|
295 | 328 |
|
| 329 | + /** |
| 330 | + * @param {FocusEvent} event |
| 331 | + */ |
296 | 332 | function settingsBlurHandler(event) {
|
297 |
| - if (!getHelpButton().contains(document.activeElement) && |
298 |
| - !getHelpButton().contains(event.relatedTarget) && |
299 |
| - !getSettingsButton().contains(document.activeElement) && |
300 |
| - !getSettingsButton().contains(event.relatedTarget) |
301 |
| - ) { |
| 333 | + const helpBtn = getHelpButton(); |
| 334 | + const settingsBtn = getSettingsButton(); |
| 335 | + const helpUnfocused = helpBtn === null || |
| 336 | + (!helpBtn.contains(document.activeElement) && |
| 337 | + !elemContainsTarget(helpBtn, event.relatedTarget)); |
| 338 | + const settingsUnfocused = settingsBtn === null || |
| 339 | + (!settingsBtn.contains(document.activeElement) && |
| 340 | + !elemContainsTarget(settingsBtn, event.relatedTarget)); |
| 341 | + if (helpUnfocused && settingsUnfocused) { |
302 | 342 | window.hidePopoverMenus();
|
303 | 343 | }
|
304 | 344 | }
|
305 | 345 |
|
306 | 346 | if (!isSettingsPage) {
|
307 | 347 | // We replace the existing "onclick" callback.
|
308 |
| - const settingsButton = getSettingsButton(); |
309 |
| - const settingsMenu = document.getElementById("settings"); |
| 348 | + // These elements must exist, as (outside of the settings page) |
| 349 | + // `settings.js` is only loaded after the settings button is clicked. |
| 350 | + const settingsButton = nonnull(getSettingsButton()); |
| 351 | + const settingsMenu = nonnull(document.getElementById("settings")); |
310 | 352 | settingsButton.onclick = event => {
|
311 |
| - if (settingsMenu.contains(event.target)) { |
| 353 | + if (elemContainsTarget(settingsMenu, event.target)) { |
312 | 354 | return;
|
313 | 355 | }
|
314 | 356 | event.preventDefault();
|
315 | 357 | const shouldDisplaySettings = settingsMenu.style.display === "none";
|
316 | 358 |
|
317 |
| - window.hideAllModals(); |
| 359 | + window.hideAllModals(false); |
318 | 360 | if (shouldDisplaySettings) {
|
319 | 361 | displaySettings();
|
320 | 362 | }
|
321 | 363 | };
|
322 | 364 | settingsButton.onblur = settingsBlurHandler;
|
323 |
| - settingsButton.querySelector("a").onblur = settingsBlurHandler; |
| 365 | + // the settings button should always have a link in it |
| 366 | + nonnull(settingsButton.querySelector("a")).onblur = settingsBlurHandler; |
324 | 367 | onEachLazy(settingsMenu.querySelectorAll("input"), el => {
|
325 | 368 | el.onblur = settingsBlurHandler;
|
326 | 369 | });
|
|
0 commit comments