Bug 931891 - Backed out bug 887515 and the followups (bug 896291, 909662, 896896). r=ttaubert, a=lsblakk
authorJared Wein <jwein@mozilla.com>
Mon, 16 Dec 2013 14:52:10 -0500
changeset 175323 6895de3528c960e0fc6c21f951b4c9b8b49a0bfb
parent 175322 9b6627823cf117f1663eb7174006d449ab1a8cf2
child 175324 7d667fc1bc2026143d9151d9589460b56a2dc900
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert, lsblakk
bugs931891, 887515, 896291, 909662, 896896
milestone28.0a2
Bug 931891 - Backed out bug 887515 and the followups (bug 896291, 909662, 896896). r=ttaubert, a=lsblakk
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_bug887515.js
browser/base/content/test/general/browser_bug896291_closeMaxSessionStoreTabs.js
browser/base/content/test/general/browser_bug906190.js
browser/components/sessionstore/nsISessionStore.idl
browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
browser/components/sessionstore/src/SessionStore.jsm
browser/components/sessionstore/test/browser_345898.js
browser/components/tabview/test/browser_tabview_bug608037.js
browser/components/tabview/test/browser_tabview_bug624847.js
browser/components/tabview/test/browser_tabview_bug628270.js
browser/components/tabview/test/browser_tabview_bug706736.js
browser/components/tabview/test/head.js
browser/locales/en-US/chrome/browser/browser.dtd
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6215,43 +6215,26 @@ function convertFromUnicode(charset, str
  * @returns a reference to the reopened tab.
  */
 function undoCloseTab(aIndex) {
   // wallpaper patch to prevent an unnecessary blank tab (bug 343895)
   var blankTabToRemove = null;
   if (gBrowser.tabs.length == 1 && isTabEmpty(gBrowser.selectedTab))
     blankTabToRemove = gBrowser.selectedTab;
 
-  let numberOfTabsToUndoClose = 0;
-  let index = Number(aIndex);
-
-
-  if (isNaN(index)) {
-    index = 0;
-    numberOfTabsToUndoClose = SessionStore.getNumberOfTabsClosedLast(window);
-  } else {
-    if (0 > index || index >= SessionStore.getClosedTabCount(window))
-      return null;
-    numberOfTabsToUndoClose = 1;
+  var tab = null;
+  if (SessionStore.getClosedTabCount(window) > (aIndex || 0)) {
+    TabView.prepareUndoCloseTab(blankTabToRemove);
+    tab = SessionStore.undoCloseTab(window, aIndex || 0);
+    TabView.afterUndoCloseTab();
+
+    if (blankTabToRemove)
+      gBrowser.removeTab(blankTabToRemove);
   }
 
-  let tab = null;
-  while (numberOfTabsToUndoClose > 0 &&
-         numberOfTabsToUndoClose--) {
-    TabView.prepareUndoCloseTab(blankTabToRemove);
-    tab = SessionStore.undoCloseTab(window, index);
-    TabView.afterUndoCloseTab();
-    if (blankTabToRemove) {
-      gBrowser.removeTab(blankTabToRemove);
-      blankTabToRemove = null;
-    }
-  }
-
-  // Reset the number of tabs closed last time to the default.
-  SessionStore.setNumberOfTabsClosedLast(window, 1);
   return tab;
 }
 
 /**
  * Re-open a closed window.
  * @param aIndex
  *        The index of the window (via SessionStore.getClosedWindowData)
  * @returns a reference to the reopened window.
@@ -7071,23 +7054,18 @@ var TabContextMenu = {
       menuItem.disabled = disabled;
 
     disabled = gBrowser.visibleTabs.length == 1;
     menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple-visible");
     for (let menuItem of menuItems)
       menuItem.disabled = disabled;
 
     // Session store
-    let undoCloseTabElement = document.getElementById("context_undoCloseTab");
-    let closedTabCount = SessionStore.getNumberOfTabsClosedLast(window);
-    undoCloseTabElement.disabled = closedTabCount == 0;
-    // Change the label of "Undo Close Tab" to specify if it will undo a batch-close
-    // or a single close.
-    let visibleLabel = closedTabCount <= 1 ? "singletablabel" : "multipletablabel";
-    undoCloseTabElement.setAttribute("label", undoCloseTabElement.getAttribute(visibleLabel));
+    document.getElementById("context_undoCloseTab").disabled =
+      SessionStore.getClosedTabCount(window) == 0;
 
     // Only one of pin/unpin should be visible
     document.getElementById("context_pinTab").hidden = this.contextTab.pinned;
     document.getElementById("context_unpinTab").hidden = !this.contextTab.pinned;
 
     // Disable "Close Tabs to the Right" if there are no tabs
     // following it and hide it when the user rightclicked on a pinned
     // tab.
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -99,18 +99,17 @@
                 accesskey="&bookmarkAllTabs.accesskey;"
                 command="Browser:BookmarkAllTabs"/>
       <menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;"
                 oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab);"/>
       <menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
                 oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/>
       <menuseparator/>
       <menuitem id="context_undoCloseTab"
-                singletablabel="&undoCloseTab.label;"
-                multipletablabel="&undoCloseTabs.label;"
+                label="&undoCloseTab.label;"
                 accesskey="&undoCloseTab.accesskey;"
                 observes="History:UndoCloseTab"/>
       <menuitem id="context_closeTab" label="&closeTab.label;" accesskey="&closeTab.accesskey;"
                 oncommand="gBrowser.removeTab(TabContextMenu.contextTab, { animate: true });"/>
     </menupopup>
 
     <!-- bug 415444/582485: event.stopPropagation is here for the cloned version
          of this menupopup -->
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1676,36 +1676,23 @@
                 throw new Error("Required argument missing: aTab");
 
               tabsToClose = this.getTabsToTheEndFrom(aTab).length;
               break;
             default:
               throw new Error("Invalid argument: " + aCloseTabs);
           }
 
-          let maxUndo =
-            Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
-          let warnOnCloseOtherTabs =
-            Services.prefs.getBoolPref("browser.tabs.warnOnCloseOtherTabs");
-          let warnOnCloseWindow =
-            Services.prefs.getBoolPref("browser.tabs.warnOnClose");
-          let isWindowClosing = aCloseTabs == this.closingTabsEnum.ALL;
-
-          let skipWarning =
-            // 1) If there is only one tab to close, we'll never warn the user.
-            tabsToClose <= 1 ||
-            // 2) If the whole window is going to be closed, don't warn the
-            //    user if the user has browser.tabs.warnOnClose set to false.
-            (isWindowClosing && !warnOnCloseWindow) ||
-            // 3) If the number of tabs are less than the undo threshold
-            //    or if the user has specifically opted-in to ignoring
-            //    this warning via the warnOnCloseOtherTabs pref.
-            (!isWindowClosing && (!warnOnCloseOtherTabs ||
-                                            tabsToClose <= maxUndo));
-          if (skipWarning)
+          if (tabsToClose <= 1)
+            return true;
+
+          const pref = aCloseTabs == this.closingTabsEnum.ALL ?
+                       "browser.tabs.warnOnClose" : "browser.tabs.warnOnCloseOtherTabs";
+          var shouldPrompt = Services.prefs.getBoolPref(pref);
+          if (!shouldPrompt)
             return true;
 
           var ps = Services.prompt;
 
           // default to true: if it were false, we wouldn't get this far
           var warnOnClose = { value: true };
           var bundle = this.mStringBundle;
 
@@ -1719,26 +1706,24 @@
             ps.confirmEx(window,
                          bundle.getString("tabs.closeWarningTitle"),
                          bundle.getFormattedString("tabs.closeWarningMultipleTabs",
                                                    [tabsToClose]),
                          (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0)
                          + (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1),
                          bundle.getString("tabs.closeButtonMultiple"),
                          null, null,
-                         bundle.getString("tabs.closeWarningPromptMe"),
+                         aCloseTabs == this.closingTabsEnum.ALL ?
+                           bundle.getString("tabs.closeWarningPromptMe") : null,
                          warnOnClose);
           var reallyClose = (buttonPressed == 0);
 
           // don't set the pref unless they press OK and it's false
-          if (reallyClose && !warnOnClose.value) {
-            let pref = isWindowClosing ? "browser.tabs.warnOnClose" :
-                                         "browser.tabs.warnOnCloseOtherTabs";
+          if (aCloseTabs == this.closingTabsEnum.ALL && reallyClose && !warnOnClose.value)
             Services.prefs.setBoolPref(pref, false);
-          }
 
           return reallyClose;
         ]]>
       </body>
       </method>
 
       <method name="getTabsToTheEndFrom">
         <parameter name="aTab"/>
@@ -1755,45 +1740,39 @@
       </method>
 
       <method name="removeTabsToTheEndFrom">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             if (this.warnAboutClosingTabs(this.closingTabsEnum.TO_END, aTab)) {
               let tabs = this.getTabsToTheEndFrom(aTab);
-              let numberOfTabsToClose = tabs.length;
-              for (let i = numberOfTabsToClose - 1; i >= 0; --i) {
+              for (let i = tabs.length - 1; i >= 0; --i) {
                 this.removeTab(tabs[i], {animate: true});
               }
-              SessionStore.setNumberOfTabsClosedLast(window, numberOfTabsToClose);
             }
           ]]>
         </body>
       </method>
 
       <method name="removeAllTabsBut">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             if (aTab.pinned)
               return;
 
             if (this.warnAboutClosingTabs(this.closingTabsEnum.OTHER)) {
               let tabs = this.visibleTabs;
               this.selectedTab = aTab;
 
-              let closedTabs = 0;
               for (let i = tabs.length - 1; i >= 0; --i) {
-                if (tabs[i] != aTab && !tabs[i].pinned) {
+                if (tabs[i] != aTab && !tabs[i].pinned)
                   this.removeTab(tabs[i], {animate: true});
-                  closedTabs++;
-                }
               }
-              SessionStore.setNumberOfTabsClosedLast(window, closedTabs);
             }
           ]]>
         </body>
       </method>
 
       <method name="removeCurrentTab">
         <parameter name="aParams"/>
         <body>
@@ -1812,18 +1791,16 @@
         <parameter name="aParams"/>
         <body>
           <![CDATA[
             if (aParams) {
               var animate = aParams.animate;
               var byMouse = aParams.byMouse;
             }
 
-            SessionStore.setNumberOfTabsClosedLast(window, 1);
-
             // Handle requests for synchronously removing an already
             // asynchronously closing tab.
             if (!animate &&
                 aTab.closing) {
               this._endRemoveTab(aTab);
               return;
             }
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -230,18 +230,16 @@ run-if = toolkit == "cocoa"
 [browser_bug817947.js]
 [browser_bug818118.js]
 [browser_bug820497.js]
 [browser_bug822367.js]
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 [browser_bug882977.js]
-[browser_bug887515.js]
-[browser_bug896291_closeMaxSessionStoreTabs.js]
 [browser_bug902156.js]
 [browser_bug906190.js]
 [browser_canonizeURL.js]
 [browser_clearplugindata.js]
 [browser_contentAreaClick.js]
 [browser_contextSearchTabPosition.js]
 [browser_ctrlTab.js]
 [browser_customize.js]
deleted file mode 100644
--- a/browser/base/content/test/general/browser_bug887515.js
+++ /dev/null
@@ -1,75 +0,0 @@
-function numClosedTabs()
-  SessionStore.getNumberOfTabsClosedLast(window);
-
-var originalTab;
-var tab1Loaded = false;
-var tab2Loaded = false;
-
-function verifyUndoMultipleClose() {
-  if (!tab1Loaded || !tab2Loaded)
-    return;
-
-  gBrowser.removeAllTabsBut(originalTab);
-  updateTabContextMenu();
-  let undoCloseTabElement = document.getElementById("context_undoCloseTab");
-  ok(!undoCloseTabElement.disabled, "Undo Close Tabs should be enabled.");
-  is(numClosedTabs(), 2, "There should be 2 closed tabs.");
-  is(gBrowser.tabs.length, 1, "There should only be 1 open tab");
-  updateTabContextMenu();
-  is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("multipletablabel"),
-     "The label should be showing that the command will restore multiple tabs");
-  undoCloseTab();
-
-  is(gBrowser.tabs.length, 3, "There should be 3 open tabs");
-  updateTabContextMenu();
-  is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
-     "The label should be showing that the command will restore a single tab");
-
-  gBrowser.removeTabsToTheEndFrom(originalTab);
-  updateTabContextMenu();
-  ok(!undoCloseTabElement.disabled, "Undo Close Tabs should be enabled.");
-  is(numClosedTabs(), 2, "There should be 2 closed tabs.");
-  is(gBrowser.tabs.length, 1, "There should only be 1 open tab");
-  updateTabContextMenu();
-  is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("multipletablabel"),
-     "The label should be showing that the command will restore multiple tabs");
-
-  finish();
-}
-
-function test() {
-  waitForExplicitFinish();
-
-  Services.prefs.setBoolPref("browser.tabs.animate", false);
-  registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("browser.tabs.animate");
-    originalTab.linkedBrowser.loadURI("about:blank");
-    originalTab = null;
-  });
-
-  let undoCloseTabElement = document.getElementById("context_undoCloseTab");
-  updateTabContextMenu();
-  is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
-     "The label should be showing that the command will restore a single tab");
-
-  originalTab = gBrowser.selectedTab;
-  gBrowser.selectedBrowser.loadURI("http://mochi.test:8888/");
-  var tab1 = gBrowser.addTab("http://mochi.test:8888/");
-  var tab2 = gBrowser.addTab("http://mochi.test:8888/");
-  var browser1 = gBrowser.getBrowserForTab(tab1);
-  browser1.addEventListener("load", function onLoad1() {
-    browser1.removeEventListener("load", onLoad1, true);
-    tab1Loaded = true;
-    tab1 = null;
-
-    verifyUndoMultipleClose();
-  }, true);
-  var browser2 = gBrowser.getBrowserForTab(tab2);
-  browser2.addEventListener("load", function onLoad2() {
-    browser2.removeEventListener("load", onLoad2, true);
-    tab2Loaded = true;
-    tab2 = null;
-
-    verifyUndoMultipleClose();
-  }, true);
-}
deleted file mode 100644
--- a/browser/base/content/test/general/browser_bug896291_closeMaxSessionStoreTabs.js
+++ /dev/null
@@ -1,108 +0,0 @@
-function numClosedTabs()
-  Cc["@mozilla.org/browser/sessionstore;1"].
-    getService(Ci.nsISessionStore).
-    getNumberOfTabsClosedLast(window);
-
-let originalTab;
-let maxTabsUndo;
-let maxTabsUndoPlusOne;
-let acceptRemoveAllTabsDialogListener;
-let cancelRemoveAllTabsDialogListener;
-
-function test() {
-  waitForExplicitFinish();
-  Services.prefs.setBoolPref("browser.tabs.animate", false);
-
-  registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("browser.tabs.animate");
-
-    originalTab.linkedBrowser.loadURI("about:blank");
-    originalTab = null;
-  });
-
-  // Creating and throwing away this tab guarantees that the
-  // number of tabs closed in the previous tab-close operation is 1.
-  let throwaway_tab = gBrowser.addTab("http://mochi.test:8888/");
-  gBrowser.removeTab(throwaway_tab);
-
-  let undoCloseTabElement = document.getElementById("context_undoCloseTab");
-  updateTabContextMenu();
-  is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
-     "The label should be showing that the command will restore a single tab");
-
-  originalTab = gBrowser.selectedTab;
-  gBrowser.selectedBrowser.loadURI("http://mochi.test:8888/");
-
-  maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
-  maxTabsUndoPlusOne = maxTabsUndo + 1;
-  let numberOfTabsLoaded = 0;
-  for (let i = 0; i < maxTabsUndoPlusOne; i++) {
-    let tab = gBrowser.addTab("http://mochi.test:8888/");
-    let browser = gBrowser.getBrowserForTab(tab);
-    browser.addEventListener("load", function onLoad() {
-      browser.removeEventListener("load", onLoad, true);
-
-      if (++numberOfTabsLoaded == maxTabsUndoPlusOne)
-        verifyUndoMultipleClose();
-    }, true);
-  }
-}
-
-function verifyUndoMultipleClose() {
-  info("all tabs opened and loaded");
-  cancelRemoveAllTabsDialogListener = new WindowListener("chrome://global/content/commonDialog.xul", cancelRemoveAllTabsDialog);
-  Services.wm.addListener(cancelRemoveAllTabsDialogListener);
-  gBrowser.removeAllTabsBut(originalTab);
-}
-
-function cancelRemoveAllTabsDialog(domWindow) {
-  ok(true, "dialog appeared in response to multiple tab close action");
-  domWindow.document.documentElement.cancelDialog();
-  Services.wm.removeListener(cancelRemoveAllTabsDialogListener);
-
-  acceptRemoveAllTabsDialogListener = new WindowListener("chrome://global/content/commonDialog.xul", acceptRemoveAllTabsDialog);
-  Services.wm.addListener(acceptRemoveAllTabsDialogListener);
-  waitForCondition(function () gBrowser.tabs.length == 1 + maxTabsUndoPlusOne, function verifyCancel() {
-    is(gBrowser.tabs.length, 1 + maxTabsUndoPlusOne, /* The '1 +' is for the original tab */
-       "All tabs should still be open after the 'Cancel' option on the prompt is chosen");
-    gBrowser.removeAllTabsBut(originalTab);
-  }, "Waited too long to find that no tabs were closed.");
-}
-
-function acceptRemoveAllTabsDialog(domWindow) {
-  ok(true, "dialog appeared in response to multiple tab close action");
-  domWindow.document.documentElement.acceptDialog();
-  Services.wm.removeListener(acceptRemoveAllTabsDialogListener);
-
-  waitForCondition(function () gBrowser.tabs.length == 1, function verifyAccept() {
-    is(gBrowser.tabs.length, 1,
-       "All other tabs should be closed after the 'OK' option on the prompt is chosen");
-    finish();
-  }, "Waited too long for the other tabs to be closed.");
-}
-
-function WindowListener(aURL, aCallback) {
-  this.callback = aCallback;
-  this.url = aURL;
-}
-WindowListener.prototype = {
-  onOpenWindow: function(aXULWindow) {
-    var domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindow);
-    var self = this;
-    domWindow.addEventListener("load", function() {
-      domWindow.removeEventListener("load", arguments.callee, false);
-
-      info("domWindow.document.location.href: " + domWindow.document.location.href);
-      if (domWindow.document.location.href != self.url)
-        return;
-
-      // Allow other window load listeners to execute before passing to callback
-      executeSoon(function() {
-        self.callback(domWindow);
-      });
-    }, false);
-  },
-  onCloseWindow: function(aXULWindow) {},
-  onWindowTitleChange: function(aXULWindow, aNewTitle) {}
-}
--- a/browser/base/content/test/general/browser_bug906190.js
+++ b/browser/base/content/test/general/browser_bug906190.js
@@ -207,17 +207,18 @@ function test1C() {
   // mixed content blocker is persistent across tabs.
   var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestWin.gBrowser.selectedBrowser);
   ok(!notification, "OK: Mixed Content Doorhanger did not appear again in Test 1C!");
 
   var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1C");
 
   // remove tabs
