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}