(function (root) { "use strict"; const FONT_STYLE_KEY = "glagolifyFontStyle"; const TAB_STATES_KEY = "glagolifyTabStates"; const FONT_STYLES = new Set(["round", "angular-sans", "angular", "missal-angular"]); const DEFAULT_FONT_STYLE = "round"; function createBackgroundController(api) { const tabStates = new Map(); let fontStyle = DEFAULT_FONT_STYLE; const fontStyleReady = Promise.resolve(api.storage.local.get(FONT_STYLE_KEY)) .then((stored) => { if (stored && FONT_STYLES.has(stored[FONT_STYLE_KEY])) { fontStyle = stored[FONT_STYLE_KEY]; } }) .catch(() => undefined); const tabStatesReady = Promise.resolve(api.storage.session.get(TAB_STATES_KEY)) .then((stored) => { const states = stored && stored[TAB_STATES_KEY]; if (!states || typeof states !== "object" || Array.isArray(states)) { return; } for (const [storedTabId, enabled] of Object.entries(states)) { const tabId = Number(storedTabId); if (validTabId(tabId) && typeof enabled === "boolean") { tabStates.set(tabId, enabled); } } }) .catch(() => undefined); const controllerReady = Promise.all([fontStyleReady, tabStatesReady]); function validTabId(tabId) { return Number.isInteger(tabId) && tabId >= 0; } async function persistTabStates() { await api.storage.session.set({ [TAB_STATES_KEY]: Object.fromEntries(tabStates) }); } async function broadcast(tabId, enabled) { await fontStyleReady; try { await api.tabs.sendMessage(tabId, { type: "glagolify:set-enabled", enabled, fontStyle }); return true; } catch (error) { return false; } } function handleMessage(message, sender) { if (!message || typeof message.type !== "string") { return undefined; } if (message.type === "glagolify:document-ready") { const tabId = sender && sender.tab && sender.tab.id; return controllerReady.then(() => ({ enabled: validTabId(tabId) && tabStates.get(tabId) === true, fontStyle })); } if (message.type === "glagolify:get-tab-state") { const tabId = message.tabId; return controllerReady.then(async () => { if (!validTabId(tabId)) { return { enabled: false, available: false, fontStyle }; } const enabled = tabStates.get(tabId) === true; const available = await broadcast(tabId, enabled); return { enabled, available, fontStyle }; }); } if (message.type === "glagolify:set-tab-enabled") { const tabId = message.tabId; if (!validTabId(tabId) || typeof message.enabled !== "boolean") { return controllerReady.then(() => ({ enabled: false, available: false, fontStyle })); } return controllerReady.then(async () => { tabStates.set(tabId, message.enabled); await persistTabStates(); const available = await broadcast(tabId, message.enabled); return { enabled: message.enabled, available, fontStyle }; }); } if (message.type === "glagolify:set-font-style") { if (!FONT_STYLES.has(message.fontStyle)) { return controllerReady.then(() => ({ fontStyle, accepted: false })); } return controllerReady.then(async () => { await api.storage.local.set({ [FONT_STYLE_KEY]: message.fontStyle }); fontStyle = message.fontStyle; await Promise.all( [...tabStates] .filter(([, tabEnabled]) => tabEnabled) .map(([tabId]) => broadcast(tabId, true)) ); return { fontStyle, accepted: true }; }); } return undefined; } api.runtime.onMessage.addListener((message, sender, sendResponse) => { const response = handleMessage(message, sender); if (response === undefined) { return false; } Promise.resolve(response).then( (value) => sendResponse(value), () => sendResponse(undefined) ); return true; }); api.tabs.onRemoved.addListener(async (tabId) => { await tabStatesReady; if (tabStates.delete(tabId)) { await persistTabStates(); } }); return { tabStates, broadcast, controllerReady, getFontStyle: () => fontStyle }; } const exported = Object.freeze({ createBackgroundController }); const extensionApi = typeof browser === "object" ? browser : typeof chrome === "object" ? chrome : null; if (extensionApi && extensionApi.runtime && extensionApi.tabs) { createBackgroundController(extensionApi); } if (typeof module === "object" && module.exports) { module.exports = exported; } root.GlagolifyBackground = exported; })(typeof globalThis === "object" ? globalThis : this);