-  gTestWin.gBrowser.removeAllTabsBut(mainTab);
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
   gTestWin.gBrowser.selectTabAtIndex(0);
 
   var childTabLink = gHttpTestRoot2 + "file_bug906190_2.html";
   setUpTest("Test2", "linkForTest2", test2, childTabLink);
 }
 
 //------------------------ Test 2 ------------------------------
 
@@ -264,17 +265,18 @@ function test2C() {
   // mixed content blocker should only persist if pages are from the same domain.
   var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestWin.gBrowser.selectedBrowser);
   ok(notification, "OK: Mixed Content Doorhanger did appear again in Test 2C!");
 
   var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 2C");
 
   // remove tabs
-  gTestWin.gBrowser.removeAllTabsBut(mainTab);
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
   gTestWin.gBrowser.selectTabAtIndex(0);
 
   // file_bug906190_3_4.html redirects to page test1.example.com/* using meta-refresh
   var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
   setUpTest("Test3", "linkForTest3", test3, childTabLink);
 }
 
 //------------------------ Test 3 ------------------------------
@@ -331,17 +333,18 @@ function test3E() {
   // The Doorhanger should >> NOT << appear!
   var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestWin.gBrowser.selectedBrowser);
   ok(!notification, "OK: Mixed Content Doorhanger did appear again in Test 3E!");
 
   var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 3E");
 
   // remove tabs
