1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,176 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +this.EXPORTED_SYMBOLS = ["RecentlyClosedTabsAndWindowsMenuUtils"]; 1.9 + 1.10 +const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.11 + 1.12 +var Ci = Components.interfaces; 1.13 +var Cc = Components.classes; 1.14 +var Cr = Components.results; 1.15 +var Cu = Components.utils; 1.16 + 1.17 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.18 +Cu.import("resource://gre/modules/Services.jsm"); 1.19 + 1.20 +XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", 1.21 + "resource://gre/modules/PluralForm.jsm"); 1.22 + 1.23 +let navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); 1.24 +let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); 1.25 + 1.26 +this.RecentlyClosedTabsAndWindowsMenuUtils = { 1.27 + 1.28 + /** 1.29 + * Builds up a document fragment of UI items for the recently closed tabs. 1.30 + * @param aWindow 1.31 + * The window that the tabs were closed in. 1.32 + * @param aTagName 1.33 + * The tag name that will be used when creating the UI items. 1.34 + * @param aPrefixRestoreAll (defaults to false) 1.35 + * Whether the 'restore all tabs' item is suffixed or prefixed to the list. 1.36 + * If suffixed (the default) a separator will be inserted before it. 1.37 + * @param aRestoreAllLabel (defaults to "menuRestoreAllTabs.label") 1.38 + * Which localizable string to use for the 'restore all tabs' item. 1.39 + * @returns A document fragment with UI items for each recently closed tab. 1.40 + */ 1.41 + getTabsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false, 1.42 + aRestoreAllLabel="menuRestoreAllTabs.label") { 1.43 + let doc = aWindow.document; 1.44 + let fragment = doc.createDocumentFragment(); 1.45 + if (ss.getClosedTabCount(aWindow) != 0) { 1.46 + let closedTabs = JSON.parse(ss.getClosedTabData(aWindow)); 1.47 + for (let i = 0; i < closedTabs.length; i++) { 1.48 + let element = doc.createElementNS(kNSXUL, aTagName); 1.49 + element.setAttribute("label", closedTabs[i].title); 1.50 + if (closedTabs[i].image) { 1.51 + setImage(closedTabs[i], element); 1.52 + } 1.53 + element.setAttribute("value", i); 1.54 + if (aTagName == "menuitem") { 1.55 + element.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon"); 1.56 + } 1.57 + element.setAttribute("oncommand", "undoCloseTab(" + i + ");"); 1.58 + 1.59 + // Set the targetURI attribute so it will be shown in tooltip and trigger 1.60 + // onLinkHovered. SessionStore uses one-based indexes, so we need to 1.61 + // normalize them. 1.62 + let tabData = closedTabs[i].state; 1.63 + let activeIndex = (tabData.index || tabData.entries.length) - 1; 1.64 + if (activeIndex >= 0 && tabData.entries[activeIndex]) { 1.65 + element.setAttribute("targetURI", tabData.entries[activeIndex].url); 1.66 + } 1.67 + 1.68 + element.addEventListener("click", this._undoCloseMiddleClick, false); 1.69 + if (i == 0) 1.70 + element.setAttribute("key", "key_undoCloseTab"); 1.71 + fragment.appendChild(element); 1.72 + } 1.73 + 1.74 + let restoreAllTabs = doc.createElementNS(kNSXUL, aTagName); 1.75 + restoreAllTabs.classList.add("restoreallitem"); 1.76 + restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel)); 1.77 + restoreAllTabs.setAttribute("oncommand", 1.78 + "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab();"); 1.79 + if (!aPrefixRestoreAll) { 1.80 + fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator")); 1.81 + fragment.appendChild(restoreAllTabs); 1.82 + } else { 1.83 + fragment.insertBefore(restoreAllTabs, fragment.firstChild); 1.84 + } 1.85 + } 1.86 + return fragment; 1.87 + }, 1.88 + 1.89 + /** 1.90 + * Builds up a document fragment of UI items for the recently closed windows. 1.91 + * @param aWindow 1.92 + * A window that can be used to create the elements and document fragment. 1.93 + * @param aTagName 1.94 + * The tag name that will be used when creating the UI items. 1.95 + * @param aPrefixRestoreAll (defaults to false) 1.96 + * Whether the 'restore all windows' item is suffixed or prefixed to the list. 1.97 + * If suffixed (the default) a separator will be inserted before it. 1.98 + * @param aRestoreAllLabel (defaults to "menuRestoreAllWindows.label") 1.99 + * Which localizable string to use for the 'restore all windows' item. 1.100 + * @returns A document fragment with UI items for each recently closed window. 1.101 + */ 1.102 + getWindowsFragment: function(aWindow, aTagName, aPrefixRestoreAll=false, 1.103 + aRestoreAllLabel="menuRestoreAllWindows.label") { 1.104 + let closedWindowData = JSON.parse(ss.getClosedWindowData()); 1.105 + let fragment = aWindow.document.createDocumentFragment(); 1.106 + if (closedWindowData.length != 0) { 1.107 + let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel"); 1.108 + let menuLabelStringSingleTab = 1.109 + navigatorBundle.GetStringFromName("menuUndoCloseWindowSingleTabLabel"); 1.110 + 1.111 + let doc = aWindow.document; 1.112 + for (let i = 0; i < closedWindowData.length; i++) { 1.113 + let undoItem = closedWindowData[i]; 1.114 + let otherTabsCount = undoItem.tabs.length - 1; 1.115 + let label = (otherTabsCount == 0) ? menuLabelStringSingleTab 1.116 + : PluralForm.get(otherTabsCount, menuLabelString); 1.117 + let menuLabel = label.replace("#1", undoItem.title) 1.118 + .replace("#2", otherTabsCount); 1.119 + let item = doc.createElementNS(kNSXUL, aTagName); 1.120 + item.setAttribute("label", menuLabel); 1.121 + let selectedTab = undoItem.tabs[undoItem.selected - 1]; 1.122 + if (selectedTab.image) { 1.123 + setImage(selectedTab, item); 1.124 + } 1.125 + if (aTagName == "menuitem") { 1.126 + item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon"); 1.127 + } 1.128 + item.setAttribute("oncommand", "undoCloseWindow(" + i + ");"); 1.129 + 1.130 + // Set the targetURI attribute so it will be shown in tooltip. 1.131 + // SessionStore uses one-based indexes, so we need to normalize them. 1.132 + let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1; 1.133 + if (activeIndex >= 0 && selectedTab.entries[activeIndex]) 1.134 + item.setAttribute("targetURI", selectedTab.entries[activeIndex].url); 1.135 + 1.136 + if (i == 0) 1.137 + item.setAttribute("key", "key_undoCloseWindow"); 1.138 + fragment.appendChild(item); 1.139 + } 1.140 + 1.141 + // "Open All in Windows" 1.142 + let restoreAllWindows = doc.createElementNS(kNSXUL, aTagName); 1.143 + restoreAllWindows.classList.add("restoreallitem"); 1.144 + restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName(aRestoreAllLabel)); 1.145 + restoreAllWindows.setAttribute("oncommand", 1.146 + "for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();"); 1.147 + if (!aPrefixRestoreAll) { 1.148 + fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator")); 1.149 + fragment.appendChild(restoreAllWindows); 1.150 + } else { 1.151 + fragment.insertBefore(restoreAllWindows, fragment.firstChild); 1.152 + } 1.153 + } 1.154 + return fragment; 1.155 + }, 1.156 + 1.157 + 1.158 + /** 1.159 + * Re-open a closed tab and put it to the end of the tab strip. 1.160 + * Used for a middle click. 1.161 + * @param aEvent 1.162 + * The event when the user clicks the menu item 1.163 + */ 1.164 + _undoCloseMiddleClick: function(aEvent) { 1.165 + if (aEvent.button != 1) 1.166 + return; 1.167 + 1.168 + aEvent.view.undoCloseTab(aEvent.originalTarget.getAttribute("value")); 1.169 + aEvent.view.gBrowser.moveTabToEnd(); 1.170 + }, 1.171 +}; 1.172 + 1.173 +function setImage(aItem, aElement) { 1.174 + let iconURL = aItem.image; 1.175 + // don't initiate a connection just to fetch a favicon (see bug 467828) 1.176 + if (/^https?:/.test(iconURL)) 1.177 + iconURL = "moz-anno:favicon:" + iconURL; 1.178 + aElement.setAttribute("image", iconURL); 1.179 +}