summaryrefslogtreecommitdiffstats
path: root/browser/components/translations/content/TranslationsPanelShared.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/translations/content/TranslationsPanelShared.sys.mjs')
-rw-r--r--browser/components/translations/content/TranslationsPanelShared.sys.mjs122
1 files changed, 122 insertions, 0 deletions
diff --git a/browser/components/translations/content/TranslationsPanelShared.sys.mjs b/browser/components/translations/content/TranslationsPanelShared.sys.mjs
new file mode 100644
index 0000000000..570528df3f
--- /dev/null
+++ b/browser/components/translations/content/TranslationsPanelShared.sys.mjs
@@ -0,0 +1,122 @@
+/* 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/. */
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs",
+});
+
+/**
+ * A class containing static functionality that is shared by both
+ * the FullPageTranslationsPanel and SelectTranslationsPanel classes.
+ */
+export class TranslationsPanelShared {
+ static #langListsInitState = new Map();
+
+ /**
+ * Defines lazy getters for accessing elements in the document based on provided entries.
+ *
+ * @param {Document} document - The document object.
+ * @param {object} lazyElements - An object where lazy getters will be defined.
+ * @param {object} entries - An object of key/value pairs for which to define lazy getters.
+ */
+ static defineLazyElements(document, lazyElements, entries) {
+ for (const [name, discriminator] of Object.entries(entries)) {
+ let element;
+ Object.defineProperty(lazyElements, name, {
+ get: () => {
+ if (!element) {
+ if (discriminator[0] === ".") {
+ // Lookup by class
+ element = document.querySelector(discriminator);
+ } else {
+ // Lookup by id
+ element = document.getElementById(discriminator);
+ }
+ }
+ if (!element) {
+ throw new Error(`Could not find "${name}" at "#${discriminator}".`);
+ }
+ return element;
+ },
+ });
+ }
+ }
+
+ /**
+ * Retrieves the initialization state of language lists for the specified panel.
+ *
+ * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel
+ * - The panel for which to look up the state.
+ */
+ static getLangListsInitState(panel) {
+ return TranslationsPanelShared.#langListsInitState.get(panel.id);
+ }
+
+ /**
+ * Builds the <menulist> of languages for both the "from" and "to". This can be
+ * called every time the popup is shown, as it will retry when there is an error
+ * (such as a network error) or be a noop if it's already initialized.
+ *
+ * @param {Document} document - The document object.
+ * @param {FullPageTranslationsPanel | SelectTranslationsPanel} panel
+ * - The panel for which to ensure language lists are built.
+ */
+ static async ensureLangListsBuilt(document, panel, innerWindowId) {
+ const { id } = panel;
+ switch (
+ TranslationsPanelShared.#langListsInitState.get(`${id}-${innerWindowId}`)
+ ) {
+ case "initialized":
+ // This has already been initialized.
+ return;
+ case "error":
+ case undefined:
+ // attempt to initialize
+ break;
+ default:
+ throw new Error(
+ `Unknown langList phase ${
+ TranslationsPanelShared.#langListsInitState
+ }`
+ );
+ }
+ /** @type {SupportedLanguages} */
+ const { languagePairs, fromLanguages, toLanguages } =
+ await lazy.TranslationsParent.getSupportedLanguages();
+
+ // Verify that we are in a proper state.
+ if (languagePairs.length === 0) {
+ throw new Error("No translation languages were retrieved.");
+ }
+
+ const fromPopups = panel.querySelectorAll(
+ ".translations-panel-language-menupopup-from"
+ );
+ const toPopups = panel.querySelectorAll(
+ ".translations-panel-language-menupopup-to"
+ );
+
+ for (const popup of fromPopups) {
+ for (const { langTag, displayName } of fromLanguages) {
+ const fromMenuItem = document.createXULElement("menuitem");
+ fromMenuItem.setAttribute("value", langTag);
+ fromMenuItem.setAttribute("label", displayName);
+ popup.appendChild(fromMenuItem);
+ }
+ }
+
+ for (const popup of toPopups) {
+ for (const { langTag, displayName } of toLanguages) {
+ const toMenuItem = document.createXULElement("menuitem");
+ toMenuItem.setAttribute("value", langTag);
+ toMenuItem.setAttribute("label", displayName);
+ popup.appendChild(toMenuItem);
+ }
+ }
+
+ TranslationsPanelShared.#langListsInitState.set(id, "initialized");
+ }
+}