-  gTestWin.gBrowser.removeAllTabsBut(mainTab);
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
   gTestWin.gBrowser.selectTabAtIndex(0);
 
   var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
   setUpTest("Test4", "linkForTest4", test4, childTabLink);
 }
 
 //------------------------ Test 4 ------------------------------
 
@@ -398,17 +401,18 @@ function test4E() {
   // The Doorhanger >> SHOULD << appear!
   var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestWin.gBrowser.selectedBrowser);
   ok(notification, "OK: Mixed Content Doorhanger did appear again in Test 4E!");
 
   var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 4E");
 
   // remove tabs
-  gTestWin.gBrowser.removeAllTabsBut(mainTab);
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
   gTestWin.gBrowser.selectTabAtIndex(0);
 
   // the sjs files returns a 302 redirect- note, same origins
   var childTabLink = gHttpTestRoot1 + "file_bug906190.sjs";
   setUpTest("Test5", "linkForTest5", test5, childTabLink);
 }
 
 //------------------------ Test 5 ------------------------------
@@ -457,17 +461,18 @@ function test5C() {
   // Currently it >> APPEARS << - see follow up bug 914860
   var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestWin.gBrowser.selectedBrowser);
   todo(!notification, "OK: Mixed Content Doorhanger did not appear again in Test 5C!");
 
   var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
   todo_is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 5C!");
 
   // remove tabs
