зеркало из https://github.com/mozilla/gecko-dev.git
Bug 595601 - Option to not load tabs from inactive groups on initial browser startup (and until such time as the tab(s) become part of an active group); r=zpao
This commit is contained in:
Родитель
66ce76121f
Коммит
f868df08cb
|
@ -785,6 +785,8 @@ pref("browser.sessionstore.max_resumed_crashes", 1);
|
||||||
// Other tabs won't be restored until they are selected
|
// Other tabs won't be restored until they are selected
|
||||||
// N = The number of tabs to restore at the same time
|
// N = The number of tabs to restore at the same time
|
||||||
pref("browser.sessionstore.max_concurrent_tabs", 3);
|
pref("browser.sessionstore.max_concurrent_tabs", 3);
|
||||||
|
// Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
|
||||||
|
pref("browser.sessionstore.restore_hidden_tabs", false);
|
||||||
|
|
||||||
// allow META refresh by default
|
// allow META refresh by default
|
||||||
pref("accessibility.blockautorefresh", false);
|
pref("accessibility.blockautorefresh", false);
|
||||||
|
|
|
@ -64,6 +64,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabview_bug595518.js \
|
browser_tabview_bug595518.js \
|
||||||
browser_tabview_bug595521.js \
|
browser_tabview_bug595521.js \
|
||||||
browser_tabview_bug595560.js \
|
browser_tabview_bug595560.js \
|
||||||
|
browser_tabview_bug595601.js \
|
||||||
browser_tabview_bug595804.js \
|
browser_tabview_bug595804.js \
|
||||||
browser_tabview_bug595930.js \
|
browser_tabview_bug595930.js \
|
||||||
browser_tabview_bug595943.js \
|
browser_tabview_bug595943.js \
|
||||||
|
|
|
@ -1,93 +1,121 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
function test() {
|
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||||
const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html";
|
|
||||||
const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/";
|
|
||||||
|
|
||||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html";
|
||||||
|
const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/";
|
||||||
|
|
||||||
|
let state = {
|
||||||
|
windows: [{
|
||||||
|
tabs: [{
|
||||||
|
entries: [{ url: DUMMY_PAGE_URL }],
|
||||||
|
hidden: true,
|
||||||
|
attributes: {},
|
||||||
|
extData: {
|
||||||
|
"tabview-tab":
|
||||||
|
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
|
||||||
|
'"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' +
|
||||||
|
'"imageData":null,"title":null}'
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
entries: [{ url: DUMMY_PAGE_URL_2 }],
|
||||||
|
hidden: false,
|
||||||
|
attributes: {},
|
||||||
|
extData: {
|
||||||
|
"tabview-tab":
|
||||||
|
'{"bounds":{"left":315,"top":29,"width":111,"height":84},' +
|
||||||
|
'"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' +
|
||||||
|
'"imageData":null,"title":null}'
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
selected:2,
|
||||||
|
_closedTabs: [],
|
||||||
|
extData: {
|
||||||
|
"tabview-groups": '{"nextID":3,"activeGroupId":2}',
|
||||||
|
"tabview-group":
|
||||||
|
'{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' +
|
||||||
|
'"userSize":null,"title":"","id":1},' +
|
||||||
|
'"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' +
|
||||||
|
'"userSize":null,"title":"","id":2}}',
|
||||||
|
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}'
|
||||||
|
}, sizemode:"normal"
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
// open a new window and setup the window state.
|
registerCleanupFunction(function () {
|
||||||
let newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
|
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
|
||||||
newWin.addEventListener("load", function(event) {
|
});
|
||||||
this.removeEventListener("load", arguments.callee, false);
|
|
||||||
|
|
||||||
let newState = {
|
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false);
|
||||||
windows: [{
|
|
||||||
tabs: [{
|
|
||||||
entries: [{ url: DUMMY_PAGE_URL }],
|
|
||||||
hidden: true,
|
|
||||||
attributes: {},
|
|
||||||
extData: {
|
|
||||||
"tabview-tab":
|
|
||||||
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
|
|
||||||
'"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' +
|
|
||||||
'"imageData":null,"title":null}'
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
entries: [{ url: DUMMY_PAGE_URL_2 }],
|
|
||||||
hidden: false,
|
|
||||||
attributes: {},
|
|
||||||
extData: {
|
|
||||||
"tabview-tab":
|
|
||||||
'{"bounds":{"left":315,"top":29,"width":111,"height":84},' +
|
|
||||||
'"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' +
|
|
||||||
'"imageData":null,"title":null}'
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
selected:2,
|
|
||||||
_closedTabs: [],
|
|
||||||
extData: {
|
|
||||||
"tabview-groups": '{"nextID":3,"activeGroupId":2}',
|
|
||||||
"tabview-group":
|
|
||||||
'{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' +
|
|
||||||
'"userSize":null,"title":"","id":1},' +
|
|
||||||
'"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' +
|
|
||||||
'"userSize":null,"title":"","id":2}}',
|
|
||||||
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}'
|
|
||||||
}, sizemode:"normal"
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
ss.setWindowState(newWin, JSON.stringify(newState), true);
|
|
||||||
|
|
||||||
let firstTab = newWin.gBrowser.tabs[0];
|
testTabSwitchAfterRestore(function () {
|
||||||
let secondTab = newWin.gBrowser.tabs[1];
|
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", true);
|
||||||
|
|
||||||
// wait until the first tab is fully loaded
|
testTabSwitchAfterRestore(function () {
|
||||||
let browser = newWin.gBrowser.getBrowserForTab(firstTab);
|
waitForFocus(finish);
|
||||||
let onLoad = function() {
|
});
|
||||||
browser.removeEventListener("load", onLoad, true);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
is(browser.currentURI.spec, DUMMY_PAGE_URL,
|
function testTabSwitchAfterRestore(callback) {
|
||||||
"The url of first tab url is dummy_page.html");
|
newWindowWithState(state, function (win) {
|
||||||
|
registerCleanupFunction(function () win.close());
|
||||||
|
|
||||||
// check the hidden state of both tabs.
|
let [firstTab, secondTab] = win.gBrowser.tabs;
|
||||||
ok(firstTab.hidden, "The first tab is hidden");
|
is(firstTab.linkedBrowser.currentURI.spec, DUMMY_PAGE_URL,
|
||||||
ok(!secondTab.hidden, "The second tab is not hidden");
|
"The url of first tab url is dummy_page.html");
|
||||||
is(secondTab, newWin.gBrowser.selectedTab, "The second tab is selected");
|
|
||||||
|
|
||||||
// when the second tab is hidden, the iframe should be initialized and
|
// check the hidden state of both tabs.
|
||||||
// the first tab should be visible.
|
ok(firstTab.hidden, "The first tab is hidden");
|
||||||
let onTabHide = function() {
|
ok(!secondTab.hidden, "The second tab is not hidden");
|
||||||
newWin.gBrowser.tabContainer.removeEventListener("TabHide", onTabHide, true);
|
is(secondTab, win.gBrowser.selectedTab, "The second tab is selected");
|
||||||
|
|
||||||
ok(newWin.TabView.getContentWindow(), "");
|
// when the second tab is hidden, Panorama should be initialized and
|
||||||
|
// the first tab should be visible.
|
||||||
|
let container = win.gBrowser.tabContainer;
|
||||||
|
container.addEventListener("TabHide", function onTabHide() {
|
||||||
|
container.removeEventListener("TabHide", onTabHide, false);
|
||||||
|
|
||||||
ok(!firstTab.hidden, "The first tab is not hidden");
|
ok(win.TabView.getContentWindow(), "Panorama is loaded");
|
||||||
is(firstTab, newWin.gBrowser.selectedTab, "The first tab is selected");
|
ok(!firstTab.hidden, "The first tab is not hidden");
|
||||||
ok(secondTab.hidden, "The second tab is hidden");
|
is(firstTab, win.gBrowser.selectedTab, "The first tab is selected");
|
||||||
|
ok(secondTab.hidden, "The second tab is hidden");
|
||||||
|
|
||||||
// clean up and finish
|
callback();
|
||||||
newWin.close();
|
}, false);
|
||||||
|
|
||||||
finish();
|
// switch to another tab
|
||||||
};
|
win.switchToTabHavingURI(DUMMY_PAGE_URL);
|
||||||
newWin.gBrowser.tabContainer.addEventListener("TabHide", onTabHide, true);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// switch to another tab
|
function newWindowWithState(state, callback) {
|
||||||
newWin.switchToTabHavingURI(DUMMY_PAGE_URL);
|
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||||
}
|
let win = window.openDialog(getBrowserURL(), "_blank", opts);
|
||||||
browser.addEventListener("load", onLoad, true);
|
|
||||||
|
whenWindowLoaded(win, function () {
|
||||||
|
ss.setWindowState(win, JSON.stringify(state), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
whenWindowStateReady(win, function () {
|
||||||
|
afterAllTabsLoaded(function () callback(win), win);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function whenWindowLoaded(win, callback) {
|
||||||
|
win.addEventListener("load", function onLoad() {
|
||||||
|
win.removeEventListener("load", onLoad, false);
|
||||||
|
executeSoon(callback);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function whenWindowStateReady(win, callback) {
|
||||||
|
win.addEventListener("SSWindowStateReady", function onReady() {
|
||||||
|
win.removeEventListener("SSWindowStateReady", onReady, false);
|
||||||
|
executeSoon(callback);
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,134 +1,97 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
let newTabOne;
|
let win;
|
||||||
let originalTab;
|
let cw;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
originalTab = gBrowser.visibleTabs[0];
|
let onLoad = function (tvwin) {
|
||||||
newTabOne = gBrowser.addTab("http://mochi.test:8888/");
|
win = tvwin;
|
||||||
|
registerCleanupFunction(function () win.close());
|
||||||
let browser = gBrowser.getBrowserForTab(newTabOne);
|
win.gBrowser.loadOneTab("http://mochi.test:8888/", {inBackground: true});
|
||||||
let onLoad = function() {
|
|
||||||
browser.removeEventListener("load", onLoad, true);
|
|
||||||
|
|
||||||
// show the tab view
|
|
||||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
|
||||||
TabView.toggle();
|
|
||||||
}
|
|
||||||
browser.addEventListener("load", onLoad, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onTabViewWindowLoaded() {
|
|
||||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
|
||||||
ok(TabView.isVisible(), "Tab View is visible");
|
|
||||||
|
|
||||||
afterAllTabItemsUpdated(function() {
|
|
||||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
|
||||||
testOne(contentWindow);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function testOne(contentWindow) {
|
|
||||||
onSearchEnabledAndDisabled(contentWindow, function() {
|
|
||||||
testTwo(contentWindow);
|
|
||||||
});
|
|
||||||
// press cmd/ctrl F
|
|
||||||
EventUtils.synthesizeKey("f", { accelKey: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function testTwo(contentWindow) {
|
|
||||||
onSearchEnabledAndDisabled(contentWindow, function() {
|
|
||||||
testThree(contentWindow);
|
|
||||||
});
|
|
||||||
// press /
|
|
||||||
EventUtils.synthesizeKey("VK_SLASH", { type: "keydown" }, contentWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testThree(contentWindow) {
|
|
||||||
let groupItem = createEmptyGroupItem(contentWindow, 200);
|
|
||||||
|
|
||||||
let onTabViewHidden = function() {
|
|
||||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
|
||||||
TabView.toggle();
|
|
||||||
};
|
};
|
||||||
let onTabViewShown = function() {
|
|
||||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
|
||||||
|
|
||||||
is(contentWindow.UI.getActiveTab(), groupItem.getChild(0),
|
let onShow = function () {
|
||||||
|
cw = win.TabView.getContentWindow();
|
||||||
|
ok(win.TabView.isVisible(), "Tab View is visible");
|
||||||
|
afterAllTabItemsUpdated(testOne, win);
|
||||||
|
};
|
||||||
|
|
||||||
|
newWindowWithTabView(onShow, onLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOne() {
|
||||||
|
whenSearchEnabledAndDisabled(testTwo);
|
||||||
|
// press cmd/ctrl F
|
||||||
|
EventUtils.synthesizeKey("f", {accelKey: true}, cw);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTwo() {
|
||||||
|
whenSearchEnabledAndDisabled(testThree);
|
||||||
|
// press /
|
||||||
|
EventUtils.synthesizeKey("VK_SLASH", {}, cw);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testThree() {
|
||||||
|
let onTabViewShown = function () {
|
||||||
|
is(cw.UI.getActiveTab(), groupItem.getChild(0),
|
||||||
"The active tab is newly created tab item");
|
"The active tab is newly created tab item");
|
||||||
|
|
||||||
let onSearchEnabled = function() {
|
let onSearchEnabled = function () {
|
||||||
contentWindow.removeEventListener(
|
let doc = cw.document;
|
||||||
"tabviewsearchenabled", onSearchEnabled, false);
|
let searchBox = cw.iQ("#searchbox");
|
||||||
|
let hasFocus = doc.hasFocus() && doc.activeElement == searchBox[0];
|
||||||
|
ok(hasFocus, "The search box has focus");
|
||||||
|
|
||||||
let searchBox = contentWindow.iQ("#searchbox");
|
let tab = win.gBrowser.tabs[1];
|
||||||
|
searchBox.val(tab._tabViewTabItem.$tabTitle[0].innerHTML);
|
||||||
|
|
||||||
ok(contentWindow.document.hasFocus() &&
|
cw.performSearch();
|
||||||
contentWindow.document.activeElement == searchBox[0],
|
|
||||||
"The search box has focus");
|
|
||||||
searchBox.val(newTabOne._tabViewTabItem.$tabTitle[0].innerHTML);
|
|
||||||
|
|
||||||
contentWindow.performSearch();
|
whenTabViewIsHidden(function () {
|
||||||
|
is(tab, win.gBrowser.selectedTab, "The search result tab is shown");
|
||||||
let checkSelectedTab = function() {
|
waitForFocus(finish);
|
||||||
window.removeEventListener("tabviewhidden", checkSelectedTab, false);
|
}, win);
|
||||||
is(newTabOne, gBrowser.selectedTab, "The search result tab is shown");
|
|
||||||
cleanUpAndFinish(groupItem.getChild(0), contentWindow);
|
|
||||||
};
|
|
||||||
window.addEventListener("tabviewhidden", checkSelectedTab, false);
|
|
||||||
|
|
||||||
// use the tabview menu (the same as pressing cmd/ctrl + e)
|
// use the tabview menu (the same as pressing cmd/ctrl + e)
|
||||||
document.getElementById("menu_tabview").doCommand();
|
win.document.getElementById("menu_tabview").doCommand();
|
||||||
};
|
};
|
||||||
contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled, false);
|
|
||||||
EventUtils.synthesizeKey("VK_SLASH", { type: "keydown" }, contentWindow);
|
whenSearchEnabled(onSearchEnabled);
|
||||||
|
EventUtils.synthesizeKey("VK_SLASH", {}, cw);
|
||||||
};
|
};
|
||||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
|
||||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
whenTabViewIsHidden(function () {
|
||||||
|
showTabView(onTabViewShown, win);
|
||||||
|
}, win);
|
||||||
|
|
||||||
// click on the + button
|
// click on the + button
|
||||||
|
let groupItem = createEmptyGroupItem(cw, 300, 300, 200);
|
||||||
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
|
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
|
||||||
ok(newTabButton[0], "New tab button exists");
|
ok(newTabButton[0], "New tab button exists");
|
||||||
|
|
||||||
EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
|
EventUtils.sendMouseEvent({type: "click"}, newTabButton[0], cw);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSearchEnabledAndDisabled(contentWindow, callback) {
|
function whenSearchEnabledAndDisabled(callback) {
|
||||||
let onSearchEnabled = function() {
|
whenSearchEnabled(function () {
|
||||||
contentWindow.removeEventListener(
|
whenSearchDisabled(callback);
|
||||||
"tabviewsearchenabled", onSearchEnabled, false);
|
cw.hideSearch();
|
||||||
contentWindow.addEventListener("tabviewsearchdisabled", onSearchDisabled, false);
|
});
|
||||||
contentWindow.hideSearch();
|
}
|
||||||
}
|
|
||||||
let onSearchDisabled = function() {
|
function whenSearchEnabled(callback) {
|
||||||
contentWindow.removeEventListener(
|
cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
|
||||||
"tabviewsearchdisabled", onSearchDisabled, false);
|
cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
|
||||||
callback();
|
callback();
|
||||||
}
|
}, false);
|
||||||
contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanUpAndFinish(tabItem, contentWindow) {
|
function whenSearchDisabled(callback) {
|
||||||
gBrowser.selectedTab = originalTab;
|
cw.addEventListener("tabviewsearchdisabled", function onSearchDisabled() {
|
||||||
gBrowser.removeTab(newTabOne);
|
cw.removeEventListener("tabviewsearchdisabled", onSearchDisabled, false);
|
||||||
gBrowser.removeTab(tabItem.tab);
|
callback();
|
||||||
|
}, false);
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyGroupItem(contentWindow, padding) {
|
|
||||||
let pageBounds = contentWindow.Items.getPageBounds();
|
|
||||||
pageBounds.inset(padding, padding);
|
|
||||||
|
|
||||||
let box = new contentWindow.Rect(pageBounds);
|
|
||||||
box.width = 300;
|
|
||||||
box.height = 300;
|
|
||||||
|
|
||||||
let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box });
|
|
||||||
|
|
||||||
return emptyGroupItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||||
|
|
||||||
|
const TAB_STATE_NEEDS_RESTORE = 1;
|
||||||
|
const TAB_STATE_RESTORING = 2;
|
||||||
|
|
||||||
|
let stateBackup = ss.getBrowserState();
|
||||||
|
|
||||||
|
let state = {windows:[{tabs:[
|
||||||
|
// first group
|
||||||
|
{entries:[{url:"http://example.com#1"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#1\",\"groupID\":2}"}},
|
||||||
|
{entries:[{url:"http://example.com#2"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#2\",\"groupID\":2}"}},
|
||||||
|
{entries:[{url:"http://example.com#3"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#3\",\"groupID\":2}"}},
|
||||||
|
{entries:[{url:"http://example.com#4"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#4\",\"groupID\":2}"}},
|
||||||
|
|
||||||
|
// second group
|
||||||
|
{entries:[{url:"http://example.com#5"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#5\",\"groupID\":1}"}},
|
||||||
|
{entries:[{url:"http://example.com#6"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#6\",\"groupID\":1}"}},
|
||||||
|
{entries:[{url:"http://example.com#7"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#7\",\"groupID\":1}"}},
|
||||||
|
{entries:[{url:"http://example.com#8"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#8\",\"groupID\":1}"}}
|
||||||
|
],selected:5,extData:{
|
||||||
|
"tabview-groups":"{\"nextID\":8,\"activeGroupId\":1}","tabview-group":"{\"1\":{\"bounds\":{\"left\":15,\"top\":10,\"width\":415,\"height\":367},\"userSize\":{\"x\":415,\"y\":367},\"title\":\"\",\"id\":1},\"2\":{\"bounds\":{\"left\":286,\"top\":488,\"width\":418,\"height\":313},\"title\":\"\",\"id\":2}}",
|
||||||
|
"tabview-ui":"{\"pageBounds\":{\"left\":0,\"top\":0,\"width\":940,\"height\":1075}}"
|
||||||
|
}}]};
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false);
|
||||||
|
|
||||||
|
TabsProgressListener.init();
|
||||||
|
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
TabsProgressListener.uninit();
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
|
||||||
|
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
|
||||||
|
|
||||||
|
ss.setBrowserState(stateBackup);
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 3);
|
||||||
|
|
||||||
|
TabView._initFrame(function () {
|
||||||
|
executeSoon(testRestoreWithHiddenTabs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRestoreWithHiddenTabs() {
|
||||||
|
let checked = false;
|
||||||
|
let ssReady = false;
|
||||||
|
let tabsRestored = false;
|
||||||
|
|
||||||
|
let check = function () {
|
||||||
|
if (checked || !ssReady || !tabsRestored)
|
||||||
|
return;
|
||||||
|
|
||||||
|
checked = true;
|
||||||
|
|
||||||
|
is(gBrowser.tabs.length, 8, "there are now eight tabs");
|
||||||
|
is(gBrowser.visibleTabs.length, 4, "four visible tabs");
|
||||||
|
|
||||||
|
let cw = TabView.getContentWindow();
|
||||||
|
is(cw.GroupItems.groupItems.length, 2, "there are now two groupItems");
|
||||||
|
|
||||||
|
testSwitchToInactiveGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
whenSessionStoreReady(function () {
|
||||||
|
ssReady = true;
|
||||||
|
check();
|
||||||
|
});
|
||||||
|
|
||||||
|
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
|
||||||
|
if (4 < needsRestore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TabsProgressListener.unsetCallback();
|
||||||
|
is(needsRestore, 4, "4/8 tabs restored");
|
||||||
|
|
||||||
|
tabsRestored = true;
|
||||||
|
check();
|
||||||
|
});
|
||||||
|
|
||||||
|
ss.setBrowserState(JSON.stringify(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSwitchToInactiveGroup() {
|
||||||
|
let firstProgress = true;
|
||||||
|
|
||||||
|
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
|
||||||
|
if (firstProgress) {
|
||||||
|
firstProgress = false;
|
||||||
|
is(isRestoring, 3, "restoring 3 tabs concurrently");
|
||||||
|
} else {
|
||||||
|
ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsRestore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TabsProgressListener.unsetCallback();
|
||||||
|
|
||||||
|
is(gBrowser.visibleTabs.length, 4, "four visible tabs");
|
||||||
|
waitForFocus(finish);
|
||||||
|
});
|
||||||
|
|
||||||
|
gBrowser.selectedTab = gBrowser.tabs[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
function whenSessionStoreReady(callback) {
|
||||||
|
window.addEventListener("SSWindowStateReady", function onReady() {
|
||||||
|
window.removeEventListener("SSWindowStateReady", onReady, false);
|
||||||
|
executeSoon(callback);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countTabs() {
|
||||||
|
let needsRestore = 0, isRestoring = 0;
|
||||||
|
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
|
||||||
|
while (windowsEnum.hasMoreElements()) {
|
||||||
|
let window = windowsEnum.getNext();
|
||||||
|
if (window.closed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||||
|
let browser = window.gBrowser.tabs[i].linkedBrowser;
|
||||||
|
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||||
|
isRestoring++;
|
||||||
|
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||||
|
needsRestore++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [needsRestore, isRestoring];
|
||||||
|
}
|
||||||
|
|
||||||
|
let TabsProgressListener = {
|
||||||
|
init: function () {
|
||||||
|
gBrowser.addTabsProgressListener(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit: function () {
|
||||||
|
this.unsetCallback();
|
||||||
|
gBrowser.removeTabsProgressListener(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
setCallback: function (callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
},
|
||||||
|
|
||||||
|
unsetCallback: function () {
|
||||||
|
delete this.callback;
|
||||||
|
},
|
||||||
|
|
||||||
|
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||||
|
let isNetwork = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
|
||||||
|
let isWindow = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
|
||||||
|
|
||||||
|
if (!(this.callback && isNetwork && isWindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
let finalize = function () {
|
||||||
|
if (wasRestoring)
|
||||||
|
delete aBrowser.__wasRestoring;
|
||||||
|
|
||||||
|
self.callback.apply(null, countTabs());
|
||||||
|
};
|
||||||
|
|
||||||
|
let isRestoring = aBrowser.__SS_restoreState == TAB_STATE_RESTORING;
|
||||||
|
let wasRestoring = !aBrowser.__SS_restoreState && aBrowser.__wasRestoring;
|
||||||
|
let hasStopped = aStateFlags & Ci.nsIWebProgressListener.STATE_STOP;
|
||||||
|
|
||||||
|
if (isRestoring && !hasStopped)
|
||||||
|
aBrowser.__wasRestoring = true;
|
||||||
|
|
||||||
|
if (hasStopped && (isRestoring || wasRestoring))
|
||||||
|
finalize();
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ function test() {
|
||||||
if (!callback)
|
if (!callback)
|
||||||
callback = finish;
|
callback = finish;
|
||||||
|
|
||||||
|
assertOneSingleGroupItem();
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,7 @@ function test() {
|
||||||
// some callback waiting to be fired after gBrowser.loadOneTab(). After
|
// some callback waiting to be fired after gBrowser.loadOneTab(). After
|
||||||
// that the browser is in a state where loadURI() will create a new entry
|
// that the browser is in a state where loadURI() will create a new entry
|
||||||
// in the session history (that is vital for back/forward functionality).
|
// in the session history (that is vital for back/forward functionality).
|
||||||
afterAllTabsLoaded(function () SimpleTest.executeSoon(continueTest));
|
afterAllTabsLoaded(function () executeSoon(continueTest));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -190,7 +191,7 @@ function enterAndLeavePrivateBrowsing(callback) {
|
||||||
pb.privateBrowsingEnabled = false;
|
pb.privateBrowsingEnabled = false;
|
||||||
else {
|
else {
|
||||||
Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete");
|
Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete");
|
||||||
afterAllTabsLoaded(callback);
|
afterAllTabsLoaded(function () executeSoon(callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,8 @@ function test() {
|
||||||
|
|
||||||
showTabView(function () {
|
showTabView(function () {
|
||||||
cw = TabView.getContentWindow();
|
cw = TabView.getContentWindow();
|
||||||
|
assertNumberOfGroups('start', 1);
|
||||||
|
|
||||||
createGroupItem();
|
createGroupItem();
|
||||||
|
|
||||||
afterAllTabsLoaded(function () {
|
afterAllTabsLoaded(function () {
|
||||||
|
|
|
@ -93,9 +93,13 @@ function newWindowWithTabView(shownCallback, loadCallback, width, height) {
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
function afterAllTabsLoaded(callback, win) {
|
function afterAllTabsLoaded(callback, win) {
|
||||||
|
const TAB_STATE_NEEDS_RESTORE = 1;
|
||||||
|
|
||||||
win = win || window;
|
win = win || window;
|
||||||
|
|
||||||
let stillToLoad = 0;
|
let stillToLoad = 0;
|
||||||
|
let restoreHiddenTabs = Services.prefs.getBoolPref(
|
||||||
|
"browser.sessionstore.restore_hidden_tabs");
|
||||||
|
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
this.removeEventListener("load", onLoad, true);
|
this.removeEventListener("load", onLoad, true);
|
||||||
|
@ -105,8 +109,14 @@ function afterAllTabsLoaded(callback, win) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let a = 0; a < win.gBrowser.tabs.length; a++) {
|
for (let a = 0; a < win.gBrowser.tabs.length; a++) {
|
||||||
let browser = win.gBrowser.tabs[a].linkedBrowser;
|
let tab = win.gBrowser.tabs[a];
|
||||||
if (browser.contentDocument.readyState != "complete" ||
|
let browser = tab.linkedBrowser;
|
||||||
|
|
||||||
|
let isRestorable = !(tab.hidden && !restoreHiddenTabs &&
|
||||||
|
browser.__SS_restoreState &&
|
||||||
|
browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE);
|
||||||
|
|
||||||
|
if (isRestorable && browser.contentDocument.readyState != "complete" ||
|
||||||
browser.webProgress.isLoadingDocument) {
|
browser.webProgress.isLoadingDocument) {
|
||||||
stillToLoad++;
|
stillToLoad++;
|
||||||
browser.addEventListener("load", onLoad, true);
|
browser.addEventListener("load", onLoad, true);
|
||||||
|
@ -114,7 +124,7 @@ function afterAllTabsLoaded(callback, win) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stillToLoad)
|
if (!stillToLoad)
|
||||||
callback();
|
executeSoon(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
|
|
@ -224,6 +224,9 @@ SessionStoreService.prototype = {
|
||||||
|
|
||||||
// number of tabs to restore concurrently, pref controlled.
|
// number of tabs to restore concurrently, pref controlled.
|
||||||
_maxConcurrentTabRestores: null,
|
_maxConcurrentTabRestores: null,
|
||||||
|
|
||||||
|
// whether to restore hidden tabs or not, pref controlled.
|
||||||
|
_restoreHiddenTabs: null,
|
||||||
|
|
||||||
// The state from the previous session (after restoring pinned tabs)
|
// The state from the previous session (after restoring pinned tabs)
|
||||||
_lastSessionState: null,
|
_lastSessionState: null,
|
||||||
|
@ -281,6 +284,10 @@ SessionStoreService.prototype = {
|
||||||
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
||||||
this._prefBranch.addObserver("sessionstore.max_concurrent_tabs", this, true);
|
this._prefBranch.addObserver("sessionstore.max_concurrent_tabs", this, true);
|
||||||
|
|
||||||
|
this._restoreHiddenTabs =
|
||||||
|
this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
|
||||||
|
this._prefBranch.addObserver("sessionstore.restore_hidden_tabs", this, true);
|
||||||
|
|
||||||
// Make sure gRestoreTabsProgressListener has a reference to sessionstore
|
// Make sure gRestoreTabsProgressListener has a reference to sessionstore
|
||||||
// so that it can make calls back in
|
// so that it can make calls back in
|
||||||
gRestoreTabsProgressListener.ss = this;
|
gRestoreTabsProgressListener.ss = this;
|
||||||
|
@ -598,6 +605,10 @@ SessionStoreService.prototype = {
|
||||||
this._maxConcurrentTabRestores =
|
this._maxConcurrentTabRestores =
|
||||||
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
this._prefBranch.getIntPref("sessionstore.max_concurrent_tabs");
|
||||||
break;
|
break;
|
||||||
|
case "sessionstore.restore_hidden_tabs":
|
||||||
|
this._restoreHiddenTabs =
|
||||||
|
this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "timer-callback": // timer call back for delayed saving
|
case "timer-callback": // timer call back for delayed saving
|
||||||
|
@ -1078,6 +1089,10 @@ SessionStoreService.prototype = {
|
||||||
this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab));
|
this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab));
|
||||||
// Just put it at the end of the list of visible tabs;
|
// Just put it at the end of the list of visible tabs;
|
||||||
this._tabsToRestore.visible.push(aTab);
|
this._tabsToRestore.visible.push(aTab);
|
||||||
|
|
||||||
|
// let's kick off tab restoration again to ensure this tab gets restored
|
||||||
|
// with "restore_hidden_tabs" == false (now that it has become visible)
|
||||||
|
this.restoreNextTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default delay of 2 seconds gives enough time to catch multiple TabShow
|
// Default delay of 2 seconds gives enough time to catch multiple TabShow
|
||||||
|
@ -2944,7 +2959,7 @@ SessionStoreService.prototype = {
|
||||||
if (this._tabsToRestore.visible.length) {
|
if (this._tabsToRestore.visible.length) {
|
||||||
nextTabArray = this._tabsToRestore.visible;
|
nextTabArray = this._tabsToRestore.visible;
|
||||||
}
|
}
|
||||||
else if (this._tabsToRestore.hidden.length) {
|
else if (this._restoreHiddenTabs && this._tabsToRestore.hidden.length) {
|
||||||
nextTabArray = this._tabsToRestore.hidden;
|
nextTabArray = this._tabsToRestore.hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,7 @@ _BROWSER_TEST_FILES = \
|
||||||
browser_589246.js \
|
browser_589246.js \
|
||||||
browser_590268.js \
|
browser_590268.js \
|
||||||
browser_590563.js \
|
browser_590563.js \
|
||||||
|
browser_595601-restore_hidden.js \
|
||||||
browser_597315.js \
|
browser_597315.js \
|
||||||
browser_597315_index.html \
|
browser_597315_index.html \
|
||||||
browser_597315_a.html \
|
browser_597315_a.html \
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||||
|
getService(Ci.nsISessionStore);
|
||||||
|
|
||||||
|
const TAB_STATE_NEEDS_RESTORE = 1;
|
||||||
|
const TAB_STATE_RESTORING = 2;
|
||||||
|
|
||||||
|
let stateBackup = ss.getBrowserState();
|
||||||
|
|
||||||
|
let state = {windows:[{tabs:[
|
||||||
|
{entries:[{url:"http://example.com#1"}]},
|
||||||
|
{entries:[{url:"http://example.com#2"}]},
|
||||||
|
{entries:[{url:"http://example.com#3"}]},
|
||||||
|
{entries:[{url:"http://example.com#4"}]},
|
||||||
|
{entries:[{url:"http://example.com#5"}], hidden: true},
|
||||||
|
{entries:[{url:"http://example.com#6"}], hidden: true},
|
||||||
|
{entries:[{url:"http://example.com#7"}], hidden: true},
|
||||||
|
{entries:[{url:"http://example.com#8"}], hidden: true}
|
||||||
|
]}]};
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
|
||||||
|
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
|
||||||
|
|
||||||
|
TabsProgressListener.uninit();
|
||||||
|
|
||||||
|
ss.setBrowserState(stateBackup);
|
||||||
|
});
|
||||||
|
|
||||||
|
TabsProgressListener.init();
|
||||||
|
|
||||||
|
Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 3);
|
||||||
|
|
||||||
|
// First stage: restoreHiddenTabs = true
|
||||||
|
// Second stage: restoreHiddenTabs = false
|
||||||
|
test_loadTabs(true, function () {
|
||||||
|
test_loadTabs(false, function () {
|
||||||
|
waitForFocus(finish);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_loadTabs(restoreHiddenTabs, callback) {
|
||||||
|
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", restoreHiddenTabs);
|
||||||
|
|
||||||
|
let expectedTabs = restoreHiddenTabs ? 8 : 4;
|
||||||
|
|
||||||
|
let firstProgress = true;
|
||||||
|
|
||||||
|
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
|
||||||
|
if (firstProgress) {
|
||||||
|
firstProgress = false;
|
||||||
|
is(isRestoring, 3, "restoring 3 tabs concurrently");
|
||||||
|
} else {
|
||||||
|
ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gBrowser.tabs.length - needsRestore == expectedTabs) {
|
||||||
|
TabsProgressListener.unsetCallback();
|
||||||
|
is(gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ss.setBrowserState(JSON.stringify(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
function countTabs() {
|
||||||
|
let needsRestore = 0, isRestoring = 0;
|
||||||
|
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
|
||||||
|
while (windowsEnum.hasMoreElements()) {
|
||||||
|
let window = windowsEnum.getNext();
|
||||||
|
if (window.closed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||||
|
let browser = window.gBrowser.tabs[i].linkedBrowser;
|
||||||
|
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||||
|
isRestoring++;
|
||||||
|
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||||
|
needsRestore++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [needsRestore, isRestoring];
|
||||||
|
}
|
||||||
|
|
||||||
|
let TabsProgressListener = {
|
||||||
|
init: function () {
|
||||||
|
gBrowser.addTabsProgressListener(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
uninit: function () {
|
||||||
|
this.unsetCallback();
|
||||||
|
gBrowser.removeTabsProgressListener(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
setCallback: function (callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
},
|
||||||
|
|
||||||
|
unsetCallback: function () {
|
||||||
|
delete this.callback;
|
||||||
|
},
|
||||||
|
|
||||||
|
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||||
|
if (this.callback && aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
|
||||||
|
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||||
|
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||||
|
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||||
|
this.callback.apply(null, countTabs());
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,8 +47,20 @@ function waitForBrowserState(aState, aSetStateCallback) {
|
||||||
let windowsOpen = 1;
|
let windowsOpen = 1;
|
||||||
let listening = false;
|
let listening = false;
|
||||||
let windowObserving = false;
|
let windowObserving = false;
|
||||||
|
let restoreHiddenTabs = Services.prefs.getBoolPref(
|
||||||
|
"browser.sessionstore.restore_hidden_tabs");
|
||||||
|
|
||||||
aState.windows.forEach(function(winState) expectedTabsRestored += winState.tabs.length);
|
aState.windows.forEach(function (winState) {
|
||||||
|
winState.tabs.forEach(function (tabState) {
|
||||||
|
if (restoreHiddenTabs || !tabState.hidden)
|
||||||
|
expectedTabsRestored++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// There must be only hidden tabs and restoreHiddenTabs = false. We still
|
||||||
|
// expect one of them to be restored because it gets shown automatically.
|
||||||
|
if (!expectedTabsRestored)
|
||||||
|
expectedTabsRestored = 1;
|
||||||
|
|
||||||
function onSSTabRestored(aEvent) {
|
function onSSTabRestored(aEvent) {
|
||||||
if (++tabsRestored == expectedTabsRestored) {
|
if (++tabsRestored == expectedTabsRestored) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче