From 2e9e3aa98203c125a71d1b730c036ae10b050b06 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 24 Nov 2021 20:31:23 -0800 Subject: [PATCH] wip --- src/librustdoc/html/static/js/main.js | 10 +- src/librustdoc/html/static/js/settings.js | 4 +- src/librustdoc/html/static/js/storage.js | 177 ++++++++++++---------- src/librustdoc/html/templates/page.html | 18 +-- 4 files changed, 109 insertions(+), 100 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 5661d4973342f..fbb19a9b63b0e 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,7 +1,7 @@ // Local js definitions: /* global addClass, getSettingValue, hasClass, searchState */ /* global onEach, onEachLazy, removeClass */ -/* global switchTheme, useSystemTheme */ +/* global useSystemTheme */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { @@ -60,6 +60,7 @@ function resourcePath(basename, extension) { window.currentCrate = getVar("current-crate"); window.searchJS = resourcePath("search", ".js"); window.searchIndexJS = resourcePath("search-index", ".js"); + window.availableThemes = getVar("themes").split(","); var sidebarVars = document.getElementById("sidebar-vars"); if (sidebarVars) { window.sidebarCurrent = { @@ -130,7 +131,6 @@ function hideThemeButtonState() { (function () { var themeChoices = getThemesElement(); var themePicker = getThemePickerElement(); - var availableThemes = getVar("themes").split(","); function switchThemeButtonState() { if (themeChoices.style.display === "block") { @@ -155,12 +155,12 @@ function hideThemeButtonState() { themePicker.onclick = switchThemeButtonState; themePicker.onblur = handleThemeButtonsBlur; - availableThemes.forEach(function(item) { + window.availableThemes.forEach(function(item) { var but = document.createElement("button"); but.textContent = item; but.onclick = function() { - switchTheme(window.currentTheme, window.mainTheme, item, true); - useSystemTheme(false); + useOneTheme(item); + applyThemeUpdate(); }; but.onblur = handleThemeButtonsBlur; themeChoices.appendChild(but); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 4f10e14e8558c..b7bd758afd02b 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, applyThemeUpdate */ (function () { function changeSetting(settingName, value) { @@ -9,7 +9,7 @@ case "preferred-dark-theme": case "preferred-light-theme": case "use-system-theme": - updateSystemTheme(); + applyThemeUpdate(); break; } } diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 606c237aea7d0..ccc075c1fb26c 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -1,6 +1,4 @@ var darkThemes = ["dark", "ayu"]; -window.currentTheme = document.getElementById("themeStyle"); -window.mainTheme = document.getElementById("mainThemeStyle"); var settingsDataset = (function () { var settingsElement = document.getElementById("default-settings"); @@ -30,10 +28,6 @@ function getSettingValue(settingName) { return null; } -var localStoredTheme = getSettingValue("theme"); - -var savedHref = []; - // eslint-disable-next-line no-unused-vars function hasClass(elem, className) { return elem && elem.classList && elem.classList.contains(className); @@ -104,35 +98,15 @@ function getCurrentValue(name) { } } -function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { - var newHref = mainStyleElem.href.replace( - /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css"); - - // If this new value comes from a system setting or from the previously - // saved theme, no need to save it. - if (saveTheme) { - updateLocalStorage("rustdoc-theme", newTheme); - } - - if (styleElem.href === newHref) { - return; - } +function themeURL(themeName) { + var mainThemeURL = document.getElementById("mainThemeStyle").href; + return mainThemeURL.replace(/rustdoc([^/]*)\.css/, themeName + "$1.css"); +} - var found = false; - if (savedHref.length === 0) { - onEachLazy(document.getElementsByTagName("link"), function(el) { - savedHref.push(el.href); - }); - } - onEach(savedHref, function(el) { - if (el === newHref) { - found = true; - return true; - } - }); - if (found) { - styleElem.href = newHref; - } +function useOneTheme(value) { + updateLocalStorage("rustdoc-theme", value); + useSystemTheme(false); + applyThemeUpdate(); } // This function is called from "main.js". @@ -151,68 +125,105 @@ function useSystemTheme(value) { } } -var updateSystemTheme = (function() { +// Returns "light" or "dark" depending on the user's browser preferences +// (that is, independent of any rustdoc settings). +function getSystemTheme() { if (!window.matchMedia) { - // fallback to the CSS computed value - return function() { - var cssTheme = getComputedStyle(document.documentElement) - .getPropertyValue('content'); - - switchTheme( - window.currentTheme, - window.mainTheme, - JSON.parse(cssTheme) || "light", - true - ); - }; + // In rustdoc.css we have: + // @media (prefers-color-scheme: light) { + // html { + // content: "light"; + // } + // } + // @media (prefers-color-scheme: dark) { + // html { + // content: "dark"; + // } + // } + + return getComputedStyle(document.documentElement) + .getPropertyValue('content') || "light"; + } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + return "dark"; + } else { + return "light"; } +} - // only listen to (prefers-color-scheme: dark) because light is the default - var mql = window.matchMedia("(prefers-color-scheme: dark)"); - - function handlePreferenceChange(mql) { - // maybe the user has disabled the setting in the meantime! - if (getSettingValue("use-system-theme") !== "false") { - var lightTheme = getSettingValue("preferred-light-theme") || "light"; - var darkTheme = getSettingValue("preferred-dark-theme") || "dark"; - - if (mql.matches) { - // prefers a dark theme - switchTheme(window.currentTheme, window.mainTheme, darkTheme, true); - } else { - // prefers a light theme, or has no preference - switchTheme(window.currentTheme, window.mainTheme, lightTheme, true); - } - - // note: we save the theme so that it doesn't suddenly change when - // the user disables "use-system-theme" and reloads the page or - // navigates to another page +// If there is a specific theme selected, or if "Use System Theme" is selected +// and there is a specific theme for the current light or dark mode, return +// the appropriate theme's name. Otherwise, return null. +function getThemeOverride() { + if (getSettingValue("use-system-theme") !== "false") { + var lightOverride = getSettingValue("preferred-light-theme"); + var darkOverride = getSettingValue("preferred-dark-theme"); + + var preferred = getSystemTheme(); + if (preferred == "light" && lightOverride && lightOverride != "light") { + console.log("lightoverride ", lightOverride); + return lightOverride; + } else if (preferred == "dark" && darkOverride && darkOverride != "dark") { + console.log("darkoverride ", darkOverride) + return darkOverride; + } else { + console.log("use default"); + return null; } + } else { + console.log("getsettingvalue ", getSettingValue("theme")); + return getSettingValue("theme") || null; } +} - mql.addListener(handlePreferenceChange); - - return function() { - handlePreferenceChange(mql); - }; -})(); +const nonDefaultThemeID = "nonDefaultThemeStyle"; + +function applyThemeUpdate() { + var lightOverride = getSettingValue("preferred-light-theme"); + var darkOverride = getSettingValue("preferred-dark-theme"); + var allOverride = getSettingValue("theme"); + if (allOverride) { + document.getElementById(nonDefaultThemeID).href = themeURL(allOverride); + } else { + if (lightOverride) { + document.getElementById("lightThemeStyle").href = themeURL(lightOverride); + } + if (darkOverride) { + document.getElementById("darkThemeStyle").href = themeURL(darkOverride); + } + document.getElementById(nonDefaultThemeID).href = ""; + } +} -if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { +function updatePreferredDarkTheme() { // update the preferred dark theme if the user is already using a dark theme // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 + var localStoredTheme = getSettingValue("theme"); if (getSettingValue("use-system-theme") === null && getSettingValue("preferred-dark-theme") === null && darkThemes.indexOf(localStoredTheme) >= 0) { updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); } +} - // call the function to initialize the theme at least once! - updateSystemTheme(); -} else { - switchTheme( - window.currentTheme, - window.mainTheme, - getSettingValue("theme") || "light", - false - ); +// If there's a theme override that's not covered by one of the default +// dark / light themes, we write it to the document head. We use +// document.write rather than appendChild intentionally. Stylesheets added +// with document.write are render-blocking, while those added with appendChild +// are not. We want render blocking behavior to avoid a flash of unstyled +// content. +function applyThemeOverride() { + var override = getThemeOverride(); + if (override) { + document.write(''); + } else { + document.write(''); + } +} + +updatePreferredDarkTheme(); +applyThemeOverride(); +if (window.matchMedia) { + var mql = window.matchMedia("(prefers-color-scheme: dark)"); + mql.addEventListener('change', applyThemeUpdate); } diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 2a783c6da57e4..ada0a82ce80b6 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -12,16 +12,14 @@ {#- -#} - {%- for theme in themes -%} - - {%- endfor -%} + {#- -#} + {#- -#}