-  gTestWin.gBrowser.removeAllTabsBut(mainTab);
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
   gTestWin.gBrowser.selectTabAtIndex(0);
 
   // the sjs files returns a 302 redirect - note, different origins
   var childTabLink = gHttpTestRoot2 + "file_bug906190.sjs";
   setUpTest("Test6", "linkForTest6", test6, childTabLink);
 }
 
 //------------------------ Test 6 ------------------------------
--- a/browser/components/sessionstore/nsISessionStore.idl
+++ b/browser/components/sessionstore/nsISessionStore.idl
@@ -20,17 +20,17 @@ interface nsIDOMNode;
  * global |window| object to the API, though (or |top| from a sidebar).
  * From elsewhere you can get browser windows through the nsIWindowMediator
  * by looking for "navigator:browser" windows.
  *
  * * "Tabbrowser tabs" are all the child nodes of a browser window's
  * |gBrowser.tabContainer| such as e.g. |gBrowser.selectedTab|.
  */
 
-[scriptable, uuid(63a4d9f4-373f-11e3-a237-fa91a24410d2)]
+[scriptable, uuid(6fdf7a49-c6ac-4bfe-a5da-aad6c4116168)]
 interface nsISessionStore : nsISupports
 {
   /**
    * Is it possible to restore the previous session. Will always be false when
    * in Private Browsing mode.
    */
   attribute boolean canRestoreLastSession;
 
@@ -96,30 +96,16 @@ interface nsISessionStore : nsISupports
    * @param aTab    is the tabbrowser tab to duplicate (can be from a different window).
    * @param aDelta  is the offset to the history entry to load in the duplicated tab.
    * @returns a reference to the newly created tab.
    */
   nsIDOMNode duplicateTab(in nsIDOMWindow aWindow, in nsIDOMNode aTab,
                           [optional] in long aDelta);
 
   /**
-   * Set the number of tabs that was closed during the last close-tabs
-   * operation. This helps us keep track of batch-close operations so
-   * we can restore multiple tabs at once.
-   */
-  void setNumberOfTabsClosedLast(in nsIDOMWindow aWindow, in unsigned long aNumber);
-
-  /**
-   * Get the number of tabs that was closed during the last close-tabs
-   * operation. This helps us keep track of batch-close operations so
-   * we can restore multiple tabs at once.
-   */
-  unsigned long getNumberOfTabsClosedLast(in nsIDOMWindow aWindow);
-
-  /**
    * Get the number of restore-able tabs for a browser window
    */
   unsigned long getClosedTabCount(in nsIDOMWindow aWindow);
 
   /**
    * Get closed tab data
    *
    * @param aWindow is the browser window for which to get closed tab data
--- a/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
+++ b/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
@@ -61,17 +61,17 @@ this.RecentlyClosedTabsAndWindowsMenuUti
           element.setAttribute("key", "key_undoCloseTab");
         fragment.appendChild(element);
       }
 
       fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
       let restoreAllTabs = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
       restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllTabs.label"));
       restoreAllTabs.setAttribute("oncommand",
-              "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab(0);");
+              "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab();");
     }
     return fragment;
   },
 
   /**
   * Builds up a document fragment of UI items for the recently closed windows.
   * @param   aWindow
   *          A window that can be used to create the elements and document fragment.
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -185,24 +185,16 @@ this.SessionStore = {
   setTabState: function ss_setTabState(aTab, aState) {
     SessionStoreInternal.setTabState(aTab, aState);
   },
 
   duplicateTab: function ss_duplicateTab(aWindow, aTab, aDelta = 0) {
     return SessionStoreInternal.duplicateTab(aWindow, aTab, aDelta);
   },
 
-  getNumberOfTabsClosedLast: function ss_getNumberOfTabsClosedLast(aWindow) {
-    return SessionStoreInternal.getNumberOfTabsClosedLast(aWindow);
-  },
-
-  setNumberOfTabsClosedLast: function ss_setNumberOfTabsClosedLast(aWindow, aNumber) {
-    return SessionStoreInternal.setNumberOfTabsClosedLast(aWindow, aNumber);
-  },
-
   getClosedTabCount: function ss_getClosedTabCount(aWindow) {
     return SessionStoreInternal.getClosedTabCount(aWindow);
   },
 
   getClosedTabData: function ss_getClosedTabDataAt(aWindow) {
     return SessionStoreInternal.getClosedTabData(aWindow);
   },
 
@@ -1612,45 +1604,16 @@ let SessionStoreInternal = {
       aWindow.gBrowser.addTab();
 
     this.restoreTabs(aWindow, [newTab], [tabState], 0,
                      true /* Load this tab right away. */);
 
     return newTab;
   },
 
