Bug 459550 - Port Bug 448976 (turn the Session Restore prompt into an error page) to SeaMonkey. r+sr=Neil, a=wanted2+.
This commit is contained in:
Родитель
c8f621edc5
Коммит
1158298990
|
@ -196,7 +196,6 @@ pref("browser.tabs.opentabfor.middleclick", false);
|
||||||
pref("browser.tabs.opentabfor.urlbar", false);
|
pref("browser.tabs.opentabfor.urlbar", false);
|
||||||
pref("browser.tabs.tooltippreview.enable", true);
|
pref("browser.tabs.tooltippreview.enable", true);
|
||||||
pref("browser.tabs.tooltippreview.width", 300);
|
pref("browser.tabs.tooltippreview.width", 300);
|
||||||
pref("browser.tabs.undoclose.depth", 3);
|
|
||||||
pref("browser.tabs.autoHide", true);
|
pref("browser.tabs.autoHide", true);
|
||||||
pref("browser.tabs.forceHide", false);
|
pref("browser.tabs.forceHide", false);
|
||||||
pref("browser.tabs.warnOnClose", true);
|
pref("browser.tabs.warnOnClose", true);
|
||||||
|
@ -321,6 +320,11 @@ pref("browser.sessionstore.postdata", 0);
|
||||||
// on which sites to save text data, POSTDATA and cookies
|
// on which sites to save text data, POSTDATA and cookies
|
||||||
// 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
|
// 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
|
||||||
pref("browser.sessionstore.privacy_level", 1);
|
pref("browser.sessionstore.privacy_level", 1);
|
||||||
|
// number of crashes that can occur before the about:sessionrestore page is displayed
|
||||||
|
// (this pref has no effect if more than 6 hours have passed since the last crash)
|
||||||
|
pref("browser.sessionstore.max_resumed_crashes", 1);
|
||||||
|
// how many tabs can be reopened (per window)
|
||||||
|
pref("browser.sessionstore.max_tabs_undo", 10);
|
||||||
|
|
||||||
pref("shell.checkDefaultClient", true);
|
pref("shell.checkDefaultClient", true);
|
||||||
// We want to check if we are the default client for browser and mail. See
|
// We want to check if we are the default client for browser and mail. See
|
||||||
|
|
|
@ -744,7 +744,7 @@
|
||||||
|
|
||||||
var undoItem = document.getAnonymousElementByAttribute(this, "tbattr", "tabbrowser-undoclosetab");
|
var undoItem = document.getAnonymousElementByAttribute(this, "tbattr", "tabbrowser-undoclosetab");
|
||||||
undoItem.setAttribute("disabled", this.savedBrowsers.length == 0);
|
undoItem.setAttribute("disabled", this.savedBrowsers.length == 0);
|
||||||
undoItem.hidden = this.mPrefs.getIntPref("browser.tabs.undoclose.depth") <= 0;
|
undoItem.hidden = this.mPrefs.getIntPref("browser.sessionstore.max_tabs_undo") <= 0;
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -1425,7 +1425,7 @@
|
||||||
// Save the tab for undo.
|
// Save the tab for undo.
|
||||||
// Even though we navigate to about:blank, it costs more RAM than
|
// Even though we navigate to about:blank, it costs more RAM than
|
||||||
// really closing the tab. The pref controls how far you can undo
|
// really closing the tab. The pref controls how far you can undo
|
||||||
var maxUndoDepth = this.mPrefs.getIntPref("browser.tabs.undoclose.depth");
|
var maxUndoDepth = this.mPrefs.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||||
var oldSH = oldBrowser.webNavigation.sessionHistory;
|
var oldSH = oldBrowser.webNavigation.sessionHistory;
|
||||||
var inOnLoad = oldBrowser.docShell.isExecutingOnLoadHandler;
|
var inOnLoad = oldBrowser.docShell.isExecutingOnLoadHandler;
|
||||||
if (maxUndoDepth <= 0 || oldSH.count == 0 || aDisableUndo || inOnLoad) {
|
if (maxUndoDepth <= 0 || oldSH.count == 0 || aDisableUndo || inOnLoad) {
|
||||||
|
|
|
@ -0,0 +1,328 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the nsSessionStore component.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Simon Bünzli <zeniko@gmail.com>
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
var gStateObject;
|
||||||
|
var gTreeData;
|
||||||
|
|
||||||
|
// Page initialization
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
// the crashed session state is kept inside a textbox so that SessionStore picks it up
|
||||||
|
// (for when the tab is closed or the session crashes right again)
|
||||||
|
var sessionData = document.getElementById("sessionData");
|
||||||
|
if (!sessionData.value) {
|
||||||
|
var ss = Components.classes["@mozilla.org/suite/sessionstartup;1"].getService(Components.interfaces.nsISessionStartup);
|
||||||
|
sessionData.value = ss.state;
|
||||||
|
if (!sessionData.value) {
|
||||||
|
document.getElementById("errorTryAgain").disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make sure the data is tracked to be restored in case of a subsequent crash
|
||||||
|
var event = document.createEvent("UIEvents");
|
||||||
|
event.initUIEvent("input", true, true, window, 0);
|
||||||
|
sessionData.dispatchEvent(event);
|
||||||
|
|
||||||
|
var s = new Components.utils.Sandbox("about:blank");
|
||||||
|
gStateObject = Components.utils.evalInSandbox("(" + sessionData.value + ")", s);
|
||||||
|
|
||||||
|
initTreeView();
|
||||||
|
|
||||||
|
document.getElementById("errorTryAgain").focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
function initTreeView() {
|
||||||
|
var tabList = document.getElementById("tabList");
|
||||||
|
var winLabel = tabList.getAttribute("_window_label");
|
||||||
|
|
||||||
|
gTreeData = [];
|
||||||
|
gStateObject.windows.forEach(function(aWinData, aIx) {
|
||||||
|
var winState = {
|
||||||
|
label: winLabel.replace("%S", (aIx + 1)),
|
||||||
|
open: true,
|
||||||
|
checked: true,
|
||||||
|
ix: aIx
|
||||||
|
};
|
||||||
|
winState.tabs = aWinData.tabs.map(function(aTabData) {
|
||||||
|
var entry = aTabData.entries[aTabData.index - 1] || { url: "about:blank" };
|
||||||
|
var iconURL = aTabData.attributes && aTabData.attributes.image || null;
|
||||||
|
// don't initiate a connection just to fetch a favicon (see bug 462863)
|
||||||
|
if (/^https?:/.test(iconURL))
|
||||||
|
iconURL = "moz-anno:favicon:" + iconURL;
|
||||||
|
return {
|
||||||
|
label: entry.title || entry.url,
|
||||||
|
checked: true,
|
||||||
|
src: iconURL,
|
||||||
|
parent: winState
|
||||||
|
};
|
||||||
|
});
|
||||||
|
gTreeData.push(winState);
|
||||||
|
for each (var tab in winState.tabs)
|
||||||
|
gTreeData.push(tab);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
tabList.view = treeView;
|
||||||
|
tabList.view.selection.select(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// User actions
|
||||||
|
|
||||||
|
function restoreSession() {
|
||||||
|
document.getElementById("errorTryAgain").disabled = true;
|
||||||
|
|
||||||
|
// remove all unselected tabs from the state before restoring it
|
||||||
|
var ix = gStateObject.windows.length - 1;
|
||||||
|
for (var t = gTreeData.length - 1; t >= 0; t--) {
|
||||||
|
if (treeView.isContainer(t)) {
|
||||||
|
if (gTreeData[t].checked === 0)
|
||||||
|
// this window will be restored partially
|
||||||
|
gStateObject.windows[ix].tabs =
|
||||||
|
gStateObject.windows[ix].tabs.filter(function(aTabData, aIx)
|
||||||
|
gTreeData[t].tabs[aIx].checked);
|
||||||
|
else if (!gTreeData[t].checked)
|
||||||
|
// this window won't be restored at all
|
||||||
|
gStateObject.windows.splice(ix, 1);
|
||||||
|
ix--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var stateString = gStateObject.toSource();
|
||||||
|
|
||||||
|
var ss = Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore);
|
||||||
|
var top = getBrowserWindow();
|
||||||
|
|
||||||
|
// if there's only this page open, reuse the window for restoring the session
|
||||||
|
if (top.gBrowser.tabContainer.childNodes.length == 1) {
|
||||||
|
ss.setWindowState(top, stateString, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the session into a new window and close the current tab
|
||||||
|
var newWindow = top.openDialog(top.location, "_blank", "chrome,dialog=no,all", "about:blank");
|
||||||
|
var tab = top.gBrowser.selectedTab;
|
||||||
|
newWindow.addEventListener("load", function() {
|
||||||
|
newWindow.removeEventListener("load", arguments.callee, true);
|
||||||
|
ss.setWindowState(newWindow, stateString, true);
|
||||||
|
|
||||||
|
top.gBrowser.removeTab(tab);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startNewSession() {
|
||||||
|
getBrowserWindow().BrowserHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onListClick(aEvent) {
|
||||||
|
// don't react to right-clicks
|
||||||
|
if (aEvent.button == 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var row = {}, col = {};
|
||||||
|
treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY, row, col, {});
|
||||||
|
if (col.value) {
|
||||||
|
// restore this specific tab in the same window for middle-clicking
|
||||||
|
// or Ctrl+clicking on a tab's title
|
||||||
|
if ((aEvent.button == 1 || aEvent.ctrlKey) && col.value.id == "title" &&
|
||||||
|
!treeView.isContainer(row.value))
|
||||||
|
restoreSingleTab(row.value, aEvent.shiftKey);
|
||||||
|
else if (col.value.id == "restore")
|
||||||
|
toggleRowChecked(row.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onListKeyDown(aEvent) {
|
||||||
|
switch (aEvent.keyCode)
|
||||||
|
{
|
||||||
|
case KeyEvent.DOM_VK_SPACE:
|
||||||
|
toggleRowChecked(document.getElementById("tabList").currentIndex);
|
||||||
|
break;
|
||||||
|
case KeyEvent.DOM_VK_RETURN:
|
||||||
|
var ix = document.getElementById("tabList").currentIndex;
|
||||||
|
if (aEvent.ctrlKey && !treeView.isContainer(ix))
|
||||||
|
restoreSingleTab(ix, aEvent.shiftKey);
|
||||||
|
break;
|
||||||
|
case KeyEvent.DOM_VK_UP:
|
||||||
|
case KeyEvent.DOM_VK_DOWN:
|
||||||
|
case KeyEvent.DOM_VK_PAGE_UP:
|
||||||
|
case KeyEvent.DOM_VK_PAGE_DOWN:
|
||||||
|
case KeyEvent.DOM_VK_HOME:
|
||||||
|
case KeyEvent.DOM_VK_END:
|
||||||
|
aEvent.preventDefault(); // else the page scrolls unwantedly
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
|
||||||
|
function getBrowserWindow() {
|
||||||
|
return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebNavigation)
|
||||||
|
.QueryInterface(Components.interfaces.nsIDocShellTreeItem).rootTreeItem
|
||||||
|
.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleRowChecked(aIx) {
|
||||||
|
var item = gTreeData[aIx];
|
||||||
|
item.checked = !item.checked;
|
||||||
|
treeView.treeBox.invalidateRow(aIx);
|
||||||
|
|
||||||
|
function isChecked(aItem) aItem.checked;
|
||||||
|
|
||||||
|
if (treeView.isContainer(aIx)) {
|
||||||
|
// (un)check all tabs of this window as well
|
||||||
|
for each (var tab in item.tabs) {
|
||||||
|
tab.checked = item.checked;
|
||||||
|
treeView.treeBox.invalidateRow(gTreeData.indexOf(tab));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// update the window's checkmark as well (0 means "partially checked")
|
||||||
|
item.parent.checked = item.parent.tabs.every(isChecked) ? true :
|
||||||
|
item.parent.tabs.some(isChecked) ? 0 : false;
|
||||||
|
treeView.treeBox.invalidateRow(gTreeData.indexOf(item.parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("errorTryAgain").disabled = !gTreeData.some(isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreSingleTab(aIx, aShifted) {
|
||||||
|
var tabbrowser = getBrowserWindow().gBrowser;
|
||||||
|
var newTab = tabbrowser.addTab();
|
||||||
|
var item = gTreeData[aIx];
|
||||||
|
|
||||||
|
var ss = Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore);
|
||||||
|
var tabState = gStateObject.windows[item.parent.ix]
|
||||||
|
.tabs[aIx - gTreeData.indexOf(item.parent) - 1];
|
||||||
|
ss.setTabState(newTab, tabState.toSource());
|
||||||
|
|
||||||
|
// respect the preference as to whether to select the tab (the Shift key inverses)
|
||||||
|
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||||
|
if (prefBranch.getBoolPref("browser.tabs.loadInBackground") != !aShifted)
|
||||||
|
tabbrowser.selectedTab = newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tree controller
|
||||||
|
|
||||||
|
var treeView = {
|
||||||
|
_atoms: {},
|
||||||
|
_getAtom: function(aName)
|
||||||
|
{
|
||||||
|
if (!this._atoms[aName]) {
|
||||||
|
var as = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
|
||||||
|
this._atoms[aName] = as.getAtom(aName);
|
||||||
|
}
|
||||||
|
return this._atoms[aName];
|
||||||
|
},
|
||||||
|
|
||||||
|
treeBox: null,
|
||||||
|
selection: null,
|
||||||
|
|
||||||
|
get rowCount() { return gTreeData.length; },
|
||||||
|
setTree: function(treeBox) { this.treeBox = treeBox; },
|
||||||
|
getCellText: function(idx, column) { return gTreeData[idx].label; },
|
||||||
|
isContainer: function(idx) { return "open" in gTreeData[idx]; },
|
||||||
|
getCellValue: function(idx, column){ return gTreeData[idx].checked; },
|
||||||
|
isContainerOpen: function(idx) { return gTreeData[idx].open; },
|
||||||
|
isContainerEmpty: function(idx) { return false; },
|
||||||
|
isSeparator: function(idx) { return false; },
|
||||||
|
isSorted: function() { return false; },
|
||||||
|
isEditable: function(idx, column) { return false; },
|
||||||
|
getLevel: function(idx) { return this.isContainer(idx) ? 0 : 1; },
|
||||||
|
|
||||||
|
getParentIndex: function(idx) {
|
||||||
|
if (!this.isContainer(idx))
|
||||||
|
for (var t = idx - 1; t >= 0 ; t--)
|
||||||
|
if (this.isContainer(t))
|
||||||
|
return t;
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasNextSibling: function(idx, after) {
|
||||||
|
var thisLevel = this.getLevel(idx);
|
||||||
|
for (var t = after + 1; t < gTreeData.length; t++)
|
||||||
|
if (this.getLevel(t) <= thisLevel)
|
||||||
|
return this.getLevel(t) == thisLevel;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleOpenState: function(idx) {
|
||||||
|
if (!this.isContainer(idx))
|
||||||
|
return;
|
||||||
|
var item = gTreeData[idx];
|
||||||
|
if (item.open) {
|
||||||
|
// remove this window's tab rows from the view
|
||||||
|
var thisLevel = this.getLevel(idx);
|
||||||
|
for (var t = idx + 1; t < gTreeData.length && this.getLevel(t) > thisLevel; t++);
|
||||||
|
var deletecount = t - idx - 1;
|
||||||
|
gTreeData.splice(idx + 1, deletecount);
|
||||||
|
this.treeBox.rowCountChanged(idx + 1, -deletecount);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// add this window's tab rows to the view
|
||||||
|
var toinsert = gTreeData[idx].tabs;
|
||||||
|
for (var i = 0; i < toinsert.length; i++)
|
||||||
|
gTreeData.splice(idx + i + 1, 0, toinsert[i]);
|
||||||
|
this.treeBox.rowCountChanged(idx + 1, toinsert.length);
|
||||||
|
}
|
||||||
|
item.open = !item.open;
|
||||||
|
this.treeBox.invalidateRow(idx);
|
||||||
|
},
|
||||||
|
|
||||||
|
getCellProperties: function(idx, column, prop) {
|
||||||
|
if (column.id == "restore" && this.isContainer(idx) && gTreeData[idx].checked === 0)
|
||||||
|
prop.AppendElement(this._getAtom("partial"));
|
||||||
|
if (column.id == "title")
|
||||||
|
prop.AppendElement(this._getAtom(this.getImageSrc(idx, column) ? "icon" : "noicon"));
|
||||||
|
},
|
||||||
|
|
||||||
|
getRowProperties: function(idx, prop) {
|
||||||
|
var winState = gTreeData[idx].parent || gTreeData[idx];
|
||||||
|
if (winState.ix % 2 != 0)
|
||||||
|
prop.AppendElement(this._getAtom("alternate"));
|
||||||
|
},
|
||||||
|
|
||||||
|
getImageSrc: function(idx, column) {
|
||||||
|
if (column.id == "title")
|
||||||
|
return gTreeData[idx].src || null;
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getProgressMode : function(idx, column) { },
|
||||||
|
cycleHeader: function(column) { },
|
||||||
|
cycleCell: function(idx, column) { },
|
||||||
|
selectionChanged: function() { },
|
||||||
|
performAction: function(action) { },
|
||||||
|
performActionOnCell: function(action, index, column) { },
|
||||||
|
getColumnProperties: function(column, prop) { }
|
||||||
|
};
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
# the License. You may obtain a copy of the License at
|
||||||
|
# http://www.mozilla.org/MPL/
|
||||||
|
#
|
||||||
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
# for the specific language governing rights and limitations under the
|
||||||
|
# License.
|
||||||
|
#
|
||||||
|
# The Original Code is the nsSessionStore component.
|
||||||
|
#
|
||||||
|
# The Initial Developer of the Original Code is
|
||||||
|
# Simon Bünzli <zeniko@gmail.com>
|
||||||
|
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
# the Initial Developer. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s):
|
||||||
|
#
|
||||||
|
# Alternatively, the contents of this file may be used under the terms of
|
||||||
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
# of those above. If you wish to allow use of your version of this file only
|
||||||
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
# use your version of this file under the terms of the MPL, indicate your
|
||||||
|
# decision by deleting the provisions above and replace them with the notice
|
||||||
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
# the provisions above, a recipient may use your version of this file under
|
||||||
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK *****
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html [
|
||||||
|
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
|
||||||
|
%brandDTD;
|
||||||
|
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
|
||||||
|
%htmlDTD;
|
||||||
|
<!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
|
||||||
|
%netErrorDTD;
|
||||||
|
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||||
|
%globalDTD;
|
||||||
|
<!ENTITY % restorepageDTD SYSTEM "chrome://communicator/locale/aboutSessionRestore.dtd">
|
||||||
|
%restorepageDTD;
|
||||||
|
]>
|
||||||
|
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>&restorepage.tabtitle;</title>
|
||||||
|
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
|
||||||
|
<link rel="stylesheet" href="chrome://communicator/skin/aboutSessionRestore.css" type="text/css" media="all"/>
|
||||||
|
<link rel="icon" type="image/png" href="chrome://global/skin/icons/question-16.png"/>
|
||||||
|
|
||||||
|
<script type="application/javascript" src="chrome://communicator/content/aboutSessionRestore.js"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body dir="&locale.dir;">
|
||||||
|
|
||||||
|
<!-- PAGE CONTAINER (for styling purposes only) -->
|
||||||
|
<div id="errorPageContainer">
|
||||||
|
|
||||||
|
<!-- Error Title -->
|
||||||
|
<div id="errorTitle">
|
||||||
|
<h1 id="errorTitleText">&restorepage.pagetitle;</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- LONG CONTENT (the section most likely to require scrolling) -->
|
||||||
|
<div id="errorLongContent">
|
||||||
|
|
||||||
|
<!-- Short Description -->
|
||||||
|
<div id="errorShortDesc">
|
||||||
|
<p id="errorShortDescText">&restorepage.issueDesc;</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
|
||||||
|
<div id="errorLongDesc">
|
||||||
|
<p>&restorepage.remedies;</p>
|
||||||
|
<ul>
|
||||||
|
<li>&restorepage.dueToChrome;</li>
|
||||||
|
<li>&restorepage.dueToContent;</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Short Description -->
|
||||||
|
<div id="errorTrailerDesc">
|
||||||
|
<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
id="tabList" flex="1" seltype="single" hidecolumnpicker="true"
|
||||||
|
onclick="onListClick(event);" onkeydown="onListKeyDown(event);"
|
||||||
|
_window_label="&restorepage.windowLabel;">
|
||||||
|
<treecols>
|
||||||
|
<treecol id="restore" type="checkbox" label="&restorepage.restoreHeader;"/>
|
||||||
|
<splitter class="tree-splitter"/>
|
||||||
|
<treecol primary="true" id="title" label="&restorepage.listHeader;" flex="1"/>
|
||||||
|
</treecols>
|
||||||
|
<treechildren flex="1"/>
|
||||||
|
</tree>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
|
<hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="buttons">
|
||||||
|
<button id="errorTryAgain" label="&restorepage.restoreButton;"
|
||||||
|
accesskey="&restorepage.restore.access;"
|
||||||
|
oncommand="restoreSession();"/>
|
||||||
|
<button id="errorCancel" label="&restorepage.cancelButton;"
|
||||||
|
accesskey="&restorepage.cancel.access;"
|
||||||
|
oncommand="startNewSession();"/>
|
||||||
|
</hbox>
|
||||||
|
<!-- holds the session data for when the tab is closed -->
|
||||||
|
<input type="text" id="sessionData" style="display: none;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -46,6 +46,8 @@ comm.jar:
|
||||||
% overlay chrome://messenger-smime/content/msgReadSecurityInfo.xul chrome://communicator/content/helpMessengerOverlay.xul
|
% overlay chrome://messenger-smime/content/msgReadSecurityInfo.xul chrome://communicator/content/helpMessengerOverlay.xul
|
||||||
% content communicator-platform %content/communicator-platform/ platform xpcnativewrappers=yes
|
% content communicator-platform %content/communicator-platform/ platform xpcnativewrappers=yes
|
||||||
% content communicator-region %content/communicator-region/ xpcnativewrappers=yes
|
% content communicator-region %content/communicator-region/ xpcnativewrappers=yes
|
||||||
|
content/communicator/aboutSessionRestore.js
|
||||||
|
content/communicator/aboutSessionRestore.xhtml
|
||||||
content/communicator/askViewZoom.xul
|
content/communicator/askViewZoom.xul
|
||||||
content/communicator/askViewZoom.js
|
content/communicator/askViewZoom.js
|
||||||
content/communicator/browserBindings.xul
|
content/communicator/browserBindings.xul
|
||||||
|
|
|
@ -46,6 +46,7 @@ MODULE = suitecommon
|
||||||
|
|
||||||
EXTRA_COMPONENTS = \
|
EXTRA_COMPONENTS = \
|
||||||
nsAboutCertError.js \
|
nsAboutCertError.js \
|
||||||
|
nsAboutSessionRestore.js \
|
||||||
nsSessionStartup.js \
|
nsSessionStartup.js \
|
||||||
nsSessionStore.js \
|
nsSessionStore.js \
|
||||||
nsSuiteGlue.js \
|
nsSuiteGlue.js \
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the nsSessionStore component.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Simon Bünzli <zeniko@gmail.com>
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
function AboutSessionRestore() { }
|
||||||
|
AboutSessionRestore.prototype = {
|
||||||
|
classDescription: "about:sessionrestore",
|
||||||
|
contractID: "@mozilla.org/network/protocol/about;1?what=sessionrestore",
|
||||||
|
classID: Components.ID("{a03c813e-abe8-41de-8d0c-5aa85f877696}"),
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIAboutModule]),
|
||||||
|
|
||||||
|
getURIFlags: function(aURI) {
|
||||||
|
return Components.interfaces.nsIAboutModule.ALLOW_SCRIPT;
|
||||||
|
},
|
||||||
|
|
||||||
|
newChannel: function(aURI) {
|
||||||
|
let ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
|
||||||
|
let channel = ios.newChannel("chrome://communicator/content/aboutSessionRestore.xhtml",
|
||||||
|
null, null);
|
||||||
|
channel.originalURI = aURI;
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function NSGetModule(compMgr, fileSpec) {
|
||||||
|
return XPCOMUtils.generateModule([AboutSessionRestore]);
|
||||||
|
}
|
|
@ -90,9 +90,9 @@ SessionStartup.prototype = {
|
||||||
* Initialize the component
|
* Initialize the component
|
||||||
*/
|
*/
|
||||||
init: function sss_init() {
|
init: function sss_init() {
|
||||||
this._prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
|
let prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
.getService(Components.interfaces.nsIPrefService)
|
.getService(Components.interfaces.nsIPrefService)
|
||||||
.getBranch("browser.");
|
.getBranch("browser.");
|
||||||
|
|
||||||
// get file references
|
// get file references
|
||||||
var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
|
var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||||
|
@ -100,11 +100,11 @@ SessionStartup.prototype = {
|
||||||
let sessionFile = dirService.get("ProfD", Components.interfaces.nsILocalFile);
|
let sessionFile = dirService.get("ProfD", Components.interfaces.nsILocalFile);
|
||||||
sessionFile.append("sessionstore.js");
|
sessionFile.append("sessionstore.js");
|
||||||
|
|
||||||
let doResumeSession = this._prefBranch.getBoolPref("sessionstore.resume_session_once") ||
|
let doResumeSession = prefBranch.getBoolPref("sessionstore.resume_session_once") ||
|
||||||
this._prefBranch.getIntPref("startup.page") == 3;
|
prefBranch.getIntPref("startup.page") == 3;
|
||||||
|
|
||||||
// only read the session file if config allows possibility of restoring
|
// only read the session file if config allows possibility of restoring
|
||||||
var resumeFromCrash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
|
var resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
|
||||||
if ((!resumeFromCrash && !doResumeSession) || !sessionFile.exists())
|
if ((!resumeFromCrash && !doResumeSession) || !sessionFile.exists())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ SessionStartup.prototype = {
|
||||||
initialState.session.state == STATE_RUNNING_STR;
|
initialState.session.state == STATE_RUNNING_STR;
|
||||||
|
|
||||||
// set the startup type
|
// set the startup type
|
||||||
if (lastSessionCrashed && resumeFromCrash && this._doRecoverSession())
|
if (lastSessionCrashed && resumeFromCrash)
|
||||||
this._sessionType = Components.interfaces.nsISessionStartup.RECOVER_SESSION;
|
this._sessionType = Components.interfaces.nsISessionStartup.RECOVER_SESSION;
|
||||||
else if (!lastSessionCrashed && doResumeSession)
|
else if (!lastSessionCrashed && doResumeSession)
|
||||||
this._sessionType = Components.interfaces.nsISessionStartup.RESUME_SESSION;
|
this._sessionType = Components.interfaces.nsISessionStartup.RESUME_SESSION;
|
||||||
|
@ -201,78 +201,6 @@ SessionStartup.prototype = {
|
||||||
return this._sessionType;
|
return this._sessionType;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ........ Auxiliary Functions .............. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* prompt user whether or not to restore the previous session,
|
|
||||||
* if the browser crashed
|
|
||||||
* @returns bool
|
|
||||||
*/
|
|
||||||
_doRecoverSession: function sss_doRecoverSession() {
|
|
||||||
// if the prompt fails, recover anyway
|
|
||||||
var recover = true;
|
|
||||||
|
|
||||||
// allow extensions to hook in a more elaborate restore prompt
|
|
||||||
// XXXzeniko drop this when we're using our own dialog instead of a standard prompt
|
|
||||||
var dialogURI = null;
|
|
||||||
try {
|
|
||||||
dialogURI = this._prefBranch.getCharPref("sessionstore.restore_prompt_uri");
|
|
||||||
}
|
|
||||||
catch (ex) { }
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (dialogURI) { // extension provided dialog
|
|
||||||
var params = Components.classes["@mozilla.org/embedcomp/dialogparam;1"]
|
|
||||||
.createInstance(Components.interfaces.nsIDialogParamBlock);
|
|
||||||
// default to recovering
|
|
||||||
params.SetInt(0, 0);
|
|
||||||
Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
|
||||||
.getService(Components.interfaces.nsIWindowWatcher)
|
|
||||||
.openWindow(null, dialogURI, "_blank", "chrome,modal,centerscreen,titlebar", params);
|
|
||||||
recover = params.GetInt(0) == 0;
|
|
||||||
}
|
|
||||||
else { // basic prompt with no options
|
|
||||||
// get app name from branding properties
|
|
||||||
var brandStringBundle = this._getStringBundle("chrome://branding/locale/brand.properties");
|
|
||||||
var brandShortName = brandStringBundle.GetStringFromName("brandShortName");
|
|
||||||
|
|
||||||
// create prompt strings
|
|
||||||
var ssStringBundle = this._getStringBundle("chrome://communicator/locale/sessionstore.properties");
|
|
||||||
var restoreTitle = ssStringBundle.formatStringFromName("restoredTitle", [brandShortName], 1);
|
|
||||||
var restoreText = ssStringBundle.formatStringFromName("restoredMsg", [brandShortName], 1);
|
|
||||||
var okTitle = ssStringBundle.GetStringFromName("okTitle");
|
|
||||||
var cancelTitle = ssStringBundle.GetStringFromName("cancelTitle");
|
|
||||||
|
|
||||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIPromptService);
|
|
||||||
|
|
||||||
// set the buttons that will appear on the dialog
|
|
||||||
var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
|
|
||||||
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
|
|
||||||
promptService.BUTTON_POS_0_DEFAULT;
|
|
||||||
var buttonChoice = promptService.confirmEx(null, restoreTitle, restoreText,
|
|
||||||
flags, okTitle, cancelTitle, null,
|
|
||||||
null, {});
|
|
||||||
recover = (buttonChoice == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ex) { dump(ex + "\n"); } // if the prompt fails, recover anyway
|
|
||||||
return recover;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to get localized string bundles
|
|
||||||
* @param aURI
|
|
||||||
* @returns nsIStringBundle
|
|
||||||
*/
|
|
||||||
_getStringBundle: function sss_getStringBundle(aURI) {
|
|
||||||
var bundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
|
||||||
.getService(Components.interfaces.nsIStringBundleService);
|
|
||||||
var appLocale = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
|
|
||||||
.getService(Components.interfaces.nsILocaleService).getApplicationLocale();
|
|
||||||
return bundleService.createBundle(aURI, appLocale);
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ........ Storage API .............. */
|
/* ........ Storage API .............. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Dietrich Ayala <dietrich@mozilla.com>
|
* Dietrich Ayala <dietrich@mozilla.com>
|
||||||
|
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -93,8 +94,6 @@ const CAPABILITIES = [
|
||||||
"Subframes", "Plugins", "Javascript", "MetaRedirects", "Images"
|
"Subframes", "Plugins", "Javascript", "MetaRedirects", "Images"
|
||||||
];
|
];
|
||||||
|
|
||||||
// module for JSON conversion (needed for the nsISessionStore API)
|
|
||||||
Components.utils.import("resource://gre/modules/JSON.jsm");
|
|
||||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
function debug(aMsg) {
|
function debug(aMsg) {
|
||||||
|
@ -117,8 +116,9 @@ SessionStoreService.prototype = {
|
||||||
Components.interfaces.nsIObserver,
|
Components.interfaces.nsIObserver,
|
||||||
Components.interfaces.nsISupportsWeakReference]),
|
Components.interfaces.nsISupportsWeakReference]),
|
||||||
|
|
||||||
// xul:tab attributes to (re)store (extensions might want to hook in here)
|
// xul:tab attributes to (re)store (extensions might want to hook in here);
|
||||||
xulAttributes: [],
|
// the favicon is always saved for the about:sessionrestore page
|
||||||
|
xulAttributes: ["image"],
|
||||||
|
|
||||||
// set default load state
|
// set default load state
|
||||||
_loadState: STATE_STOPPED,
|
_loadState: STATE_STOPPED,
|
||||||
|
@ -145,6 +145,12 @@ SessionStoreService.prototype = {
|
||||||
// not-"dirty" windows usually don't need to have their data updated
|
// not-"dirty" windows usually don't need to have their data updated
|
||||||
_dirtyWindows: {},
|
_dirtyWindows: {},
|
||||||
|
|
||||||
|
// collection of session states yet to be restored
|
||||||
|
_statesToRestore: {},
|
||||||
|
|
||||||
|
// counts the number of crashes since the last clean start
|
||||||
|
_recentCrashes: 0,
|
||||||
|
|
||||||
/* ........ Global Event Handlers .............. */
|
/* ........ Global Event Handlers .............. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,9 +185,9 @@ SessionStoreService.prototype = {
|
||||||
this._resume_from_crash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
|
this._resume_from_crash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
|
||||||
this._prefBranch.addObserver("sessionstore.resume_from_crash", this, true);
|
this._prefBranch.addObserver("sessionstore.resume_from_crash", this, true);
|
||||||
|
|
||||||
// observe prefs changes so we can modify stored data to match
|
// this pref is only read at startup, so no need to observe it
|
||||||
this._prefBranch.addObserver("tabs.undoclose.depth", this, true);
|
this._sessionhistory_max_entries =
|
||||||
this._prefBranch.addObserver("sessionstore.max_tabs_undo", this, true);
|
this._prefBranch.getIntPref("sessionhistory.max_entries");
|
||||||
|
|
||||||
// get file references
|
// get file references
|
||||||
var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
|
var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||||
|
@ -211,6 +217,20 @@ SessionStoreService.prototype = {
|
||||||
let lastSessionCrashed =
|
let lastSessionCrashed =
|
||||||
this._initialState && this._initialState.session && this._initialState.session.state &&
|
this._initialState && this._initialState.session && this._initialState.session.state &&
|
||||||
this._initialState.session.state == STATE_RUNNING_STR;
|
this._initialState.session.state == STATE_RUNNING_STR;
|
||||||
|
// if last session crashed, backup the session
|
||||||
|
if (lastSessionCrashed) {
|
||||||
|
this._recentCrashes = (this._initialState.session &&
|
||||||
|
this._initialState.session.recentCrashes || 0) + 1;
|
||||||
|
|
||||||
|
if (this._needsRestorePage(this._initialState, this._recentCrashes)) {
|
||||||
|
// replace the crashed session with a restore-page-only session
|
||||||
|
let pageData = {
|
||||||
|
url: "about:sessionrestore",
|
||||||
|
formdata: { "#sessionData": iniString }
|
||||||
|
};
|
||||||
|
this._initialState = { windows: [{ tabs: [{ entries: [pageData] }] }] };
|
||||||
|
}
|
||||||
|
}
|
||||||
// make sure that at least the first window doesn't have anything hidden
|
// make sure that at least the first window doesn't have anything hidden
|
||||||
if (this._initialState.windows[0])
|
if (this._initialState.windows[0])
|
||||||
delete this._initialState.windows[0].hidden;
|
delete this._initialState.windows[0].hidden;
|
||||||
|
@ -324,18 +344,6 @@ SessionStoreService.prototype = {
|
||||||
break;
|
break;
|
||||||
case "nsPref:changed": // catch pref changes
|
case "nsPref:changed": // catch pref changes
|
||||||
switch (aData) {
|
switch (aData) {
|
||||||
// if the user decreases the max number of closed tabs they want
|
|
||||||
// preserved update our internal states to match that max
|
|
||||||
// misak: this shouldn't be needed, will remove in final patch
|
|
||||||
//case "tabs.undoclose.depth":
|
|
||||||
// var ix;
|
|
||||||
// for (ix in this._windows) {
|
|
||||||
// this._windows[ix]._closedTabs.splice(this._prefBranch.getIntPref("tabs.undoclose.depth"));
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
case "sessionstore.max_tabs_undo":
|
|
||||||
//todo: we need some way to syncronise sessionstore.max_tabs_undo and tabs.undoclose.depth
|
|
||||||
break;
|
|
||||||
case "sessionstore.interval":
|
case "sessionstore.interval":
|
||||||
this._interval = this._prefBranch.getIntPref("sessionstore.interval");
|
this._interval = this._prefBranch.getIntPref("sessionstore.interval");
|
||||||
// reset timer and save
|
// reset timer and save
|
||||||
|
@ -433,10 +441,6 @@ SessionStoreService.prototype = {
|
||||||
this._loadState = STATE_RUNNING;
|
this._loadState = STATE_RUNNING;
|
||||||
this._lastSaveTime = Date.now();
|
this._lastSaveTime = Date.now();
|
||||||
|
|
||||||
// don't save during the first ten seconds
|
|
||||||
// (until most of the pages have been restored)
|
|
||||||
this.saveStateDelayed(aWindow, 10000);
|
|
||||||
|
|
||||||
// restore a crashed session resp. resume the last session if requested
|
// restore a crashed session resp. resume the last session if requested
|
||||||
if (this._initialState) {
|
if (this._initialState) {
|
||||||
// make sure that the restored tabs are first in the window
|
// make sure that the restored tabs are first in the window
|
||||||
|
@ -444,14 +448,25 @@ SessionStoreService.prototype = {
|
||||||
this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0;
|
this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0;
|
||||||
this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow));
|
this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow));
|
||||||
delete this._initialState;
|
delete this._initialState;
|
||||||
|
|
||||||
|
// mark ourselves as running
|
||||||
|
this.saveState(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Nothing to restore, notify observers things are complete.
|
// Nothing to restore, notify observers things are complete.
|
||||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
observerService.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
|
observerService.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
|
||||||
|
|
||||||
|
// the next delayed save request should execute immediately
|
||||||
|
this._lastSaveTime -= this._interval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// this window was opened by _openWindowWithState
|
||||||
|
else if (!this._isWindowLoaded(aWindow)) {
|
||||||
|
let followUp = this._statesToRestore[aWindow.__SS_restoreID].windows.length == 1;
|
||||||
|
this.restoreWindow(aWindow, this._statesToRestore[aWindow.__SS_restoreID], true, followUp);
|
||||||
|
}
|
||||||
|
|
||||||
var tabbrowser = aWindow.getBrowser();
|
var tabbrowser = aWindow.getBrowser();
|
||||||
var tabpanels = tabbrowser.mPanelContainer;
|
var tabpanels = tabbrowser.mPanelContainer;
|
||||||
|
@ -474,6 +489,16 @@ SessionStoreService.prototype = {
|
||||||
* Window reference
|
* Window reference
|
||||||
*/
|
*/
|
||||||
onClose: function sss_onClose(aWindow) {
|
onClose: function sss_onClose(aWindow) {
|
||||||
|
// this window was about to be restored - conserve its original data, if any
|
||||||
|
let isFullyLoaded = this._isWindowLoaded(aWindow);
|
||||||
|
if (!isFullyLoaded) {
|
||||||
|
if (!aWindow.__SSi)
|
||||||
|
aWindow.__SSi = "window" + Date.now();
|
||||||
|
this._window[aWindow.__SSi] = this._statesToRestore[aWindow.__SS_restoreID];
|
||||||
|
delete this._statesToRestore[aWindow.__SS_restoreID];
|
||||||
|
delete aWindow.__SS_restoreID;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore windows not tracked by SessionStore
|
// ignore windows not tracked by SessionStore
|
||||||
if (!aWindow.__SSi || !this._windows[aWindow.__SSi]) {
|
if (!aWindow.__SSi || !this._windows[aWindow.__SSi]) {
|
||||||
return;
|
return;
|
||||||
|
@ -490,22 +515,23 @@ SessionStoreService.prototype = {
|
||||||
tabbrowser.removeEventListener("TabClose", this, true);
|
tabbrowser.removeEventListener("TabClose", this, true);
|
||||||
tabbrowser.removeEventListener("TabSelect", this, true);
|
tabbrowser.removeEventListener("TabSelect", this, true);
|
||||||
|
|
||||||
|
let winData = this._windows[aWindow.__SSi];
|
||||||
|
windata._closedTabs = tabbrowser.savedBrowsers.map(function(e) { return e.tabData; });
|
||||||
if (this._loadState == STATE_RUNNING) { // window not closed during a regular shut-down
|
if (this._loadState == STATE_RUNNING) { // window not closed during a regular shut-down
|
||||||
// update all window data for a last time
|
// update all window data for a last time
|
||||||
this._collectWindowData(aWindow);
|
this._collectWindowData(aWindow);
|
||||||
|
|
||||||
// preserve this window's data (in case it was the last navigator:browser)
|
// preserve this window's data (in case it was the last navigator:browser)
|
||||||
var winData = this._windows[aWindow.__SSi];
|
|
||||||
winData.title = aWindow.content.document.title;
|
|
||||||
winData._closedTabs = tabbrowser.savedBrowsers.map(function(e) { return e.tabData; });
|
|
||||||
|
|
||||||
// if this is a popup window, append it to what we've already got (cf. bug 368677)
|
// if this is a popup window, append it to what we've already got (cf. bug 368677)
|
||||||
if (!this._lastClosedWindows || !winData.isPopup)
|
if (!this._lastClosedWindows || !winData.isPopup)
|
||||||
this._lastClosedWindows = [winData];
|
this._lastClosedWindows = [winData];
|
||||||
else
|
else
|
||||||
this._lastClosedWindows.push(winData);
|
this._lastClosedWindows.push(winData);
|
||||||
|
|
||||||
this._updateCookies(this._lastClosedWindows);
|
if (isFullyLoaded) {
|
||||||
|
winData.title = aWindow.content.document.title;
|
||||||
|
this._updateCookies(this._lastClosedWindows);
|
||||||
|
}
|
||||||
|
|
||||||
// clear this window from the list
|
// clear this window from the list
|
||||||
delete this._windows[aWindow.__SSi];
|
delete this._windows[aWindow.__SSi];
|
||||||
|
@ -519,14 +545,7 @@ SessionStoreService.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache the window state until the window is completely gone
|
// cache the window state until the window is completely gone
|
||||||
aWindow.__SS_dyingCache = this._windows[aWindow.__SSi] || winData;
|
aWindow.__SS_dyingCache = winData;
|
||||||
|
|
||||||
// reset the _tab property to avoid keeping the tab's XUL element alive
|
|
||||||
// longer than we need it
|
|
||||||
var tabCount = aWindow.__SS_dyingCache.tabs.length;
|
|
||||||
for (var t = 0; t < tabCount; t++) {
|
|
||||||
delete aWindow.__SS_dyingCache.tabs[t]._tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete aWindow.__SSi;
|
delete aWindow.__SSi;
|
||||||
},
|
},
|
||||||
|
@ -591,7 +610,7 @@ SessionStoreService.prototype = {
|
||||||
event.initEvent("SSTabClosing", true, false);
|
event.initEvent("SSTabClosing", true, false);
|
||||||
aTab.dispatchEvent(event);
|
aTab.dispatchEvent(event);
|
||||||
|
|
||||||
var maxTabsUndo = this._prefBranch.getIntPref("tabs.undoclose.depth");
|
var maxTabsUndo = this._prefBranch.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||||
// don't update our internal state if we don't have to
|
// don't update our internal state if we don't have to
|
||||||
if (maxTabsUndo == 0) {
|
if (maxTabsUndo == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -601,10 +620,6 @@ SessionStoreService.prototype = {
|
||||||
var tabState = this._collectTabData(aTab);
|
var tabState = this._collectTabData(aTab);
|
||||||
this._updateTextAndScrollDataForTab(aWindow, aTab.linkedBrowser, tabState);
|
this._updateTextAndScrollDataForTab(aWindow, aTab.linkedBrowser, tabState);
|
||||||
|
|
||||||
// reset the _tab property to avoid keeping the tab's XUL element alive
|
|
||||||
// longer than we need it
|
|
||||||
delete tabState._tab;
|
|
||||||
|
|
||||||
// store closed-tab data for undo
|
// store closed-tab data for undo
|
||||||
if (tabState.entries.length > 0) {
|
if (tabState.entries.length > 0) {
|
||||||
let tabTitle = aTab.label;
|
let tabTitle = aTab.label;
|
||||||
|
@ -695,9 +710,16 @@ SessionStoreService.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setBrowserState: function sss_setBrowserState(aState) {
|
setBrowserState: function sss_setBrowserState(aState) {
|
||||||
|
try {
|
||||||
|
var state = this._safeEval("(" + aState + ")");
|
||||||
|
}
|
||||||
|
catch (ex) { /* invalid state object - don't restore anything */ }
|
||||||
|
if (!state || !state.windows)
|
||||||
|
throw (Components.returnCode = Components.results.NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
var window = this._getMostRecentBrowserWindow();
|
var window = this._getMostRecentBrowserWindow();
|
||||||
if (!window) {
|
if (!window) {
|
||||||
this._openWindowWithState("(" + aState + ")");
|
this._openWindowWithState(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,7 +731,7 @@ SessionStoreService.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// restore to the given state
|
// restore to the given state
|
||||||
this.restoreWindow(window, "(" + aState + ")", true);
|
this.restoreWindow(window, state, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
getWindowState: function sss_getWindowState(aWindow) {
|
getWindowState: function sss_getWindowState(aWindow) {
|
||||||
|
@ -745,10 +767,8 @@ SessionStoreService.prototype = {
|
||||||
if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi)
|
if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi)
|
||||||
throw (Components.returnCode = Components.results.NS_ERROR_INVALID_ARG);
|
throw (Components.returnCode = Components.results.NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
tabState._tab = aTab;
|
|
||||||
|
|
||||||
var window = aTab.ownerDocument.defaultView;
|
var window = aTab.ownerDocument.defaultView;
|
||||||
this.restoreHistoryPrecursor(window, [tabState], 0, 0, 0);
|
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
duplicateTab: function sss_duplicateTab(aWindow, aTab) {
|
duplicateTab: function sss_duplicateTab(aWindow, aTab) {
|
||||||
|
@ -761,14 +781,12 @@ SessionStoreService.prototype = {
|
||||||
this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true);
|
this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true);
|
||||||
|
|
||||||
var newTab = aWindow.getBrowser().addTab();
|
var newTab = aWindow.getBrowser().addTab();
|
||||||
tabState._tab = newTab;
|
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, 0, 0);
|
||||||
this.restoreHistoryPrecursor(aWindow, [tabState], 0, 0, 0);
|
|
||||||
|
|
||||||
return newTab;
|
return newTab;
|
||||||
},
|
},
|
||||||
|
|
||||||
getClosedTabCount: function sss_getClosedTabCount(aWindow) {
|
getClosedTabCount: function sss_getClosedTabCount(aWindow) {
|
||||||
//misak: 2 lines uncommented
|
|
||||||
if (!aWindow.__SSi && aWindow.__SS_dyingCache)
|
if (!aWindow.__SSi && aWindow.__SS_dyingCache)
|
||||||
return aWindow.__SS_dyingCache._closedTabs.length;
|
return aWindow.__SS_dyingCache._closedTabs.length;
|
||||||
|
|
||||||
|
@ -776,8 +794,8 @@ SessionStoreService.prototype = {
|
||||||
// XXXzeniko shouldn't we throw here?
|
// XXXzeniko shouldn't we throw here?
|
||||||
return 0; // not a browser window, or not otherwise tracked by SS.
|
return 0; // not a browser window, or not otherwise tracked by SS.
|
||||||
|
|
||||||
return aWindow.getBrowser().savedBrowsers.length;
|
let closedTabs = aWindow.getBrowser().savedBrowsers.map(function(e) { return e.tabData; });
|
||||||
//return this._windows[aWindow.__SSi]._closedTabs.length;
|
return closedTabs.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
getClosedTabData: function sss_getClosedTabDataAt(aWindow) {
|
getClosedTabData: function sss_getClosedTabDataAt(aWindow) {
|
||||||
|
@ -786,7 +804,8 @@ SessionStoreService.prototype = {
|
||||||
|
|
||||||
if (!aWindow.__SSi)
|
if (!aWindow.__SSi)
|
||||||
return this._toJSONString(aWindow.__SS_dyingCache._closedTabs);
|
return this._toJSONString(aWindow.__SS_dyingCache._closedTabs);
|
||||||
return this._toJSONString(aWindow.getBrowser().savedBrowsers.map(function(e) { return e.tabData; }))
|
let closedTabs = aWindow.getBrowser().savedBrowsers.map(function(e) { return e.tabData; });
|
||||||
|
return this._toJSONString(closedTabs);
|
||||||
},
|
},
|
||||||
|
|
||||||
undoCloseTab: function sss_undoCloseTab(aWindow, aIndex) {
|
undoCloseTab: function sss_undoCloseTab(aWindow, aIndex) {
|
||||||
|
@ -804,9 +823,9 @@ SessionStoreService.prototype = {
|
||||||
let browser = aWindow.gBrowser;
|
let browser = aWindow.gBrowser;
|
||||||
|
|
||||||
// Seamonkey has it's own undoclosetab functionality
|
// Seamonkey has it's own undoclosetab functionality
|
||||||
tab = browser.restoreTab(aIndex);
|
var newTab = browser.restoreTab(aIndex);
|
||||||
|
|
||||||
return tab;
|
return newTab;
|
||||||
},
|
},
|
||||||
|
|
||||||
getWindowValue: function sss_getWindowValue(aWindow, aKey) {
|
getWindowValue: function sss_getWindowValue(aWindow, aKey) {
|
||||||
|
@ -903,7 +922,7 @@ SessionStoreService.prototype = {
|
||||||
if (!browser || !browser.currentURI)
|
if (!browser || !browser.currentURI)
|
||||||
// can happen when calling this function right after .addTab()
|
// can happen when calling this function right after .addTab()
|
||||||
return tabData;
|
return tabData;
|
||||||
else if (browser.parentNode.__SS_data && browser.parentNode.__SS_data._tab)
|
else if (browser.parentNode.__SS_data && browser.parentNode.__SS_data._tabStillLoading)
|
||||||
// use the data to be restored when the tab hasn't been completely loaded
|
// use the data to be restored when the tab hasn't been completely loaded
|
||||||
return browser.parentNode.__SS_data;
|
return browser.parentNode.__SS_data;
|
||||||
|
|
||||||
|
@ -913,8 +932,11 @@ SessionStoreService.prototype = {
|
||||||
}
|
}
|
||||||
catch (ex) { } // this could happen if we catch a tab during (de)initialization
|
catch (ex) { } // this could happen if we catch a tab during (de)initialization
|
||||||
|
|
||||||
|
// XXXzeniko anchor navigation doesn't reset __SS_data, so we could reuse
|
||||||
|
// data even when we shouldn't (e.g. Back, different anchor)
|
||||||
if (history && browser.parentNode.__SS_data &&
|
if (history && browser.parentNode.__SS_data &&
|
||||||
browser.parentNode.__SS_data.entries[history.index] && !aFullData) {
|
browser.parentNode.__SS_data.entries[history.index] &&
|
||||||
|
history.index < this._sessionhistory_max_entries - 1 && !aFullData) {
|
||||||
tabData = browser.parentNode.__SS_data;
|
tabData = browser.parentNode.__SS_data;
|
||||||
tabData.index = history.index + 1;
|
tabData.index = history.index + 1;
|
||||||
}
|
}
|
||||||
|
@ -1141,7 +1163,8 @@ SessionStoreService.prototype = {
|
||||||
for (var i = 0; i < browsers.length; i++) {
|
for (var i = 0; i < browsers.length; i++) {
|
||||||
try {
|
try {
|
||||||
var tabData = this._windows[aWindow.__SSi].tabs[i];
|
var tabData = this._windows[aWindow.__SSi].tabs[i];
|
||||||
if (browsers[i].parentNode.__SS_data && browsers[i].parentNode.__SS_data._tab)
|
if (browsers[i].parentNode.__SS_data &&
|
||||||
|
browsers[i].parentNode.__SS_data._tabStillLoading)
|
||||||
continue; // ignore incompletely initialized tabs
|
continue; // ignore incompletely initialized tabs
|
||||||
this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData);
|
this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData);
|
||||||
}
|
}
|
||||||
|
@ -1209,7 +1232,8 @@ SessionStoreService.prototype = {
|
||||||
}
|
}
|
||||||
var isHTTPS = this._getURIFromString((aContent.parent || aContent).
|
var isHTTPS = this._getURIFromString((aContent.parent || aContent).
|
||||||
document.location.href).schemeIs("https");
|
document.location.href).schemeIs("https");
|
||||||
if (aFullData || this._checkPrivacyLevel(isHTTPS)) {
|
if (aFullData || this._checkPrivacyLevel(isHTTPS) ||
|
||||||
|
aContent.top.document.location.href == "about:sessionrestore") {
|
||||||
if (aFullData || aUpdateFormData) {
|
if (aFullData || aUpdateFormData) {
|
||||||
let formData = this._collectFormDataForFrame(aContent.document);
|
let formData = this._collectFormDataForFrame(aContent.document);
|
||||||
if (formData)
|
if (formData)
|
||||||
|
@ -1271,8 +1295,12 @@ SessionStoreService.prototype = {
|
||||||
let data = {};
|
let data = {};
|
||||||
do {
|
do {
|
||||||
let id = node.id ? "#" + node.id : XPathHelper.generate(node);
|
let id = node.id ? "#" + node.id : XPathHelper.generate(node);
|
||||||
if (node instanceof Components.interfaces.nsIDOMHTMLInputElement)
|
if (node instanceof Components.interfaces.nsIDOMHTMLInputElement) {
|
||||||
data[id] = node.type == "checkbox" || node.type == "radio" ? node.checked : node.value;
|
if (node.type != "file")
|
||||||
|
data[id] = node.type == "checkbox" || node.type == "radio" ? node.checked : node.value;
|
||||||
|
else
|
||||||
|
data[id] = { type: "file", value: node.value };
|
||||||
|
}
|
||||||
else if (node instanceof Components.interfaces.nsIDOMHTMLTextAreaElement)
|
else if (node instanceof Components.interfaces.nsIDOMHTMLTextAreaElement)
|
||||||
data[id] = node.value;
|
data[id] = node.value;
|
||||||
else if (!node.multiple)
|
else if (!node.multiple)
|
||||||
|
@ -1398,6 +1426,8 @@ SessionStoreService.prototype = {
|
||||||
if (this._loadState == STATE_RUNNING) {
|
if (this._loadState == STATE_RUNNING) {
|
||||||
// update the data for all windows with activities since the last save operation
|
// update the data for all windows with activities since the last save operation
|
||||||
this._forEachBrowserWindow(function(aWindow) {
|
this._forEachBrowserWindow(function(aWindow) {
|
||||||
|
if (!this._isWindowLoaded(aWindow)) // window data is still in _statesToRestore
|
||||||
|
return;
|
||||||
if (aUpdateAll || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
|
if (aUpdateAll || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
|
||||||
this._collectWindowData(aWindow);
|
this._collectWindowData(aWindow);
|
||||||
}
|
}
|
||||||
|
@ -1419,6 +1449,16 @@ SessionStoreService.prototype = {
|
||||||
nonPopupCount++;
|
nonPopupCount++;
|
||||||
}
|
}
|
||||||
this._updateCookies(total);
|
this._updateCookies(total);
|
||||||
|
|
||||||
|
// collect the data for all windows yet to be restored
|
||||||
|
for (ix in this._statesToRestore) {
|
||||||
|
for each (let winData in this._statesToRestore[ix].windows) {
|
||||||
|
total.push(winData);
|
||||||
|
if (!winData.isPopup)
|
||||||
|
nonPopupCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if no non-popup browser window remains open, return the state of the last closed window(s)
|
// if no non-popup browser window remains open, return the state of the last closed window(s)
|
||||||
if (nonPopupCount == 0 && this._lastClosedWindows) {
|
if (nonPopupCount == 0 && this._lastClosedWindows) {
|
||||||
// prepend the last non-popup browser window, so that if the user loads more tabs
|
// prepend the last non-popup browser window, so that if the user loads more tabs
|
||||||
|
@ -1439,6 +1479,9 @@ SessionStoreService.prototype = {
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
_getWindowState: function sss_getWindowState(aWindow) {
|
_getWindowState: function sss_getWindowState(aWindow) {
|
||||||
|
if (!this._isWindowLoaded(aWindow))
|
||||||
|
return this._statesToRestore[aWindow.__SS_restoreID];
|
||||||
|
|
||||||
if (this._loadState == STATE_RUNNING) {
|
if (this._loadState == STATE_RUNNING) {
|
||||||
this._collectWindowData(aWindow);
|
this._collectWindowData(aWindow);
|
||||||
}
|
}
|
||||||
|
@ -1451,6 +1494,9 @@ SessionStoreService.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_collectWindowData: function sss_collectWindowData(aWindow) {
|
_collectWindowData: function sss_collectWindowData(aWindow) {
|
||||||
|
if (!this._isWindowLoaded(aWindow))
|
||||||
|
return;
|
||||||
|
|
||||||
// update the internal state data for this window
|
// update the internal state data for this window
|
||||||
this._saveWindowHistory(aWindow);
|
this._saveWindowHistory(aWindow);
|
||||||
this._updateTextAndScrollData(aWindow);
|
this._updateTextAndScrollData(aWindow);
|
||||||
|
@ -1525,12 +1571,13 @@ SessionStoreService.prototype = {
|
||||||
var tabbrowser = aWindow.getBrowser();
|
var tabbrowser = aWindow.getBrowser();
|
||||||
var openTabCount = aOverwriteTabs ? tabbrowser.browsers.length : -1;
|
var openTabCount = aOverwriteTabs ? tabbrowser.browsers.length : -1;
|
||||||
var newTabCount = winData.tabs.length;
|
var newTabCount = winData.tabs.length;
|
||||||
|
let tabs = [];
|
||||||
|
|
||||||
for (var t = 0; t < newTabCount; t++) {
|
for (var t = 0; t < newTabCount; t++) {
|
||||||
winData.tabs[t]._tab = t < openTabCount ? tabbrowser.mTabs[t] : tabbrowser.addTab();
|
tabs.push(t < openTabCount ? tabbrowser.mTabs[t] : tabbrowser.addTab());
|
||||||
// when resuming at startup: add additionally requested pages to the end
|
// when resuming at startup: add additionally requested pages to the end
|
||||||
if (!aOverwriteTabs && root._firstTabs) {
|
if (!aOverwriteTabs && root._firstTabs) {
|
||||||
tabbrowser.moveTabTo(winData.tabs[t]._tab, t);
|
tabbrowser.moveTabTo(tabs[t], t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,8 +1593,8 @@ SessionStoreService.prototype = {
|
||||||
this.restoreCookies(winData.cookies);
|
this.restoreCookies(winData.cookies);
|
||||||
}
|
}
|
||||||
if (winData.extData) {
|
if (winData.extData) {
|
||||||
if (!this._windows[aWindow.__SSi].extData) {
|
if (aOverwriteTabs || !this._windows[aWindow.__SSi].extData) {
|
||||||
this._windows[aWindow.__SSi].extData = {}
|
this._windows[aWindow.__SSi].extData = {};
|
||||||
}
|
}
|
||||||
for (var key in winData.extData) {
|
for (var key in winData.extData) {
|
||||||
this._windows[aWindow.__SSi].extData[key] = winData.extData[key];
|
this._windows[aWindow.__SSi].extData[key] = winData.extData[key];
|
||||||
|
@ -1569,18 +1616,20 @@ SessionStoreService.prototype = {
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
this.restoreHistoryPrecursor(aWindow, winData.tabs, (aOverwriteTabs ?
|
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
|
||||||
(parseInt(winData.selected) || 1) : 0), 0, 0);
|
(aOverwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0);
|
||||||
|
|
||||||
this._notifyIfAllWindowsRestored();
|
this._notifyIfAllWindowsRestored();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage history restoration for a window
|
* Manage history restoration for a window
|
||||||
|
* @param aWindow
|
||||||
|
* Window to restore the tabs into
|
||||||
* @param aTabs
|
* @param aTabs
|
||||||
* Array of tab data
|
|
||||||
* @param aCurrentTabs
|
|
||||||
* Array of tab references
|
* Array of tab references
|
||||||
|
* @param aTabData
|
||||||
|
* Array of tab data
|
||||||
* @param aSelectTab
|
* @param aSelectTab
|
||||||
* Index of selected tab
|
* Index of selected tab
|
||||||
* @param aIx
|
* @param aIx
|
||||||
|
@ -1588,21 +1637,22 @@ SessionStoreService.prototype = {
|
||||||
* @param aCount
|
* @param aCount
|
||||||
* Counter for number of times delaying b/c browser or history aren't ready
|
* Counter for number of times delaying b/c browser or history aren't ready
|
||||||
*/
|
*/
|
||||||
restoreHistoryPrecursor: function sss_restoreHistoryPrecursor(aWindow, aTabs, aSelectTab, aIx, aCount) {
|
restoreHistoryPrecursor:
|
||||||
|
function sss_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount) {
|
||||||
var tabbrowser = aWindow.getBrowser();
|
var tabbrowser = aWindow.getBrowser();
|
||||||
|
|
||||||
// make sure that all browsers and their histories are available
|
// make sure that all browsers and their histories are available
|
||||||
// - if one's not, resume this check in 100ms (repeat at most 10 times)
|
// - if one's not, resume this check in 100ms (repeat at most 10 times)
|
||||||
for (var t = aIx; t < aTabs.length; t++) {
|
for (var t = aIx; t < aTabs.length; t++) {
|
||||||
try {
|
try {
|
||||||
if (!tabbrowser.getBrowserForTab(aTabs[t]._tab).webNavigation.sessionHistory) {
|
if (!tabbrowser.getBrowserForTab(aTabs[t]).webNavigation.sessionHistory) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ex) { // in case browser or history aren't ready yet
|
catch (ex) { // in case browser or history aren't ready yet
|
||||||
if (aCount < 10) {
|
if (aCount < 10) {
|
||||||
var restoreHistoryFunc = function(self) {
|
var restoreHistoryFunc = function(self) {
|
||||||
self.restoreHistoryPrecursor(aWindow, aTabs, aSelectTab, aIx, aCount + 1);
|
self.restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount + 1);
|
||||||
}
|
}
|
||||||
aWindow.setTimeout(restoreHistoryFunc, 100, this);
|
aWindow.setTimeout(restoreHistoryFunc, 100, this);
|
||||||
return;
|
return;
|
||||||
|
@ -1612,10 +1662,11 @@ SessionStoreService.prototype = {
|
||||||
|
|
||||||
// mark the tabs as loading
|
// mark the tabs as loading
|
||||||
for (t = 0; t < aTabs.length; t++) {
|
for (t = 0; t < aTabs.length; t++) {
|
||||||
var tab = aTabs[t]._tab;
|
var tab = aTabs[t];
|
||||||
var browser = tabbrowser.getBrowserForTab(tab);
|
var browser = tabbrowser.getBrowserForTab(tab);
|
||||||
|
|
||||||
if (!aTabs[t].entries || aTabs[t].entries.length == 0) {
|
aTabData[t]._tabStillLoading = true;
|
||||||
|
if (!aTabData[t].entries || aTabData[t].entries.length == 0) {
|
||||||
// make sure to blank out this tab's content
|
// make sure to blank out this tab's content
|
||||||
// (just purging the tab's history won't be enough)
|
// (just purging the tab's history won't be enough)
|
||||||
browser.contentDocument.location = "about:blank";
|
browser.contentDocument.location = "about:blank";
|
||||||
|
@ -1632,24 +1683,31 @@ SessionStoreService.prototype = {
|
||||||
|
|
||||||
// wall-paper fix for bug 439675: make sure that the URL to be loaded
|
// wall-paper fix for bug 439675: make sure that the URL to be loaded
|
||||||
// is always visible in the address bar
|
// is always visible in the address bar
|
||||||
let activeIndex = (aTabs[t].index || aTabs[t].entries.length) - 1;
|
let activeIndex = (aTabData[t].index || aTabData[t].entries.length) - 1;
|
||||||
let activePageData = aTabs[t].entries[activeIndex] || null;
|
let activePageData = aTabData[t].entries[activeIndex] || null;
|
||||||
browser.userTypedValue = activePageData ? activePageData.url || null : null;
|
browser.userTypedValue = activePageData ? activePageData.url || null : null;
|
||||||
|
|
||||||
// keep the data around to prevent dataloss in case
|
// keep the data around to prevent dataloss in case
|
||||||
// a tab gets closed before it's been properly restored
|
// a tab gets closed before it's been properly restored
|
||||||
browser.parentNode.__SS_data = aTabs[t];
|
browser.parentNode.__SS_data = aTabData[t];
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure to restore the selected tab first (if any)
|
// make sure to restore the selected tab first (if any)
|
||||||
if (aSelectTab-- && aTabs[aSelectTab]) {
|
if (aSelectTab-- && aTabs[aSelectTab]) {
|
||||||
aTabs.unshift(aTabs.splice(aSelectTab, 1)[0]);
|
aTabs.unshift(aTabs.splice(aSelectTab, 1)[0]);
|
||||||
tabbrowser.selectedTab = aTabs[0]._tab;
|
aTabData.unshift(aTabData.splice(aSelectTab, 1)[0]);
|
||||||
|
tabbrowser.selectedTab = aTabs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._isWindowLoaded(aWindow)) {
|
||||||
|
// from now on, the data will come from the actual window
|
||||||
|
delete this._statesToRestore[aWindow.__SS_restoreID];
|
||||||
|
delete aWindow.__SS_restoreID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper hash for ensuring unique frame IDs
|
// helper hash for ensuring unique frame IDs
|
||||||
var idMap = { used: {} };
|
var idMap = { used: {} };
|
||||||
this.restoreHistory(aWindow, aTabs, idMap);
|
this.restoreHistory(aWindow, aTabs, aTabData, idMap);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1657,22 +1715,25 @@ SessionStoreService.prototype = {
|
||||||
* @param aWindow
|
* @param aWindow
|
||||||
* Window reference
|
* Window reference
|
||||||
* @param aTabs
|
* @param aTabs
|
||||||
|
* Array of tab references
|
||||||
|
* @param aTabData
|
||||||
* Array of tab data
|
* Array of tab data
|
||||||
* @param aIdMap
|
* @param aIdMap
|
||||||
* Hash for ensuring unique frame IDs
|
* Hash for ensuring unique frame IDs
|
||||||
*/
|
*/
|
||||||
restoreHistory: function sss_restoreHistory(aWindow, aTabs, aIdMap) {
|
restoreHistory: function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
while (aTabs.length > 0 && (!aTabs[0]._tab || !aTabs[0]._tab.parentNode)) {
|
while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
|
||||||
aTabs.shift(); // this tab got removed before being completely restored
|
aTabs.shift(); // this tab got removed before being completely restored
|
||||||
|
aTabData.shift();
|
||||||
}
|
}
|
||||||
if (aTabs.length == 0) {
|
if (aTabs.length == 0) {
|
||||||
return; // no more tabs to restore
|
return; // no more tabs to restore
|
||||||
}
|
}
|
||||||
|
|
||||||
var tabData = aTabs.shift();
|
var tab = aTabs.shift();
|
||||||
|
var tabData = aTabData.shift();
|
||||||
|
|
||||||
var tab = tabData._tab;
|
|
||||||
var browser = aWindow.getBrowser().getBrowserForTab(tab);
|
var browser = aWindow.getBrowser().getBrowserForTab(tab);
|
||||||
var history = browser.webNavigation.sessionHistory;
|
var history = browser.webNavigation.sessionHistory;
|
||||||
|
|
||||||
|
@ -1685,8 +1746,12 @@ SessionStoreService.prototype = {
|
||||||
tabData.entries = [];
|
tabData.entries = [];
|
||||||
}
|
}
|
||||||
if (tabData.extData) {
|
if (tabData.extData) {
|
||||||
tab.__SS_extdata = tabData.extData;
|
tab.__SS_extdata = {};
|
||||||
|
for (let key in tabData.extData)
|
||||||
|
tab.__SS_extdata[key] = tabData.extData[key];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
delete tab.__SS_extdata;
|
||||||
|
|
||||||
for (var i = 0; i < tabData.entries.length; i++) {
|
for (var i = 0; i < tabData.entries.length; i++) {
|
||||||
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], aIdMap), true);
|
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], aIdMap), true);
|
||||||
|
@ -1743,7 +1808,7 @@ SessionStoreService.prototype = {
|
||||||
browser.addEventListener("load", browser.__SS_restore, true);
|
browser.addEventListener("load", browser.__SS_restore, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aIdMap); }, 0);
|
aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap); }, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1842,7 +1907,7 @@ SessionStoreService.prototype = {
|
||||||
* A tab's docshell (containing the sessionStorage)
|
* A tab's docshell (containing the sessionStorage)
|
||||||
*/
|
*/
|
||||||
_deserializeSessionStorage: function sss_deserializeSessionStorage(aStorageData, aDocShell) {
|
_deserializeSessionStorage: function sss_deserializeSessionStorage(aStorageData, aDocShell) {
|
||||||
let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
|
let ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
|
||||||
for (let url in aStorageData) {
|
for (let url in aStorageData) {
|
||||||
let uri = ioService.newURI(url, null, null);
|
let uri = ioService.newURI(url, null, null);
|
||||||
let storage = aDocShell.getSessionStorageForURI(uri);
|
let storage = aDocShell.getSessionStorageForURI(uri);
|
||||||
|
@ -1878,7 +1943,7 @@ SessionStoreService.prototype = {
|
||||||
RegExp.$1 == aPrefix && hasExpectedURL(aContent.document, aURL)) {
|
RegExp.$1 == aPrefix && hasExpectedURL(aContent.document, aURL)) {
|
||||||
var document = aContent.document;
|
var document = aContent.document;
|
||||||
var node = RegExp.$2 ? document.getElementById(RegExp.$3) : document.getElementsByName(RegExp.$3)[0] || null;
|
var node = RegExp.$2 ? document.getElementById(RegExp.$3) : document.getElementsByName(RegExp.$3)[0] || null;
|
||||||
if (node && "value" in node) {
|
if (node && "value" in node && node.type != "file") {
|
||||||
node.value = decodeURI(RegExp.$4);
|
node.value = decodeURI(RegExp.$4);
|
||||||
|
|
||||||
var event = document.createEvent("UIEvents");
|
var event = document.createEvent("UIEvents");
|
||||||
|
@ -1900,7 +1965,10 @@ SessionStoreService.prototype = {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let value = aData[key];
|
let value = aData[key];
|
||||||
if (typeof value == "string") {
|
if (typeof value == "string" && node.type != "file") {
|
||||||
|
if (node.value == value)
|
||||||
|
continue; // don't dispatch an input event for no change
|
||||||
|
|
||||||
node.value = value;
|
node.value = value;
|
||||||
|
|
||||||
let event = aDocument.createEvent("UIEvents");
|
let event = aDocument.createEvent("UIEvents");
|
||||||
|
@ -1913,6 +1981,8 @@ SessionStoreService.prototype = {
|
||||||
try {
|
try {
|
||||||
node.selectedIndex = value;
|
node.selectedIndex = value;
|
||||||
} catch (ex) { /* throws for invalid indices */ }
|
} catch (ex) { /* throws for invalid indices */ }
|
||||||
|
else if (value && value.type && value.type == node.type)
|
||||||
|
node.value = value.value;
|
||||||
else if (value && typeof value.indexOf == "function" && node.options) {
|
else if (value && typeof value.indexOf == "function" && node.options) {
|
||||||
Array.forEach(node.options, function(aOpt, aIx) {
|
Array.forEach(node.options, function(aOpt, aIx) {
|
||||||
aOpt.selected = value.indexOf(aIx) > -1;
|
aOpt.selected = value.indexOf(aIx) > -1;
|
||||||
|
@ -2031,11 +2101,20 @@ SessionStoreService.prototype = {
|
||||||
if (!isNaN(aLeft) && !isNaN(aTop) && (aLeft != win_("screenX") || aTop != win_("screenY"))) {
|
if (!isNaN(aLeft) && !isNaN(aTop) && (aLeft != win_("screenX") || aTop != win_("screenY"))) {
|
||||||
aWindow.moveTo(aLeft, aTop);
|
aWindow.moveTo(aLeft, aTop);
|
||||||
}
|
}
|
||||||
if (aSizeMode == "maximized" && win_("sizemode") != "maximized") {
|
switch (aSizeMode)
|
||||||
aWindow.maximize();
|
{
|
||||||
}
|
case "maximized":
|
||||||
else if (aSizeMode && aSizeMode != "maximized" && win_("sizemode") != "normal") {
|
if (win_("sizemode") != "maximized")
|
||||||
aWindow.restore();
|
aWindow.maximize();
|
||||||
|
break
|
||||||
|
case "minimized":
|
||||||
|
if (win_("sizemode") != "minimized")
|
||||||
|
aWindow.minimize();
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (win_("sizemode") != "normal")
|
||||||
|
aWindow.restore();
|
||||||
|
break
|
||||||
}
|
}
|
||||||
var sidebar = aWindow.document.getElementById("sidebar-box");
|
var sidebar = aWindow.document.getElementById("sidebar-box");
|
||||||
if (sidebar.getAttribute("sidebarcommand") != aSidebar) {
|
if (sidebar.getAttribute("sidebarcommand") != aSidebar) {
|
||||||
|
@ -2044,7 +2123,7 @@ SessionStoreService.prototype = {
|
||||||
// since resizing/moving a window brings it to the foreground,
|
// since resizing/moving a window brings it to the foreground,
|
||||||
// we might want to re-focus the last focused window
|
// we might want to re-focus the last focused window
|
||||||
if (this.windowToFocus) {
|
if (this.windowToFocus) {
|
||||||
this.windowToFocus.focus();
|
this.windowToFocus.content.focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2124,11 +2203,24 @@ SessionStoreService.prototype = {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var oState = this._getCurrentState(aUpdateAll);
|
var oState = this._getCurrentState(aUpdateAll);
|
||||||
oState.session = { state: ((this._loadState == STATE_RUNNING) ? STATE_RUNNING_STR : STATE_STOPPED_STR) };
|
oState.session = {
|
||||||
|
state: this._loadState == STATE_RUNNING ? STATE_RUNNING_STR : STATE_STOPPED_STR,
|
||||||
|
lastUpdate: Date.now()
|
||||||
|
};
|
||||||
|
if (this._recentCrashes)
|
||||||
|
oState.session.recentCrashes = this._recentCrashes;
|
||||||
|
|
||||||
|
this._saveStateObject(oState);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write a state object to disk
|
||||||
|
*/
|
||||||
|
_saveStateObject: function sss_saveStateObject(aStateObj) {
|
||||||
var stateString = Components.classes["@mozilla.org/supports-string;1"]
|
var stateString = Components.classes["@mozilla.org/supports-string;1"]
|
||||||
.createInstance(Components.interfaces.nsISupportsString);
|
.createInstance(Components.interfaces.nsISupportsString);
|
||||||
stateString.data = oState.toSource();
|
// parentheses are for backwards compatibility with older sessionstore files
|
||||||
|
stateString.data = "(" + this._toJSONString(aStateObj) + ")";
|
||||||
|
|
||||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
|
@ -2207,13 +2299,10 @@ SessionStoreService.prototype = {
|
||||||
.openWindow(null, this._prefBranch.getCharPref("chromeURL"), "_blank",
|
.openWindow(null, this._prefBranch.getCharPref("chromeURL"), "_blank",
|
||||||
"chrome,dialog=no,all", argString);
|
"chrome,dialog=no,all", argString);
|
||||||
|
|
||||||
window.__SS_state = aState;
|
do {
|
||||||
var _this = this;
|
var ID = "window" + Math.random();
|
||||||
window.addEventListener("load", function(aEvent) {
|
} while (ID in this._statesToRestore);
|
||||||
aEvent.currentTarget.removeEventListener("load", arguments.callee, true);
|
this._statesToRestore[(window.__SS_restoreID = ID)] = aState;
|
||||||
_this.restoreWindow(aEvent.currentTarget, aEvent.currentTarget.__SS_state, true, true);
|
|
||||||
delete aEvent.currentTarget.__SS_state;
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
},
|
},
|
||||||
|
@ -2342,6 +2431,37 @@ SessionStoreService.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aState is a session state
|
||||||
|
* @param aRecentCrashes is the number of consecutive crashes
|
||||||
|
* @returns whether a restore page will be needed for the session state
|
||||||
|
*/
|
||||||
|
_needsRestorePage: function sss_needsRestorePage(aState, aRecentCrashes) {
|
||||||
|
const SIX_HOURS_IN_MS = 6 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// don't wrap a single about:sessionrestore page
|
||||||
|
let winData = aState.windows || null;
|
||||||
|
if (winData && winData.length == 1 && winData[0].tabs &&
|
||||||
|
winData[0].tabs.length == 1 && winData[0].tabs[0].entries &&
|
||||||
|
winData[0].tabs[0].entries.length == 1 &&
|
||||||
|
winData[0].tabs[0].entries[0].url == "about:sessionrestore")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// don't automatically restore in Safe Mode
|
||||||
|
let XRE = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime);
|
||||||
|
if (XRE.inSafeMode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
let max_resumed_crashes =
|
||||||
|
this._prefBranch.getIntPref("sessionstore.max_resumed_crashes");
|
||||||
|
let sessionAge = aState.session && aState.session.lastUpdate &&
|
||||||
|
(Date.now() - aState.session.lastUpdate);
|
||||||
|
|
||||||
|
return max_resumed_crashes != -1 &&
|
||||||
|
(aRecentCrashes > max_resumed_crashes ||
|
||||||
|
sessionAge && sessionAge >= SIX_HOURS_IN_MS);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* safe eval'ing
|
* safe eval'ing
|
||||||
*/
|
*/
|
||||||
|
@ -2353,20 +2473,15 @@ SessionStoreService.prototype = {
|
||||||
* Converts a JavaScript object into a JSON string
|
* Converts a JavaScript object into a JSON string
|
||||||
* (see http://www.json.org/ for more information).
|
* (see http://www.json.org/ for more information).
|
||||||
*
|
*
|
||||||
* The inverse operation consists of eval("(" + JSON_string + ")");
|
* The inverse operation consists of JSON.parse(JSON_string).
|
||||||
* and should be provably safe.
|
|
||||||
*
|
*
|
||||||
* @param aJSObject is the object to be converted
|
* @param aJSObject is the object to be converted
|
||||||
* @return the object's JSON representation
|
* @returns the object's JSON representation
|
||||||
*/
|
*/
|
||||||
_toJSONString: function sss_toJSONString(aJSObject) {
|
_toJSONString: function sss_toJSONString(aJSObject) {
|
||||||
let str = JSONModule.toString(aJSObject, ["_tab", "_hosts", "_formDataSaved"] /* keys to drop */);
|
// XXXzeniko drop the following keys used only for internal bookkeeping:
|
||||||
|
// _tabStillLoading, _hosts, _formDataSaved
|
||||||
// sanity check - so that API consumers can just eval this string
|
return JSON.stringify(aJSObject);
|
||||||
if (!JSONModule.isMostlyHarmless(str))
|
|
||||||
throw new Error("JSON conversion failed unexpectedly!");
|
|
||||||
|
|
||||||
return str;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifyIfAllWindowsRestored: function sss_notifyIfAllWindowsRestored() {
|
_notifyIfAllWindowsRestored: function sss_notifyIfAllWindowsRestored() {
|
||||||
|
@ -2381,6 +2496,16 @@ SessionStoreService.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param aWindow
|
||||||
|
* Window reference
|
||||||
|
* @returns whether this window's data is still cached in _statesToRestore
|
||||||
|
* because it's not fully loaded yet
|
||||||
|
*/
|
||||||
|
_isWindowLoaded: function sss_isWindowLoaded(aWindow) {
|
||||||
|
return !aWindow.__SS_restoreID;
|
||||||
|
},
|
||||||
|
|
||||||
/* ........ Storage API .............. */
|
/* ........ Storage API .............. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -242,6 +242,7 @@ bin/components/libzipwriter.so
|
||||||
bin/components/nsSessionStartup.js
|
bin/components/nsSessionStartup.js
|
||||||
bin/components/nsSessionStore.js
|
bin/components/nsSessionStore.js
|
||||||
bin/components/sessionstore.xpt
|
bin/components/sessionstore.xpt
|
||||||
|
bin/components/aboutSessionRestore.js
|
||||||
|
|
||||||
; JavaScript components
|
; JavaScript components
|
||||||
bin/components/FeedProcessor.js
|
bin/components/FeedProcessor.js
|
||||||
|
|
|
@ -246,6 +246,7 @@ bin\sqlite3.dll
|
||||||
bin\components\nsSessionStartup.js
|
bin\components\nsSessionStartup.js
|
||||||
bin\components\nsSessionStore.js
|
bin\components\nsSessionStore.js
|
||||||
bin\components\sessionstore.xpt
|
bin\components\sessionstore.xpt
|
||||||
|
bin\components\aboutSessionRestore.js
|
||||||
|
|
||||||
; JavaScript components
|
; JavaScript components
|
||||||
bin\components\FeedProcessor.js
|
bin\components\FeedProcessor.js
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!ENTITY restorepage.tabtitle "Restore Session">
|
||||||
|
<!ENTITY restorepage.pagetitle "Would you like to restore your session?">
|
||||||
|
<!-- LOCALIZATION NOTE: If "closed unexpectedly" sounds too awkward in the translation,
|
||||||
|
you may translate "crash" instead (even though it's IT-speak) -->
|
||||||
|
<!ENTITY restorepage.issueDesc "Your previous &brandShortName; session closed unexpectedly. We sincerely apologize for the inconvenience. You can restore the tabs and windows from your previous session, or start a new session if they are no longer needed.">
|
||||||
|
<!ENTITY restorepage.remedies "If &brandShortName; closes repeatedly:">
|
||||||
|
<!ENTITY restorepage.dueToChrome "Try disabling any recently added extensions in the Add-ons Manager.">
|
||||||
|
<!ENTITY restorepage.dueToContent "Try restoring your session without any Web pages you suspect might be causing the problem:">
|
||||||
|
|
||||||
|
<!ENTITY restorepage.restoreButton "Restore Previous Session">
|
||||||
|
<!ENTITY restorepage.restore.access "R">
|
||||||
|
<!ENTITY restorepage.cancelButton "Start New Session">
|
||||||
|
<!ENTITY restorepage.cancel.access "S">
|
||||||
|
|
||||||
|
<!ENTITY restorepage.restoreHeader "Restore">
|
||||||
|
<!ENTITY restorepage.listHeader "Windows and Tabs">
|
||||||
|
<!-- LOCALIZATION NOTE: %S will be replaced with a number. -->
|
||||||
|
<!ENTITY restorepage.windowLabel "Window %S">
|
|
@ -1,7 +0,0 @@
|
||||||
restoredTitle= %S - Restore Previous Session
|
|
||||||
restoredMsg=Your last %S session closed unexpectedly. You can restore the tabs and windows from your previous session, or start a new session if you think the problem was related to a page you were viewing.
|
|
||||||
|
|
||||||
# Localization note: It is recommended that okTitle be longer than cancelTitle
|
|
||||||
# so that hitting the more prominent button doesn't lead to dataloss (see bug 346264).
|
|
||||||
okTitle=Restore Previous Session
|
|
||||||
cancelTitle=Start New Session
|
|
|
@ -29,7 +29,6 @@
|
||||||
locale/@AB_CD@/communicator/openLocation.properties (%chrome/common/openLocation.properties)
|
locale/@AB_CD@/communicator/openLocation.properties (%chrome/common/openLocation.properties)
|
||||||
locale/@AB_CD@/communicator/passwordManager.dtd (%chrome/common/passwordManager.dtd)
|
locale/@AB_CD@/communicator/passwordManager.dtd (%chrome/common/passwordManager.dtd)
|
||||||
locale/@AB_CD@/communicator/printPreview.dtd (%chrome/common/printPreview.dtd)
|
locale/@AB_CD@/communicator/printPreview.dtd (%chrome/common/printPreview.dtd)
|
||||||
locale/@AB_CD@/communicator/sessionstore.properties (%chrome/common/sessionstore.properties)
|
|
||||||
locale/@AB_CD@/communicator/shellservice.properties (%chrome/common/shellservice.properties)
|
locale/@AB_CD@/communicator/shellservice.properties (%chrome/common/shellservice.properties)
|
||||||
locale/@AB_CD@/communicator/sanitize.dtd (%chrome/common/sanitize.dtd)
|
locale/@AB_CD@/communicator/sanitize.dtd (%chrome/common/sanitize.dtd)
|
||||||
locale/@AB_CD@/communicator/tasksOverlay.dtd (%chrome/common/tasksOverlay.dtd)
|
locale/@AB_CD@/communicator/tasksOverlay.dtd (%chrome/common/tasksOverlay.dtd)
|
||||||
|
@ -38,6 +37,7 @@
|
||||||
locale/@AB_CD@/communicator/utilityOverlay.properties (%chrome/common/utilityOverlay.properties)
|
locale/@AB_CD@/communicator/utilityOverlay.properties (%chrome/common/utilityOverlay.properties)
|
||||||
locale/@AB_CD@/communicator/viewZoomOverlay.dtd (%chrome/common/viewZoomOverlay.dtd)
|
locale/@AB_CD@/communicator/viewZoomOverlay.dtd (%chrome/common/viewZoomOverlay.dtd)
|
||||||
locale/@AB_CD@/communicator/viewZoomOverlay.properties (%chrome/common/viewZoomOverlay.properties)
|
locale/@AB_CD@/communicator/viewZoomOverlay.properties (%chrome/common/viewZoomOverlay.properties)
|
||||||
|
locale/@AB_CD@/communicator/aboutSessionRestore.dtd (%chrome/common/aboutSessionRestore.dtd)
|
||||||
locale/@AB_CD@/communicator/bookmarks/addBookmark.dtd (%chrome/common/bookmarks/addBookmark.dtd)
|
locale/@AB_CD@/communicator/bookmarks/addBookmark.dtd (%chrome/common/bookmarks/addBookmark.dtd)
|
||||||
locale/@AB_CD@/communicator/bookmarks/bm-props.dtd (%chrome/common/bookmarks/bm-props.dtd)
|
locale/@AB_CD@/communicator/bookmarks/bm-props.dtd (%chrome/common/bookmarks/bm-props.dtd)
|
||||||
locale/@AB_CD@/communicator/bookmarks/bookmarks.dtd (%chrome/common/bookmarks/bookmarks.dtd)
|
locale/@AB_CD@/communicator/bookmarks/bookmarks.dtd (%chrome/common/bookmarks/bookmarks.dtd)
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the nsSessionStore component.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Simon Bünzli <zeniko@gmail.com>
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Michael Ventnor <m.ventnor@gmail.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#tabList {
|
||||||
|
width: 100%;
|
||||||
|
height: 12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(icon),
|
||||||
|
treechildren::-moz-tree-image(noicon) {
|
||||||
|
padding-right: 2px;
|
||||||
|
margin: 0px 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(noicon) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-item.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(container, noicon) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-folder-closed.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(container, noicon, open) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-folder-open.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-checkbox(checked) {
|
||||||
|
list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-checkbox(partial) {
|
||||||
|
list-style-image: url("chrome://global/skin/checkbox/cbox-check-dis.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-row(alternate) {
|
||||||
|
background-color: -moz-oddtreerow;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-row(alternate, selected) {
|
||||||
|
background-color: Highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttons {
|
||||||
|
-moz-margin-start: 80px;
|
||||||
|
}
|
||||||
|
#buttons > button {
|
||||||
|
margin-top: 2em;
|
||||||
|
-moz-margin-start: 5px;
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ classic.jar:
|
||||||
skin/classic/communicator/preferences.css (communicator/preferences.css)
|
skin/classic/communicator/preferences.css (communicator/preferences.css)
|
||||||
skin/classic/communicator/prefpanels.css (communicator/prefpanels.css)
|
skin/classic/communicator/prefpanels.css (communicator/prefpanels.css)
|
||||||
skin/classic/communicator/smileys.css (communicator/smileys.css)
|
skin/classic/communicator/smileys.css (communicator/smileys.css)
|
||||||
|
skin/classic/communicator/aboutSessionRestore.css (communicator/aboutSessionRestore.css)
|
||||||
skin/classic/communicator/bookmarks/bookmark-folder-button.gif (communicator/bookmarks/bookmark-folder-button.gif)
|
skin/classic/communicator/bookmarks/bookmark-folder-button.gif (communicator/bookmarks/bookmark-folder-button.gif)
|
||||||
skin/classic/communicator/bookmarks/bookmark-folder-closed.png (communicator/bookmarks/bookmark-folder-closed.png)
|
skin/classic/communicator/bookmarks/bookmark-folder-closed.png (communicator/bookmarks/bookmark-folder-closed.png)
|
||||||
skin/classic/communicator/bookmarks/bookmark-folder-dis.png (communicator/bookmarks/bookmark-folder-dis.png)
|
skin/classic/communicator/bookmarks/bookmark-folder-dis.png (communicator/bookmarks/bookmark-folder-dis.png)
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the nsSessionStore component.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Simon Bünzli <zeniko@gmail.com>
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Michael Ventnor <m.ventnor@gmail.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#tabList {
|
||||||
|
width: 100%;
|
||||||
|
height: 12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(icon),
|
||||||
|
treechildren::-moz-tree-image(noicon) {
|
||||||
|
padding-right: 2px;
|
||||||
|
margin: 0px 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(noicon) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-item.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(container, noicon) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-folder-closed.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(container, noicon, open) {
|
||||||
|
list-style-image: url("chrome://communicator/skin/bookmarks/bookmark-folder-open.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-checkbox {
|
||||||
|
list-style-image: url("chrome://global/skin/checkbox/cbox.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-checkbox(checked) {
|
||||||
|
list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-checkbox(partial) {
|
||||||
|
list-style-image: url("chrome://global/skin/checkbox/cbox-check-dis.gif");
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ modern.jar:
|
||||||
skin/modern/communicator/helpOverlay.css (communicator/helpOverlay.css)
|
skin/modern/communicator/helpOverlay.css (communicator/helpOverlay.css)
|
||||||
skin/modern/communicator/smileys.css (communicator/smileys.css)
|
skin/modern/communicator/smileys.css (communicator/smileys.css)
|
||||||
skin/modern/communicator/communicator.css (communicator/communicator.css)
|
skin/modern/communicator/communicator.css (communicator/communicator.css)
|
||||||
|
skin/modern/communicator/aboutSessionRestore.css (communicator/aboutSessionRestore.css)
|
||||||
skin/modern/communicator/bookmarks/bookmark-folder-closed.gif (communicator/bookmarks/bookmark-folder-closed.gif)
|
skin/modern/communicator/bookmarks/bookmark-folder-closed.gif (communicator/bookmarks/bookmark-folder-closed.gif)
|
||||||
skin/modern/communicator/bookmarks/bookmark-folder-dis.gif (communicator/bookmarks/bookmark-folder-dis.gif)
|
skin/modern/communicator/bookmarks/bookmark-folder-dis.gif (communicator/bookmarks/bookmark-folder-dis.gif)
|
||||||
skin/modern/communicator/bookmarks/bookmark-folder-open.gif (communicator/bookmarks/bookmark-folder-open.gif)
|
skin/modern/communicator/bookmarks/bookmark-folder-open.gif (communicator/bookmarks/bookmark-folder-open.gif)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче