|
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