tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

profile-selector.mjs (5814B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
      6 import { html } from "chrome://global/content/vendor/lit.all.mjs";
      7 
      8 // eslint-disable-next-line import/no-unassigned-import
      9 import "chrome://browser/content/profiles/profile-card.mjs";
     10 // eslint-disable-next-line import/no-unassigned-import
     11 import "chrome://global/content/elements/moz-checkbox.mjs";
     12 
     13 const { SelectableProfileService } = ChromeUtils.importESModule(
     14  "resource:///modules/profiles/SelectableProfileService.sys.mjs"
     15 );
     16 
     17 /**
     18 * The element for display SelectableProfiles in the profile selector window
     19 */
     20 export class ProfileSelector extends MozLitElement {
     21  static properties = {
     22    profiles: { type: Array },
     23    showSelector: { type: Boolean },
     24  };
     25 
     26  static queries = {
     27    checkbox: "moz-checkbox",
     28    profileCards: { all: "profile-card" },
     29    createProfileCard: "new-profile-card",
     30  };
     31 
     32  #initPromise = null;
     33  #startupParams = null;
     34 
     35  constructor() {
     36    super();
     37 
     38    this.#initPromise = this.init();
     39    if (window.arguments?.[0] instanceof Ci.nsIDialogParamBlock) {
     40      this.#startupParams = window.arguments[0];
     41    }
     42  }
     43 
     44  get isStartupUI() {
     45    return !!this.#startupParams;
     46  }
     47 
     48  /**
     49   * Sets the return block for the startup UI.
     50   *
     51   * @param {SelectableProfile} profile The profile to launch
     52   * @param {string[]} args Any additional command line arguments to append
     53   */
     54  async setLaunchArguments(profile, args = []) {
     55    if (!this.#startupParams) {
     56      return;
     57    }
     58 
     59    this.#startupParams.SetInt(
     60      0,
     61      Ci.nsIToolkitProfileService.launchWithProfile
     62    );
     63    // Set start offline to false.
     64    this.#startupParams.SetInt(1, 0);
     65    // Number of new arguments.
     66    this.#startupParams.SetInt(2, args.length);
     67 
     68    this.#startupParams.objects.insertElementAt(await profile.rootDir, 0);
     69    this.#startupParams.objects.insertElementAt(await profile.localDir, 1);
     70 
     71    this.#startupParams.SetNumberStrings(args.length);
     72    for (let i = 0; i < args.length; i++) {
     73      this.#startupParams.SetString(i, args[i]);
     74    }
     75  }
     76 
     77  async getUpdateComplete() {
     78    let result = await super.getUpdateComplete();
     79    await this.#initPromise;
     80    return result;
     81  }
     82 
     83  async init() {
     84    if (this.initialized) {
     85      return;
     86    }
     87 
     88    document.addEventListener("LaunchProfile", this);
     89    document.addEventListener("CreateProfile", this);
     90    document.addEventListener("DeleteProfile", this);
     91 
     92    this.selectableProfileService = SelectableProfileService;
     93 
     94    await this.selectableProfileService.init();
     95    await this.selectableProfileService.maybeSetupDataStore();
     96    this.profiles = await this.selectableProfileService.getAllProfiles();
     97    this.showSelector =
     98      this.selectableProfileService.groupToolkitProfile.showProfileSelector;
     99 
    100    if (!this.profiles.length) {
    101      await this.selectableProfileService.setShowProfileSelectorWindow(false);
    102    }
    103 
    104    this.initialized = true;
    105    this.#initPromise = null;
    106 
    107    if (this.isStartupUI) {
    108      window.addEventListener("unload", () => {
    109        // In case the user closed the window manually.
    110        this.selectableProfileService.uninit();
    111      });
    112    }
    113  }
    114 
    115  handleCheckboxToggle() {
    116    this.showSelector = this.checkbox.checked;
    117    let state = this.showSelector ? "enabled" : "disabled";
    118    Glean.profilesSelectorWindow.showAtStartup.record({ value: state });
    119    this.selectableProfileService.setShowProfileSelectorWindow(
    120      this.showSelector
    121    );
    122  }
    123 
    124  async launchProfile(profile, url) {
    125    if (this.isStartupUI) {
    126      await this.setLaunchArguments(profile, url ? ["-url", url] : []);
    127      await this.selectableProfileService.uninit();
    128    } else {
    129      this.selectableProfileService.launchInstance(profile, url ? [url] : []);
    130    }
    131 
    132    window.close();
    133  }
    134 
    135  async handleEvent(event) {
    136    switch (event.type) {
    137      case "LaunchProfile": {
    138        Glean.profilesSelectorWindow.launch.record();
    139        let { profile, url } = event.detail;
    140        await this.launchProfile(profile, url);
    141        break;
    142      }
    143      case "CreateProfile": {
    144        let profile =
    145          await this.selectableProfileService.createNewProfile(false);
    146        await this.launchProfile(profile, "about:newprofile");
    147        break;
    148      }
    149      case "DeleteProfile": {
    150        let profile = event.detail;
    151        await this.launchProfile(profile, "about:deleteprofile");
    152        break;
    153      }
    154    }
    155  }
    156 
    157  render() {
    158    if (!this.profiles) {
    159      return null;
    160    }
    161 
    162    return html`<link
    163        rel="stylesheet"
    164        href="chrome://browser/content/profiles/profile-selector.css"
    165      />
    166      <link
    167        rel="stylesheet"
    168        href="chrome://global/skin/in-content/common.css"
    169      />
    170      <img
    171        class="logo"
    172        data-l10n-id="profile-window-logo"
    173        data-l10n-attrs="alt"
    174        src="chrome://branding/content/about-logo.svg"
    175      />
    176      <h1 data-l10n-id="profile-window-heading"></h1>
    177      <p class="profiles-body-text" data-l10n-id="profile-window-body"></p>
    178      <div class="profile-list">
    179        ${this.profiles.map(
    180          p => html`<profile-card .profile=${p}></profile-card>`
    181        )}
    182        <new-profile-card></new-profile-card>
    183      </div>
    184      <moz-checkbox
    185        @click=${this.handleCheckboxToggle}
    186        data-l10n-id="profile-window-checkbox-label-2"
    187        ?checked=${this.showSelector}
    188      >
    189        <span
    190          slot="description"
    191          data-l10n-id="profile-window-checkbox-subcopy"
    192          ?hidden=${this.showSelector}
    193        ></span>
    194      </moz-checkbox>`;
    195  }
    196 }
    197 
    198 customElements.define("profile-selector", ProfileSelector);