зеркало из https://github.com/mozilla/pjs.git
Bug 579361 - Enhance SessionStore service in Fennec [r=vingtetun]
This commit is contained in:
Родитель
ab02cbfb32
Коммит
ff2b05499a
|
@ -1163,11 +1163,8 @@ KeyModule.prototype = {
|
|||
handleEvent: function handleEvent(evInfo) {
|
||||
if (evInfo.event.type == "keydown" || evInfo.event.type == "keyup" || evInfo.event.type == "keypress") {
|
||||
let keyer = this._browserViewContainer.customKeySender;
|
||||
if (keyer) {
|
||||
if (keyer)
|
||||
keyer.dispatchKeyEvent(evInfo.event);
|
||||
evInfo.event.preventDefault();
|
||||
evInfo.event.stopPropagation();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
</div>
|
||||
|
||||
<div id="about">
|
||||
<img src="chrome://browser/skin/images/mozilla-32.png"/> <a href="http://www.mozilla.com/about/">&aboutHome.aboutMozilla;</a>
|
||||
<img src="chrome://browser/skin/images/mozilla-32.png"/> <a href="http://www.mozilla.com/about/">&aboutHome.aboutMozilla;</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -162,15 +162,19 @@
|
|||
|
||||
let tabs = data.windows[0].tabs;
|
||||
for (let i=0; i<tabs.length; i++) {
|
||||
let url = tabs[i].url;
|
||||
let tabData = tabs[i];
|
||||
if ("entries" in tabData)
|
||||
tabData = tabData.entries[0];
|
||||
|
||||
let url = tabData.url;
|
||||
if (url.indexOf("about:") == 0)
|
||||
continue;
|
||||
|
||||
let title = tabs[i].title;
|
||||
let title = tabData.title;
|
||||
if (!title)
|
||||
continue;
|
||||
|
||||
let uri = chromeWin.makeURI(url);
|
||||
let uri = chromeWin.Util.makeURI(url);
|
||||
let favicon = chromeWin.gFaviconService.getFaviconImageForPage(uri).spec;
|
||||
|
||||
let outer = document.createElement("div");
|
||||
|
|
|
@ -444,7 +444,8 @@
|
|||
},
|
||||
set currentURI(aURI) { this.loadURI(aURI.spec, null, null, null); },
|
||||
referringURI: null,
|
||||
get sessionHistory() { throw "sessionHistory: Not Remoteable"; },
|
||||
get sessionHistory() { return null; },
|
||||
set sessionHistory(aValue) { },
|
||||
|
||||
_currentURI: null,
|
||||
_browser: this,
|
||||
|
|
|
@ -102,7 +102,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
_titleChanged : function(aBrowser) {
|
||||
_titleChanged: function(aBrowser) {
|
||||
var browser = Browser.selectedBrowser;
|
||||
if (browser && aBrowser != browser)
|
||||
return;
|
||||
|
@ -131,7 +131,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
_updateButtons : function(aBrowser) {
|
||||
_updateButtons: function(aBrowser) {
|
||||
let back = document.getElementById("cmd_back");
|
||||
let forward = document.getElementById("cmd_forward");
|
||||
|
||||
|
@ -150,7 +150,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
_tabSelect : function(aEvent) {
|
||||
_tabSelect: function(aEvent) {
|
||||
let browser = Browser.selectedBrowser;
|
||||
this._titleChanged(browser);
|
||||
this._updateToolbar();
|
||||
|
@ -159,7 +159,7 @@ var BrowserUI = {
|
|||
this.updateStar();
|
||||
},
|
||||
|
||||
showToolbar : function showToolbar(aEdit) {
|
||||
showToolbar: function showToolbar(aEdit) {
|
||||
this.hidePanel();
|
||||
this._editURI(aEdit);
|
||||
if (aEdit)
|
||||
|
@ -195,7 +195,7 @@ var BrowserUI = {
|
|||
this._edit.value = aCaption;
|
||||
},
|
||||
|
||||
_editURI : function _editURI(aEdit) {
|
||||
_editURI: function _editURI(aEdit) {
|
||||
var icons = document.getElementById("urlbar-icons");
|
||||
if (aEdit && icons.getAttribute("mode") != "edit") {
|
||||
icons.setAttribute("mode", "edit");
|
||||
|
@ -236,7 +236,7 @@ var BrowserUI = {
|
|||
return null;
|
||||
},
|
||||
|
||||
pushDialog : function pushDialog(aDialog) {
|
||||
pushDialog: function pushDialog(aDialog) {
|
||||
// If we have a dialog push it on the stack and set the attr for CSS
|
||||
if (aDialog) {
|
||||
this.lockToolbar();
|
||||
|
@ -246,7 +246,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
popDialog : function popDialog() {
|
||||
popDialog: function popDialog() {
|
||||
if (this._dialogs.length) {
|
||||
this._dialogs.pop();
|
||||
this.unlockToolbar();
|
||||
|
@ -297,7 +297,7 @@ var BrowserUI = {
|
|||
return targetNode ? true : false;
|
||||
},
|
||||
|
||||
switchPane : function switchPane(id) {
|
||||
switchPane: function switchPane(id) {
|
||||
let button = document.getElementsByAttribute("linkedpanel", id)[0];
|
||||
if (button)
|
||||
button.checked = true;
|
||||
|
@ -329,7 +329,7 @@ var BrowserUI = {
|
|||
return this.starButton = document.getElementById("tool-star");
|
||||
},
|
||||
|
||||
sizeControls : function(windowW, windowH) {
|
||||
sizeControls: function(windowW, windowH) {
|
||||
// tabs
|
||||
document.getElementById("tabs").resize();
|
||||
|
||||
|
@ -344,7 +344,7 @@ var BrowserUI = {
|
|||
formHelper.top = windowH - formHelper.getBoundingClientRect().height;
|
||||
},
|
||||
|
||||
init : function() {
|
||||
init: function() {
|
||||
this._edit = document.getElementById("urlbar-edit");
|
||||
this._throbber = document.getElementById("urlbar-throbber");
|
||||
this._favicon = document.getElementById("urlbar-favicon");
|
||||
|
@ -401,12 +401,12 @@ var BrowserUI = {
|
|||
FormHelperUI.init();
|
||||
},
|
||||
|
||||
uninit : function() {
|
||||
uninit: function() {
|
||||
ExtensionsView.uninit();
|
||||
ConsoleView.uninit();
|
||||
},
|
||||
|
||||
update : function(aState) {
|
||||
update: function(aState) {
|
||||
let icons = document.getElementById("urlbar-icons");
|
||||
let browser = Browser.selectedBrowser;
|
||||
|
||||
|
@ -430,7 +430,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
_updateIcon : function(aIconSrc) {
|
||||
_updateIcon: function(aIconSrc) {
|
||||
this._favicon.src = aIconSrc || "";
|
||||
if (Browser.selectedTab.isLoading()) {
|
||||
this._throbber.hidden = false;
|
||||
|
@ -444,7 +444,7 @@ var BrowserUI = {
|
|||
}
|
||||
},
|
||||
|
||||
getDisplayURI : function(browser) {
|
||||
getDisplayURI: function(browser) {
|
||||
if (!this._URIFixup)
|
||||
this._URIFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
|
||||
|
||||
|
@ -457,7 +457,7 @@ var BrowserUI = {
|
|||
},
|
||||
|
||||
/* Set the location to the current content */
|
||||
updateURI : function() {
|
||||
updateURI: function() {
|
||||
var browser = Browser.selectedBrowser;
|
||||
|
||||
// FIXME: deckbrowser should not fire TabSelect on the initial tab (bug 454028)
|
||||
|
@ -477,7 +477,7 @@ var BrowserUI = {
|
|||
this._setURI(urlString);
|
||||
},
|
||||
|
||||
goToURI : function(aURI) {
|
||||
goToURI: function(aURI) {
|
||||
aURI = aURI || this._edit.value;
|
||||
if (!aURI)
|
||||
return;
|
||||
|
@ -509,7 +509,7 @@ var BrowserUI = {
|
|||
gHistSvc.markPageAsTyped(uri);
|
||||
},
|
||||
|
||||
showAutoComplete : function showAutoComplete() {
|
||||
showAutoComplete: function showAutoComplete() {
|
||||
if (this.isAutoCompleteOpen())
|
||||
return;
|
||||
|
||||
|
@ -533,7 +533,7 @@ var BrowserUI = {
|
|||
return this._edit.popup.popupOpen;
|
||||
},
|
||||
|
||||
doButtonSearch : function(button) {
|
||||
doButtonSearch: function(button) {
|
||||
if (!("engine" in button) || !button.engine)
|
||||
return;
|
||||
|
||||
|
@ -561,14 +561,14 @@ var BrowserUI = {
|
|||
getBrowser().loadURIWithFlags(submission.uri.spec, flags, null, null, submission.postData);
|
||||
},
|
||||
|
||||
updateStar : function() {
|
||||
updateStar: function() {
|
||||
if (PlacesUtils.getMostRecentBookmarkForURI(Browser.selectedBrowser.currentURI) != -1)
|
||||
this.starButton.setAttribute("starred", "true");
|
||||
else
|
||||
this.starButton.removeAttribute("starred");
|
||||
},
|
||||
|
||||
newTab : function newTab(aURI, aOwner) {
|
||||
newTab: function newTab(aURI, aOwner) {
|
||||
aURI = aURI || "about:blank";
|
||||
let tab = Browser.addTab(aURI, true, aOwner);
|
||||
|
||||
|
@ -598,15 +598,24 @@ var BrowserUI = {
|
|||
this.newTab(aURI, aOwner);
|
||||
},
|
||||
|
||||
closeTab : function closeTab(aTab) {
|
||||
closeTab: function closeTab(aTab) {
|
||||
// If no tab is passed in, assume the current tab
|
||||
Browser.closeTab(aTab || Browser.selectedTab);
|
||||
},
|
||||
|
||||
selectTab : function selectTab(aTab) {
|
||||
selectTab: function selectTab(aTab) {
|
||||
Browser.selectedTab = aTab;
|
||||
},
|
||||
|
||||
undoCloseTab: function undoCloseTab(aIndex) {
|
||||
let tab = null;
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
if (ss.getClosedTabCount(window) > (aIndex || 0)) {
|
||||
tab = ss.undoCloseTab(window, aIndex || 0);
|
||||
}
|
||||
return tab;
|
||||
},
|
||||
|
||||
isTabsVisible: function isTabsVisible() {
|
||||
// The _1, _2 and _3 are to make the js2 emacs mode happy
|
||||
let [leftvis,_1,_2,_3] = Browser.computeSidebarVisibility();
|
||||
|
@ -824,6 +833,7 @@ var BrowserUI = {
|
|||
case "cmd_menu":
|
||||
case "cmd_newTab":
|
||||
case "cmd_closeTab":
|
||||
case "cmd_undoCloseTab":
|
||||
case "cmd_actions":
|
||||
case "cmd_panel":
|
||||
case "cmd_sanitize":
|
||||
|
@ -916,6 +926,9 @@ var BrowserUI = {
|
|||
case "cmd_closeTab":
|
||||
this.closeTab();
|
||||
break;
|
||||
case "cmd_undoCloseTab":
|
||||
this.undoCloseTab();
|
||||
break;
|
||||
case "cmd_sanitize":
|
||||
{
|
||||
// disable the button temporarily to indicate something happened
|
||||
|
|
|
@ -200,8 +200,8 @@ function onDebugKeyPress(ev) {
|
|||
const q = 81; // toggle orientation
|
||||
const r = 82; // reset visible rect
|
||||
const s = 83;
|
||||
const t = 84; // debug given list of tiles separated by space
|
||||
const u = 85;
|
||||
const t = 84;
|
||||
const u = 85; // debug given list of tiles separated by space
|
||||
const v = 86;
|
||||
const w = 87;
|
||||
const x = 88;
|
||||
|
@ -278,7 +278,7 @@ function onDebugKeyPress(ev) {
|
|||
case b:
|
||||
window.tileMapMode = true;
|
||||
break;
|
||||
case t:
|
||||
case u:
|
||||
let ijstrs = window.prompt('row,col plz').split(' ');
|
||||
for each (let ijstr in ijstrs) {
|
||||
let [i, j] = ijstr.split(',').map(function (x) { return parseInt(x); });
|
||||
|
@ -2584,6 +2584,7 @@ Tab.prototype = {
|
|||
|
||||
// Create the browser using the current width the dynamically size the height
|
||||
let browser = this._browser = document.createElement("browser");
|
||||
this._chromeTab.linkedBrowser = browser;
|
||||
|
||||
browser.setAttribute("style", "overflow: -moz-hidden-unscrollable; visibility: hidden;");
|
||||
browser.setAttribute("type", "content");
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
<command id="cmd_newTab" label="&newtab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
|
||||
<command id="cmd_closeTab" label="&closetab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
|
||||
<command id="cmd_remoteTabs" oncommand="WeaveGlue.openRemoteTabs();"/>
|
||||
<command id="cmd_undoCloseTab" oncommand="CommandUpdater.doCommand(this.id);"/>
|
||||
|
||||
<!-- bookmarking -->
|
||||
<command id="cmd_star" label="&star.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
|
||||
|
@ -185,6 +186,7 @@
|
|||
<!-- tabs -->
|
||||
<key id="key_newTab" key="t" modifiers="accel" command="cmd_newTab"/>
|
||||
<key id="key_closeTab" key="w" modifiers="accel" command="cmd_closeTab"/>
|
||||
<key id="key_undoCloseTab" key="t" modifiers="accel,shift" command="cmd_undoCloseTab"/>
|
||||
</keyset>
|
||||
|
||||
<stack flex="1" id="stack">
|
||||
|
|
|
@ -58,6 +58,7 @@ _BROWSER_FILES = \
|
|||
browser_viewport.js \
|
||||
browser_navigation.js \
|
||||
browser_preferences_basic.js \
|
||||
browser_sessionstore.js \
|
||||
browser_blank_01.html \
|
||||
browser_blank_02.html \
|
||||
browser_select.html \
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
var testURL = "chrome://mochikit/content/browser/mobile/chrome/browser_blank_01.html";
|
||||
|
||||
// A queue to order the tests and a handle for each test
|
||||
var gTests = [];
|
||||
var gCurrentTest = null;
|
||||
|
||||
function pageLoaded(url) {
|
||||
return function() {
|
||||
let tab = gCurrentTest._tab;
|
||||
return !tab.isLoading() && tab.browser.currentURI.spec == url;
|
||||
}
|
||||
}
|
||||
|
||||
var ss = null;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Entry point (must be named "test")
|
||||
function test() {
|
||||
// The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()"
|
||||
// We call "finish()" when the tests are finished
|
||||
waitForExplicitFinish();
|
||||
|
||||
ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
|
||||
// Start the tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Iterating tests by shifting test out one by one as runNextTest is called.
|
||||
function runNextTest() {
|
||||
// Run the next test until all tests completed
|
||||
if (gTests.length > 0) {
|
||||
gCurrentTest = gTests.shift();
|
||||
info(gCurrentTest.desc);
|
||||
gCurrentTest.run();
|
||||
}
|
||||
else {
|
||||
// Cleanup. All tests are completed at this point
|
||||
try {
|
||||
// Add any cleanup code here
|
||||
}
|
||||
finally {
|
||||
// We must finialize the tests
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Loading a page and test setting tab values
|
||||
gTests.push({
|
||||
desc: "Loading a page and test setting tab values",
|
||||
_tab: null,
|
||||
|
||||
run: function() {
|
||||
Browser.addTab("about:blank", true);
|
||||
this._tab = Browser.addTab(testURL, true);
|
||||
|
||||
// Wait for the tab to load, then do the test
|
||||
waitFor(gCurrentTest.onPageReady, pageLoaded(testURL));
|
||||
},
|
||||
|
||||
onPageReady: function() {
|
||||
// Add some data
|
||||
ss.setTabValue(gCurrentTest._tab.chromeTab, "test1", "hello");
|
||||
is(ss.getTabValue(gCurrentTest._tab.chromeTab, "test1"), "hello", "Set/Get tab value matches");
|
||||
|
||||
// Close tab and then undo the close
|
||||
gCurrentTest.numTabs = Browser.tabs.length;
|
||||
gCurrentTest.numClosed = ss.getClosedTabCount(window);
|
||||
|
||||
Browser.closeTab(gCurrentTest._tab);
|
||||
|
||||
is(Browser.tabs.length, gCurrentTest.numTabs - 1, "Tab was closed");
|
||||
is(ss.getClosedTabCount(window), gCurrentTest.numClosed + 1, "Tab was stored");
|
||||
|
||||
// SessionStore works with chrome tab elements, not JS tab objects.
|
||||
// Map the _tab from chrome to JS
|
||||
gCurrentTest._tab = Browser.getTabFromChrome(ss.undoCloseTab(window, 0));
|
||||
|
||||
// Wait for the tab to load, then do the test
|
||||
waitFor(gCurrentTest.onPageUndo, pageLoaded(testURL));
|
||||
},
|
||||
|
||||
onPageUndo: function() {
|
||||
is(Browser.tabs.length, gCurrentTest.numTabs, "Tab was reopened");
|
||||
is(ss.getClosedTabCount(window), gCurrentTest.numClosed, "Tab was removed from store");
|
||||
|
||||
is(ss.getTabValue(gCurrentTest._tab.chromeTab, "test1"), "hello", "Set/Get tab value matches after un-close");
|
||||
|
||||
ss.deleteTabValue(gCurrentTest._tab.chromeTab, "test1");
|
||||
is(ss.getTabValue(gCurrentTest._tab.chromeTab, "test1"), "", "Set/Get tab value matches after removing value");
|
||||
|
||||
// Shutdown
|
||||
Browser.closeTab(gCurrentTest._tab);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
|
@ -43,8 +43,12 @@ VPATH = @srcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = browsercomps
|
||||
XPIDL_MODULE = browsercompsbase
|
||||
MODULE = MobileComponents
|
||||
XPIDL_MODULE = MobileComponents
|
||||
|
||||
XPIDLSRCS = \
|
||||
SessionStore.idl \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_COMPONENTS = \
|
||||
AboutRedirector.js \
|
||||
|
|
|
@ -26,14 +26,14 @@ category JavaScript-global-property sidebar @mozilla.org/sidebar;1
|
|||
category JavaScript-global-property external @mozilla.org/sidebar;1
|
||||
|
||||
# SessionStore.js
|
||||
component {90c3dfaf-4245-46d3-9bc1-1d8251ff8c01} SessionStore.js
|
||||
contract @mozilla.org/mobile/sessionstore;1 {90c3dfaf-4245-46d3-9bc1-1d8251ff8c01}
|
||||
category app-startup SessionStore service,@mozilla.org/mobile/sessionstore;1
|
||||
component {8c1f07d6-cba3-4226-a315-8bd43d67d032} SessionStore.js
|
||||
contract @mozilla.org/browser/sessionstore;1 {8c1f07d6-cba3-4226-a315-8bd43d67d032}
|
||||
category app-startup SessionStore service,@mozilla.org/browser/sessionstore;1
|
||||
|
||||
# BrowserStartup.js
|
||||
component {1d542abc-c88b-4636-a4ef-075b49806317} BrowserStartup.js
|
||||
contract @mozilla.org/mobile/browser-startup;1 {1d542abc-c88b-4636-a4ef-075b49806317}
|
||||
category app-startup BrowserStartup service,@mozilla.org/mobile/browser-startup;1
|
||||
contract @mozilla.org/browser/browser-startup;1 {1d542abc-c88b-4636-a4ef-075b49806317}
|
||||
category app-startup BrowserStartup service,@mozilla.org/browser/browser-startup;1
|
||||
category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
|
||||
category agent-style-sheets browser-cursor-stylesheet chrome://browser/content/cursor.css
|
||||
|
||||
|
@ -64,8 +64,8 @@ contract @mozilla.org/embedcomp/prompt-service;1 {9a61149b-2276-4a0a-b79c-be994a
|
|||
|
||||
# BrowserCLH.js
|
||||
component {be623d20-d305-11de-8a39-0800200c9a66} BrowserCLH.js
|
||||
contract @mozilla.org/mobile/browser-clh;1 {be623d20-d305-11de-8a39-0800200c9a66}
|
||||
category command-line-handler m-browser @mozilla.org/mobile/browser-clh;1
|
||||
contract @mozilla.org/browser/browser-clh;1 {be623d20-d305-11de-8a39-0800200c9a66}
|
||||
category command-line-handler m-browser @mozilla.org/browser/browser-clh;1
|
||||
|
||||
# ContentDispatchChooser.js
|
||||
component {5a072a22-1e66-4100-afc1-07aed8b62fc5} ContentDispatchChooser.js
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* ***** 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 Session Store component.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mark Finkle <mfinkle@mozilla.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 ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
interface nsIDOMNode;
|
||||
|
||||
/**
|
||||
* nsISessionStore keeps track of the current browsing state.
|
||||
*
|
||||
* The nsISessionStore API operates mostly on browser windows and the browser
|
||||
* tabs contained in them.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(a0a52a85-4032-41d7-b183-9d21009e0a65)]
|
||||
interface nsISessionStore : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the current browsing state.
|
||||
* @returns a JSON string representing the session state.
|
||||
*/
|
||||
AString getBrowserState();
|
||||
|
||||
/**
|
||||
* Get the number of restore-able tabs for a browser window
|
||||
*/
|
||||
unsigned long getClosedTabCount(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* Get closed tab data
|
||||
*
|
||||
* @param aWindow is the browser window for which to get closed tab data
|
||||
* @returns a JSON string representing the list of closed tabs.
|
||||
*/
|
||||
AString getClosedTabData(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* @param aWindow is the browser window to reopen a closed tab in.
|
||||
* @param aIndex is the index of the tab to be restored (FIFO ordered).
|
||||
* @returns a reference to the reopened tab.
|
||||
*/
|
||||
nsIDOMNode undoCloseTab(in nsIDOMWindow aWindow, in unsigned long aIndex);
|
||||
|
||||
/**
|
||||
* @param aWindow is the browser window associated with the closed tab.
|
||||
* @param aIndex is the index of the closed tab to be removed (FIFO ordered).
|
||||
*/
|
||||
nsIDOMNode forgetClosedTab(in nsIDOMWindow aWindow, in unsigned long aIndex);
|
||||
|
||||
/**
|
||||
* @param aTab is the browser tab to get the value for.
|
||||
* @param aKey is the value's name.
|
||||
*
|
||||
* @returns A string value or an empty string if none is set.
|
||||
*/
|
||||
AString getTabValue(in nsIDOMNode aTab, in AString aKey);
|
||||
|
||||
/**
|
||||
* @param aTab is the browser tab to set the value for.
|
||||
* @param aKey is the value's name.
|
||||
* @param aStringValue is the value itself (use JSON.stringify/parse before setting JS objects).
|
||||
*/
|
||||
void setTabValue(in nsIDOMNode aTab, in AString aKey, in AString aStringValue);
|
||||
|
||||
/**
|
||||
* @param aTab is the browser tab to get the value for.
|
||||
* @param aKey is the value's name.
|
||||
*/
|
||||
void deleteTabValue(in nsIDOMNode aTab, in AString aKey);
|
||||
};
|
|
@ -37,6 +37,7 @@
|
|||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -62,13 +63,17 @@ const STATE_QUITTING = -1;
|
|||
function SessionStore() { }
|
||||
|
||||
SessionStore.prototype = {
|
||||
classID: Components.ID("{90c3dfaf-4245-46d3-9bc1-1d8251ff8c01}"),
|
||||
classID: Components.ID("{8c1f07d6-cba3-4226-a315-8bd43d67d032}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionStore,
|
||||
Ci.nsIDOMEventListener,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
_windows: {},
|
||||
_lastSaveTime: 0,
|
||||
_interval: 15000,
|
||||
_maxTabsUndo: 5,
|
||||
|
||||
init: function ss_init() {
|
||||
// Get file references
|
||||
|
@ -90,6 +95,7 @@ SessionStore.prototype = {
|
|||
|
||||
try {
|
||||
this._interval = Services.prefs.getIntPref("sessionstore.interval");
|
||||
this._maxTabsUndo = Services.prefs.getIntPref("sessionstore.max_tabs_undo");
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
|
@ -171,18 +177,30 @@ SessionStore.prototype = {
|
|||
this.onTabLoad(window, aEvent.currentTarget, aEvent);
|
||||
break;
|
||||
case "TabOpen":
|
||||
case "TabClose":
|
||||
let browser = window.Browser.getTabFromChrome(aEvent.originalTarget).browser;
|
||||
case "TabClose": {
|
||||
let browser = aEvent.originalTarget.linkedBrowser;
|
||||
if (aEvent.type == "TabOpen") {
|
||||
this.onTabAdd(window, browser);
|
||||
}
|
||||
else {
|
||||
this.onTabClose(window, aEvent.originalTarget);
|
||||
this.onTabClose(window, browser);
|
||||
this.onTabRemove(window, browser);
|
||||
}
|
||||
break;
|
||||
case "TabSelect":
|
||||
this.onTabSelect(window);
|
||||
}
|
||||
case "TabSelect": {
|
||||
let browser = aEvent.originalTarget.linkedBrowser;
|
||||
this.onTabSelect(window, browser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function ss_receiveMessage(aMessage) {
|
||||
let window = aMessage.target.ownerDocument.defaultView;
|
||||
switch (aMessage.name) {
|
||||
case "pageshow":
|
||||
this.onTabLoad(window, aMessage.target, aMessage);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -198,7 +216,7 @@ SessionStore.prototype = {
|
|||
|
||||
// Assign it a unique identifier (timestamp) and create its data object
|
||||
aWindow.__SSID = "window" + Date.now();
|
||||
this._windows[aWindow.__SSID] = { tabs: [], selected: 0 };
|
||||
this._windows[aWindow.__SSID] = { tabs: [], selected: 0, closedTabs: [] };
|
||||
|
||||
// Perform additional initialization when the first window is loading
|
||||
if (this._loadState == STATE_STOPPED) {
|
||||
|
@ -247,46 +265,62 @@ SessionStore.prototype = {
|
|||
},
|
||||
|
||||
onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
|
||||
aBrowser.addEventListener("load", this, true);
|
||||
aBrowser.addEventListener("pageshow", this, true);
|
||||
aBrowser.messageManager.addMessageListener("pageshow", this, true);
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
|
||||
if (!aNoNotification)
|
||||
this.saveStateDelayed();
|
||||
this._updateCrashReportURL(aWindow);
|
||||
},
|
||||
|
||||
onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
|
||||
aBrowser.removeEventListener("load", this, true);
|
||||
aBrowser.removeEventListener("pageshow", this, true);
|
||||
aBrowser.messageManager.removeMessageListener("pageshow", this, true);
|
||||
|
||||
delete aBrowser.__SS_data;
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
if (!aNoNotification)
|
||||
this.saveStateDelayed();
|
||||
},
|
||||
|
||||
onTabClose: function ss_onTabClose(aWindow, aTab) {
|
||||
},
|
||||
|
||||
onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aEvent) {
|
||||
// react on "load" and solitary "pageshow" events (the first "pageshow"
|
||||
// following "load" is too late for deleting the data caches)
|
||||
if (aEvent.type != "load" && !aEvent.persisted) {
|
||||
onTabClose: function ss_onTabClose(aWindow, aBrowser) {
|
||||
if (this._maxTabsUndo == 0)
|
||||
return;
|
||||
|
||||
if (aWindow.Browser.tabs.length > 0) {
|
||||
// Bundle this browser's data and extra data and save in the closedTabs
|
||||
// window property
|
||||
let data = aBrowser.__SS_data;
|
||||
data.extraData = aBrowser.__SS_extdata;
|
||||
|
||||
this._windows[aWindow.__SSID].closedTabs.unshift(data);
|
||||
let length = this._windows[aWindow.__SSID].closedTabs.length;
|
||||
if (length > this._maxTabsUndo)
|
||||
this._windows[aWindow.__SSID].closedTabs.splice(this._maxTabsUndo, length - this._maxTabsUndo);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aMessage) {
|
||||
delete aBrowser.__SS_data;
|
||||
this._collectTabData(aBrowser);
|
||||
|
||||
this.saveStateDelayed(aWindow);
|
||||
|
||||
this.saveStateDelayed();
|
||||
this._updateCrashReportURL(aWindow);
|
||||
},
|
||||
|
||||
onTabSelect: function ss_onTabSelect(aWindow) {
|
||||
onTabSelect: function ss_onTabSelect(aWindow, aBrowser) {
|
||||
if (this._loadState != STATE_RUNNING)
|
||||
return;
|
||||
|
||||
let index = 0;
|
||||
let browser = aWindow.Browser;
|
||||
let tabs = browser.tabs;
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
if (tabs[i].browser == aBrowser) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._windows[aWindow.__SSID].selected = index + 1; // 1-based
|
||||
this._updateCrashReportURL(aWindow);
|
||||
},
|
||||
|
||||
|
@ -308,6 +342,13 @@ SessionStore.prototype = {
|
|||
},
|
||||
|
||||
saveState: function ss_saveState() {
|
||||
let data = this._getCurrentState();
|
||||
this._writeFile(this._sessionFile, JSON.stringify(data));
|
||||
|
||||
this._lastSaveTime = Date.now();
|
||||
},
|
||||
|
||||
_getCurrentState: function ss_getCurrentState() {
|
||||
let self = this;
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
self._collectWindowData(aWindow);
|
||||
|
@ -317,14 +358,15 @@ SessionStore.prototype = {
|
|||
let index;
|
||||
for (index in this._windows)
|
||||
data.windows.push(this._windows[index]);
|
||||
|
||||
this._writeFile(this._sessionFile, JSON.stringify(data));
|
||||
|
||||
this._lastSaveTime = Date.now();
|
||||
return data;
|
||||
},
|
||||
|
||||
|
||||
_collectTabData: function ss__collectTabData(aBrowser) {
|
||||
let tabData = { url: aBrowser.currentURI.spec, title: aBrowser.contentTitle };
|
||||
let tabData = { entries: [{}] };
|
||||
tabData.entries[0] = { url: aBrowser.currentURI.spec, title: aBrowser.contentTitle };
|
||||
tabData.index = 1;
|
||||
tabData.attributes = { image: aBrowser.mIconURL };
|
||||
|
||||
aBrowser.__SS_data = tabData;
|
||||
},
|
||||
|
||||
|
@ -338,8 +380,13 @@ SessionStore.prototype = {
|
|||
|
||||
let tabs = aWindow.Browser.tabs;
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
if (tabs[i].browser.__SS_data)
|
||||
winData.tabs.push(tabs[i].browser.__SS_data);
|
||||
if (tabs[i].browser.__SS_data) {
|
||||
let browser = tabs[i].browser;
|
||||
let tabData = browser.__SS_data;
|
||||
if (browser.__SS_extdata)
|
||||
tabData.extData = browser.__SS_extdata;
|
||||
winData.tabs.push(tabData);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -396,6 +443,89 @@ SessionStore.prototype = {
|
|||
Components.utils.reportError("SessionStore:" + ex);
|
||||
}
|
||||
#endif
|
||||
},
|
||||
|
||||
getBrowserState: function ss_getBrowserState() {
|
||||
let data = this._getCurrentState();
|
||||
return JSON.stringify(data);
|
||||
},
|
||||
|
||||
getClosedTabCount: function ss_getClosedTabCount(aWindow) {
|
||||
if (!aWindow || !aWindow.__SSID)
|
||||
return 0; // not a browser window, or not otherwise tracked by SS.
|
||||
|
||||
return this._windows[aWindow.__SSID].closedTabs.length;
|
||||
},
|
||||
|
||||
getClosedTabData: function ss_getClosedTabData(aWindow) {
|
||||
if (!aWindow.__SSID)
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
return JSON.stringify(this._windows[aWindow.__SSID].closedTabs);
|
||||
},
|
||||
|
||||
undoCloseTab: function ss_undoCloseTab(aWindow, aIndex) {
|
||||
if (!aWindow.__SSID)
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let closedTabs = this._windows[aWindow.__SSID].closedTabs;
|
||||
if (!closedTabs)
|
||||
return null;
|
||||
|
||||
// default to the most-recently closed tab
|
||||
aIndex = aIndex || 0;
|
||||
if (!(aIndex in closedTabs))
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
// fetch the data of closed tab, while removing it from the array
|
||||
let closedTab = closedTabs.splice(aIndex, 1).shift();
|
||||
|
||||
// create a new tab and bring to front
|
||||
let tab = aWindow.Browser.addTab(closedTab.entries[0].url, true);
|
||||
|
||||
// Put back the extra data
|
||||
tab.browser.__SS_extdata = closedTab.extraData;
|
||||
|
||||
// TODO: save and restore more data (position, field values, etc)
|
||||
|
||||
return tab.chromeTab;
|
||||
},
|
||||
|
||||
forgetClosedTab: function ss_forgetClosedTab(aWindow, aIndex) {
|
||||
if (!aWindow.__SSID)
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let closedTabs = this._windows[aWindow.__SSID].closedTabs;
|
||||
|
||||
// default to the most-recently closed tab
|
||||
aIndex = aIndex || 0;
|
||||
if (!(aIndex in closedTabs))
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
// remove closed tab from the array
|
||||
closedTabs.splice(aIndex, 1);
|
||||
},
|
||||
|
||||
getTabValue: function ss_getTabValue(aTab, aKey) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
let data = browser.__SS_extdata || {};
|
||||
return data[aKey] || "";
|
||||
},
|
||||
|
||||
setTabValue: function ss_setTabValue(aTab, aKey, aStringValue) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
if (!browser.__SS_extdata)
|
||||
browser.__SS_extdata = {};
|
||||
browser.__SS_extdata[aKey] = aStringValue;
|
||||
this.saveStateDelayed();
|
||||
},
|
||||
|
||||
deleteTabValue: function ss_deleteTabValue(aTab, aKey) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
if (browser.__SS_extdata && browser.__SS_extdata[aKey])
|
||||
delete browser.__SS_extdata[aKey];
|
||||
else
|
||||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче