diff --git a/src/ZenThemesCommon.mjs b/src/ZenThemesCommon.mjs index 5da3ce4..11e030c 100644 --- a/src/ZenThemesCommon.mjs +++ b/src/ZenThemesCommon.mjs @@ -48,6 +48,7 @@ var ZenThemesCommon = { ); } } + return this.themes; }, @@ -105,4 +106,15 @@ var ZenThemesCommon = { } }; }, + + debounce(mainFunction, wait) { + let timerFlag; + + return (...args) => { + clearTimeout(timerFlag); + timerFlag = setTimeout(() => { + mainFunction(...args); + }, wait); + }; + }, }; diff --git a/src/ZenThemesImporter.mjs b/src/ZenThemesImporter.mjs index c14c2f9..0df876c 100644 --- a/src/ZenThemesImporter.mjs +++ b/src/ZenThemesImporter.mjs @@ -1,22 +1,29 @@ -const kZenStylesheetThemeHeader = ` -/* Zen Themes - Generated by ZenThemeImporter. - * DO NOT EDIT THIS FILE DIRECTLY! - * Your changes will be overwritten. - * Instead, go to the preferences and edit the themes there. - */ +const kZenStylesheetThemeHeader = '/* Zen Themes - Generated by ZenThemesImporter.'; +const kZenStylesheetThemeHeaderBody = `* DO NOT EDIT THIS FILE DIRECTLY! +* Your changes will be overwritten. +* Instead, go to the preferences and edit the themes there. +*/ `; const kenStylesheetFooter = ` /* End of Zen Themes */ `; +const getCurrentDateTime = () => + new Intl.DateTimeFormat('en-US', { + dateStyle: 'full', + timeStyle: 'full', + }).format(new Date().getTime()); var gZenStylesheetManager = { async writeStylesheet(path, themes) { let content = kZenStylesheetThemeHeader; + content += `\n* FILE GENERATED AT: ${getCurrentDateTime()}\n`; + content += kZenStylesheetThemeHeaderBody; for (let theme of themes) { if (theme.enabled !== undefined && !theme.enabled) { continue; } + content += this.getThemeCSS(theme); } @@ -29,26 +36,36 @@ var gZenStylesheetManager = { getThemeCSS(theme) { let css = '\n'; + + css += `/* Name: ${theme.name} */\n`; + css += `/* Description: ${theme.description} */\n`; + css += `/* Author: @${theme.author} */\n`; + if (theme._readmeURL) { - css += `/* Name: ${theme.name} */\n`; - css += `/* Description: ${theme.description} */\n`; - css += `/* Author: @${theme.author} */\n`; css += `/* Readme: ${theme.readme} */\n`; } + css += `@import url("${theme._chromeURL}");\n`; + return css; }, }; -var gZenThemeImporter = new (class { +var gZenThemesImporter = new (class { constructor() { - console.info('ZenThemeImporter: Initiating Zen theme importer'); + console.info('[ZenThemesImporter]: Initializing Zen Themes Importer'); + try { window.SessionStore.promiseInitialized.then(async () => { - this.insertStylesheet(); + if (Services.prefs.getBoolPref('zen.themes.disable-all', false)) { + console.log('[ZenThemesImporter]: Disabling all themes.'); + return; + } + + const themes = await this.getEnabledThemes(); const themesWithPreferences = await Promise.all( - Object.values(await ZenThemesCommon.getThemes()).map(async (theme) => { + themes.map(async (theme) => { const preferences = await ZenThemesCommon.getThemePreferences(theme); return { @@ -60,12 +77,16 @@ var gZenThemeImporter = new (class { ); this.writeToDom(themesWithPreferences); + + await this.insertStylesheet(); }); - console.info('ZenThemeImporter: Zen theme imported'); + console.info('[ZenThemesImporter]: Zen Themes imported'); } catch (e) { - console.error('ZenThemeImporter: Error importing Zen theme: ', e); + console.error('[ZenThemesImporter]: Error importing Zen Themes: ', e); } + Services.prefs.addObserver('zen.themes.updated-value-observer', this.rebuildThemeStylesheet.bind(this), false); + Services.prefs.addObserver('zen.themes.disable-all', this.handleDisableThemes.bind(this), false); } get sss() { @@ -79,9 +100,16 @@ var gZenThemeImporter = new (class { return PathUtils.join(PathUtils.profileDir, 'chrome', 'zen-themes.css'); } - async rebuildThemeStylesheet() { - ZenThemesCommon.themes = null; - await this.updateStylesheet(); + async handleDisableThemes() { + if (Services.prefs.getBoolPref('zen.themes.disable-all', false)) { + console.log('[ZenThemesImporter]: Disabling themes module.'); + + await this.removeStylesheet(); + } else { + console.log('[ZenThemesImporter]: Enabling themes module.'); + + await this.rebuildThemeStylesheet(); + } } get styleSheetURI() { @@ -99,21 +127,32 @@ var gZenThemeImporter = new (class { if (await IOUtils.exists(this.styleSheetPath)) { await this.sss.loadAndRegisterSheet(this.styleSheetURI, this.sss.AGENT_SHEET); } + + if (this.sss.sheetRegistered(this.styleSheetURI, this.sss.AGENT_SHEET)) { + console.debug('[ZenThemesImporter]: Sheet successfully registered'); + } } async removeStylesheet() { await this.sss.unregisterSheet(this.styleSheetURI, this.sss.AGENT_SHEET); + await IOUtils.remove(this.styleSheetPath, { ignoreAbsent: true }); + + if (!this.sss.sheetRegistered(this.styleSheetURI, this.sss.AGENT_SHEET) && !(await IOUtils.exists(this.styleSheetPath))) { + console.debug('[ZenThemesImporter]: Sheet successfully unregistered'); + } } - async updateStylesheet() { + async rebuildThemeStylesheet() { if (Services.focus.activeWindow !== window) { return; } - console.log('ZenThemeImporter: Updating Zen themes'); + ZenThemesCommon.themes = null; + await this.removeStylesheet(); - const themes = Object.values(await ZenThemesCommon.getThemes()); + const themes = await this.getEnabledThemes(); + await this.writeStylesheet(themes); const themesWithPreferences = await Promise.all( @@ -134,6 +173,22 @@ var gZenThemeImporter = new (class { await this.insertStylesheet(); } + async getEnabledThemes() { + const themeObject = await ZenThemesCommon.getThemes(); + const themes = Object.values(themeObject).filter((theme) => theme.enabled === undefined || theme.enabled); + + const themeList = themes.map(({ name }) => name).join(', '); + + const message = + themeList !== '' + ? `[ZenThemesImporter]: Loading enabled Zen themes: ${themeList}.` + : '[ZenThemesImporter]: No enabled Zen themes.'; + + console.log(message); + + return themes; + } + setDefaults(themesWithPreferences) { for (const { preferences, enabled } of themesWithPreferences) { if (enabled !== undefined && !enabled) { @@ -237,7 +292,7 @@ var gZenThemeImporter = new (class { } } - async writeStylesheet(themeList) { + async writeStylesheet(themeList = []) { const themes = []; ZenThemesCommon.themes = null; diff --git a/src/actors/ZenThemeMarketplaceParent.sys.mjs b/src/actors/ZenThemeMarketplaceParent.sys.mjs index b92abea..cd60bbd 100644 --- a/src/actors/ZenThemeMarketplaceParent.sys.mjs +++ b/src/actors/ZenThemeMarketplaceParent.sys.mjs @@ -104,12 +104,16 @@ export class ZenThemeMarketplaceParent extends JSWindowActorParent { await this.checkForThemeChanges(); } - getStyleSheetFullContent(style) { - return ` - @-moz-document url-prefix("chrome:") { - ${style} - } - `; + getStyleSheetFullContent(style = '') { + let stylesheet = '@-moz-document url-prefix("chrome:") {'; + + for (const line of style.split('\n')) { + stylesheet += ` ${line}`; + } + + stylesheet += '}'; + + return stylesheet; } async downloadUrlToFile(url, path, isStyleSheet = false) {