Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  BuiltInThemes.sys.mjs   Sprache: unbekannt

 
/* 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,
        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);
  }

  /**
   * 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.
   *
   * @param {string} id
   *   A theme's ID.
   * @returns {boolean}
   *   Returns true if the theme is expired. False otherwise.
   */
  themeIsExpired(id) {
    let themeInfo = this.builtInThemeMap.get(id);
    return themeInfo?.expiry && new Date(themeInfo.expiry) < new Date();
  }

  /**
   * @param {string} id
   *   The theme's id.
   * @returns {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.
   * @returns {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} colorwayId
   *   The ID of the colorway add-on.
   * @returns {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} colorwayId
   *   The ID of the colorway add-on.
   * @returns {string}
   *   L10nId for intensity value of the colorway with the provided id, null if
   *   there's none.
   */
  getColorwayIntensityL10nId(colorwayId) {
    const result = ColorwayIntensityIdPostfixToL10nMap.find(([postfix]) =>
      colorwayId.endsWith(postfix)
    );
    return result ? result[1] : null;
  }

  /**
   * @param {string} colorwayId
   *   The ID of the colorway add-on.
   * @returns {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();

[ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge