]> git.proxmox.com Git - rustc.git/blobdiff - src/librustdoc/html/static/storage.js
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / src / librustdoc / html / static / storage.js
index e10e330402f5edf3ca56fae7f527ab7bad8cdcb2..d081781f14be15b8fba7e86ca367c87c2365b405 100644 (file)
-/*!
- * Copyright 2018 The Rust Project Developers. See the COPYRIGHT
- * file at the top-level directory of this distribution and at
- * http://rust-lang.org/COPYRIGHT.
- *
- * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
- * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
- * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
- * option. This file may not be copied, modified, or distributed
- * except according to those terms.
- */
+// From rust:
+/* global resourcesSuffix, getSettingValue */
 
+var darkThemes = ["dark", "ayu"];
 var currentTheme = document.getElementById("themeStyle");
 var mainTheme = document.getElementById("mainThemeStyle");
 
+var settingsDataset = (function () {
+    var settingsElement = document.getElementById("default-settings");
+    if (settingsElement === null) {
+        return null;
+    }
+    var dataset = settingsElement.dataset;
+    if (dataset === undefined) {
+        return null;
+    }
+    return dataset;
+})();
+
+function getSettingValue(settingName) {
+    var current = getCurrentValue('rustdoc-' + settingName);
+    if (current !== null) {
+        return current;
+    }
+    if (settingsDataset !== null) {
+        var def = settingsDataset[settingName.replace(/-/g,'_')];
+        if (def !== undefined) {
+            return def;
+        }
+    }
+    return null;
+}
+
+var localStoredTheme = getSettingValue("theme");
+
 var savedHref = [];
 
-function onEach(arr, func) {
+function hasClass(elem, className) {
+    return elem && elem.classList && elem.classList.contains(className);
+}
+
+function addClass(elem, className) {
+    if (!elem || !elem.classList) {
+        return;
+    }
+    elem.classList.add(className);
+}
+
+function removeClass(elem, className) {
+    if (!elem || !elem.classList) {
+        return;
+    }
+    elem.classList.remove(className);
+}
+
+function onEach(arr, func, reversed) {
     if (arr && arr.length > 0 && func) {
-        for (var i = 0; i < arr.length; i++) {
-            if (func(arr[i]) === true) {
-                return true;
+        var length = arr.length;
+        var i;
+        if (reversed !== true) {
+            for (i = 0; i < length; ++i) {
+                if (func(arr[i]) === true) {
+                    return true;
+                }
+            }
+        } else {
+            for (i = length - 1; i >= 0; --i) {
+                if (func(arr[i]) === true) {
+                    return true;
+                }
             }
         }
     }
     return false;
 }
 
+function onEachLazy(lazyArray, func, reversed) {
+    return onEach(
+        Array.prototype.slice.call(lazyArray),
+        func,
+        reversed);
+}
+
+function hasOwnProperty(obj, property) {
+    return Object.prototype.hasOwnProperty.call(obj, property);
+}
+
 function usableLocalStorage() {
     // Check if the browser supports localStorage at all:
-    if (typeof(Storage) === "undefined") {
+    if (typeof Storage === "undefined") {
         return false;
     }
     // Check if we can access it; this access will fail if the browser
     // preferences deny access to localStorage, e.g., to prevent storage of
     // "cookies" (or cookie-likes, as is the case here).
     try {
-        window.localStorage;
+        return window.localStorage !== null && window.localStorage !== undefined;
     } catch(err) {
         // Storage is supported, but browser preferences deny access to it.
         return false;
     }
-
-    return true;
 }
 
 function updateLocalStorage(name, value) {
@@ -59,18 +116,24 @@ function getCurrentValue(name) {
     return null;
 }
 
-function switchTheme(styleElem, mainStyleElem, newTheme) {
+function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
     var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
     var fullNewTheme = newTheme + resourcesSuffix + ".css";
     var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);
 
+    // If this new value comes from a system setting or from the previously
+    // saved theme, no need to save it.
+    if (saveTheme === true) {
+        updateLocalStorage("rustdoc-theme", newTheme);
+    }
+
     if (styleElem.href === newHref) {
         return;
     }
 
     var found = false;
     if (savedHref.length === 0) {
-        onEach(document.getElementsByTagName("link"), function(el) {
+        onEachLazy(document.getElementsByTagName("link"), function(el) {
             savedHref.push(el.href);
         });
     }
@@ -82,8 +145,85 @@ function switchTheme(styleElem, mainStyleElem, newTheme) {
     });
     if (found === true) {
         styleElem.href = newHref;
-        updateLocalStorage('rustdoc-theme', newTheme);
     }
 }
 
-switchTheme(currentTheme, mainTheme, getCurrentValue('rustdoc-theme') || 'light');
+function useSystemTheme(value) {
+    if (value === undefined) {
+        value = true;
+    }
+
+    updateLocalStorage("rustdoc-use-system-theme", value);
+
+    // update the toggle if we're on the settings page
+    var toggle = document.getElementById("use-system-theme");
+    if (toggle && toggle instanceof HTMLInputElement) {
+        toggle.checked = value;
+    }
+}
+
+var updateSystemTheme = (function() {
+    if (!window.matchMedia) {
+        // fallback to the CSS computed value
+        return function() {
+            let cssTheme = getComputedStyle(document.documentElement)
+                .getPropertyValue('content');
+
+            switchTheme(
+                currentTheme,
+                mainTheme,
+                JSON.parse(cssTheme) || light,
+                true
+            );
+        };
+    }
+
+    // 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(currentTheme, mainTheme, darkTheme, true);
+            } else {
+                // prefers a light theme, or has no preference
+                switchTheme(currentTheme, 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
+        }
+    }
+
+    mql.addListener(handlePreferenceChange);
+
+    return function() {
+        handlePreferenceChange(mql);
+    };
+})();
+
+if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
+    // 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
+    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(
+        currentTheme,
+        mainTheme,
+        getSettingValue("theme") || "light",
+        false
+    );
+}