Bug 1472910 - Close all unselected tabs except those pinned with gBrowser.removeAllTabsBut(aTab) when aTab is multi-selected. r?jaws draft multiselect_close_other_tabs
authorAbdoulaye O. Ly <ablayelyfondou@gmail.com>
Thu, 12 Jul 2018 06:49:04 +0000
branchmultiselect_close_other_tabs
changeset 817594 9406ae33d830258d00a1f93329e0ca4358aebe8d
parent 817076 3aca103e49150145dbff910be15e7886b7c4495a
push id116126
push userbmo:ablayelyfondou@gmail.com
push dateFri, 13 Jul 2018 01:07:52 +0000
reviewersjaws
bugs1472910
milestone63.0a1
Bug 1472910 - Close all unselected tabs except those pinned with gBrowser.removeAllTabsBut(aTab) when aTab is multi-selected. r?jaws MozReview-Commit-ID: 9gqSJmiBbCs
browser/base/content/tabbrowser.js
browser/base/content/test/tabs/browser.ini
browser/base/content/test/tabs/browser_multiselect_tabs_close_other_tabs.js
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -2485,22 +2485,32 @@ window._gBrowser = {
   warnAboutClosingTabs(aCloseTabs, aTab, aOptionalMessage) {
     var tabsToClose;
     switch (aCloseTabs) {
       case this.closingTabsEnum.ALL:
         tabsToClose = this.tabs.length - this._removingTabs.length -
           gBrowser._numPinnedTabs;
         break;
       case this.closingTabsEnum.OTHER:
-        tabsToClose = this.visibleTabs.length - 1 - gBrowser._numPinnedTabs;
+        if (!aTab) {
+          throw new Error("Required argument missing: aTab");
+        }
+        if (aTab.multiselected) {
+          tabsToClose = this.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned).length;
+        } else {
+          // If aTab is pinned, it will already be considered
+          // with gBrowser._numPinnedTabs.
+          tabsToClose = this.visibleTabs.length - gBrowser._numPinnedTabs -
+            (aTab.pinned ? 0 : 1);
+        }
         break;
       case this.closingTabsEnum.TO_END:
-        if (!aTab)
+        if (!aTab) {
           throw new Error("Required argument missing: aTab");
-
+        }
         tabsToClose = this.getTabsToTheEndFrom(aTab).length;
         break;
       case this.closingTabsEnum.MULTI_SELECTED:
         tabsToClose = this.multiSelectedTabsCount;
         break;
       default:
         throw new Error("Invalid argument: " + aCloseTabs);
     }
@@ -2568,24 +2578,33 @@ window._gBrowser = {
   removeTabsToTheEndFrom(aTab) {
     if (!this.warnAboutClosingTabs(this.closingTabsEnum.TO_END, aTab))
       return;
 
     let tabs = this.getTabsToTheEndFrom(aTab);
     this.removeTabs(tabs);
   },
 
+  /**
+   * In a multi-select context, all unpinned and unselected tabs are removed.
+   * Otherwise all unpinned tabs except aTab are removed.
+   */
   removeAllTabsBut(aTab) {
-    if (!this.warnAboutClosingTabs(this.closingTabsEnum.OTHER)) {
+    if (!this.warnAboutClosingTabs(this.closingTabsEnum.OTHER, aTab)) {
       return;
     }
 
-    let tabs = this.visibleTabs.filter(tab => tab != aTab && !tab.pinned);
-    this.selectedTab = aTab;
-    this.removeTabs(tabs);
+    let tabsToRemove = [];
+    if (aTab && aTab.multiselected) {
+      tabsToRemove = this.visibleTabs.filter(tab => !tab.multiselected && !tab.pinned);
+    } else {
+      tabsToRemove = this.visibleTabs.filter(tab => tab != aTab && !tab.pinned);
+      this.selectedTab = aTab;
+    }
+    this.removeTabs(tabsToRemove);
   },
 
   removeMultiSelectedTabs() {
     if (!this.warnAboutClosingTabs(this.closingTabsEnum.MULTI_SELECTED)) {
       return;
     }
 
     this.removeTabs(this.selectedTabs);
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -15,16 +15,17 @@ tags = audiochannel
 [browser_bug580956.js]
 [browser_close_tab_by_dblclick.js]
 [browser_contextmenu_openlink_after_tabnavigated.js]
 skip-if = (verify && debug && (os == 'linux'))
 support-files =
   test_bug1358314.html
 [browser_isLocalAboutURI.js]
 [browser_multiselect_tabs_active_tab_selected_by_default.js]
+[browser_multiselect_tabs_close_other_tabs.js]
 [browser_multiselect_tabs_close_using_shortcuts.js]
 [browser_multiselect_tabs_close.js]
 [browser_multiselect_tabs_mute_unmute.js]
 [browser_multiselect_tabs_pin_unpin.js]
 [browser_multiselect_tabs_positional_attrs.js]
 [browser_multiselect_tabs_reload.js]
 [browser_multiselect_tabs_using_Ctrl.js]
 [browser_multiselect_tabs_using_Shift.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_multiselect_tabs_close_other_tabs.js
@@ -0,0 +1,108 @@
+const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
+const PREF_WARN_ON_CLOSE = "browser.tabs.warnOnCloseOtherTabs";
+
+add_task(async function setPref() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_MULTISELECT_TABS, true],
+      [PREF_WARN_ON_CLOSE, false]
+    ]
+  });
+});
+
+add_task(async function withAMultiSelectedTab() {
+  let initialTab = gBrowser.selectedTab;
+  let tab1 = await addTab();
+  let tab2 = await addTab();
+  let tab3 = await addTab();
+  let tab4 = await addTab();
+
+  is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
+
+  await triggerClickOn(tab1, { ctrlKey: true });
+
+  let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned");
+  gBrowser.pinTab(tab4);
+  await tab4Pinned;
+
+  ok(initialTab.multiselected, "InitialTab is multiselected");
+  ok(tab1.multiselected, "Tab1 is multiselected");
+  ok(!tab2.multiselected, "Tab2 is not multiselected");
+  ok(!tab3.multiselected, "Tab3 is not multiselected");
+  ok(!tab4.multiselected, "Tab4 is not multiselected");
+  ok(tab4.pinned, "Tab4 is pinned");
+  is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
+  is(gBrowser.selectedTab, initialTab, "InitialTab is the active tab");
+
+  let closingTabs = [tab2, tab3];
+  let tabClosingPromises = [];
+  for (let tab of closingTabs) {
+    tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab));
+  }
+
+  gBrowser.removeAllTabsBut(tab1);
+
+  for (let promise of tabClosingPromises) {
+    await promise;
+  }
+
+  ok(!initialTab.closing, "InitialTab is not closing");
+  ok(!tab1.closing, "Tab1 is not closing");
+  ok(tab2.closing, "Tab2 is closing");
+  ok(tab3.closing, "Tab3 is closing");
+  ok(!tab4.closing, "Tab4 is not closing");
+  is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
+  is(gBrowser.selectedTab, initialTab, "InitialTab is still the active tab");
+
+  gBrowser.clearMultiSelectedTabs(false);
+  BrowserTestUtils.removeTab(tab1);
+  BrowserTestUtils.removeTab(tab4);
+});
+
+add_task(async function withNotAMultiSelectedTab() {
+  let initialTab = gBrowser.selectedTab;
+  let tab1 = await addTab();
+  let tab2 = await addTab();
+  let tab3 = await addTab();
+  let tab4 = await addTab();
+
+  is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
+
+  await BrowserTestUtils.switchTab(gBrowser, tab1);
+  await triggerClickOn(tab2, { ctrlKey: true });
+
+  let tab4Pinned = BrowserTestUtils.waitForEvent(tab4, "TabPinned");
+  gBrowser.pinTab(tab4);
+  await tab4Pinned;
+
+  ok(!initialTab.multiselected, "InitialTab is not multiselected");
+  ok(tab1.multiselected, "Tab1 is multiselected");
+  ok(tab2.multiselected, "Tab2 is multiselected");
+  ok(!tab3.multiselected, "Tab3 is not multiselected");
+  ok(!tab4.multiselected, "Tab4 is not multiselected");
+  ok(tab4.pinned, "Tab4 is pinned");
+  is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
+  is(gBrowser.selectedTab, tab1, "Tab1 is the active tab");
+
+  let closingTabs = [tab1, tab2, tab3];
+  let tabClosingPromises = [];
+  for (let tab of closingTabs) {
+    tabClosingPromises.push(BrowserTestUtils.waitForTabClosing(tab));
+  }
+
+  await BrowserTestUtils.switchTab(gBrowser, gBrowser.removeAllTabsBut(initialTab));
+
+  for (let promise of tabClosingPromises) {
+    await promise;
+  }
+
+  ok(!initialTab.closing, "InitialTab is not closing");
+  ok(tab1.closing, "Tab1 is closing");
+  ok(tab2.closing, "Tab2 is closing");
+  ok(tab3.closing, "Tab3 is closing");
+  ok(!tab4.closing, "Tab4 is not closing");
+  is(gBrowser.multiSelectedTabsCount, 0, "Zero multiselected tabs");
+  is(gBrowser.selectedTab, initialTab, "InitialTab is the active tab now");
+
+  BrowserTestUtils.removeTab(tab4);
+});