let logging = false; new (class ExtensionPopup { BROWSER_STORAGE_KEY = "transparentZenSettings"; globalSettings = {}; siteSettings = {}; enableStylingSwitch = document.getElementById("enable-styling"); refetchCSSButton = document.getElementById("refetch-css"); websitesList = document.getElementById("websites-list"); currentSiteFeatures = document.getElementById("current-site-toggles"); currentSiteHostname = ""; autoUpdateSwitch = document.getElementById("auto-update"); lastFetchedTime = document.getElementById("last-fetched-time"); constructor() { if (logging) console.log("Initializing ExtensionPopup"); // Load settings and initialize the popup this.loadSettings().then(() => { this.getCurrentTabInfo().then(() => { this.restoreSettings(); this.bindEvents(); }); }); // Bind event listeners this.refetchCSSButton.addEventListener("click", this.refetchCSS.bind(this)); this.autoUpdateSwitch.addEventListener( "change", this.saveSettings.bind(this) ); // Setup auto-update and display last fetched time this.setupAutoUpdate(); this.displayLastFetchedTime(); this.displayAddonVersion(); } async getCurrentTabInfo() { if (logging) console.log("getCurrentTabInfo called"); try { const tabs = await browser.tabs.query({ active: true, currentWindow: true, }); if (tabs.length > 0) { const url = new URL(tabs[0].url); this.currentSiteHostname = url.hostname; console.info("Current site hostname:", this.currentSiteHostname); } } catch (error) { console.error("Error getting current tab info:", error); } } bindEvents() { if (logging) console.log("bindEvents called"); // Bind event listeners for settings changes this.enableStylingSwitch.addEventListener("change", () => { this.saveSettings(); this.updateActiveTabStyling(); }); this.currentSiteFeatures.addEventListener("change", (event) => { if (event.target.type === "checkbox") { this.saveSettings(); this.updateActiveTabStyling(); } }); } restoreSettings() { if (logging) console.log("restoreSettings called"); // Restore global settings this.enableStylingSwitch.checked = this.globalSettings.enableStyling ?? true; this.autoUpdateSwitch.checked = this.globalSettings.autoUpdate ?? false; this.loadCurrentSiteFeatures(); } async loadSettings() { if (logging) console.log("loadSettings called"); // Load global settings const globalData = await browser.storage.local.get( this.BROWSER_STORAGE_KEY ); this.globalSettings = globalData[this.BROWSER_STORAGE_KEY] || { enableStyling: true, autoUpdate: false, lastFetchedTime: null, }; // Load site-specific settings if on a specific site if (this.currentSiteHostname) { const siteKey = `${this.BROWSER_STORAGE_KEY}.${this.currentSiteHostname}`; const siteData = await browser.storage.local.get(siteKey); this.siteSettings = siteData[siteKey] || {}; await this.loadCurrentSiteFeatures(); } } saveSettings() { if (logging) console.log("saveSettings called"); // Save global settings this.globalSettings.enableStyling = this.enableStylingSwitch.checked; this.globalSettings.autoUpdate = this.autoUpdateSwitch.checked; browser.storage.local .set({ [this.BROWSER_STORAGE_KEY]: this.globalSettings, }) .then(() => { if (logging) console.log("Global settings saved"); this.updateActiveTabStyling(); }); // Save site-specific settings if (this.currentSiteHostname) { const siteKey = `${this.BROWSER_STORAGE_KEY}.${this.currentSiteHostname}`; const featureSettings = {}; this.currentSiteFeatures .querySelectorAll("input[type=checkbox]") .forEach((checkbox) => { const [, feature] = checkbox.name.split("|"); featureSettings[feature] = checkbox.checked; }); this.siteSettings = featureSettings; browser.storage.local .set({ [siteKey]: featureSettings, }) .then(() => { if (logging) console.log("Site settings saved"); this.updateActiveTabStyling(); }); } console.info("Settings saved", { global: this.globalSettings, site: this.siteSettings, }); } async loadCurrentSiteFeatures() { if (logging) console.log("loadCurrentSiteFeatures called"); try { const stylesData = await browser.storage.local.get("styles"); const styles = stylesData.styles?.website || {}; this.currentSiteFeatures.innerHTML = ""; const currentSiteKey = Object.keys(styles).find((site) => this.isCurrentSite(site.replace(".css", "")) ); if (!currentSiteKey) { const requestThemeButton = document.createElement("button"); requestThemeButton.className = "action-button primary"; requestThemeButton.innerHTML = `Request Theme for ${this.currentSiteHostname}`; requestThemeButton.addEventListener("click", () => { const issueUrl = `https://github.com/sameerasw/my-internet/issues/new?template=website-theme-request.md&title=[THEME] ${this.currentSiteHostname}&body=Please add a theme for ${this.currentSiteHostname}`; window.open(issueUrl, "_blank"); }); this.currentSiteFeatures.appendChild(requestThemeButton); return; } // Load site-specific settings before creating toggles const siteKey = `${this.BROWSER_STORAGE_KEY}.${this.currentSiteHostname}`; const siteData = await browser.storage.local.get(siteKey); this.siteSettings = siteData[siteKey] || {}; const features = styles[currentSiteKey]; for (const [feature, css] of Object.entries(features)) { const displayFeatureName = feature.includes("-") ? feature.split("-")[1] : feature; const isChecked = this.siteSettings[feature] ?? true; const featureToggle = document.createElement("div"); featureToggle.className = "feature-toggle"; featureToggle.innerHTML = ` ${displayFeatureName} `; this.currentSiteFeatures.appendChild(featureToggle); } } catch (error) { console.error("Error loading current site features:", error); this.currentSiteFeatures.innerHTML = "
Error loading features.
"; } } isCurrentSite(siteName) { if (logging) console.log("isCurrentSite called with", siteName); if (!this.currentSiteHostname) return false; if (siteName.startsWith("+")) { const baseSiteName = siteName.slice(1); return this.currentSiteHostname.endsWith(baseSiteName); } if (this.currentSiteHostname === siteName) return true; if (this.currentSiteHostname === `www.${siteName}`) return true; return false; } async refetchCSS() { if (logging) console.log("refetchCSS called"); this.refetchCSSButton.textContent = "Fetching..."; try { const response = await fetch( "https://sameerasw.github.io/my-internet/styles.json", { headers: { "Cache-Control": "no-cache", }, } ); if (!response.ok) throw new Error("Failed to fetch styles.json"); const styles = await response.json(); await browser.storage.local.set({ styles }); await browser.storage.local.set({ lastFetchedTime: Date.now() }); this.loadCurrentSiteFeatures(); // this.loadWebsitesList(); this.updateActiveTabStyling(); this.refetchCSSButton.textContent = "Done!"; setTimeout(() => { this.refetchCSSButton.textContent = "Refetch latest styles"; }, 2000); console.info("All styles refetched and updated from GitHub." + styles); this.displayLastFetchedTime(); } catch (error) { this.refetchCSSButton.textContent = "Error!"; setTimeout(() => { this.refetchCSSButton.textContent = "Refetch latest styles"; }, 2000); console.error("Error refetching styles:", error); } } async updateActiveTabStyling() { if (logging) console.log("updateActiveTabStyling called"); const tabs = await browser.tabs.query({ active: true, currentWindow: true, }); if (tabs.length > 0) { this.applyCSSToTab(tabs[0]); } } async applyCSSToTab(tab) { if (logging) console.log("applyCSSToTab called with", tab); const url = new URL(tab.url); const hostname = url.hostname; try { await browser.tabs.removeCSS(tab.id, { code: "/* Placeholder for removing CSS */", }); } catch (error) {} if (!this.shouldApplyCSS(hostname)) return; try { const stylesData = await browser.storage.local.get("styles"); const styles = stylesData.styles?.website || {}; let siteKey = null; for (const site of Object.keys(styles)) { const siteName = site.replace(/\.css$/, ""); if (siteName.startsWith("+")) { const baseSiteName = siteName.slice(1); if (hostname.endsWith(baseSiteName)) { siteKey = site; break; } } else if (hostname === siteName || hostname === `www.${siteName}`) { siteKey = site; break; } } if (siteKey && styles[siteKey]) { const features = styles[siteKey]; const siteStorageKey = `${this.BROWSER_STORAGE_KEY}.${hostname}`; const siteData = await browser.storage.local.get(siteStorageKey); const featureSettings = siteData[siteStorageKey] || {}; let combinedCSS = ""; for (const [feature, css] of Object.entries(features)) { if (featureSettings[feature] !== false) { combinedCSS += css + "\n"; } } if (combinedCSS) { await browser.tabs.insertCSS(tab.id, { code: combinedCSS }); console.info(`Applied CSS to ${hostname}`); } } } catch (error) { console.error(`Error applying CSS to ${hostname}:`, error); } } shouldApplyCSS(hostname) { if (logging) console.log("shouldApplyCSS called with", hostname); return this.globalSettings.enableStyling !== false; } async displayAddonVersion() { if (logging) console.log("displayAddonVersion called"); const manifest = browser.runtime.getManifest(); const version = manifest.version; document.getElementById( "addon-version" ).textContent = `Version: ${version}`; } setupAutoUpdate() { if (logging) console.log("setupAutoUpdate called"); if (this.autoUpdateSwitch.checked) { browser.runtime.sendMessage({ action: "enableAutoUpdate" }); } else { browser.runtime.sendMessage({ action: "disableAutoUpdate" }); } } displayLastFetchedTime() { if (logging) console.log("displayLastFetchedTime called"); browser.storage.local.get("lastFetchedTime").then((result) => { if (result.lastFetchedTime) { this.lastFetchedTime.textContent = `Last fetched: ${new Date( result.lastFetchedTime ).toLocaleString()}`; } }); } })();