tor-browser

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

commit a732f23dada401e66d35fd2754a64ffb8f623a0b
parent ee0aa61469c0c92714b456b38962725f6644f26f
Author: Giulia Cardieri <gcardieri@mozilla.com>
Date:   Tue, 25 Nov 2025 14:25:21 +0000

Bug 1929675 - Update shortcut interaction from hover to click. r=ngrato,ai-frontend-reviewers,yjamora

Differential Revision: https://phabricator.services.mozilla.com/D273450

Diffstat:
Mbrowser/app/profile/firefox.js | 1+
Mbrowser/components/genai/GenAI.sys.mjs | 43+++++++++++++++++++++++++++++++++++++------
Mbrowser/components/genai/tests/browser/browser_chat_shortcuts.js | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -2206,6 +2206,7 @@ pref("browser.ml.chat.provider", ""); pref("browser.ml.chat.shortcuts", true); pref("browser.ml.chat.shortcuts.custom", true); pref("browser.ml.chat.shortcuts.longPress", 60000); +pref("browser.ml.chat.shortcut.onboardingMouseoverCount", 0); pref("browser.ml.chat.sidebar", true); pref("browser.ml.linkPreview.allowedLanguages", "en"); diff --git a/browser/components/genai/GenAI.sys.mjs b/browser/components/genai/GenAI.sys.mjs @@ -108,6 +108,12 @@ XPCOMUtils.defineLazyPreferenceGetter( "sidebarTools", "sidebar.main.tools" ); +XPCOMUtils.defineLazyPreferenceGetter( + lazy, + "shortcutMouseoverCount", + "browser.ml.chat.shortcut.onboardingMouseoverCount", + 0 +); export const GenAI = { // Cache of potentially localized prompt @@ -448,12 +454,8 @@ export const GenAI = { return mozMessageBarEl; }; - // Detect hover to build and open the popup - aiActionButton.addEventListener("mouseover", async () => { - if (chatShortcutsOptionsPanel.state != "closed") { - return; - } - + // build the ask popup + const buildPopup = async () => { aiActionButton.setAttribute("type", buttonActiveState); const vbox = chatShortcutsOptionsPanel.querySelector("vbox"); vbox.innerHTML = ""; @@ -551,6 +553,35 @@ export const GenAI = { provider: this.getProviderId(), warning: showWarning, }); + }; + + // ask popup shows on mouseover only in the first two times + const hasMouseoverOnPopup = () => { + const mouseoverCounter = lazy.shortcutMouseoverCount; + const maxMouseoverCount = 2; + + if (mouseoverCounter >= maxMouseoverCount) { + return; + } + + if (chatShortcutsOptionsPanel.state == "closed") { + Services.prefs.setIntPref( + "browser.ml.chat.shortcut.onboardingMouseoverCount", + mouseoverCounter + 1 + ); + buildPopup(); + } + }; + + aiActionButton.addEventListener("mouseover", hasMouseoverOnPopup); + + // Detect click to build and toggle the popup + aiActionButton.addEventListener("click", async () => { + if (chatShortcutsOptionsPanel.state != "closed") { + chatShortcutsOptionsPanel.hidePopup(); + return; + } + buildPopup(); }); }, diff --git a/browser/components/genai/tests/browser/browser_chat_shortcuts.js b/browser/components/genai/tests/browser/browser_chat_shortcuts.js @@ -38,6 +38,7 @@ add_task(async function test_show_shortcuts() { await SpecialPowers.pushPrefEnv({ set: [ ["browser.ml.chat.shortcuts", true], + ["browser.ml.chat.shortcut.onboardingMouseoverCount", 0], ["browser.ml.chat.provider", "http://localhost:8080"], ], }); @@ -73,15 +74,82 @@ add_task(async function test_show_shortcuts() { const popup = document.getElementById("chat-shortcuts-options-panel"); Assert.equal(popup.state, "closed", "Popup is closed"); + Assert.equal( + Services.prefs.getIntPref( + "browser.ml.chat.shortcut.onboardingMouseoverCount" + ), + 0, + "Pref should start at 0" + ); + EventUtils.sendMouseEvent({ type: "mouseover" }, shortcuts); await BrowserTestUtils.waitForEvent(popup, "popupshown"); + Assert.equal( + Services.prefs.getIntPref( + "browser.ml.chat.shortcut.onboardingMouseoverCount" + ), + 1, + "Pref should be 1 after mouseover" + ); + Assert.equal( + popup.state, + "open", + "Popup is open with mouseover the first time" + ); + const hidePopup = BrowserTestUtils.waitForEvent(popup, "popuphidden"); + popup.hidePopup(); + await hidePopup; - Assert.equal(popup.state, "open", "Popup is open"); - events = Glean.genaiChatbot.shortcutsExpanded.testGetValue(); - Assert.equal(events.length, 1, "One shortcuts opened"); - Assert.equal(events[0].extra.selection, 2, "Selected hi"); + EventUtils.sendMouseEvent({ type: "mouseover" }, shortcuts); + await BrowserTestUtils.waitForEvent(popup, "popupshown"); + Assert.equal( + Services.prefs.getIntPref( + "browser.ml.chat.shortcut.onboardingMouseoverCount" + ), + 2, + "Pref should be 2 after second mouseover" + ); + + Assert.equal( + popup.state, + "open", + "Popup is open with mouseover the second time" + ); + const hidePopupSecondTime = BrowserTestUtils.waitForEvent( + popup, + "popuphidden" + ); + popup.hidePopup(); + await hidePopupSecondTime; + + EventUtils.sendMouseEvent({ type: "mouseover" }, shortcuts); + Assert.equal( + Services.prefs.getIntPref( + "browser.ml.chat.shortcut.onboardingMouseoverCount" + ), + 2, + "Pref should still be 2 after third mouseover" + ); + Assert.equal( + popup.state, + "closed", + "Popup doesn't open with mouseover after the second time" + ); + + let beforeClick = Glean.genaiChatbot.shortcutsExpanded.testGetValue(); + EventUtils.sendMouseEvent({ type: "click" }, shortcuts); + await BrowserTestUtils.waitForEvent(popup, "popupshown"); + Assert.equal(popup.state, "open", "Popup open with click"); + let afterClick = Glean.genaiChatbot.shortcutsExpanded.testGetValue(); + Assert.equal( + afterClick.length, + beforeClick.length + 1, + "One shortcuts opened" + ); + const lastEvent = afterClick[afterClick.length - 1]; + Assert.equal(lastEvent.extra.selection, 2, "Selected hi"); Assert.equal( - events[0].extra.warning, + lastEvent.extra.warning, "false", "Warning lable value is correct" ); @@ -145,7 +213,7 @@ add_task(async function test_show_shortcuts_second_tab() { const stub = sandbox.stub(GenAI, "addAskChatItems"); const shortcuts = document.querySelector("#ai-action-button"); - EventUtils.sendMouseEvent({ type: "mouseover" }, shortcuts); + EventUtils.sendMouseEvent({ type: "click" }, shortcuts); Assert.equal(stub.callCount, 1, "Shortcuts added on select"); Assert.equal(stub.firstCall.args[0], browser, "Got correct browser"); @@ -202,8 +270,8 @@ add_task(async function test_show_warning_label() { "Selected enough text" ); - // Hover button - EventUtils.sendMouseEvent({ type: "mouseover" }, aiActionButton); + // Click button + EventUtils.sendMouseEvent({ type: "click" }, aiActionButton); const chatShortcutsOptionsPanel = document.getElementById( "chat-shortcuts-options-panel"