forked from mirrors/gecko-dev
		
	 3c0c3a2676
			
		
	
	
		3c0c3a2676
		
	
	
	
	
		
			
			This patch was generated as follows: Run: `./mach esmify --imports . --prefix=toolkit/mozapps/extensions/AddonManager` In the output there are linter/prettifier errors due to unused XPCOMUtils or separate importESModule calls. These have been fixed manually and verified with `./mach lint --outgoing`. The `esmify` script also inserts many unwanted newlines around imports that are broken on two lines due to length. Due to the number of these, I fixed them programatically. 1. Create patch from the changes so far. 2. From the patch, delete all lines that consist of "+" (i.e. added blank line). 3. Reset the working dir and apply the revised patch. 4. Verify that the diff between step 1 and 3 looks reasonable. 5. Verify that this patch as a whole looks reasonable. Commands: ``` git diff > rename.diff :%g/^+$/d git commit -va -m WIP-rename git revert HEAD git apply --recount rename.diff git diff HEAD^ # and verify that the removed lines are ok. git commit -va # one last review to verify correctness of whole patch. git rebase -i HEAD~3 # drop the WIP + reverted commit, pick only the last. ``` `git apply` has the `--recount` option to force it to ignore mismatches in line counts, which happens because we deleted added lines (^+$) without fixing up the line counts in the file headers. Differential Revision: https://phabricator.services.mozilla.com/D179874
		
			
				
	
	
		
			307 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
 | |
|   BuiltInThemeConfig: "resource:///modules/BuiltInThemeConfig.sys.mjs",
 | |
| });
 | |
| 
 | |
| const ColorwayL10n = new Localization(["browser/colorways.ftl"], true);
 | |
| 
 | |
| const kActiveThemePref = "extensions.activeThemeID";
 | |
| const kRetainedThemesPref = "browser.theme.retainedExpiredThemes";
 | |
| 
 | |
| const ColorwayIntensityIdPostfixToL10nMap = [
 | |
|   ["-soft-colorway@mozilla.org", "colorway-intensity-soft"],
 | |
|   ["-balanced-colorway@mozilla.org", "colorway-intensity-balanced"],
 | |
|   ["-bold-colorway@mozilla.org", "colorway-intensity-bold"],
 | |
| ];
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(
 | |
|   lazy,
 | |
|   "retainedThemes",
 | |
|   kRetainedThemesPref,
 | |
|   null,
 | |
|   null,
 | |
|   val => {
 | |
|     if (!val) {
 | |
|       return [];
 | |
|     }
 | |
| 
 | |
|     let parsedVal;
 | |
|     try {
 | |
|       parsedVal = JSON.parse(val);
 | |
|     } catch (ex) {
 | |
|       console.log(`${kRetainedThemesPref} has invalid value.`);
 | |
|       return [];
 | |
|     }
 | |
| 
 | |
|     return parsedVal;
 | |
|   }
 | |
| );
 | |
| 
 | |
