summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/accountcreation/content/accountHub.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/accountcreation/content/accountHub.js')
-rw-r--r--comm/mail/components/accountcreation/content/accountHub.js277
1 files changed, 277 insertions, 0 deletions
diff --git a/comm/mail/components/accountcreation/content/accountHub.js b/comm/mail/components/accountcreation/content/accountHub.js
new file mode 100644
index 0000000000..a703ffce16
--- /dev/null
+++ b/comm/mail/components/accountcreation/content/accountHub.js
@@ -0,0 +1,277 @@
+/* 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/. */
+
+"use strict";
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+/**
+ * Holds the main controller class.
+ *
+ * @type {?AccountHubControllerClass}
+ */
+var AccountHubController;
+
+/**
+ * Controller class to handle the primary views of the account setup flow.
+ * This class acts as a sort of controller to lazily load the needed views upon
+ * request. It doesn't handle any data and it should only be used to switch
+ * between the different setup flows.
+ * All methods of this class should be private, except for the open() method.
+ */
+class AccountHubControllerClass {
+ /**
+ * The account hub main modal dialog.
+ *
+ * @type {?HTMLElement}
+ */
+ #modal = null;
+
+ /**
+ * The currently visible view inside the dialog.
+ *
+ * @type {?HTMLElement}
+ */
+ #currentView = null;
+
+ /**
+ * Object containing all strings to trigger the needed methods for the various
+ * views.
+ */
+ #accounts = {
+ START: () => this.#viewStart(),
+ MAIL: () => this.#viewEmailSetup(),
+ CALENDAR: () => this.#viewCalendarSetup(),
+ ADDRESS_BOOK: () => this.#viewAddressBookSetup(),
+ CHAT: () => this.#viewChatSetup(),
+ FEED: () => this.#viewFeedSetup(),
+ NNTP: () => this.#viewNNTPSetup(),
+ IMPORT: () => this.#viewImportSetup(),
+ };
+
+ constructor() {
+ this.ready = this.#init();
+ }
+
+ async #init() {
+ await this.#loadScript("container");
+ const element = document.createElement("account-hub-container");
+ document.body.appendChild(element);
+ this.#modal = element.modal;
+
+ let closeButton = this.#modal.querySelector("#closeButton");
+ closeButton.hidden = !MailServices.accounts.accounts.length;
+ closeButton.addEventListener("click", () => this.#modal.close());
+
+ // Listen from closing requests coming from child elements.
+ this.#modal.addEventListener(
+ "request-close",
+ event => {
+ event.stopPropagation();
+ this.#modal.close();
+ },
+ {
+ capture: true,
+ }
+ );
+
+ this.#modal.addEventListener(
+ "open-view",
+ event => {
+ event.stopPropagation();
+ this.open(event.detail.type);
+ },
+ {
+ capture: true,
+ }
+ );
+
+ this.#modal.addEventListener("close", event => {
+ // Don't allow the dialog to be closed if some operations are can't be
+ // aborted or the UI can't be cleared.
+ if (!this.#reset()) {
+ event.preventDefault();
+ }
+ });
+
+ this.#modal.addEventListener("cancel", event => {
+ if (
+ !MailServices.accounts.accounts.length &&
+ !Services.prefs.getBoolPref("app.use_without_mail_account", false)
+ ) {
+ // Prevent closing the modal if no account is currently present and the
+ // user didn't request using Thunderbird without an email account.
+ event.preventDefault();
+ return;
+ }
+
+ // Don't allow the dialog to be canceled via the ESC key if some
+ // operations are in progress and can't be aborted or the UI can't be
+ // cleared.
+ if (!this.#reset()) {
+ event.preventDefault();
+ }
+ });
+ }
+
+ /**
+ * Check if we don't currently have the needed custom element for the
+ * requested view and load the needed script. We do this to avoid loading all
+ * the unnecessary account creation files.
+ *
+ * @param {string} view - The name of the view to load.
+ * @returns {Promise<void>} Resolves when custom element of the view is usable.
+ */
+ #loadScript(view) {
+ if (customElements.get(`account-hub-${view}`)) {
+ return Promise.resolve();
+ }
+ // eslint-disable-next-line no-unsanitized/method
+ return import(
+ `chrome://messenger/content/accountcreation/views/${view}.mjs`
+ );
+ }
+
+ /**
+ * Create a custom element and append it to the modal inner HTML, or simply
+ * show it if it was already loaded.
+ *
+ * @param {string} id - The ID of the template to clone.
+ */
+ #loadView(id) {
+ this.#hideViews();
+
+ let view = this.#modal.querySelector(id);
+ if (view) {
+ view.hidden = false;
+ this.#currentView = view;
+ // Update the UI to make sure we're refreshing old views.
+ this.#currentView.initUI();
+ return;
+ }
+
+ view = document.createElement(id);
+ this.#modal.appendChild(view);
+ this.#currentView = view;
+ }
+
+ /**
+ * Hide all the currently visible views.
+ */
+ #hideViews() {
+ for (let view of this.#modal.querySelectorAll(".account-hub-view")) {
+ view.hidden = true;
+ }
+ }
+
+ /**
+ * Open the main modal dialog and load the requested account setup view, or
+ * fallback to the initial start screen.
+ *
+ * @param {?string} type - Which account flow to load when the modal opens.
+ */
+ open(type = "START") {
+ // Interrupt if something went wrong while cleaning up a previously loaded
+ // view.
+ if (!this.#reset()) {
+ return;
+ }
+
+ this.#accounts[type].call();
+ if (!this.#modal.open) {
+ this.#modal.showModal();
+ }
+ }
+
+ /**
+ * Check if we have a current class and try to trigger the rest in order to
+ * handle abort operations and markup clean up, if possible.
+ *
+ * @returns {boolean} - True if the reset process was successful or we didn't
+ * have anything to reset.
+ */
+ #reset() {
+ let isClean = this.#currentView?.reset() ?? true;
+ // If the reset operation was successful, clear the current class.
+ if (isClean) {
+ this.#hideViews();
+ this.#currentView = null;
+ }
+ return isClean;
+ }
+
+ /**
+ * Show the initial view of the account hub dialog.
+ */
+ async #viewStart() {
+ await this.#loadScript("start");
+ this.#loadView("account-hub-start");
+ }
+
+ /**
+ * Show the email setup view.
+ */
+ async #viewEmailSetup() {
+ await this.#loadScript("email");
+ this.#loadView("account-hub-email");
+ }
+
+ /**
+ * TODO: Show the calendar setup view.
+ */
+ #viewCalendarSetup() {
+ console.log("Calendar setup");
+ }
+
+ /**
+ * TODO: Show the address book setup view.
+ */
+ #viewAddressBookSetup() {
+ console.log("Address Book setup");
+ }
+
+ /**
+ * TODO: Show the chat setup view.
+ */
+ #viewChatSetup() {
+ console.log("Chat setup");
+ }
+
+ /**
+ * TODO: Show the feed setup view.
+ */
+ #viewFeedSetup() {
+ console.log("Feed setup");
+ }
+
+ /**
+ * TODO: Show the newsgroup setup view.
+ */
+ #viewNNTPSetup() {
+ console.log("Newsgroup setup");
+ }
+
+ /**
+ * TODO: Show the import setup view.
+ */
+ #viewImportSetup() {
+ console.log("Import setup");
+ }
+}
+
+/**
+ * Open the account hub dialog and show the requested view.
+ *
+ * @param {?string} type - The type of view that should be loaded when the modal
+ * is showed. See AccountHubController::#accounts for a list references.
+ */
+async function openAccountHub(type) {
+ if (!AccountHubController) {
+ AccountHubController = new AccountHubControllerClass();
+ }
+ await AccountHubController.ready;
+ AccountHubController.open(type);
+}