From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../content/TranslationsPanelShared.sys.mjs | 93 +++++++++++++++++++--- 1 file changed, 81 insertions(+), 12 deletions(-) (limited to 'browser/components/translations/content/TranslationsPanelShared.sys.mjs') diff --git a/browser/components/translations/content/TranslationsPanelShared.sys.mjs b/browser/components/translations/content/TranslationsPanelShared.sys.mjs index 570528df3f..f5045f57e0 100644 --- a/browser/components/translations/content/TranslationsPanelShared.sys.mjs +++ b/browser/components/translations/content/TranslationsPanelShared.sys.mjs @@ -11,9 +11,53 @@ ChromeUtils.defineESModuleGetters(lazy, { /** * A class containing static functionality that is shared by both * the FullPageTranslationsPanel and SelectTranslationsPanel classes. + * + * It is recommended to read the documentation above the TranslationsParent class + * definition to understand the scope of the Translations architecture throughout + * Firefox. + * + * @see TranslationsParent + * + * The static instance of this class is a singleton in the parent process, and is + * available throughout all windows and tabs, just like the static instance of + * the TranslationsParent class. + * + * Unlike the TranslationsParent, this class is never instantiated as an actor + * outside of the static-context functionality defined below. */ export class TranslationsPanelShared { - static #langListsInitState = new Map(); + /** + * A map from Translations Panel instances to their initialized states. + * There is one instance of each panel per top ChromeWindow in Firefox. + * + * See the documentation above the TranslationsParent class for a detailed + * explanation of the translations architecture throughout Firefox. + * + * @see TranslationsParent + * + * @type {Map} + */ + static #langListsInitState = new WeakMap(); + + /** + * True if the next language-list initialization to fail for testing. + * + * @see TranslationsPanelShared.ensureLangListsBuilt + * + * @type {boolean} + */ + static #simulateLangListError = false; + + /** + * Clears cached data regarding the initialization state of the + * FullPageTranslationsPanel or the SelectTranslationsPanel. + * + * This is only needed for test runners to ensure that each test + * starts from a clean slate. + */ + static clearCache() { + this.#langListsInitState = new WeakMap(); + } /** * Defines lazy getters for accessing elements in the document based on provided entries. @@ -45,6 +89,18 @@ export class TranslationsPanelShared { } } + /** + * Ensures that the next call to ensureLangListBuilt wil fail + * for the purpose of testing the error state. + * + * @see TranslationsPanelShared.ensureLangListsBuilt + * + * @type {boolean} + */ + static simulateLangListError() { + this.#simulateLangListError = true; + } + /** * Retrieves the initialization state of language lists for the specified panel. * @@ -52,7 +108,7 @@ export class TranslationsPanelShared { * - The panel for which to look up the state. */ static getLangListsInitState(panel) { - return TranslationsPanelShared.#langListsInitState.get(panel.id); + return TranslationsPanelShared.#langListsInitState.get(panel); } /** @@ -64,17 +120,17 @@ export class TranslationsPanelShared { * @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}`) - ) { + static async ensureLangListsBuilt(document, panel) { + const { panel: panelElement } = panel.elements; + switch (TranslationsPanelShared.#langListsInitState.get(panel)) { case "initialized": // This has already been initialized. return; case "error": case undefined: - // attempt to initialize + // Set the error state in case there is an early exit at any point. + // This will be set to "initialized" if everything succeeds. + TranslationsPanelShared.#langListsInitState.set(panel, "error"); break; default: throw new Error( @@ -88,18 +144,28 @@ export class TranslationsPanelShared { await lazy.TranslationsParent.getSupportedLanguages(); // Verify that we are in a proper state. - if (languagePairs.length === 0) { + if (languagePairs.length === 0 || this.#simulateLangListError) { + this.#simulateLangListError = false; throw new Error("No translation languages were retrieved."); } - const fromPopups = panel.querySelectorAll( + const fromPopups = panelElement.querySelectorAll( ".translations-panel-language-menupopup-from" ); - const toPopups = panel.querySelectorAll( + const toPopups = panelElement.querySelectorAll( ".translations-panel-language-menupopup-to" ); for (const popup of fromPopups) { + // For the moment, the FullPageTranslationsPanel includes its own + // menu item for "Choose another language" as the first item in the list + // with an empty-string for its value. The SelectTranslationsPanel has + // only languages in its list with BCP-47 tags for values. As such, + // this loop works for both panels, to remove all of the languages + // from the list, but ensuring that any empty-string items are retained. + while (popup.lastChild?.value) { + popup.lastChild.remove(); + } for (const { langTag, displayName } of fromLanguages) { const fromMenuItem = document.createXULElement("menuitem"); fromMenuItem.setAttribute("value", langTag); @@ -109,6 +175,9 @@ export class TranslationsPanelShared { } for (const popup of toPopups) { + while (popup.lastChild?.value) { + popup.lastChild.remove(); + } for (const { langTag, displayName } of toLanguages) { const toMenuItem = document.createXULElement("menuitem"); toMenuItem.setAttribute("value", langTag); @@ -117,6 +186,6 @@ export class TranslationsPanelShared { } } - TranslationsPanelShared.#langListsInitState.set(id, "initialized"); + TranslationsPanelShared.#langListsInitState.set(panel, "initialized"); } } -- cgit v1.2.3