From 995789018939d6ebea2a3c6473c3f46b90d048b0 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Fri, 23 Feb 2024 21:30:34 +0000 Subject: [PATCH] Bug 1870300 - Add SelectTranslationsPanel class r=translations-reviewers,fluent-reviewers,desktop-theme-reviewers,bolsson,gregtatum,emilio Adds a new class for SelectTranslationsPanel. Differential Revision: https://phabricator.services.mozilla.com/D200502 --- browser/base/content/browser-context.inc | 3 +- browser/base/content/browser.js | 5 + browser/base/content/main-popupset.inc.xhtml | 1 + .../content/selectTranslationsPanel.inc.xhtml | 102 +++++++++++++ .../content/selectTranslationsPanel.js | 141 ++++++++++++++++++ .../content/translationsPanel.inc.xhtml | 3 +- browser/components/translations/jar.mn | 1 + .../locales-preview/select-translations.ftl | 21 +++ browser/themes/shared/translations/panel.css | 57 ++++++- 9 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 browser/components/translations/content/selectTranslationsPanel.inc.xhtml create mode 100644 browser/components/translations/content/selectTranslationsPanel.js diff --git a/browser/base/content/browser-context.inc b/browser/base/content/browser-context.inc index 9230c07f6a96..15bc856ae8c9 100644 --- a/browser/base/content/browser-context.inc +++ b/browser/base/content/browser-context.inc @@ -358,7 +358,8 @@ + data-l10n-id="main-context-menu-translate-selection" + oncommand="SelectTranslationsPanel.open(event);"/> diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d11b5d6e34b3..99a850988f13 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -182,6 +182,11 @@ XPCOMUtils.defineLazyScriptGetter( "gPermissionPanel", "chrome://browser/content/browser-sitePermissionPanel.js" ); +XPCOMUtils.defineLazyScriptGetter( + this, + "SelectTranslationsPanel", + "chrome://browser/content/translations/selectTranslationsPanel.js" +); XPCOMUtils.defineLazyScriptGetter( this, "TranslationsPanel", diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml index 4074f35ffc62..605d6de5a2b1 100644 --- a/browser/base/content/main-popupset.inc.xhtml +++ b/browser/base/content/main-popupset.inc.xhtml @@ -496,6 +496,7 @@ #include ../../components/controlcenter/content/permissionPanel.inc.xhtml #include ../../components/controlcenter/content/protectionsPanel.inc.xhtml #include ../../components/downloads/content/downloadsPanel.inc.xhtml +#include ../../components/translations/content/selectTranslationsPanel.inc.xhtml #include ../../components/translations/content/translationsPanel.inc.xhtml #include browser-allTabsMenu.inc.xhtml diff --git a/browser/components/translations/content/selectTranslationsPanel.inc.xhtml b/browser/components/translations/content/selectTranslationsPanel.inc.xhtml new file mode 100644 index 000000000000..72e2bd7095dc --- /dev/null +++ b/browser/components/translations/content/selectTranslationsPanel.inc.xhtml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/components/translations/content/selectTranslationsPanel.js b/browser/components/translations/content/selectTranslationsPanel.js new file mode 100644 index 000000000000..3fb0ea48f8f3 --- /dev/null +++ b/browser/components/translations/content/selectTranslationsPanel.js @@ -0,0 +1,141 @@ +/* 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/. */ + +/* eslint-env mozilla/browser-window */ + +/** + * This singleton class controls the Translations popup panel. + */ +var SelectTranslationsPanel = new (class { + /** @type {Console?} */ + #console; + + /** + * Lazily get a console instance. Note that this script is loaded in very early to + * the browser loading process, and may run before the console is available. In + * this case the console will return as `undefined`. + * + * @returns {Console | void} + */ + get console() { + if (!this.#console) { + try { + this.#console = console.createInstance({ + maxLogLevelPref: "browser.translations.logLevel", + prefix: "Translations", + }); + } catch { + // The console may not be initialized yet. + } + } + return this.#console; + } + + /** + * Where the lazy elements are stored. + * + * @type {Record?} + */ + #lazyElements; + + /** + * Lazily creates the dom elements, and lazily selects them. + * + * @returns {Record} + */ + get elements() { + if (!this.#lazyElements) { + // Lazily turn the template into a DOM element. + /** @type {HTMLTemplateElement} */ + const wrapper = document.getElementById( + "template-select-translations-panel" + ); + + const panel = wrapper.content.firstElementChild; + const settingsButton = document.getElementById( + "translations-panel-settings" + ); + wrapper.replaceWith(wrapper.content); + + // Lazily select the elements. + this.#lazyElements = { + panel, + settingsButton, + }; + + /** + * Define a getter on #lazyElements that gets the element by an id + * or class name. + */ + const getter = (name, discriminator) => { + let element; + Object.defineProperty(this.#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; + }, + }); + }; + + // Getters by id + getter("betaIcon", "select-translations-panel-beta-icon"); + getter("copyButton", "select-translations-panel-copy-button"); + getter("doneButton", "select-translations-panel-done-button"); + getter("fromLabel", "select-translations-panel-from-label"); + getter("fromMenuList", "select-translations-panel-from"); + getter("header", "select-translations-panel-header"); + getter("multiview", "select-translations-panel-multiview"); + getter("textArea", "select-translations-panel-translation-area"); + getter("toLabel", "select-translations-panel-to-label"); + getter("toMenuList", "select-translations-panel-to"); + getter( + "translateFullPageButton", + "select-translations-panel-translate-full-page-button" + ); + } + + return this.#lazyElements; + } + + /** + * Close the Select Translations Panel. + */ + close() { + PanelMultiView.hidePopup(this.elements.panel); + } + + /** + * Open the Select Translations Panel. + */ + async open(event) { + // TODO(Bug 1878721) Rework the logic of where to open the panel. + // + // For the moment, the Select Translations panel opens at the + // AppMenu Button, but it will eventually need to open near + // to the selected content. + const appMenuButton = document.getElementById("PanelUI-menu-button"); + const { panel, textArea } = this.elements; + + panel.addEventListener("popupshown", () => textArea.focus(), { + once: true, + }); + await PanelMultiView.openPopup(panel, appMenuButton, { + position: "bottomright topright", + triggerEvent: event, + }).catch(error => this.console?.error(error)); + } +})(); diff --git a/browser/components/translations/content/translationsPanel.inc.xhtml b/browser/components/translations/content/translationsPanel.inc.xhtml index 18769eec8319..ce8e77fb0058 100644 --- a/browser/components/translations/content/translationsPanel.inc.xhtml +++ b/browser/components/translations/content/translationsPanel.inc.xhtml @@ -27,7 +27,8 @@ - diff --git a/browser/components/translations/jar.mn b/browser/components/translations/jar.mn index 5f30e6f73ffc..b352e4b9313a 100644 --- a/browser/components/translations/jar.mn +++ b/browser/components/translations/jar.mn @@ -3,4 +3,5 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. browser.jar: + content/browser/translations/selectTranslationsPanel.js (content/selectTranslationsPanel.js) content/browser/translations/translationsPanel.js (content/translationsPanel.js) diff --git a/browser/locales-preview/select-translations.ftl b/browser/locales-preview/select-translations.ftl index ac6c2648bace..731abaff1ac7 100644 --- a/browser/locales-preview/select-translations.ftl +++ b/browser/locales-preview/select-translations.ftl @@ -28,3 +28,24 @@ main-context-menu-translate-link-text = # $language (string) - The localized display name of the target language main-context-menu-translate-link-text-to-language = .label = Translate Link Text to { $language } + +# Text displayed in the select translations panel header. +select-translations-panel-header = Translation + +# Text displayed above the from-language dropdown menu. +select-translations-panel-from-label = From + +# Text displayed above the to-language dropdown menu. +select-translations-panel-to-label = To + +# Text displayed on the copy button. +select-translations-panel-copy-button = Copy + +# Text displayed on the done button. +select-translations-panel-done-button = Done + +# Text displayed on translate-full-page button. +select-translations-panel-translate-full-page-button = Translate full page + +# Text displayed as a placeholder in the translated text area. +select-translations-panel-placeholder-text = Translated text will appear here. diff --git a/browser/themes/shared/translations/panel.css b/browser/themes/shared/translations/panel.css index b7e961846d73..e160b599cf1b 100644 --- a/browser/themes/shared/translations/panel.css +++ b/browser/themes/shared/translations/panel.css @@ -46,7 +46,7 @@ h1.translations-panel-header-wrapper { line-height: 1.6; } -#translations-panel-settings > image { +.translations-panel-settings-gear-icon > image { /* Override the panel-info-button with a gear icon. */ list-style-image: url(chrome://global/skin/icons/settings.svg); } @@ -54,7 +54,6 @@ h1.translations-panel-header-wrapper { .translations-panel-content { padding: var(--arrowpanel-padding); padding-block-end: 8px; - gap: var(--arrowpanel-padding); } #translations-panel-lang-selection > label { @@ -116,3 +115,57 @@ h1.translations-panel-header-wrapper { border-radius: 4px; padding: 12px; } + +.select-translations-panel-button { + align-items: center; + justify-content: center; + margin-inline: 0; +} + +.select-translations-panel-content { + padding: var(--arrowpanel-padding); + padding-block: 4px; +} + +.select-translations-panel-copy-button { + background-color: transparent; + font: message-box; + font-weight: var(--font-weight-bold); + &::before { + content: url(chrome://global/skin/icons/edit-copy.svg); + fill: currentColor; + margin-inline-end: 5px; + -moz-context-properties: fill; + } +} + +.select-translations-panel-header { + padding: var(--arrowpanel-padding); + text-align: initial; +} + +.select-translations-panel-label { + margin-inline: 2px; +} + +#select-translations-panel-lang-selection { + gap: 6px; +} + +#select-translations-panel-translation-area { + background-color: transparent; + border: none; + border-radius: 4px; + height: 8em; + margin-inline: 5px; + outline: 2px solid var(--arrowpanel-dimmed); + overflow: auto; + padding: 4px; + resize: none; + /* This manual focus styling may no longer be needed after Bug 1881256 lands. + https://bugzilla.mozilla.org/show_bug.cgi?id=1881256 */ + &:focus { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); + } +}