tor-browser

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

commit c7f62c9b514cc7ae291f9d91270142f658e0d1ff
parent 6f18fa3f98d2a9370ba9843b93f94efacd85ae93
Author: Jeremy Swinarton <jswinarton@mozilla.com>
Date:   Mon, 29 Dec 2025 16:16:28 +0000

Bug 2001906: Improve multiselect behaviour for tab notes r=dwalker,tabbrowser-reviewers

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

Diffstat:
Mbrowser/components/tabbrowser/content/tabbrowser.js | 12++++++++++--
Mbrowser/components/tabnotes/test/browser/browser_tab_notes_menu.js | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 127 insertions(+), 2 deletions(-)

diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js @@ -9833,9 +9833,17 @@ var TabContextMenu = { let contextAddNote = document.getElementById("context_addNote"); let contextUpdateNote = document.getElementById("context_updateNote"); if (gBrowser._tabNotesEnabled) { + // Tab notes behaviour is disabled if a user has a selection of tabs that + // contains more than one canonical URL. + let multiselectingDiverseUrls = + this.multiselected && + !this.contextTabs.every( + t => t.canonicalUrl === this.contextTabs[0].canonicalUrl + ); + contextAddNote.disabled = - this.multiselected || !this.TabNotes.isEligible(this.contextTab); - contextUpdateNote.disabled = this.multiselected; + multiselectingDiverseUrls || !this.TabNotes.isEligible(this.contextTab); + contextUpdateNote.disabled = multiselectingDiverseUrls; this.TabNotes.has(this.contextTab).then(hasNote => { contextAddNote.hidden = hasNote; diff --git a/browser/components/tabnotes/test/browser/browser_tab_notes_menu.js b/browser/components/tabnotes/test/browser/browser_tab_notes_menu.js @@ -128,11 +128,16 @@ add_task(async function test_tabContextMenu_prefDisabled() { let tab = BrowserTestUtils.addTab(gBrowser, "https://www.example.com"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); let addNoteElement = document.getElementById("context_addNote"); + let updateNoteElement = document.getElementById("context_updateNote"); let tabContextMenu = await getContextMenu(tab, "tabContextMenu"); Assert.ok( addNoteElement.hidden, "'Add Note' is hidden from context menu when pref disabled" ); + Assert.ok( + updateNoteElement.hidden, + "'Update Note' is hidden from context menu when pref disabled" + ); await closeContextMenu(tabContextMenu); BrowserTestUtils.removeTab(tab); await SpecialPowers.popPrefEnv(); @@ -291,3 +296,115 @@ add_task(async function test_deleteTabNote() { BrowserTestUtils.removeTab(tab); await SpecialPowers.popPrefEnv(); }); + +add_task(async function test_ineligibleTabsDisableMenus() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.tabs.notes.enabled", true]], + }); + + let tabContextMenu = document.getElementById("tabContextMenu"); + let addNoteEntry = document.querySelector("#context_addNote"); + let updateNoteEntry = document.querySelector("#context_updateNote"); + + let eligibleTab = BrowserTestUtils.addTab( + gBrowser, + "https://www.example.com" + ); + await BrowserTestUtils.browserLoaded(eligibleTab.linkedBrowser); + + let ineligibleTab = BrowserTestUtils.addTab(gBrowser, "about:logo"); + await BrowserTestUtils.browserLoaded(ineligibleTab.linkedBrowser); + + info( + "Test that an eligible tab without a note has an enabled 'Add Note' entry" + ); + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + !addNoteEntry.hasAttribute("disabled"), + "Eligible tab has enabled 'Add Note' entry" + ); + await closeContextMenu(tabContextMenu); + + info("Test that an ineligible tab has a disabled 'Add Note' entry"); + await getContextMenu(ineligibleTab, "tabContextMenu"); + Assert.ok( + addNoteEntry.hasAttribute("disabled"), + "Ineligible tab has disabled 'Add Note' entry" + ); + await closeContextMenu(tabContextMenu); + + info( + "Test that a multiselection with at least one ineligible tab has a disabled 'Add Note' entry" + ); + gBrowser.selectedTabs = [eligibleTab, ineligibleTab]; + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + addNoteEntry.hasAttribute("disabled"), + "Multiselection with an ineligible tab has disabled 'Add Note' entry" + ); + await closeContextMenu(tabContextMenu); + + let eligibleSameCanonicalUrl = BrowserTestUtils.addTab( + gBrowser, + "https://www.example.com" + ); + await BrowserTestUtils.browserLoaded(eligibleSameCanonicalUrl.linkedBrowser); + let eligibleDifferentCanonicalUrl = BrowserTestUtils.addTab( + gBrowser, + "https://www.example.com/abc" + ); + await BrowserTestUtils.browserLoaded( + eligibleDifferentCanonicalUrl.linkedBrowser + ); + + info( + "Test that a multiselection with two tabs with the same canonical URL and no note has an enabled 'Add Note' entry" + ); + gBrowser.selectedTabs = [eligibleTab, eligibleSameCanonicalUrl]; + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + !addNoteEntry.hasAttribute("disabled"), + "Multiselection with two same canonical URLs has enabled 'Add Note' entry" + ); + await closeContextMenu(tabContextMenu); + + info( + "Test that a multiselection with two tabs with different canonical URLs has a disabled 'Add Note' entry" + ); + gBrowser.selectedTabs = [eligibleTab, eligibleDifferentCanonicalUrl]; + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + addNoteEntry.hasAttribute("disabled"), + "Multiselection with two different canonical URLs has disabled 'Add Note' entry" + ); + await closeContextMenu(tabContextMenu); + + info( + "Test that an eligible tab with a note has an enabled 'Update Note' entry" + ); + gBrowser.selectedTabs = [eligibleTab]; + await TabNotes.set(eligibleTab, "Some tab note"); + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + !updateNoteEntry.hasAttribute("disabled"), + "Eligible tab has enabled 'Update Note' entry" + ); + await closeContextMenu(tabContextMenu); + + info( + "Test that a multiselection with a tab with a note and an ineligible tab has a disabled 'Update Note' entry" + ); + gBrowser.selectedTabs = [eligibleTab, ineligibleTab]; + await getContextMenu(eligibleTab, "tabContextMenu"); + Assert.ok( + updateNoteEntry.hasAttribute("disabled"), + "Multiselection with a tab with note and ineligible tab has disabled 'Update Note' entry" + ); + await closeContextMenu(tabContextMenu); + + BrowserTestUtils.removeTab(eligibleTab); + BrowserTestUtils.removeTab(ineligibleTab); + BrowserTestUtils.removeTab(eligibleSameCanonicalUrl); + BrowserTestUtils.removeTab(eligibleDifferentCanonicalUrl); + await SpecialPowers.popPrefEnv(); +});