PageSourceSearch

https://app.ventory.one/static/main/js/theme.2a5bc50f119e.js

js ventory.one collected 2026-10-04 22:43:10 UTC 9,480 bytes, 262 lines download raw bytes

1(function () {
2    "use strict";
3
4    var STORAGE_KEY = "ventoryone-theme";
5    var DARK_THEME = "dark";
6    var LIGHT_THEME = "light";
7    var THEME_CHANGE_EVENT = "ventoryone:themechange";
8
9    function getStoredTheme() {
10        try {
11            var storedTheme = window.localStorage.getItem(STORAGE_KEY);
12            return storedTheme === DARK_THEME || storedTheme === LIGHT_THEME ? storedTheme : null;
13        } catch (error) {
14            return null;
15        }
16    }
17
18    function storeTheme(theme) {
19        try {
20            window.localStorage.setItem(STORAGE_KEY, theme);
21        } catch (error) {
22            // The applied theme remains usable for the current page when storage is unavailable.
23        }
24    }
25
26    function getCurrentTheme() {
27        return document.documentElement.dataset.theme === DARK_THEME ? DARK_THEME : LIGHT_THEME;
28    }
29
30    function getThemeColors() {
31        var styles = window.getComputedStyle(document.documentElement);
32
33        return {
34            text: styles.getPropertyValue("--vo-chart-text").trim(),
35            mutedText: styles.getPropertyValue("--vo-chart-muted-text").trim(),
36            grid: styles.getPropertyValue("--vo-chart-grid").trim(),
37            tooltipBackground: styles.getPropertyValue("--vo-chart-tooltip-background").trim(),
38            tooltipBorder: styles.getPropertyValue("--vo-chart-tooltip-border").trim(),
39        };
40    }
41
42    function applyLegacyScaleTheme(scale, colors) {
43        if (!scale) {
44            return;
45        }
46
47        scale.gridLines = scale.gridLines || {};
48        scale.gridLines.color = colors.grid;
49        scale.gridLines.zeroLineColor = colors.grid;
50        scale.ticks = scale.ticks || {};
51        scale.ticks.fontColor = colors.mutedText;
52
53        if (scale.scaleLabel) {
54            scale.scaleLabel.fontColor = colors.text;
55        }
56    }
57
58    // Modern (Chart.js v3+) options are a resolver proxy: replacing a node
59    // (scale.grid = scale.grid || {}) corrupts it and later throws
60    // "t.startsWith is not a function". Only ever assign leaf values.
61    function assignColor(target, key, value) {
62        if (target && typeof value === "string" && value !== "") {
63            target[key] = value;
64        }
65    }
66
67    function applyModernScaleTheme(scale, colors) {
68        if (!scale) {
69            return;
70        }
71
72        assignColor(scale.grid, "color", colors.grid);
73        assignColor(scale.border, "color", colors.grid);
74        assignColor(scale.ticks, "color", colors.mutedText);
75        assignColor(scale.title, "color", colors.text);
76    }
77
78    function applyThemeToChartOptions(chart, colors) {
79        var options = chart.options || {};
80        var scales = options.scales || {};
81
82        ["xAxes", "yAxes"].forEach(function (axisName) {
83            (scales[axisName] || []).forEach(function (scale) {
84                applyLegacyScaleTheme(scale, colors);
85            });
86        });
87
88        Object.keys(scales).forEach(function (axisName) {
89            if (axisName !== "xAxes" && axisName !== "yAxes") {
90                applyModernScaleTheme(scales[axisName], colors);
91            }
92        });
93
94        // Legacy (v2) nodes.
95        if (options.legend && options.legend.labels) {
96            assignColor(options.legend.labels, "fontColor", colors.text);
97        }
98        if (options.tooltips) {
99            assignColor(options.tooltips, "backgroundColor", colors.tooltipBackground);
100            assignColor(options.tooltips, "titleFontColor", colors.text);
101            assignColor(options.tooltips, "bodyFontColor", colors.text);
102            assignColor(options.tooltips, "borderColor", colors.tooltipBorder);
103            options.tooltips.borderWidth = 1;
104        }
105
106        // Modern (v3+) nodes already exist via Chart.defaults after
107        // construction, so we assign leaves rather than recreating them.
108        var plugins = options.plugins;
109        if (plugins && plugins.legend && plugins.legend.labels) {
110            assignColor(plugins.legend.labels, "color", colors.text);
111        }
112        if (plugins && plugins.tooltip) {
113            assignColor(plugins.tooltip, "backgroundColor", colors.tooltipBackgroun
113d);
114            assignColor(plugins.tooltip, "titleColor", colors.text);
115            assignColor(plugins.tooltip, "bodyColor", colors.text);
116            assignColor(plugins.tooltip, "borderColor", colors.tooltipBorder);
117            plugins.tooltip.borderWidth = 1;
118        }
119    }
120
121    function applyChartDefaults(colors) {
122        if (!window.Chart || !window.Chart.defaults) {
123            return;
124        }
125
126        var defaults = window.Chart.defaults;
127        if (defaults.global) {
128            assignColor(defaults.global, "defaultFontColor", colors.text);
129            assignColor(defaults.global, "defaultColor", colors.grid);
130            return;
131        }
132
133        // Modern charts are themed entirely through defaults (a plain object,
134        // safe to mutate), so charts created later inherit the current theme
135        // without touching any live options proxy.
136        assignColor(defaults, "color", colors.text);
137        assignColor(defaults, "borderColor", colors.grid);
138        if (defaults.scale) {
139            assignColor(defaults.scale.grid, "color", colors.grid);
140            assignColor(defaults.scale.ticks, "color", colors.mutedText);
141            assignColor(defaults.scale.title, "color", colors.text);
142        }
143        if (defaults.plugins) {
144            if (defaults.plugins.legend && defaults.plugins.legend.labels) {
145                assignColor(defaults.plugins.legend.labels, "color", colors.text);
146            }
147            if (defaults.plugins.tooltip) {
148                assignColor(defaults.plugins.tooltip, "backgroundColor", colors.tooltipBackground);
149                assignColor(defaults.plugins.tooltip, "titleColor", colors.text);
150                assignColor(defaults.plugins.tooltip, "bodyColor", colors.text);
151                assignColor(defaults.plugins.tooltip, "borderColor", colors.tooltipBorder);
152            }
153        }
154    }
155
156    function getChartInstances() {
157        if (!window.Chart || !window.Chart.instances) {
158            return [];
159        }
160
161        if (typeof window.Chart.instances.values === "function") {
162            return Array.from(window.Chart.instances.values());
163        }
164
165        return Object.keys(window.Chart.instances).map(function (chartId) {
166            return window.Chart.instances[chartId];
167        });
168    }
169
170    function updateChartWithoutAnimation(chart) {
171        if (!chart || typeof chart.update !== "function") {
172            return;
173        }
174
175        var chartMajorVersion = window.Chart && window.Chart.version
176            ? Number.parseInt(window.Chart.version.split(".")[0], 10)
177            : 2;
178
179        chart.update(chartMajorVersion >= 3 ? "none" : 0);
180    }
181
182    function refreshCharts() {
183        if (!window.Chart) {
184            return;
185        }
186
187        var colors = getThemeColors();
188        applyChartDefaults(colors);
189
190        getChartInstances().forEach(function (chart) {
191            applyThemeToChartOptions(chart, colors);
192            updateChartWithoutAnimation(chart);
193        });
194    }
195
196    function updateThemeControls(theme) {
197        document.querySelectorAll("[data-theme-toggle]").forEach(function (control) {
198            var isDarkTheme = theme === DARK_THEME;
199            var nextThemeLabel = isDarkTheme ? control.dataset.lightLabel : control.dataset.darkLabel;
200
201            control.setAttribute("aria-checked", String(isDarkTheme));
202            if (nextThemeLabel) {
203                control.setAttribute("aria-label", nextThemeLabel);
204                control.setAttribute("title", nextThemeLabel);
205            }
206        });
207    }
208
209    function applyTheme(theme, persistPreference) {
210        document.documentElement.dataset.theme = theme;
211        document.documentElement.style.colorScheme = theme;
212
213        if (persistPreference) {
214            storeTheme(theme);
215        }
216
217        updateThemeControls(theme);
218        try {
219            refreshCharts();
220        } catch (error) {
221            // A third-party chart failure must not prevent the app theme from changing.
222            window.console.warn("VentoryOne chart theming could not be refreshed.", error);
223        }
224        window.dispatchEvent(new CustomEvent(THEME_CHANGE_EVENT, {detail: {theme: theme}}));
225    }
226
227    function bindThemeControls() {
228        document.querySelectorAll("[data-theme-toggle]").forEach(function (control) {
229            if (control.dataset.themeToggleBound === "true") {
230                return;
231            }
232
233            control.dataset.themeToggleBound = "true";
234            control.addEventListener("click", function () {
235                var nextTheme = getCurrentTheme() === DARK_THEME ? LIGHT_THEME : DARK_THEME;
236                applyTheme(nextTheme, true);
237            });
238        });
239    }
240
241    function initializeTheme() {
242        var initialTheme = getStoredTheme() || LIGHT_THEME;
243        bindThemeControls();
244        applyTheme(initialTheme, false);
245    }
246
247    window.VentoryTheme = {
248        apply: function (theme) {
249            if (theme === DARK_THEME || theme === LIGHT_THEME) {
250                applyTheme(theme, true);
251            }
252        },
253        current: getCurrentTheme,
254        refreshCharts: refreshCharts,
255    };
256
257    if (document.readyState === "loading") {
258        document.addEventListener("DOMContentLoaded", initializeTheme, {once: true});
259    } else {
260        initializeTheme();
261    }
262}());

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.