← Back
Editing: main.js
/* global d3:writable, require, requirejs */ // eslint-disable-line no-unused-vars /** * Theme initialization and management * * Initializes theme as early as possible, before loading any modules. * Provides automatic theme detection and switching based on user preference * and system settings. Invalid or missing preferences default to "auto" mode, * which follows the system's color scheme preference. * * @exports window.rspamd.theme.applyPreference - Apply theme preference with listener management * @exports window.rspamd.theme.getEffectiveTheme - Get effective theme for a given preference */ (function () { "use strict"; const mq = window.matchMedia("(prefers-color-scheme: dark)"); function normalizeTheme(value) { const pref = (typeof value === "string") ? value.trim().toLowerCase() : ""; const allowed = new Set(["light", "dark", "auto"]); return { isAuto: !pref || !allowed.has(pref) || pref === "auto", pref: pref }; } /** * Get effective theme based on preference * @param {string} themePref - Theme preference ("light", "dark", "auto", or invalid) * @returns {string} Effective theme: "light" or "dark" */ function getEffectiveTheme(themePref) { const {isAuto, pref} = normalizeTheme(themePref); // eslint-disable-next-line no-nested-ternary return isAuto ? (mq.matches ? "dark" : "light") : pref; } function apply(theme) { document.documentElement.setAttribute("data-bs-theme", theme); document.body.setAttribute("data-theme", theme); } function handler() { apply(getEffectiveTheme(localStorage.getItem("theme"))); } // Apply theme immediately on page load handler(); // Set up listener for system theme changes if in auto mode const {isAuto: initialIsAuto} = normalizeTheme(localStorage.getItem("theme")); if (initialIsAuto && typeof mq.addEventListener === "function") { mq.addEventListener("change", handler); } // Export theme API to window.rspamd namespace if (!window.rspamd) window.rspamd = {}; /** * Theme management API * @namespace * * @property {Function} applyPreference - Apply theme preference (handles auto mode and listener management) * @property {Function} getEffectiveTheme - Get effective theme for a given preference */ window.rspamd.theme = { /** * Apply theme preference (handles auto mode and listener management) * @param {string} themePref - Theme preference to apply */ applyPreference: (themePref) => { localStorage.setItem("theme", themePref); apply(getEffectiveTheme(themePref)); const {isAuto} = normalizeTheme(themePref); // Safe to call even if listener isn't attached (MDN doc) mq.removeEventListener("change", handler); if (isAuto) { mq.addEventListener("change", handler); } }, getEffectiveTheme: getEffectiveTheme }; }()); requirejs.config({ baseUrl: "js/lib", paths: { app: "../app", visibility: "visibility.min", bootstrap: "bootstrap.bundle.min", codejar: "codejar.min", d3: "d3.min", d3evolution: "d3evolution.min", d3pie: "d3pie.min", linenumbers: "codejar-linenumbers.min", tabulator: "tabulator.min", nprogress: "nprogress.min", prism: "prism" }, shim: { codejar: {exports: "CodeJar", deps: ["linenumbers"]}, bootstrap: {exports: "bootstrap"}, d3: {exports: "d3"}, d3evolution: {exports: "D3Evolution", deps: ["d3.global"]}, d3pie: {exports: "D3Pie", deps: ["d3.global"]}, linenumbers: {exports: "withLineNumbers", deps: ["prism"]}, prism: {exports: "Prism"} }, waitSeconds: 30, }); document.title = window.location.hostname + (window.location.port ? ":" + window.location.port : "") + (window.location.pathname !== "/" ? window.location.pathname : "") + " - Rspamd Web Interface"; // Ugly hack to get d3pie work with requirejs define("d3.global", ["d3"], (d3global) => { // eslint-disable-line strict d3 = d3global; }); // Notify user on module loading failure requirejs.onError = function (e) { "use strict"; document.getElementById("loading").classList.add("d-none"); document.getElementsByClassName("notification-area")[0].innerHTML = "<div class=\"alert alert-danger\">" + "<strong>Module loading error: " + e.requireType + ", module: " + e.requireModules + "</strong>" + "<button type=\"button\" class=\"btn btn-info btn-xs float-end\" " + "onClick=\"window.location.reload(); this.parentNode.parentNode.removeChild(this.parentNode);\" " + "title=\"Reload current page\">" + "Reload" + "</button>" + "</div>"; throw e; }; // Load main UI require(["app/rspamd"], (rspamd) => { "use strict"; rspamd.connect(); });
Save File
Cancel