mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Bug 1497980 - Add a 'Duplicate Tabs' menuitem when multiple tabs are selected. r=Felipe
Differential Revision: https://phabricator.services.mozilla.com/D11281 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
a4d48c1eb9
commit
b357a678c4
@ -7740,6 +7740,18 @@ function duplicateTabIn(aTab, where, delta) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Duplicates tabs in the current window.
|
||||
* aTab may belongs to a multiselection of tabs.
|
||||
*/
|
||||
function duplicateTabs(aTab) {
|
||||
let tabsToDuplicate = aTab.multiselected ? gBrowser.selectedTabs : [aTab];
|
||||
let newIndex = tabsToDuplicate[tabsToDuplicate.length - 1]._tPos + 1;
|
||||
for (let tab of tabsToDuplicate) {
|
||||
let newTab = SessionStore.duplicateTab(window, tab);
|
||||
gBrowser.moveTabTo(newTab, newIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
var MousePosTracker = {
|
||||
_listeners: new Set(),
|
||||
_x: 0,
|
||||
|
@ -145,6 +145,9 @@ xmlns="http://www.w3.org/1999/xhtml"
|
||||
<menuitem id="context_duplicateTab" label="&duplicateTab.label;"
|
||||
accesskey="&duplicateTab.accesskey;"
|
||||
oncommand="duplicateTabIn(TabContextMenu.contextTab, 'tab');"/>
|
||||
<menuitem id="context_duplicateTabs" label="&duplicateTabs.label;"
|
||||
accesskey="&duplicateTabs.accesskey;"
|
||||
oncommand="duplicateTabs(TabContextMenu.contextTab);"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="context_selectAllTabs" label="&selectAllTabs.label;" accesskey="&selectAllTabs.accesskey;"
|
||||
oncommand="gBrowser.selectAllTabs();"/>
|
||||
|
@ -5436,9 +5436,9 @@ var TabContextMenu = {
|
||||
let contextMoveTabToStart = document.getElementById("context_moveToStart");
|
||||
contextMoveTabToStart.disabled = selectedTabs[0]._tPos == 0 && allSelectedTabsAdjacent;
|
||||
|
||||
// Hide the "Duplicate Tab" if there is a selection present
|
||||
let contextDuplicateTab = document.getElementById("context_duplicateTab");
|
||||
contextDuplicateTab.hidden = multiselectionContext;
|
||||
// Only one of "Duplicate Tab"/"Duplicate Tabs" should be visible.
|
||||
document.getElementById("context_duplicateTab").hidden = multiselectionContext;
|
||||
document.getElementById("context_duplicateTabs").hidden = !multiselectionContext;
|
||||
|
||||
// Disable "Close Tabs to the Right" if there are no tabs
|
||||
// following it.
|
||||
|
@ -7,11 +7,13 @@ add_task(async function setPref() {
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
let tab1 = await addTab();
|
||||
let tab2 = await addTab();
|
||||
let tab3 = await addTab();
|
||||
let originalTab = gBrowser.selectedTab;
|
||||
let tab1 = await addTab("http://example.com/1");
|
||||
let tab2 = await addTab("http://example.com/2");
|
||||
let tab3 = await addTab("http://example.com/3");
|
||||
|
||||
let menuItemDuplicateTab = document.getElementById("context_duplicateTab");
|
||||
let menuItemDuplicateTabs = document.getElementById("context_duplicateTabs");
|
||||
|
||||
is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
|
||||
|
||||
@ -25,24 +27,65 @@ add_task(async function test() {
|
||||
// Check the context menu with a multiselected tabs
|
||||
updateTabContextMenu(tab2);
|
||||
is(menuItemDuplicateTab.hidden, true, "Duplicate Tab is hidden");
|
||||
is(menuItemDuplicateTabs.hidden, false, "Duplicate Tabs is visible");
|
||||
|
||||
// Check the context menu with a non-multiselected tab
|
||||
updateTabContextMenu(tab3);
|
||||
is(menuItemDuplicateTab.hidden, false, "Duplicate Tab is visible");
|
||||
is(menuItemDuplicateTabs.hidden, true, "Duplicate Tabs is hidden");
|
||||
|
||||
let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "http://mochi.test:8888/");
|
||||
let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "http://example.com/3", true);
|
||||
window.TabContextMenu.contextTab = tab3; // Set proper context for command handler
|
||||
menuItemDuplicateTab.click();
|
||||
let tab4 = await newTabOpened;
|
||||
|
||||
is(getUrl(tab4), getUrl(tab3), "tab4 should have same URL as tab3, where it was duplicated from");
|
||||
|
||||
// Selection should be cleared after duplication
|
||||
ok(!tab1.multiselected, "Tab1 is not multiselected");
|
||||
ok(!tab2.multiselected, "Tab2 is not multiselected");
|
||||
ok(!tab4.multiselected, "Tab3 is not multiselected");
|
||||
ok(!tab3.multiselected, "Tab4 is not multiselected");
|
||||
ok(!tab3.multiselected, "Tab3 is not multiselected");
|
||||
ok(!tab4.multiselected, "Tab4 is not multiselected");
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
BrowserTestUtils.removeTab(tab3);
|
||||
BrowserTestUtils.removeTab(tab4);
|
||||
is(gBrowser.selectedTab._tPos, tab4._tPos, "Tab4 should be selected");
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
await triggerClickOn(tab3, { ctrlKey: true });
|
||||
|
||||
ok(tab1.multiselected, "Tab1 is multiselected");
|
||||
ok(!tab2.multiselected, "Tab2 is not multiselected");
|
||||
ok(tab3.multiselected, "Tab3 is multiselected");
|
||||
ok(!tab4.multiselected, "Tab4 is not multiselected");
|
||||
|
||||
// Check the context menu with a non-multiselected tab
|
||||
updateTabContextMenu(tab3);
|
||||
is(menuItemDuplicateTab.hidden, true, "Duplicate Tab is hidden");
|
||||
is(menuItemDuplicateTabs.hidden, false, "Duplicate Tabs is visible");
|
||||
|
||||
// 7 tabs because there was already one open when the test starts.
|
||||
let newTabsOpened = TestUtils.waitForCondition(() => gBrowser.visibleTabs.length == 7,
|
||||
"Wait for two tabs to get created");
|
||||
window.TabContextMenu.contextTab = tab3; // Set proper context for command handler
|
||||
menuItemDuplicateTabs.click();
|
||||
await newTabsOpened;
|
||||
|
||||
await Promise.all([
|
||||
BrowserTestUtils.browserLoaded(gBrowser.visibleTabs[4].linkedBrowser, null, "http://example.com/1"),
|
||||
BrowserTestUtils.browserLoaded(gBrowser.visibleTabs[5].linkedBrowser, null, "http://example.com/3"),
|
||||
]);
|
||||
|
||||
is(originalTab, gBrowser.visibleTabs[0], "Original tab should still be first");
|
||||
is(tab1, gBrowser.visibleTabs[1], "tab1 should still be second");
|
||||
is(tab2, gBrowser.visibleTabs[2], "tab2 should still be third");
|
||||
is(tab3, gBrowser.visibleTabs[3], "tab3 should still be fourth");
|
||||
is(getUrl(gBrowser.visibleTabs[4]), getUrl(tab1),
|
||||
"the first duplicated tab should be placed next to tab3 and have URL of tab1");
|
||||
is(getUrl(gBrowser.visibleTabs[5]), getUrl(tab3),
|
||||
"the second duplicated tab should have URL of tab3 and maintain same order");
|
||||
is(tab4, gBrowser.visibleTabs[6], "tab4 should now be the still be the seventh tab");
|
||||
|
||||
let tabsToClose = gBrowser.visibleTabs.filter(t => t != originalTab);
|
||||
for (let tab of tabsToClose) {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
@ -26,7 +26,15 @@
|
||||
<!-- LOCALIZATION NOTE (duplicateTab.label): This is a command to duplicate
|
||||
a tab (i.e. it is a verb, not adjective). -->
|
||||
<!ENTITY duplicateTab.label "Duplicate Tab">
|
||||
<!-- LOCALIZATION NOTE (duplicateTab.accesskey, duplicateTabs.accesskey):
|
||||
These items have the same accesskey but will never be visible at the same time. -->
|
||||
<!ENTITY duplicateTab.accesskey "D">
|
||||
<!-- LOCALIZATION NOTE (duplicateTabs.label): This is a command to duplicate
|
||||
a tab (i.e. it is a verb, not adjective). -->
|
||||
<!ENTITY duplicateTabs.label "Duplicate Tabs">
|
||||
<!-- LOCALIZATION NOTE (duplicateTab.accesskey, duplicateTabs.accesskey):
|
||||
These items have the same accesskey but will never be visible at the same time. -->
|
||||
<!ENTITY duplicateTabs.accesskey "D">
|
||||
<!-- LOCALIZATION NOTE (closeTabsToTheEnd.label): This should indicate the
|
||||
direction in which tabs are closed, i.e. locales that use RTL mode should say
|
||||
left instead of right. -->
|
||||
|
Loading…
Reference in New Issue
Block a user