-  setNumberOfTabsClosedLast: function ssi_setNumberOfTabsClosedLast(aWindow, aNumber) {
-    if (this._disabledForMultiProcess) {
-      return;
-    }
-
-    if (!("__SSi" in aWindow)) {
-      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
-    }
-
-    return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber);
-  },
-
-  /* Used to undo batch tab-close operations. Defaults to 1. */
-  getNumberOfTabsClosedLast: function ssi_getNumberOfTabsClosedLast(aWindow) {
-    if (this._disabledForMultiProcess) {
-      return 0;
-    }
-
-    if (!("__SSi" in aWindow)) {
-      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
-    }
-    // Blank tabs cannot be undo-closed, so the number returned by
-    // the NumberOfTabsClosedLastPerWindow can be greater than the
-    // return value of getClosedTabCount. We won't restore blank
-    // tabs, so we return the minimum of these two values.
-    return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1,
-                    this.getClosedTabCount(aWindow));
-  },
-
   getClosedTabCount: function ssi_getClosedTabCount(aWindow) {
     if ("__SSi" in aWindow) {
       return this._windows[aWindow.__SSi]._closedTabs.length;
     }
 
     if (!DyingWindowCache.has(aWindow)) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
@@ -4034,21 +3997,16 @@ let DirtyWindows = {
     this._data.delete(window);
   },
 
   clear: function (window) {
     this._data.clear();
   }
 };
 
