Bug 926928 - Pull out the code that builds the 'Recently Closed Tabs' and 'Recently Closed Windows' to a separate module. r=Gijs
authorJared Wein <jwein@mozilla.com>
Mon, 14 Oct 2013 14:33:17 -0400
changeset 165653 082357277604d2f50f852f9b7d0d733d894dda9a
parent 165652 79360e1c33a56ca48ac62548c7f436fa445a04ab
child 165654 1dd4cd4890fc5c28f912dc53d1b2bf394fd129c2
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs926928
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 926928 - Pull out the code that builds the 'Recently Closed Tabs' and 'Recently Closed Windows' to a separate module. r=Gijs
browser/base/content/browser-places.js
browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
browser/components/sessionstore/src/moz.build
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -468,16 +468,19 @@ var PlacesCommandHook = {
       organizer.focus();
     }
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// HistoryMenu
 
+XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
+  "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
+
 // View for the history menu.
 function HistoryMenu(aPopupShowingEvent) {
   // Workaround for Bug 610187.  The sidebar does not include all the Places
   // views definitions, and we don't need them there.
   // Defining the prototype inheritance in the prototype itself would cause
   // browser.js to halt on "PlacesMenu is not defined" error.
   this.__proto__.__proto__ = PlacesMenu.prototype;
   PlacesMenu.call(this, aPopupShowingEvent,
@@ -526,55 +529,18 @@ HistoryMenu.prototype = {
       undoMenu.setAttribute("disabled", true);
       return;
     }
 
     // enable menu
     undoMenu.removeAttribute("disabled");
 
     // populate menu
-    var undoItems = JSON.parse(SessionStore.getClosedTabData(window));
-    for (var i = 0; i < undoItems.length; i++) {
-      var m = document.createElement("menuitem");
-      m.setAttribute("label", undoItems[i].title);
-      if (undoItems[i].image) {
-        let iconURL = undoItems[i].image;
-        // don't initiate a connection just to fetch a favicon (see bug 467828)
-        if (/^https?:/.test(iconURL))
-          iconURL = "moz-anno:favicon:" + iconURL;
-        m.setAttribute("image", iconURL);
-      }
-      m.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
-      m.setAttribute("value", i);
-      m.setAttribute("oncommand", "undoCloseTab(" + i + ");");
-
-      // Set the targetURI attribute so it will be shown in tooltip and trigger
-      // onLinkHovered. SessionStore uses one-based indexes, so we need to
-      // normalize them.
-      let tabData = undoItems[i].state;
-      let activeIndex = (tabData.index || tabData.entries.length) - 1;
-      if (activeIndex >= 0 && tabData.entries[activeIndex])
-        m.setAttribute("targetURI", tabData.entries[activeIndex].url);
-
-      m.addEventListener("click", this._undoCloseMiddleClick, false);
-      if (i == 0)
-        m.setAttribute("key", "key_undoCloseTab");
-      undoPopup.appendChild(m);
-    }
-
-    // "Restore All Tabs"
-    var strings = gNavigatorBundle;
-    undoPopup.appendChild(document.createElement("menuseparator"));
-    m = undoPopup.appendChild(document.createElement("menuitem"));
-    m.id = "menu_restoreAllTabs";
-    m.setAttribute("label", strings.getString("menuRestoreAllTabs.label"));
-    m.addEventListener("command", function() {
-      for (var i = 0; i < undoItems.length; i++)
-        undoCloseTab(0);
-    }, false);
+    let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(window, "menuitem");
+    undoPopup.appendChild(tabsFragment);
   },
 
   toggleRecentlyClosedWindows: function PHM_toggleRecentlyClosedWindows() {
     // enable/disable the Recently Closed Windows sub menu
     var undoMenu = this._rootElt.getElementsByClassName("recentlyClosedWindowsMenu")[0];
 
     // no restorable windows, so disable menu
     if (SessionStore.getClosedWindowCount() == 0)
@@ -602,55 +568,18 @@ HistoryMenu.prototype = {
       undoMenu.setAttribute("disabled", true);
       return;
     }
 
     // enable menu
     undoMenu.removeAttribute("disabled");
 
     // populate menu
-    let undoItems = JSON.parse(SessionStore.getClosedWindowData());
-    for (let i = 0; i < undoItems.length; i++) {
-      let undoItem = undoItems[i];
-      let otherTabsCount = undoItem.tabs.length - 1;
-      let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
-                                        : PluralForm.get(otherTabsCount, menuLabelString);
-      let menuLabel = label.replace("#1", undoItem.title)
-                           .replace("#2", otherTabsCount);
-      let m = document.createElement("menuitem");
-      m.setAttribute("label", menuLabel);
-      let selectedTab = undoItem.tabs[undoItem.selected - 1];
-      if (selectedTab.image) {
-        let iconURL = selectedTab.image;
-        // don't initiate a connection just to fetch a favicon (see bug 467828)
-        if (/^https?:/.test(iconURL))
-          iconURL = "moz-anno:favicon:" + iconURL;
-        m.setAttribute("image", iconURL);
-      }
-      m.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
-      m.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
-
-      // Set the targetURI attribute so it will be shown in tooltip.
-      // SessionStore uses one-based indexes, so we need to normalize them.
-      let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
-      if (activeIndex >= 0 && selectedTab.entries[activeIndex])
-        m.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
-
-      if (i == 0)
-        m.setAttribute("key", "key_undoCloseWindow");
-      undoPopup.appendChild(m);
-    }
-
-    // "Open All in Windows"
-    undoPopup.appendChild(document.createElement("menuseparator"));
-    let m = undoPopup.appendChild(document.createElement("menuitem"));
-    m.id = "menu_restoreAllWindows";
-    m.setAttribute("label", gNavigatorBundle.getString("menuRestoreAllWindows.label"));
-    m.setAttribute("oncommand",
-      "for (var i = 0; i < " + undoItems.length + "; i++) undoCloseWindow();");
+    let windowsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment(window, "menuitem");
+    undoPopup.appendChild(windowsFragment);
   },
 
   toggleTabsFromOtherComputers: function PHM_toggleTabsFromOtherComputers() {
     // This is a no-op if MOZ_SERVICES_SYNC isn't defined
 #ifdef MOZ_SERVICES_SYNC
     // Enable/disable the Tabs From Other Computers menu. Some of the menus handled
     // by HistoryMenu do not have this menuitem.
     let menuitem = this._rootElt.getElementsByClassName("syncTabsMenuItem")[0];
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
@@ -0,0 +1,139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+this.EXPORTED_SYMBOLS = ["RecentlyClosedTabsAndWindowsMenuUtils"];
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
+
+let navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+this.RecentlyClosedTabsAndWindowsMenuUtils = {
+
+  /**
+  * Builds up a document fragment of UI items for the recently closed tabs.
+  * @param   aWindow
+  *          The window that the tabs were closed in.
+  * @param   aTagName
+  *          The tag name that will be used when creating the UI items.
+  * @returns A document fragment with UI items for each recently closed tab.
+  */
+  getTabsFragment: function(aWindow, aTagName) {
+    let doc = aWindow.document;
+    let fragment = doc.createDocumentFragment();
+    if (ss.getClosedTabCount(aWindow) != 0) {
+      let closedTabs = JSON.parse(ss.getClosedTabData(aWindow));
+      for (let i = 0; i < closedTabs.length; i++) {
+        let element = doc.createElementNS(kNSXUL, aTagName);
+        element.setAttribute("label", closedTabs[i].title);
+        if (closedTabs[i].image) {
+          setImage(closedTabs[i], element);
+        }
+        element.setAttribute("value", i);
+        if (aTagName == "menuitem") {
+          element.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
+        }
+        element.setAttribute("oncommand", "undoCloseTab(" + i + ");");
+
+        // Set the targetURI attribute so it will be shown in tooltip and trigger
+        // onLinkHovered. SessionStore uses one-based indexes, so we need to
+        // normalize them.
+        let tabData = closedTabs[i].state;
+        let activeIndex = (tabData.index || tabData.entries.length) - 1;
+        if (activeIndex >= 0 && tabData.entries[activeIndex]) {
+          element.setAttribute("targetURI", tabData.entries[activeIndex].url);
+        }
+
+        element.addEventListener("click", this._undoCloseMiddleClick, false);
+        if (i == 0)
+          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.addEventListener("command", function() {
+        for (var i = 0; i < closedTabs.length; i++)
+          undoCloseTab(0);
+      }, false);
+    }
+    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.
+  * @param   aTagName
+  *          The tag name that will be used when creating the UI items.
+  * @returns A document fragment with UI items for each recently closed window.
+  */
+  getWindowsFragment: function(aWindow, aTagName) {
+    let closedWindowData = JSON.parse(ss.getClosedWindowData());
+    let fragment = aWindow.document.createDocumentFragment();
+    if (closedWindowData.length != 0) {
+      let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel");
+      let menuLabelStringSingleTab =
+        navigatorBundle.GetStringFromName("menuUndoCloseWindowSingleTabLabel");
+
+      let doc = aWindow.document;
+      for (let i = 0; i < closedWindowData.length; i++) {
+        let undoItem = closedWindowData[i];
+        let otherTabsCount = undoItem.tabs.length - 1;
+        let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
+                                          : PluralForm.get(otherTabsCount, menuLabelString);
+        let menuLabel = label.replace("#1", undoItem.title)
+                             .replace("#2", otherTabsCount);
+        let item = doc.createElementNS(kNSXUL, aTagName);
+        item.setAttribute("label", menuLabel);
+        let selectedTab = undoItem.tabs[undoItem.selected - 1];
+        if (selectedTab.image) {
+          setImage(selectedTab, item);
+        }
+        if (aTagName == "menuitem") {
+          item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
+        }
+        item.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
+
+        // Set the targetURI attribute so it will be shown in tooltip.
+        // SessionStore uses one-based indexes, so we need to normalize them.
+        let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
+        if (activeIndex >= 0 && selectedTab.entries[activeIndex])
+          item.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
+
+        if (i == 0)
+          item.setAttribute("key", "key_undoCloseWindow");
+        fragment.appendChild(item);
+      }
+
+      // "Open All in Windows"
+      fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
+      let restoreAllWindows = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
+      restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllWindows.label"));
+      restoreAllWindows.setAttribute("oncommand",
+        "for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();");
+    }
+    return fragment;
+  },
+};
+
+function setImage(aItem, aElement) {
+  let iconURL = aItem.image;
+  // don't initiate a connection just to fetch a favicon (see bug 467828)
+  if (/^https?:/.test(iconURL))
+    iconURL = "moz-anno:favicon:" + iconURL;
+  aElement.setAttribute("image", iconURL);
+}
--- a/browser/components/sessionstore/src/moz.build
+++ b/browser/components/sessionstore/src/moz.build
@@ -12,16 +12,17 @@ EXTRA_COMPONENTS += [
 
 JS_MODULES_PATH = 'modules/sessionstore'
 
 EXTRA_JS_MODULES = [
     'DocShellCapabilities.jsm',
     'DocumentUtils.jsm',
     'Messenger.jsm',
     'PrivacyLevel.jsm',
+    'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
     'SessionCookies.jsm',
     'SessionHistory.jsm',
     'SessionMigration.jsm',
     'SessionStorage.jsm',
     'SessionWorker.js',
     'TabStateCache.jsm',
     'XPathGenerator.jsm',
     '_SessionFile.jsm',