schoolbox web extension :)
1import { logger } from "./logger";
2import type { PluginId, PluginSetting, Slider } from "./storage";
3import { globalSettings, plugins, schoolboxUrls } from "./storage";
4
5export async function definePlugin(
6 pluginId: PluginId,
7 callback: (settings?: { toggle: Record<string, boolean>; slider: Record<string, Slider> }) => Promise<void> | void,
8 elementsToWaitFor: string[] = [],
9) {
10 const plugin = await plugins[pluginId].toggle.storage.getValue();
11
12 logger.info(`${plugins[pluginId].name}: ${plugin.toggle ? "enabled" : "disabled"}`);
13
14 const settings = await globalSettings.storage.getValue();
15 const urls = (await schoolboxUrls.storage.getValue()).urls;
16
17 if (plugin && typeof window !== "undefined" && urls.includes(window.location.origin)) {
18 if (settings.global && settings.plugins && plugin.toggle) {
19 const injectPlugin = () => {
20 callback(getSettingsValues(plugins[pluginId]?.settings));
21 };
22
23 const loadPlugin = () => {
24 // wait for elements to be loaded
25 if (elementsToWaitFor.length > 0) {
26 const observer = new MutationObserver((_mutations, observer) => {
27 const allElementsPresent = elementsToWaitFor.every((selector) => document.querySelector(selector) !== null);
28 if (allElementsPresent) {
29 observer.disconnect();
30 logger.info(`all elements present, injecting plugin: ${plugins[pluginId].name}`);
31 injectPlugin();
32 }
33 });
34
35 observer.observe(document.body, { childList: true, subtree: true });
36
37 // check if elements are already present
38 const allElementsPresent = elementsToWaitFor.every((selector) => document.querySelector(selector) !== null);
39 if (allElementsPresent) {
40 observer.disconnect();
41 logger.info(`all elements already present, injecting plugin: ${plugins[pluginId].name}`);
42 injectPlugin();
43 }
44 } else {
45 // no elements to wait for
46 logger.info(`injecting plugin: ${plugins[pluginId].name}`);
47 injectPlugin();
48 }
49 };
50
51 if (document.body) {
52 loadPlugin();
53 } else {
54 document.addEventListener("DOMContentLoaded", loadPlugin);
55 }
56 }
57 }
58}
59
60function getSettingsValues(settings?: Record<string, PluginSetting>) {
61 if (!settings) return undefined;
62
63 const result: {
64 toggle: Record<string, boolean>;
65 slider: Record<string, Slider>;
66 } = { toggle: {}, slider: {} };
67 for (const [key, setting] of Object.entries(settings)) {
68 if (setting.type === "toggle") {
69 const value = setting.state.get();
70 result.toggle[key] = value.toggle;
71 } else if (setting.type === "slider") {
72 const value = setting.state.get();
73 result.slider[key] = value;
74 }
75 }
76 return result;
77}