-// A map storing the number of tabs last closed per windoow. This only
-// stores the most recent tab-close operation, and is used to undo
-// batch tab-closing operations.
-let NumberOfTabsClosedLastPerWindow = new WeakMap();
-
 // This is used to help meter the number of restoring tabs. This is the control
 // point for telling the next tab to restore. It gets attached to each gBrowser
 // via gBrowser.addTabsProgressListener
 let gRestoreTabsProgressListener = {
   onStateChange: function(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
     // Ignore state changes on browsers that we've already restored and state
     // changes that aren't applicable.
     if (aBrowser.__SS_restoreState &&
--- a/browser/components/sessionstore/test/browser_345898.js
+++ b/browser/components/sessionstore/test/browser_345898.js
@@ -35,13 +35,9 @@ function test() {
   ok(test(function() ss.undoCloseTab({}, 0)),
      "Invalid window for undoCloseTab throws");
   ok(test(function() ss.undoCloseTab(window, -1)),
      "Invalid index for undoCloseTab throws");
   ok(test(function() ss.getWindowValue({}, "")),
      "Invalid window for getWindowValue throws");
   ok(test(function() ss.setWindowValue({}, "", "")),
      "Invalid window for setWindowValue throws");
-  ok(test(function() ss.getNumberOfTabsClosedLast({})),
-     "Invalid window for getNumberOfTabsClosedLast  throws");
-  ok(test(function() ss.setNumberOfTabsClosedLast({}, 1)),
-     "Invalid window for setNumberOfTabsClosedLast throws");
 }
--- a/browser/components/tabview/test/browser_tabview_bug608037.js
+++ b/browser/components/tabview/test/browser_tabview_bug608037.js
@@ -33,10 +33,10 @@ function onTabViewWindowLoaded() {
     is(groupItems[0].getChildren().length, 3, "The group still has three tab items");
 
     // clean up and finish
     hideTabView(function () {
       gBrowser.removeTab(tabOne);
       gBrowser.removeTab(tabTwo);
       finish();
     });
-  }, 0);
+  });
 }
--- a/browser/components/tabview/test/browser_tabview_bug624847.js
+++ b/browser/components/tabview/test/browser_tabview_bug624847.js
@@ -59,17 +59,17 @@ function test() {
 
       restoreTab(function () {
         prefix = 'unpinned-restored';
         assertValidPrerequisites();
         assertGroupItemPreserved();
 
         createBlankTab();
         afterAllTabsLoaded(testUndoCloseWithSelectedBlankPinnedTab);
-      }, 0);
+      });
     });
   }
 
   let testUndoCloseWithSelectedBlankPinnedTab = function () {
     prefix = 'pinned';
     assertNumberOfTabs(2);
 
     afterAllTabsLoaded(function () {
@@ -89,17 +89,17 @@ function test() {
         prefix = 'pinned-restored';
         assertValidPrerequisites();
         assertGroupItemPreserved();
 
         createBlankTab();
         gBrowser.removeTab(gBrowser.tabs[0]);
 
         afterAllTabsLoaded(finishTest);
-      }, 0);
+      });
     });
   }
 
   waitForExplicitFinish();
   registerCleanupFunction(function () TabView.hide());
 
   showTabView(function () {
     hideTabView(function () {
--- a/browser/components/tabview/test/browser_tabview_bug628270.js
+++ b/browser/components/tabview/test/browser_tabview_bug628270.js
@@ -76,17 +76,17 @@ function test() {
 
     restoreTab(function () {
       assertNumberOfTabsInGroup(groupItem, 2);
 
       activateFirstGroupItem();
       gBrowser.removeTab(gBrowser.tabs[1]);
       gBrowser.removeTab(gBrowser.tabs[1]);
       hideTabView(finishTest);
-    }, 0);
+    });
   }
 
   waitForExplicitFinish();
   assertTabViewIsHidden();
   registerCleanupFunction(function () TabView.hide());
 
   showTabView(function () {
     cw = TabView.getContentWindow();
--- a/browser/components/tabview/test/browser_tabview_bug706736.js
+++ b/browser/components/tabview/test/browser_tabview_bug706736.js
@@ -15,17 +15,17 @@ function test() {
     is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
 
     let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 1);
     is(groupItemTwo.getChildren().length, 1, "Group two has 1 tab items");
 
     whenTabViewIsHidden(function() {
       win.gBrowser.removeTab(win.gBrowser.selectedTab);
       executeSoon(function() {
-        win.undoCloseTab(0);
+        win.undoCloseTab();
 
         groupItemTwo.addSubscriber("childAdded", function onChildAdded(data) {
           groupItemTwo.removeSubscriber("childAdded", onChildAdded);
 
           is(groupItemOne.getChildren().length, 1, "Group one still has 1 tab item");
           is(groupItemTwo.getChildren().length, 1, "Group two still has 1 tab item");
         });
 
--- a/browser/components/tabview/test/head.js
+++ b/browser/components/tabview/test/head.js
@@ -357,17 +357,17 @@ function newWindowWithState(state, callb
     });
   });
 }
 
 // ----------
 function restoreTab(callback, index, win) {
   win = win || window;
 
-  let tab = win.undoCloseTab(index);
+  let tab = win.undoCloseTab(index || 0);
   let tabItem = tab._tabViewTabItem;
 
   let finalize = function () {
     afterAllTabsLoaded(function () callback(tab), win);
   };
 
   if (tabItem._reconnected) {
     finalize();
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -41,21 +41,16 @@ can reach it easily. -->
 <!ENTITY  moveToGroup.accesskey              "M">
 <!ENTITY  moveToNewGroup.label               "New Group">
 <!ENTITY  moveToNewWindow.label              "Move to New Window">
 <!ENTITY  moveToNewWindow.accesskey          "W">
 <!ENTITY  bookmarkAllTabs.label              "Bookmark All Tabs…">
 <!ENTITY  bookmarkAllTabs.accesskey          "T">
 <!ENTITY  undoCloseTab.label                 "Undo Close Tab">
 <!ENTITY  undoCloseTab.accesskey             "U">
-<!-- LOCALIZATION NOTE (undoCloseTabs.label) : This label is used
-when the previous tab-closing operation closed more than one tab. It
-replaces the undoCloseTab.label and will use the same accesskey as the
-undoCloseTab.label so users will not need to learn new keyboard controls. -->
-<!ENTITY  undoCloseTabs.label                "Undo Close Tabs">
 <!ENTITY  closeTab.label                     "Close Tab">
 <!ENTITY  closeTab.accesskey                 "c">
 
 <!ENTITY  listAllTabs.label      "List all tabs">
 
 <!ENTITY tabCmd.label "New Tab">
 <!ENTITY tabCmd.accesskey "T">
 <!ENTITY tabCmd.commandkey "t">