HEX
Server: Apache/2
System: Linux nexus-01 4.18.0-553.120.1.el8_10.x86_64 #1 SMP Mon Apr 20 18:04:27 EDT 2026 x86_64
User: aglcoke (1118)
PHP: 8.2.31
Disabled: mail,exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: //usr/share/rspamd/www/js/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",
        jquery: "jquery-3.7.1.min",
        visibility: "visibility.min",
        bootstrap: "bootstrap.bundle.min",
        codejar: "codejar.min",
        d3: "d3.min",
        d3evolution: "d3evolution.min",
        d3pie: "d3pie.min",
        fontawesome: "fontawesome.min",
        fontawesome_solid: "solid.min",
        footable: "footable.min",
        linenumbers: "codejar-linenumbers.min",
        nprogress: "nprogress.min",
        prism: "prism",
        stickytabs: "jquery.stickytabs.min"
    },
    shim: {
        app: {deps: ["jquery"]},
        codejar: {exports: "CodeJar", deps: ["linenumbers"]},
        bootstrap: {exports: "bootstrap", deps: ["jquery"]}, // Popovers require jQuery
        d3: {exports: "d3"},
        d3evolution: {exports: "D3Evolution", deps: ["d3.global", "jquery"]},
        d3pie: {exports: "D3Pie", deps: ["d3.global", "jquery"]},
        fontawesome: {exports: "FontAwesome", deps: ["fontawesome_solid"]},
        footable: {deps: ["bootstrap", "jquery"]},
        linenumbers: {exports: "withLineNumbers", deps: ["prism"]},
        prism: {exports: "Prism"},
        stickytabs: {deps: ["jquery"]}
    },
    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();
});