| class _BuiltInThemes {
 | |
|   /**
 | |
|    * The list of themes to be installed. This is exposed on the class so tests
 | |
|    * can set custom config files.
 | |
|    */
 | |
|   builtInThemeMap = lazy.BuiltInThemeConfig;
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id An addon's id string.
 | |
|    * @returns {string}
 | |
|    *   If `id` refers to a built-in theme, returns a path pointing to the
 | |
|    *   theme's preview image. Null otherwise.
 | |
|    */
 | |
|   previewForBuiltInThemeId(id) {
 | |
|     let theme = this.builtInThemeMap.get(id);
 | |
|     if (theme) {
 | |
|       return `${theme.path}preview.svg`;
 | |
|     }
 | |
| 
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * If the active theme is built-in, this function calls
 | |
|    * AddonManager.maybeInstallBuiltinAddon for that theme.
 | |
|    */
 | |
|   maybeInstallActiveBuiltInTheme() {
 | |
|     const activeThemeID = Services.prefs.getStringPref(
 | |
|       kActiveThemePref,
 | |
|       "default-theme@mozilla.org"
 | |
|     );
 | |
|     let activeBuiltInTheme = this.builtInThemeMap.get(activeThemeID);
 | |
| 
 | |
|     if (activeBuiltInTheme) {
 | |
|       lazy.AddonManager.maybeInstallBuiltinAddon(
 | |
|         activeThemeID,
 | |
|         activeBuiltInTheme.version,
 | |
|         `resource://builtin-themes/${activeBuiltInTheme.path}`
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Ensures that all built-in themes are installed and expired themes are
 | |
|    * uninstalled.
 | |
|    */
 | |
|   async ensureBuiltInThemes() {
 | |
|     let installPromises = [];
 | |
|     installPromises.push(this._uninstallExpiredThemes());
 | |
| 
 | |
|     const now = new Date();
 | |
|     for (let [id, themeInfo] of this.builtInThemeMap.entries()) {
 | |
|       if (
 | |
|         !themeInfo.expiry ||
 | |
|         lazy.retainedThemes.includes(id) ||
 | |
|         new Date(themeInfo.expiry) > now
 | |
|       ) {
 | |
|         installPromises.push(
 | |
|           lazy.AddonManager.maybeInstallBuiltinAddon(
 | |
|             id,
 | |
|             themeInfo.version,
 | |
|             themeInfo.path
 | |
|           )
 | |
|         );
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     await Promise.all(installPromises);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id
 | |
|    *   A theme's ID.
 | |
|    * @returns {boolean}
 | |
|    *   Returns true if the theme is expired. False otherwise.
 | |
|    * @note This looks up the id in a Map rather than accessing a property on
 | |
|    *   the addon itself. That makes calls to this function O(m) where m is the
 | |
|    *   total number of built-in themes offered now or in the past. Since we
 | |
|    *   are using a Map, calls are O(1) in the average case.
 | |
|    */
 | |
|   themeIsExpired(id) {
 | |
|     let themeInfo = this.builtInThemeMap.get(id);
 | |
|     return themeInfo?.expiry && new Date(themeInfo.expiry) < new Date();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id
 | |
|    *   The theme's id.
 | |
|    * @return {boolean}
 | |
|    *   True if the theme with id `id` is both expired and retained. That is,
 | |
|    *   the user has the ability to use it after its expiry date.
 | |
|    */
 | |
|   isRetainedExpiredTheme(id) {
 | |
|     return lazy.retainedThemes.includes(id) && this.themeIsExpired(id);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id
 | |
|    *   The theme's id.
 | |
|    * @return {boolean}
 | |
|    *   True if the theme with id `id` is from the currently active theme.
 | |
|    */
 | |
|   isActiveTheme(id) {
 | |
|     return (
 | |
|       id ===
 | |
|       Services.prefs.getStringPref(
 | |
|         kActiveThemePref,
 | |
|         "default-theme@mozilla.org"
 | |
|       )
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Uninstalls themes after they expire. If the expired theme is active, then
 | |
|    * it is not uninstalled. Instead, it is saved so that the user can use it
 | |
|    * indefinitely.
 | |
|    */
 | |
|   async _uninstallExpiredThemes() {
 | |
|     const activeThemeID = Services.prefs.getStringPref(
 | |
|       kActiveThemePref,
 | |
|       "default-theme@mozilla.org"
 | |
|     );
 | |
|     const now = new Date();
 | |
|     const expiredThemes = Array.from(this.builtInThemeMap.entries()).filter(
 | |
|       ([id, themeInfo]) =>
 | |
|         !!themeInfo.expiry &&
 | |
|         !lazy.retainedThemes.includes(id) &&
 | |
|         new Date(themeInfo.expiry) <= now
 | |
|     );
 | |
|     for (let [id] of expiredThemes) {
 | |
|       if (id == activeThemeID) {
 | |
|         let shouldRetain = true;
 | |
| 
 | |
|         try {
 | |
|           let addon = await lazy.AddonManager.getAddonByID(id);
 | |
|           if (addon) {
 | |
|             // Only add the id to the retain themes pref if it is
 | |
|             // also a built-in themes (and don't if it was migrated
 | |
|             // xpi files installed in the user profile).
 | |
|             shouldRetain = addon.isBuiltinColorwayTheme;
 | |
|           }
 | |
|         } catch (e) {
 | |
|           console.error(
 | |
|             `Failed to retrieve active theme AddonWrapper ${id}`,
 | |
|             e
 | |
|           );
 | |
|         }
 | |
| 
 | |
|         if (shouldRetain) {
 | |
|           this._retainLimitedTimeTheme(id);
 | |
|         }
 | |
|       } else {
 | |
|         try {
 | |
|           let addon = await lazy.AddonManager.getAddonByID(id);
 | |
|           // Only uninstall the expired colorways theme if they are not
 | |
|           // migrated builtins (because on migrated to xpi files
 | |
|           // installed in the user profile they are also removed
 | |
|           // from the retainedExpiredThemes pref).
 | |
|           if (addon?.isBuiltinColorwayTheme) {
 | |
|             await addon.uninstall();
 | |
|           }
 | |
|         } catch (e) {
 | |
|           console.error(`Failed to uninstall expired theme ${id}`, e);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Set a pref to ensure that the user can continue to use a specified theme
 | |
|    * past its expiry date.
 | |
|    * @param {string} id
 | |
|    *   The ID of the theme to retain.
 | |
|    */
 | |
|   _retainLimitedTimeTheme(id) {
 | |
|     if (!lazy.retainedThemes.includes(id)) {
 | |
|       lazy.retainedThemes.push(id);
 | |
|       Services.prefs.setStringPref(
 | |
|         kRetainedThemesPref,
 | |
|         JSON.stringify(lazy.retainedThemes)
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Removes from the retained expired theme list colorways themes that have been
 | |
|    * migrated from the one installed in the built-in XPIProvider location
 | |
|    * to an AMO hosted xpi installed in the user profile XPIProvider location.
 | |
|    * @param {string} id
 | |
|    *   The ID of the theme to remove from the retained themes list.
 | |
|    */
 | |
| 
 | |
|   unretainMigratedColorwayTheme(id) {
 | |
|     if (lazy.retainedThemes.includes(id)) {
 | |
|       const retainedThemes = lazy.retainedThemes.filter(
 | |
|         retainedThemeId => retainedThemeId !== id
 | |
|       );
 | |
|       Services.prefs.setStringPref(
 | |
|         kRetainedThemesPref,
 | |
|         JSON.stringify(retainedThemes)
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Colorway collections are usually divided into and presented as "groups".
 | |
|    * A group either contains closely related colorways, e.g. stemming from the
 | |
|    * same base color but with different intensities (soft, balanced, and bold),
 | |
|    * or if the current collection doesn't have intensities, each colorway is
 | |
|    * their own group. Group name localization is optional.
 | |
|    * @param {string} id
 | |
|    *   The ID of the colorway add-on.
 | |
|    * @return {string}
 | |
|    *   Localized colorway group name. null if there's no such name, in which
 | |
|    *   case the caller should fall back on getting a name from the add-on API.
 | |
|    */
 | |
|   getLocalizedColorwayGroupName(colorwayId) {
 | |
|     return this._getColorwayString(colorwayId, "groupName");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id
 | |
|    *   The ID of the colorway add-on.
 | |
|    * @return {string}
 | |
|    *   L10nId for intensity value of the colorway with the provided id, null if
 | |
|    *   there's none.
 | |
|    */
 | |
|   getColorwayIntensityL10nId(colorwayId) {
 | |
|     const result = ColorwayIntensityIdPostfixToL10nMap.find(
 | |
|       ([postfix, l10nId]) => colorwayId.endsWith(postfix)
 | |
|     );
 | |
|     return result ? result[1] : null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @param {string} id
 | |
|    *   The ID of the colorway add-on.
 | |
|    * @return {string}
 | |
|    *   Localized description of the colorway with the provided id, null if
 | |
|    *   there's none.
 | |
|    */
 | |
|   getLocalizedColorwayDescription(colorwayId) {
 | |
|     return this._getColorwayString(colorwayId, "description");
 | |
|   }
 | |
| 
 | |
|   _getColorwayString(colorwayId, stringType) {
 | |
|     let l10nId = this.builtInThemeMap.get(colorwayId)?.l10nId?.[stringType];
 | |
|     let s;
 | |
|     if (l10nId) {
 | |
|       [s] = ColorwayL10n.formatMessagesSync([
 | |
|         {
 | |
|           id: l10nId,
 | |
|         },
 | |
|       ]);
 | |
|     }
 | |
|     return s?.value || null;
 | |
|   }
 | |
| }
 | |
| 
 | |
| export var BuiltInThemes = new _BuiltInThemes();
 |