зеркало из https://github.com/mozilla/pjs.git
Bug 254021: Ability to open accidentally closed tabs (r=mconnor)
This commit is contained in:
Родитель
780d129c37
Коммит
8cad9e879f
|
@ -1121,6 +1121,9 @@ function delayedStartup()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// browser-specific tab augmentation
|
||||
AugmentTabs.init();
|
||||
}
|
||||
|
||||
function BrowserShutdown()
|
||||
|
@ -6599,3 +6602,57 @@ window.controllers.appendController(BrowserController);
|
|||
#include ../../../toolkit/content/debug.js
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This object is for augmenting tabs
|
||||
*/
|
||||
var AugmentTabs = {
|
||||
/**
|
||||
* Called in delayedStartup
|
||||
*/
|
||||
init: function at_init() {
|
||||
// add the tab context menu for undo-close-tab (bz254021)
|
||||
var ssEnabled = true;
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
try {
|
||||
ssEnabled = prefBranch.getBoolPref("browser.sessionstore.enabled");
|
||||
} catch (ex) {}
|
||||
|
||||
if (ssEnabled)
|
||||
this._addUndoCloseTabContextMenu();
|
||||
},
|
||||
|
||||
/**
|
||||
* Add undo-close-tab to tab context menu
|
||||
*/
|
||||
_addUndoCloseTabContextMenu: function at_addUndoCloseTabContextMenu() {
|
||||
// get tab context menu
|
||||
var tabbrowser = getBrowser();
|
||||
var tabMenu = document.getAnonymousElementByAttribute(tabbrowser,"anonid","tabContextMenu");
|
||||
|
||||
// get strings
|
||||
var menuLabel = gNavigatorBundle.getString("tabContext.undoCloseTab");
|
||||
var menuAccessKey = gNavigatorBundle.getString("tabContext.undoCloseTabAccessKey");
|
||||
|
||||
// create new menu item
|
||||
var undoCloseTabItem = document.createElement("menuitem");
|
||||
undoCloseTabItem.setAttribute("label", menuLabel);
|
||||
undoCloseTabItem.setAttribute("accesskey", menuAccessKey);
|
||||
undoCloseTabItem.addEventListener("command", this.undoCloseTab, false);
|
||||
|
||||
// add to tab context menu
|
||||
var insertPos = tabMenu.lastChild.previousSibling;
|
||||
tabMenu.insertBefore(undoCloseTabItem, insertPos);
|
||||
},
|
||||
|
||||
/**
|
||||
* Re-open the most-recently-closed tab
|
||||
*/
|
||||
undoCloseTab: function at_undoCloseTab() {
|
||||
// get session-store service
|
||||
var ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
ss.undoCloseTab(window, 0);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -46,11 +46,19 @@ interface nsIDOMWindow;
|
|||
* - and allows to restore everything into one window.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(ca4e1d40-ec1b-11da-8ad9-0800200c9a66)]
|
||||
[scriptable, uuid(38bad250-0021-11db-92e3-0800200c9a66)]
|
||||
interface nsISessionStore : nsISupports
|
||||
{
|
||||
/**
|
||||
* Initialize the service
|
||||
*/
|
||||
void init(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* @param aWindow
|
||||
* The window to reopen a closed tab in.
|
||||
* @param aIndex
|
||||
* Indicates the window to be restored (FIFO ordered).
|
||||
*/
|
||||
void undoCloseTab(in nsIDOMWindow aWindow, in unsigned long aIndex);
|
||||
};
|
||||
|
|
|
@ -423,7 +423,7 @@ SessionStoreService.prototype = {
|
|||
tabpanels.addEventListener("select", function(aEvent) {
|
||||
_this.onTabSelect(aEvent.currentTarget.ownerDocument.defaultView, aEvent.currentTarget);
|
||||
}, false);
|
||||
tabbrowser.addEventListener("TabClose", function(aEvent) {
|
||||
tabbrowser.addEventListener("DOMNodeRemoved", function(aEvent) {
|
||||
_this.onTabClose(aEvent.currentTarget.ownerDocument.defaultView, aEvent.originalTarget);
|
||||
}, false);
|
||||
},
|
||||
|
@ -540,12 +540,17 @@ SessionStoreService.prototype = {
|
|||
this._saveWindowHistory(aWindow);
|
||||
this._updateTextAndScrollData(aWindow);
|
||||
|
||||
this._windows[aWindow.__SSi]._closedTabs.unshift({
|
||||
state: this._windows[aWindow.__SSi].Tab[aTab._tPos],
|
||||
title: aTab.getAttribute("label"),
|
||||
pos: aTab._tPos
|
||||
});
|
||||
this._windows[aWindow.__SSi]._closedTabs.splice(this._getPref("sessionstore.max_tabs_undo", DEFAULT_MAX_TABS_UNDO));
|
||||
// DOMNodeRemoved is received *twice* after closing a tab, only take the first
|
||||
var tabState = this._windows[aWindow.__SSi].Tab[aTab._tPos];
|
||||
if (tabState) {
|
||||
this._windows[aWindow.__SSi]._closedTabs.unshift({
|
||||
state: tabState,
|
||||
title: aTab.getAttribute("label"),
|
||||
pos: aTab._tPos
|
||||
});
|
||||
var maxTabsUndo = this._getPref("sessionstore.max_tabs_undo", DEFAULT_MAX_TABS_UNDO);
|
||||
this._windows[aWindow.__SSi]._closedTabs.splice(maxTabsUndo);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -686,22 +691,30 @@ SessionStoreService.prototype = {
|
|||
this._windows[aWindow.__SSi]._closedTabs = IniObjectSerializer.decode(aData);
|
||||
},
|
||||
|
||||
undoCloseTab: function sss_undoCloseWindow(aWindow, aIx) {
|
||||
var tabs = this._windows[aWindow.__SSi]._closedTabs;
|
||||
|
||||
if (aIx in tabs) {
|
||||
var browser = aWindow.getBrowser();
|
||||
var tabData = tabs.splice(aIx, 1);
|
||||
tabData._tab = browser.addTab();
|
||||
|
||||
// restore the tab's position
|
||||
browser.moveTabTo(tabData._tab, tabData[0].pos);
|
||||
undoCloseTab: function sss_undoCloseTab(aWindow, aIndex) {
|
||||
var closedTabs = this._windows[aWindow.__SSi]._closedTabs;
|
||||
|
||||
// restore the tab's state
|
||||
aWindow.setTimeout(this.restoreHistory_proxy, 0, tabData, 1, 0, 0);
|
||||
// default to the most-recently closed tab
|
||||
aIndex = aIndex || 0;
|
||||
|
||||
if (aIndex in closedTabs) {
|
||||
var browser = aWindow.getBrowser();
|
||||
|
||||
// fetch the data of closed tab, while removing it from the array
|
||||
var closedTab = closedTabs.splice(aIndex, 1).shift();
|
||||
var closedTabState = closedTab.state;
|
||||
|
||||
// create a new tab
|
||||
closedTabState._tab = browser.addTab();
|
||||
|
||||
// restore the tab's position
|
||||
browser.moveTabTo(closedTabState._tab, closedTab.pos);
|
||||
|
||||
// restore tab content
|
||||
this.restoreHistoryPrecursor(aWindow, [closedTabState], 1, 0, 0);
|
||||
}
|
||||
else {
|
||||
Components.returnCode = -1; //zeniko: or should we rather fail silently?
|
||||
Components.returnCode = Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1196,11 +1209,8 @@ SessionStoreService.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
var restoreHistoryFunc = function(self) {
|
||||
self.restoreHistory_proxy(aWindow, winData.Tab, (aOverwriteTabs ?
|
||||
this.restoreHistoryPrecursor(aWindow, winData.Tab, (aOverwriteTabs ?
|
||||
(parseInt(winData.selected) || 1) : 0), 0, 0);
|
||||
};
|
||||
aWindow.setTimeout(restoreHistoryFunc, 0, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1214,7 +1224,7 @@ SessionStoreService.prototype = {
|
|||
* @param aCount
|
||||
* Counter for number of times delaying b/c browser or history aren't ready
|
||||
*/
|
||||
restoreHistory_proxy: function sss_restoreHistory_proxy(aWindow, aTabs, aSelectTab, aIx, aCount) {
|
||||
restoreHistoryPrecursor: function sss_restoreHistoryPrecursor(aWindow, aTabs, aSelectTab, aIx, aCount) {
|
||||
var tabbrowser = aWindow.getBrowser();
|
||||
|
||||
// make sure that all browsers and their histories are available
|
||||
|
@ -1228,7 +1238,7 @@ SessionStoreService.prototype = {
|
|||
catch (ex) { // in case browser or history aren't ready yet
|
||||
if (aCount < 10) {
|
||||
var restoreHistoryFunc = function(self) {
|
||||
self.restoreHistory_proxy(aWindow, aTabs, aSelectTab, aIx, aCount + 1);
|
||||
self.restoreHistoryPrecursor(aWindow, aTabs, aSelectTab, aIx, aCount + 1);
|
||||
}
|
||||
aWindow.setTimeout(restoreHistoryFunc, 100, this);
|
||||
return;
|
||||
|
|
|
@ -119,3 +119,7 @@ feedHasFeeds=Add Live Bookmark...
|
|||
feedNoFeeds=Page has no feeds
|
||||
feedShowFeedNew=Subscribe to '%S'...
|
||||
feedHasFeedsNew=Subscribe to this page...
|
||||
|
||||
# tab context menu additions
|
||||
tabContext.undoCloseTab=Undo Close Tab
|
||||
tabContext.undoCloseTabAccessKey=U
|
||||
|
|
Загрузка…
Ссылка в новой задаче