Merge fx-team to m-c a=merge
@ -266,6 +266,10 @@
|
||||
label="&savePageCmd.label;"
|
||||
accesskey="&savePageCmd.accesskey2;"
|
||||
oncommand="gContextMenu.savePageAs();"/>
|
||||
<menuitem id="context-pocket"
|
||||
label="&saveToPocketCmd.label;"
|
||||
accesskey="&saveToPocketCmd.accesskey;"
|
||||
oncommand="gContextMenu.saveToPocket();"/>
|
||||
<menu id="context-markpageMenu" label="&social.markpageMenu.label;"
|
||||
accesskey="&social.markpageMenu.accesskey;">
|
||||
<menupopup/>
|
||||
|
@ -3,6 +3,8 @@
|
||||
%brandDTD;
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
|
||||
%browserDTD;
|
||||
<!ENTITY % browserPocketDTD SYSTEM "chrome://browser/content/browser-pocket.dtd" >
|
||||
%browserPocketDTD;
|
||||
<!ENTITY % baseMenuDTD SYSTEM "chrome://browser/locale/baseMenuOverlay.dtd" >
|
||||
%baseMenuDTD;
|
||||
<!ENTITY % charsetDTD SYSTEM "chrome://global/locale/charsetMenu.dtd" >
|
||||
|
@ -387,6 +387,7 @@
|
||||
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
|
||||
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
|
||||
onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event);
|
||||
BookmarkingUI.updatePocketItemVisibility('menu_');
|
||||
if (!this.parentNode._placesView)
|
||||
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
|
||||
tooltip="bhTooltip" popupsinherittooltip="true">
|
||||
@ -460,6 +461,9 @@
|
||||
</menupopup>
|
||||
</menu>
|
||||
#endif
|
||||
<menuseparator id="menu_pocketSeparator"/>
|
||||
<menuitem id="menu_pocket" label="&pocketMenuitem.label;"
|
||||
oncommand="openUILink(Pocket.listURL, event);"/>
|
||||
<menuseparator id="bookmarksMenuItemsSeparator"/>
|
||||
<!-- Bookmarks menu items -->
|
||||
<menuseparator builder="end"
|
||||
|
@ -1565,6 +1565,12 @@ let BookmarkingUI = {
|
||||
PlacesCommandHook.updateBookmarkAllTabsCommand();
|
||||
},
|
||||
|
||||
updatePocketItemVisibility: function BUI_updatePocketItemVisibility(prefix) {
|
||||
let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button");
|
||||
document.getElementById(prefix + "pocket").hidden = hidden;
|
||||
document.getElementById(prefix + "pocketSeparator").hidden = hidden;
|
||||
},
|
||||
|
||||
_showBookmarkedNotification: function BUI_showBookmarkedNotification() {
|
||||
function getCenteringTransformForRects(rectToPosition, referenceRect) {
|
||||
let topDiff = referenceRect.top - rectToPosition.top;
|
||||
@ -1682,6 +1688,7 @@ let BookmarkingUI = {
|
||||
|
||||
onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) {
|
||||
this._updateBookmarkPageMenuItem();
|
||||
this.updatePocketItemVisibility("panelMenu_");
|
||||
// Update checked status of the toolbar toggle.
|
||||
let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar");
|
||||
let personalToolbar = document.getElementById("PersonalToolbar");
|
||||
|
10
browser/base/content/browser-pocket.dtd
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- This is a temporary file and not meant for localization; later versions
|
||||
- of Firefox include these strings in browser.dtd -->
|
||||
|
||||
<!ENTITY saveToPocketCmd.label "Save Page to Pocket">
|
||||
<!ENTITY saveToPocketCmd.accesskey "k">
|
||||
<!ENTITY pocketMenuitem.label "View Pocket List">
|
@ -883,6 +883,7 @@
|
||||
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
|
||||
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
|
||||
onpopupshowing="BookmarkingUI.onPopupShowing(event);
|
||||
BookmarkingUI.updatePocketItemVisibility('BMB_');
|
||||
BookmarkingUI.attachPlacesView(event, this);"
|
||||
tooltip="bhTooltip" popupsinherittooltip="true">
|
||||
<menuitem id="BMB_viewBookmarksSidebar"
|
||||
@ -970,6 +971,11 @@
|
||||
label="&readingList.showSidebar.label;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator id="BMB_pocketSeparator"/>
|
||||
<menuitem id="BMB_pocket"
|
||||
class="menuitem-iconic bookmark-item subviewbutton"
|
||||
label="&pocketMenuitem.label;"
|
||||
oncommand="openUILink(Pocket.listURL, event);"/>
|
||||
<menuseparator/>
|
||||
<!-- Bookmarks menu items will go here -->
|
||||
<menuitem id="BMB_bookmarksShowAll"
|
||||
|
@ -177,6 +177,17 @@ nsContextMenu.prototype = {
|
||||
SimpleServiceDiscovery.services.length > 0 &&
|
||||
CastingApps.getServicesForVideo(this.target).length > 0;
|
||||
this.setItemAttr("context-castvideo", "disabled", !shouldShowCast);
|
||||
|
||||
let canPocket = false;
|
||||
if (shouldShow && window.gBrowser &&
|
||||
this.browser.getTabBrowser() == window.gBrowser) {
|
||||
let uri = this.browser.currentURI;
|
||||
canPocket =
|
||||
CustomizableUI.getPlacementOfWidget("pocket-button") &&
|
||||
(uri.schemeIs("http") || uri.schemeIs("https") ||
|
||||
(uri.schemeIs("about") && ReaderMode.getOriginalUrl(uri.spec)));
|
||||
}
|
||||
this.showItem("context-pocket", canPocket && window.Pocket && Pocket.isLoggedIn);
|
||||
},
|
||||
|
||||
initViewItems: function CM_initViewItems() {
|
||||
@ -1621,6 +1632,22 @@ nsContextMenu.prototype = {
|
||||
saveDocument(this.browser.contentDocumentAsCPOW);
|
||||
},
|
||||
|
||||
saveToPocket: function CM_saveToPocket() {
|
||||
let pocketWidget = document.getElementById("pocket-button");
|
||||
let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
|
||||
if (!placement)
|
||||
return;
|
||||
|
||||
if (placement.area == CustomizableUI.AREA_PANEL) {
|
||||
PanelUI.show().then(function() {
|
||||
pocketWidget = document.getElementById("pocket-button");
|
||||
pocketWidget.doCommand();
|
||||
});
|
||||
} else {
|
||||
pocketWidget.doCommand();
|
||||
}
|
||||
},
|
||||
|
||||
printFrame: function CM_printFrame() {
|
||||
PrintUtils.print(this.target.ownerDocument.defaultView, this.browser);
|
||||
},
|
||||
|
@ -1504,12 +1504,8 @@
|
||||
|
||||
// Change the "remote" attribute.
|
||||
let parent = aBrowser.parentNode;
|
||||
let permanentKey = aBrowser.permanentKey;
|
||||
parent.removeChild(aBrowser);
|
||||
aBrowser.setAttribute("remote", aShouldBeRemote ? "true" : "false");
|
||||
// Tearing down the browser gives a new permanentKey but we want to
|
||||
// keep the old one. Re-set it explicitly after unbinding from DOM.
|
||||
aBrowser._permanentKey = permanentKey;
|
||||
parent.appendChild(aBrowser);
|
||||
|
||||
// Restore the progress listener.
|
||||
@ -1628,6 +1624,7 @@
|
||||
let isPreloadBrowser = aParams && aParams.isPreloadBrowser;
|
||||
|
||||
let b = document.createElementNS(NS_XUL, "browser");
|
||||
b.permanentKey = {};
|
||||
b.setAttribute("type", "content-targetable");
|
||||
b.setAttribute("message", "true");
|
||||
b.setAttribute("messagemanagergroup", "browsers");
|
||||
@ -2491,6 +2488,11 @@
|
||||
// Swap the docshells
|
||||
ourBrowser.swapDocShells(aOtherBrowser);
|
||||
|
||||
// Swap permanentKey properties.
|
||||
let ourPermanentKey = ourBrowser.permanentKey;
|
||||
ourBrowser.permanentKey = aOtherBrowser.permanentKey;
|
||||
aOtherBrowser.permanentKey = ourPermanentKey;
|
||||
|
||||
// Restore the progress listener
|
||||
this.mTabListeners[index] = tabListener =
|
||||
this.mTabProgressListener(aOurTab, ourBrowser, false);
|
||||
@ -3876,6 +3878,7 @@
|
||||
<![CDATA[
|
||||
let browserStack = document.getAnonymousElementByAttribute(this, "anonid", "browserStack");
|
||||
this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
|
||||
this.mCurrentBrowser.permanentKey = {};
|
||||
|
||||
this.mCurrentTab = this.tabContainer.firstChild;
|
||||
const nsIEventListenerService =
|
||||
|
@ -19,9 +19,9 @@ function test() {
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
ok(isUndoCloseEnabled(), "Undo Close Tab should be enabled.");
|
||||
|
||||
finish();
|
||||
BrowserTestUtils.removeTab(tab).then(() => {
|
||||
ok(isUndoCloseEnabled(), "Undo Close Tab should be enabled.");
|
||||
finish();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
@ -34,14 +34,15 @@ function preparePendingTab(aCallback) {
|
||||
let tab = gBrowser.addTab(URL);
|
||||
|
||||
whenLoaded(tab.linkedBrowser, function () {
|
||||
gBrowser.removeTab(tab);
|
||||
let [{state}] = JSON.parse(SessionStore.getClosedTabData(window));
|
||||
BrowserTestUtils.removeTab(tab).then(() => {
|
||||
let [{state}] = JSON.parse(SessionStore.getClosedTabData(window));
|
||||
|
||||
tab = gBrowser.addTab("about:blank");
|
||||
whenLoaded(tab.linkedBrowser, function () {
|
||||
SessionStore.setTabState(tab, JSON.stringify(state));
|
||||
ok(tab.hasAttribute("pending"), "tab should be pending");
|
||||
aCallback(tab);
|
||||
tab = gBrowser.addTab("about:blank");
|
||||
whenLoaded(tab.linkedBrowser, function () {
|
||||
SessionStore.setTabState(tab, JSON.stringify(state));
|
||||
ok(tab.hasAttribute("pending"), "tab should be pending");
|
||||
aCallback(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ add_task(function*() {
|
||||
let tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.loadURI(uri);
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
TabState.flush(tab.linkedBrowser);
|
||||
|
||||
let key = tab.linkedBrowser.permanentKey;
|
||||
let win = gBrowser.replaceTabWithWindow(tab);
|
||||
|
@ -12,6 +12,8 @@
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
<!ENTITY % browserPocketDTD SYSTEM "chrome://browser/content/browser-pocket.dtd">
|
||||
%browserPocketDTD;
|
||||
<!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd">
|
||||
%textcontextDTD;
|
||||
]>
|
||||
|
@ -76,6 +76,7 @@ browser.jar:
|
||||
* content/browser/browser.js (content/browser.js)
|
||||
* content/browser/browser.xul (content/browser.xul)
|
||||
content/browser/browser-pocket.properties (content/browser-pocket.properties)
|
||||
content/browser/browser-pocket.dtd (content/browser-pocket.dtd)
|
||||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
* content/browser/chatWindow.xul (content/chatWindow.xul)
|
||||
content/browser/tab-content.js (content/tab-content.js)
|
||||
|
@ -137,6 +137,10 @@
|
||||
<observes element="readingListSidebar" attribute="checked"/>
|
||||
<observes element="readingListSidebar" attribute="hidden"/>
|
||||
</toolbarbutton>
|
||||
<toolbarseparator id="panelMenu_pocketSeparator"/>
|
||||
<toolbarbutton id="panelMenu_pocket" label="&pocketMenuitem.label;"
|
||||
class="subviewbutton cui-withicon"
|
||||
oncommand="openUILink(Pocket.listURL, event);"/>
|
||||
<toolbarseparator class="small-separator"/>
|
||||
<toolbaritem id="panelMenu_bookmarksMenu"
|
||||
orient="vertical"
|
||||
|
@ -1,12 +1,14 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from distutils import spawn
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
import argparse
|
||||
|
||||
|
||||
def find_react_version(lib_dir):
|
||||
"Finds the React library version number currently used."
|
||||
for filename in os.listdir(lib_dir):
|
||||
@ -17,28 +19,82 @@ def find_react_version(lib_dir):
|
||||
print 'Please checked the %s directory.' % lib_dir
|
||||
exit(1)
|
||||
|
||||
|
||||
def append_arguments(array1, array2):
|
||||
"Appends array2 onto the end of array1"
|
||||
result = array1[:]
|
||||
result.extend(array2)
|
||||
return result
|
||||
|
||||
|
||||
def check_jsx(jsx_path):
|
||||
"Checks to see if jsx is installed or not"
|
||||
if jsx_path is None:
|
||||
print 'You do not have the react-tools installed'
|
||||
print 'Please do $ npm install -g react-tools and make sure it is available in PATH'
|
||||
exit(1)
|
||||
|
||||
|
||||
def find_react_command():
|
||||
"Searches for a jsx location and forms a runnable command"
|
||||
if sys.platform != 'win32':
|
||||
jsx_path = spawn.find_executable('jsx')
|
||||
check_jsx(jsx_path)
|
||||
return [jsx_path]
|
||||
|
||||
# Else windows.
|
||||
def find_excutable_no_extension(fileName):
|
||||
"""
|
||||
spawn.find_executable assumes a '.exe' extension on windows
|
||||
something which jsx doesn't have...
|
||||
"""
|
||||
paths = os.environ['PATH'].split(os.pathsep)
|
||||
for path in paths:
|
||||
file = os.path.join(path, fileName)
|
||||
if os.path.isfile(file):
|
||||
return path
|
||||
return None
|
||||
|
||||
# jsx isn't a true windows executable, so the standard spawn
|
||||
# processes get upset. Hence, we have to use node to run the
|
||||
# jsx file direct.
|
||||
node = spawn.find_executable('node')
|
||||
if node is None:
|
||||
print 'You do not have node installed, or it is not in your PATH'
|
||||
exit(1)
|
||||
|
||||
# We need the jsx path to make node happy
|
||||
jsx_path = find_excutable_no_extension('jsx')
|
||||
check_jsx(jsx_path)
|
||||
|
||||
# This is what node really wants to run.
|
||||
jsx_path = os.path.join(jsx_path,
|
||||
"node_modules", "react-tools", "bin", "jsx")
|
||||
|
||||
return [node, jsx_path]
|
||||
|
||||
|
||||
SHARED_LIBS_DIR=os.path.join(os.path.dirname(__file__), "content", "shared", "libs")
|
||||
REACT_VERSION=find_react_version(SHARED_LIBS_DIR)
|
||||
|
||||
src_files = [] # files to be compiled
|
||||
|
||||
# search for react-tools install
|
||||
jsx_path = spawn.find_executable('jsx')
|
||||
if jsx_path is None:
|
||||
print 'You do not have the react-tools installed'
|
||||
print 'Please do $ npm install -g react-tools'
|
||||
exit(1)
|
||||
run_command = find_react_command()
|
||||
|
||||
p = subprocess.Popen([jsx_path, '-V'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
for line in iter(p.stdout.readline, b''):
|
||||
info = line.rstrip()
|
||||
if sys.platform == 'win32':
|
||||
print 'Please ensure you are running react-tools version %s' % REACT_VERSION
|
||||
print 'You may be already, but we are not currently able to detect it'
|
||||
else:
|
||||
p = subprocess.Popen(append_arguments(run_command, ['-V']),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
for line in iter(p.stdout.readline, b''):
|
||||
info = line.rstrip()
|
||||
|
||||
if not info == REACT_VERSION:
|
||||
print 'You have the wrong version of react-tools installed'
|
||||
print 'Please use version %s' % REACT_VERSION
|
||||
exit(1)
|
||||
if not info == REACT_VERSION:
|
||||
print 'You have the wrong version of react-tools installed'
|
||||
print 'Please use version %s' % REACT_VERSION
|
||||
exit(1)
|
||||
|
||||
# parse the CLI arguments
|
||||
description = 'Loop build tool for JSX files. ' + \
|
||||
@ -63,7 +119,7 @@ for dirname, dirnames, filenames in os.walk('.'):
|
||||
|
||||
|
||||
def jsx_run_watcher(path):
|
||||
subprocess.call(['jsx', '-w', '-x', 'jsx', path, path])
|
||||
subprocess.call(append_arguments(run_command, ['-w', '-x', 'jsx', path, path]))
|
||||
|
||||
|
||||
def start_jsx_watcher_threads(dirs):
|
||||
@ -111,4 +167,4 @@ if args.watch:
|
||||
start_jsx_watcher_threads(unique_jsx_dirs)
|
||||
else:
|
||||
for d in unique_jsx_dirs:
|
||||
out = subprocess.call(['jsx', '-x', 'jsx', d, d])
|
||||
out = subprocess.call(append_arguments(run_command, ['-x', 'jsx', d, d]))
|
||||
|
@ -14,7 +14,7 @@
|
||||
"devDependencies": {
|
||||
"eslint": "0.20.x",
|
||||
"eslint-plugin-react": "2.2.x",
|
||||
"express": "3.x"
|
||||
"express": "4.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test",
|
||||
|
@ -13,10 +13,16 @@ var express = require('express');
|
||||
var app = express();
|
||||
|
||||
var port = process.env.PORT || 3000;
|
||||
var loopServerPort = process.env.LOOP_SERVER_PORT || 5000;
|
||||
var feedbackApiUrl = process.env.LOOP_FEEDBACK_API_URL ||
|
||||
"https://input.allizom.org/api/v1/feedback";
|
||||
var feedbackProductName = process.env.LOOP_FEEDBACK_PRODUCT_NAME || "Loop";
|
||||
var loopServerUrl = process.env.LOOP_SERVER_URL || "http://localhost:5000";
|
||||
|
||||
// Remove trailing slashes as double slashes in the url can confuse the server
|
||||
// responses.
|
||||
if (loopServerUrl[loopServerUrl.length - 1] === "/") {
|
||||
loopServerUrl = loopServerUrl.slice(0, -1);
|
||||
}
|
||||
|
||||
function getConfigFile(req, res) {
|
||||
"use strict";
|
||||
@ -25,7 +31,7 @@ function getConfigFile(req, res) {
|
||||
res.send([
|
||||
"var loop = loop || {};",
|
||||
"loop.config = loop.config || {};",
|
||||
"loop.config.serverUrl = 'http://localhost:" + loopServerPort + "/v0';",
|
||||
"loop.config.serverUrl = '" + loopServerUrl + "/v0';",
|
||||
"loop.config.feedbackApiUrl = '" + feedbackApiUrl + "';",
|
||||
"loop.config.feedbackProductName = '" + feedbackProductName + "';",
|
||||
// XXX Update with the real marketplace url once the FxOS Loop app is
|
||||
@ -54,7 +60,6 @@ app.get('/content/c/config.js', getConfigFile);
|
||||
// /ui - for the ui showcase
|
||||
// /content - for the standalone files.
|
||||
|
||||
app.use('/test', express.static(__dirname + '/../test'));
|
||||
app.use('/ui', express.static(__dirname + '/../ui'));
|
||||
|
||||
// This exists exclusively for the unit tests. They are served the
|
||||
@ -71,6 +76,10 @@ app.use('/content', express.static(__dirname + '/../content'));
|
||||
app.use('/content/c', express.static(__dirname + '/content'));
|
||||
app.use('/content/c', express.static(__dirname + '/../content'));
|
||||
|
||||
// Two lines for the same reason as /content above.
|
||||
app.use('/test', express.static(__dirname + '/test'));
|
||||
app.use('/test', express.static(__dirname + '/../test'));
|
||||
|
||||
// As we don't have hashes on the urls, the best way to serve the index files
|
||||
// appears to be to be to closely filter the url and match appropriately.
|
||||
function serveIndex(req, res) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
# Loop server configuration
|
||||
CONTENT_SERVER_PORT = 3001
|
||||
LOOP_SERVER_PORT = 5001
|
||||
LOOP_SERVER_URL = "http://localhost:" + str(LOOP_SERVER_PORT)
|
||||
FIREFOX_PREFERENCES = {
|
||||
"loop.server": "http://localhost:" + str(LOOP_SERVER_PORT),
|
||||
"loop.server": LOOP_SERVER_URL + "/v0",
|
||||
"browser.dom.window.dump.enabled": True,
|
||||
# Some more changes might be necesarry to have this working in offline mode
|
||||
"media.peerconnection.default_iceservers": "[]",
|
||||
|
@ -21,7 +21,7 @@ CONTENT_SERVER_ENV = os.environ.copy()
|
||||
# Set PORT so that it does not interfere with any other
|
||||
# development server that might be running
|
||||
CONTENT_SERVER_ENV.update({"PORT": str(CONTENT_SERVER_PORT),
|
||||
"LOOP_SERVER_PORT": str(LOOP_SERVER_PORT)})
|
||||
"LOOP_SERVER_URL": LOOP_SERVER_URL})
|
||||
|
||||
ROOMS_WEB_APP_URL = "http://localhost:" + str(CONTENT_SERVER_PORT) + \
|
||||
"/content/{token}"
|
||||
@ -32,7 +32,7 @@ LOOP_SERVER_ENV = os.environ.copy()
|
||||
# development server that might be running
|
||||
LOOP_SERVER_ENV.update({"NODE_ENV": "dev",
|
||||
"PORT": str(LOOP_SERVER_PORT),
|
||||
"SERVER_ADDRESS": "localhost:" + str(LOOP_SERVER_PORT),
|
||||
"SERVER_ADDRESS": LOOP_SERVER_URL,
|
||||
"ROOMS_WEB_APP_URL": ROOMS_WEB_APP_URL})
|
||||
|
||||
|
||||
|
@ -29,6 +29,8 @@ let Pocket = {
|
||||
|
||||
get hostname() Services.prefs.getCharPref("browser.pocket.hostname"),
|
||||
|
||||
get listURL() { return "https://" + Pocket.hostname; },
|
||||
|
||||
get _accessToken() {
|
||||
let sessionId, accessToken;
|
||||
let cookies = Services.cookies.getCookiesFromHost(this.hostname);
|
||||
|
@ -16,6 +16,8 @@ browser.jar:
|
||||
content/browser/pocket/panels/img/pocketlogo@2x.png (panels/img/pocketlogo@2x.png)
|
||||
content/browser/pocket/panels/img/pocketlogosolo@1x.png (panels/img/pocketlogosolo@1x.png)
|
||||
content/browser/pocket/panels/img/pocketlogosolo@2x.png (panels/img/pocketlogosolo@2x.png)
|
||||
content/browser/pocket/panels/img/pocketmenuitem16.png (panels/img/pocketmenuitem16.png)
|
||||
content/browser/pocket/panels/img/pocketmenuitem16@2x.png (panels/img/pocketmenuitem16@2x.png)
|
||||
content/browser/pocket/panels/img/pocketmultidevices@1x.png (panels/img/pocketmultidevices@1x.png)
|
||||
content/browser/pocket/panels/img/pocketmultidevices@2x.png (panels/img/pocketmultidevices@2x.png)
|
||||
content/browser/pocket/panels/img/signup_firefoxlogo@1x.png (panels/img/signup_firefoxlogo@1x.png)
|
||||
|
BIN
browser/components/pocket/panels/img/pocketmenuitem16.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
browser/components/pocket/panels/img/pocketmenuitem16@2x.png
Normal file
After Width: | Height: | Size: 422 B |
@ -10,19 +10,21 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
|
||||
const ENGINE_FLAVOR = "text/x-moz-search-engine";
|
||||
|
||||
document.addEventListener("Initialized", () => {
|
||||
if (Services.prefs.getBoolPref("browser.search.showOneOffButtons"))
|
||||
return;
|
||||
|
||||
document.getElementById("category-search").hidden = true;
|
||||
if (document.location.hash == "#search")
|
||||
document.location.hash = "";
|
||||
});
|
||||
|
||||
var gEngineView = null;
|
||||
|
||||
var gSearchPane = {
|
||||
|
||||
init: function ()
|
||||
{
|
||||
if (!Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
|
||||
document.getElementById("category-search").hidden = true;
|
||||
if (document.location.hash == "#search")
|
||||
document.location.hash = "";
|
||||
return;
|
||||
}
|
||||
|
||||
gEngineView = new EngineView(new EngineStore());
|
||||
document.getElementById("engineList").view = gEngineView;
|
||||
this.buildDefaultEngineDropDown();
|
||||
|
@ -92,6 +92,9 @@ const NOTAB_MESSAGES = new Set([
|
||||
const CLOSED_MESSAGES = new Set([
|
||||
// For a description see above.
|
||||
"SessionStore:crashedTabRevived",
|
||||
|
||||
// For a description see above.
|
||||
"SessionStore:update",
|
||||
]);
|
||||
|
||||
// These are tab events that we listen to.
|
||||
@ -338,6 +341,15 @@ let SessionStoreInternal = {
|
||||
// they get restored).
|
||||
_crashedBrowsers: new WeakSet(),
|
||||
|
||||
// A map (xul:browser -> nsIFrameLoader) that maps a browser to the last
|
||||
// associated frameLoader we heard about.
|
||||
_lastKnownFrameLoader: new WeakMap(),
|
||||
|
||||
// A map (xul:browser -> object) that maps a browser associated with a
|
||||
// recently closed tab to all its necessary state information we need to
|
||||
// properly handle final update message.
|
||||
_closedTabs: new WeakMap(),
|
||||
|
||||
// whether a setBrowserState call is in progress
|
||||
_browserSetState: false,
|
||||
|
||||
@ -612,14 +624,64 @@ let SessionStoreInternal = {
|
||||
TabState.setSyncHandler(browser, aMessage.objects.handler);
|
||||
break;
|
||||
case "SessionStore:update":
|
||||
// Ignore messages from <browser> elements that have crashed
|
||||
// and not yet been revived.
|
||||
if (this._crashedBrowsers.has(browser.permanentKey)) {
|
||||
// Ignore messages from <browser> elements that have crashed
|
||||
// and not yet been revived.
|
||||
return;
|
||||
}
|
||||
|
||||
// |browser.frameLoader| might be empty if the browser was already
|
||||
// destroyed and its tab removed. In that case we still have the last
|
||||
// frameLoader we know about to compare.
|
||||
let frameLoader = browser.frameLoader ||
|
||||
this._lastKnownFrameLoader.get(browser.permanentKey);
|
||||
|
||||
// If the message isn't targeting the latest frameLoader discard it.
|
||||
if (frameLoader != aMessage.targetFrameLoader) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record telemetry measurements done in the child and update the tab's
|
||||
// cached state. Mark the window as dirty and trigger a delayed write.
|
||||
this.recordTelemetry(aMessage.data.telemetry);
|
||||
TabState.update(browser, aMessage.data);
|
||||
this.saveStateDelayed(win);
|
||||
|
||||
// Handle any updates sent by the child after the tab was closed. This
|
||||
// might be the final update as sent by the "unload" handler but also
|
||||
// any async update message that was sent before the child unloaded.
|
||||
if (this._closedTabs.has(browser.permanentKey)) {
|
||||
let {closedTabs, tabData} = this._closedTabs.get(browser.permanentKey);
|
||||
|
||||
// Update the closed tab's state. This will be reflected in its
|
||||
// window's list of closed tabs as that refers to the same object.
|
||||
TabState.copyFromCache({linkedBrowser: browser}, tabData.state);
|
||||
|
||||
// Is this the tab's final message?
|
||||
if (aMessage.data.isFinal) {
|
||||
// We expect no further updates.
|
||||
this._closedTabs.delete(browser.permanentKey);
|
||||
// The tab state no longer needs this reference.
|
||||
delete tabData.permanentKey;
|
||||
|
||||
// Determine whether the tab state is worth saving.
|
||||
let shouldSave = this._shouldSaveTabState(tabData.state);
|
||||
let index = closedTabs.indexOf(tabData);
|
||||
|
||||
if (shouldSave && index == -1) {
|
||||
// If the tab state is worth saving and we didn't push it onto
|
||||
// the list of closed tabs when it was closed (because we deemed
|
||||
// the state not worth saving) then add it to the window's list
|
||||
// of closed tabs now.
|
||||
this.saveClosedTabData(closedTabs, tabData);
|
||||
} else if (!shouldSave && index > -1) {
|
||||
// Remove from the list of closed tabs. The update messages sent
|
||||
// after the tab was closed changed enough state so that we no
|
||||
// longer consider its data interesting enough to keep around.
|
||||
this.removeClosedTabData(closedTabs, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "SessionStore:restoreHistoryComplete":
|
||||
if (this.isCurrentEpoch(browser, aMessage.data.epoch)) {
|
||||
@ -722,25 +784,26 @@ let SessionStoreInternal = {
|
||||
* Implement nsIDOMEventListener for handling various window and tab events
|
||||
*/
|
||||
handleEvent: function ssi_handleEvent(aEvent) {
|
||||
var win = aEvent.currentTarget.ownerDocument.defaultView;
|
||||
let win = aEvent.currentTarget.ownerDocument.defaultView;
|
||||
let target = aEvent.originalTarget;
|
||||
switch (aEvent.type) {
|
||||
case "TabOpen":
|
||||
this.onTabAdd(win, aEvent.originalTarget);
|
||||
this.onTabAdd(win, target);
|
||||
break;
|
||||
case "TabClose":
|
||||
// aEvent.detail determines if the tab was closed by moving to a different window
|
||||
if (!aEvent.detail)
|
||||
this.onTabClose(win, aEvent.originalTarget);
|
||||
this.onTabRemove(win, aEvent.originalTarget);
|
||||
this.onTabClose(win, target);
|
||||
this.onTabRemove(win, target);
|
||||
break;
|
||||
case "TabSelect":
|
||||
this.onTabSelect(win);
|
||||
break;
|
||||
case "TabShow":
|
||||
this.onTabShow(win, aEvent.originalTarget);
|
||||
this.onTabShow(win, target);
|
||||
break;
|
||||
case "TabHide":
|
||||
this.onTabHide(win, aEvent.originalTarget);
|
||||
this.onTabHide(win, target);
|
||||
break;
|
||||
case "TabPinned":
|
||||
case "TabUnpinned":
|
||||
@ -748,8 +811,15 @@ let SessionStoreInternal = {
|
||||
this.saveStateDelayed(win);
|
||||
break;
|
||||
case "oop-browser-crashed":
|
||||
this.onBrowserCrashed(win, aEvent.originalTarget);
|
||||
this.onBrowserCrashed(win, target);
|
||||
break;
|
||||
case "XULFrameLoaderCreated":
|
||||
if (target.tagName == "browser" && target.frameLoader) {
|
||||
this._lastKnownFrameLoader.set(target.permanentKey, target.frameLoader);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unhandled event ${aEvent.type}?`);
|
||||
}
|
||||
this._clearRestoringWindows();
|
||||
},
|
||||
@ -943,6 +1013,9 @@ let SessionStoreInternal = {
|
||||
TAB_EVENTS.forEach(function(aEvent) {
|
||||
tabbrowser.tabContainer.addEventListener(aEvent, this, true);
|
||||
}, this);
|
||||
|
||||
// Keep track of a browser's latest frameLoader.
|
||||
aWindow.gBrowser.addEventListener("XULFrameLoaderCreated", this);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1046,6 +1119,8 @@ let SessionStoreInternal = {
|
||||
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
||||
}, this);
|
||||
|
||||
aWindow.gBrowser.removeEventListener("XULFrameLoaderCreated", this);
|
||||
|
||||
let winData = this._windows[aWindow.__SSi];
|
||||
|
||||
// Collect window data only when *not* closed during shutdown.
|
||||
@ -1311,6 +1386,11 @@ let SessionStoreInternal = {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("SwapDocShells", this);
|
||||
browser.addEventListener("oop-browser-crashed", this);
|
||||
|
||||
if (browser.frameLoader) {
|
||||
this._lastKnownFrameLoader.set(browser.permanentKey, browser.frameLoader);
|
||||
}
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
@ -1365,9 +1445,6 @@ let SessionStoreInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush all data queued in the content script before the tab is gone.
|
||||
TabState.flush(aTab.linkedBrowser);
|
||||
|
||||
// Get the latest data for this tab (generally, from the cache)
|
||||
let tabState = TabState.collect(aTab);
|
||||
|
||||
@ -1377,23 +1454,96 @@ let SessionStoreInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
// store closed-tab data for undo
|
||||
if (this._shouldSaveTabState(tabState)) {
|
||||
let tabTitle = aTab.label;
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
tabTitle = this._replaceLoadingTitle(tabTitle, tabbrowser, aTab);
|
||||
// Store closed-tab data for undo.
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
let tabTitle = this._replaceLoadingTitle(aTab.label, tabbrowser, aTab);
|
||||
let {permanentKey} = aTab.linkedBrowser;
|
||||
|
||||
this._windows[aWindow.__SSi]._closedTabs.unshift({
|
||||
state: tabState,
|
||||
title: tabTitle,
|
||||
image: tabbrowser.getIcon(aTab),
|
||||
pos: aTab._tPos,
|
||||
closedAt: Date.now()
|
||||
});
|
||||
var length = this._windows[aWindow.__SSi]._closedTabs.length;
|
||||
if (length > this._max_tabs_undo)
|
||||
this._windows[aWindow.__SSi]._closedTabs.splice(this._max_tabs_undo, length - this._max_tabs_undo);
|
||||
let tabData = {
|
||||
permanentKey,
|
||||
state: tabState,
|
||||
title: tabTitle,
|
||||
image: tabbrowser.getIcon(aTab),
|
||||
pos: aTab._tPos,
|
||||
closedAt: Date.now()
|
||||
};
|
||||
|
||||
let closedTabs = this._windows[aWindow.__SSi]._closedTabs;
|
||||
|
||||
// Determine whether the tab contains any information worth saving. Note
|
||||
// that there might be pending state changes queued in the child that
|
||||
// didn't reach the parent yet. If a tab is emptied before closing then we
|
||||
// might still remove it from the list of closed tabs later.
|
||||
if (this._shouldSaveTabState(tabState)) {
|
||||
// Save the tab state, for now. We might push a valid tab out
|
||||
// of the list but those cases should be extremely rare and
|
||||
// do probably never occur when using the browser normally.
|
||||
// (Tests or add-ons might do weird things though.)
|
||||
this.saveClosedTabData(closedTabs, tabData);
|
||||
}
|
||||
|
||||
// Remember the closed tab to properly handle any last updates included in
|
||||
// the final "update" message sent by the frame script's unload handler.
|
||||
this._closedTabs.set(permanentKey, {closedTabs, tabData});
|
||||
},
|
||||
|
||||
/**
|
||||
* Insert a given |tabData| object into the list of |closedTabs|. We will
|
||||
* determine the right insertion point based on the .closedAt properties of
|
||||
* all tabs already in the list. The list will be truncated to contain a
|
||||
* maximum of |this._max_tabs_undo| entries.
|
||||
*
|
||||
* @param closedTabs (array)
|
||||
* The list of closed tabs for a window.
|
||||
* @param tabData (object)
|
||||
* The tabData to be inserted.
|
||||
*/
|
||||
saveClosedTabData(closedTabs, tabData) {
|
||||
// Find the index of the first tab in the list
|
||||
// of closed tabs that was closed before our tab.
|
||||
let index = closedTabs.findIndex(tab => {
|
||||
return tab.closedAt < tabData.closedAt;
|
||||
});
|
||||
|
||||
// If we found no tab closed before our
|
||||
// tab then just append it to the list.
|
||||
if (index == -1) {
|
||||
index = closedTabs.length;
|
||||
}
|
||||
|
||||
// Insert tabData at the right position.
|
||||
closedTabs.splice(index, 0, tabData);
|
||||
|
||||
// Truncate the list of closed tabs, if needed.
|
||||
if (closedTabs.length > this._max_tabs_undo) {
|
||||
closedTabs.splice(this._max_tabs_undo, closedTabs.length);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the closed tab data at |index| from the list of |closedTabs|. If
|
||||
* the tab's final message is still pending we will simply discard it when
|
||||
* it arrives so that the tab doesn't reappear in the list.
|
||||
*
|
||||
* @param closedTabs (array)
|
||||
* The list of closed tabs for a window.
|
||||
* @param index (uint)
|
||||
* The index of the tab to remove.
|
||||
*/
|
||||
removeClosedTabData(closedTabs, index) {
|
||||
// Remove the given index from the list.
|
||||
let [closedTab] = closedTabs.splice(index, 1);
|
||||
|
||||
// If the closed tab's state still has a .permanentKey property then we
|
||||
// haven't seen its final update message yet. Remove it from the map of
|
||||
// closed tabs so that we will simply discard its last messages and will
|
||||
// not add it back to the list of closed tabs again.
|
||||
if (closedTab.permanentKey) {
|
||||
this._closedTabs.delete(closedTab.permanentKey);
|
||||
delete closedTab.permanentKey;
|
||||
}
|
||||
|
||||
return closedTab;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1696,18 +1846,17 @@ let SessionStoreInternal = {
|
||||
}
|
||||
|
||||
// fetch the data of closed tab, while removing it from the array
|
||||
let [closedTab] = closedTabs.splice(aIndex, 1);
|
||||
let closedTabState = closedTab.state;
|
||||
let {state, pos} = this.removeClosedTabData(closedTabs, aIndex);
|
||||
|
||||
// create a new tab
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
|
||||
|
||||
// restore tab content
|
||||
this.restoreTab(tab, closedTabState);
|
||||
this.restoreTab(tab, state);
|
||||
|
||||
// restore the tab's position
|
||||
tabbrowser.moveTabTo(tab, closedTab.pos);
|
||||
tabbrowser.moveTabTo(tab, pos);
|
||||
|
||||
// focus the tab's content area (bug 342432)
|
||||
tab.linkedBrowser.focus();
|
||||
@ -1729,7 +1878,7 @@ let SessionStoreInternal = {
|
||||
}
|
||||
|
||||
// remove closed tab from the array
|
||||
closedTabs.splice(aIndex, 1);
|
||||
this.removeClosedTabData(closedTabs, aIndex);
|
||||
},
|
||||
|
||||
getClosedWindowCount: function ssi_getClosedWindowCount() {
|
||||
|
@ -53,6 +53,10 @@ this.TabState = Object.freeze({
|
||||
|
||||
clone: function (tab) {
|
||||
return TabStateInternal.clone(tab);
|
||||
},
|
||||
|
||||
copyFromCache: function (tab, tabData, options) {
|
||||
TabStateInternal.copyFromCache(tab, tabData, options);
|
||||
}
|
||||
});
|
||||
|
||||
@ -218,7 +222,7 @@ let TabStateInternal = {
|
||||
|
||||
// Copy data from the tab state cache only if the tab has fully finished
|
||||
// restoring. We don't want to overwrite data contained in __SS_data.
|
||||
this._copyFromCache(tab, tabData, options);
|
||||
this.copyFromCache(tab, tabData, options);
|
||||
|
||||
return tabData;
|
||||
},
|
||||
@ -233,7 +237,7 @@ let TabStateInternal = {
|
||||
* @param options (object)
|
||||
* {includePrivateData: true} to always include private data
|
||||
*/
|
||||
_copyFromCache: function (tab, tabData, options = {}) {
|
||||
copyFromCache: function (tab, tabData, options = {}) {
|
||||
let data = TabStateCache.get(tab.linkedBrowser);
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -116,6 +116,12 @@ let MessageListener = {
|
||||
},
|
||||
|
||||
receiveMessage: function ({name, data}) {
|
||||
// The docShell might be gone. Don't process messages,
|
||||
// that will just lead to errors anyway.
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "SessionStore:restoreHistory":
|
||||
this.restoreHistory(data);
|
||||
@ -222,7 +228,11 @@ let SyncHandler = {
|
||||
* can occur by sending data shortly before flushing synchronously.
|
||||
*/
|
||||
flushAsync: function () {
|
||||
MessageQueue.flushAsync();
|
||||
if (!Services.prefs.getBoolPref("browser.sessionstore.debug")) {
|
||||
throw new Error("flushAsync() must be used for testing, only.");
|
||||
}
|
||||
|
||||
MessageQueue.send();
|
||||
}
|
||||
};
|
||||
|
||||
@ -680,9 +690,8 @@ let MessageQueue = {
|
||||
|
||||
// Send all data to the parent process.
|
||||
sendMessage("SessionStore:update", {
|
||||
id: this._id,
|
||||
data: data,
|
||||
telemetry: telemetry
|
||||
id: this._id, data, telemetry,
|
||||
isFinal: options.isFinal || false
|
||||
});
|
||||
|
||||
// Increase our unique message ID.
|
||||
@ -706,20 +715,6 @@ let MessageQueue = {
|
||||
|
||||
this._data.clear();
|
||||
this._lastUpdated.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* DO NOT USE - DEBUGGING / TESTING ONLY
|
||||
*
|
||||
* This function is used to simulate certain situations where race conditions
|
||||
* can occur by sending data shortly before flushing synchronously.
|
||||
*/
|
||||
flushAsync: function () {
|
||||
if (!Services.prefs.getBoolPref("browser.sessionstore.debug")) {
|
||||
throw new Error("flushAsync() must be used for testing, only.");
|
||||
}
|
||||
|
||||
this.send();
|
||||
}
|
||||
};
|
||||
|
||||
@ -759,6 +754,10 @@ function handleRevivedTab() {
|
||||
addEventListener("pagehide", handleRevivedTab);
|
||||
|
||||
addEventListener("unload", () => {
|
||||
// Upon frameLoader destruction, send a final update message to
|
||||
// the parent and flush all data currently held in the child.
|
||||
MessageQueue.send({isFinal: true});
|
||||
|
||||
// If we're browsing from the tab crashed UI to a URI that causes the tab
|
||||
// to go remote again, we catch this in the unload event handler, because
|
||||
// swapping out the non-remote browser for a remote one in
|
||||
|
@ -65,6 +65,8 @@ support-files =
|
||||
|
||||
[browser_aboutPrivateBrowsing.js]
|
||||
[browser_aboutSessionRestore.js]
|
||||
[browser_async_remove_tab.js]
|
||||
run-if = e10s
|
||||
[browser_attributes.js]
|
||||
[browser_backup_recovery.js]
|
||||
[browser_broadcast.js]
|
||||
|
@ -1,4 +1,6 @@
|
||||
function test() {
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
/** Test for Bug 350525 **/
|
||||
|
||||
function test(aLambda) {
|
||||
@ -9,8 +11,6 @@ function test() {
|
||||
return false;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
////////////////////////////
|
||||
// setWindowValue, et al. //
|
||||
////////////////////////////
|
||||
@ -56,7 +56,7 @@ function test() {
|
||||
ok(test(function() ss.deleteTabValue(tab, key)), "delete non-existent tab value");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
/////////////////////////////////////
|
||||
// getClosedTabCount, undoCloseTab //
|
||||
@ -71,29 +71,26 @@ function test() {
|
||||
// create a new tab
|
||||
let testURL = "about:";
|
||||
tab = gBrowser.addTab(testURL);
|
||||
promiseBrowserLoaded(tab.linkedBrowser).then(() => {
|
||||
// make sure that the next closed tab will increase getClosedTabCount
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// remove tab
|
||||
gBrowser.removeTab(tab);
|
||||
// make sure that the next closed tab will increase getClosedTabCount
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
|
||||
registerCleanupFunction(() => gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"));
|
||||
|
||||
// getClosedTabCount
|
||||
var newcount = ss.getClosedTabCount(window);
|
||||
ok(newcount > count, "after closing a tab, getClosedTabCount has been incremented");
|
||||
// remove tab
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
// undoCloseTab
|
||||
tab = test(function() ss.undoCloseTab(window, 0));
|
||||
ok(tab, "undoCloseTab doesn't throw")
|
||||
// getClosedTabCount
|
||||
let newcount = ss.getClosedTabCount(window);
|
||||
ok(newcount > count, "after closing a tab, getClosedTabCount has been incremented");
|
||||
|
||||
promiseTabRestored(tab).then(() => {
|
||||
is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
|
||||
// undoCloseTab
|
||||
tab = test(function() ss.undoCloseTab(window, 0));
|
||||
ok(tab, "undoCloseTab doesn't throw")
|
||||
|
||||
// clean up
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
yield promiseTabRestored(tab);
|
||||
is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
@ -2,36 +2,40 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 367052 **/
|
||||
|
||||
waitForExplicitFinish();
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
// make sure that the next closed tab will increase getClosedTabCount
|
||||
let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
|
||||
let closedTabCount = ss.getClosedTabCount(window);
|
||||
registerCleanupFunction(() => gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"));
|
||||
|
||||
// Empty the list of closed tabs.
|
||||
while (ss.getClosedTabCount(window)) {
|
||||
ss.forgetClosedTab(window, 0);
|
||||
}
|
||||
|
||||
// restore a blank tab
|
||||
let tab = gBrowser.addTab("about:");
|
||||
promiseBrowserLoaded(tab.linkedBrowser).then(() => {
|
||||
let history = tab.linkedBrowser.webNavigation.sessionHistory;
|
||||
ok(history.count >= 1, "the new tab does have at least one history entry");
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
promiseTabState(tab, {entries: []}).then(() => {
|
||||
// We may have a different sessionHistory object if the tab
|
||||
// switched from non-remote to remote.
|
||||
history = tab.linkedBrowser.webNavigation.sessionHistory;
|
||||
ok(history.count == 0, "the tab was restored without any history whatsoever");
|
||||
let count = yield promiseSHistoryCount(tab.linkedBrowser);
|
||||
ok(count >= 1, "the new tab does have at least one history entry");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
ok(ss.getClosedTabCount(window) == closedTabCount,
|
||||
"The closed blank tab wasn't added to Recently Closed Tabs");
|
||||
yield promiseTabState(tab, {entries: []});
|
||||
|
||||
// clean up
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
finish();
|
||||
});
|
||||
// We may have a different sessionHistory object if the tab
|
||||
// switched from non-remote to remote.
|
||||
count = yield promiseSHistoryCount(tab.linkedBrowser);
|
||||
is(count, 0, "the tab was restored without any history whatsoever");
|
||||
|
||||
yield promiseRemoveTab(tab);
|
||||
is(ss.getClosedTabCount(window), 0,
|
||||
"The closed blank tab wasn't added to Recently Closed Tabs");
|
||||
});
|
||||
|
||||
function promiseSHistoryCount(browser) {
|
||||
return ContentTask.spawn(browser, null, function* () {
|
||||
return docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory.count;
|
||||
});
|
||||
}
|
||||
|
@ -2,19 +2,15 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/** Private Browsing Test for Bug 394759 **/
|
||||
|
||||
let closedWindowCount = 0;
|
||||
// Prevent VM timers issues, cache now and increment it manually.
|
||||
let now = Date.now();
|
||||
"use strict";
|
||||
|
||||
const TESTS = [
|
||||
{ url: "about:config",
|
||||
key: "bug 394759 Non-PB",
|
||||
value: "uniq" + (++now) },
|
||||
value: "uniq" + r() },
|
||||
{ url: "about:mozilla",
|
||||
key: "bug 394759 PB",
|
||||
value: "uniq" + (++now) },
|
||||
value: "uniq" + r() },
|
||||
];
|
||||
|
||||
function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
|
||||
@ -33,53 +29,11 @@ function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
|
||||
function promiseTestOnWindow(aIsPrivate, aValue) {
|
||||
return Task.spawn(function*() {
|
||||
let win = yield promiseNewWindowLoaded({ "private": aIsPrivate });
|
||||
yield promiseCheckClosedWindows(aIsPrivate, aValue);
|
||||
registerCleanupFunction(() => promiseWindowClosed(win));
|
||||
});
|
||||
}
|
||||
|
||||
function promiseCheckClosedWindows(aIsPrivate, aValue) {
|
||||
return Task.spawn(function*() {
|
||||
let data = JSON.parse(ss.getClosedWindowData())[0];
|
||||
is(ss.getClosedWindowCount(), 1, "Check that the closed window count hasn't changed");
|
||||
ok(JSON.stringify(data).indexOf(aValue) > -1,
|
||||
"Check the closed window data was stored correctly");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseBlankState() {
|
||||
return Task.spawn(function*() {
|
||||
// Set interval to a large time so state won't be written while we setup
|
||||
// environment.
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 100000);
|
||||
registerCleanupFunction(() => Services.prefs.clearUserPref("browser.sessionstore.interval"));
|
||||
|
||||
// Set up the browser in a blank state. Popup windows in previous tests
|
||||
// result in different states on different platforms.
|
||||
let blankState = JSON.stringify({
|
||||
windows: [{
|
||||
tabs: [{ entries: [{ url: "about:blank" }] }],
|
||||
_closedTabs: []
|
||||
}],
|
||||
_closedWindows: []
|
||||
});
|
||||
|
||||
ss.setBrowserState(blankState);
|
||||
|
||||
// Wait for the sessionstore.js file to be written before going on.
|
||||
// Note: we don't wait for the complete event, since if asyncCopy fails we
|
||||
// would timeout.
|
||||
|
||||
yield forceSaveState();
|
||||
closedWindowCount = ss.getClosedWindowCount();
|
||||
is(closedWindowCount, 0, "Correctly set window count");
|
||||
|
||||
// Remove the sessionstore.js file before setting the interval to 0
|
||||
yield SessionFile.wipe();
|
||||
|
||||
// Make sure that sessionstore.js can be forced to be created by setting
|
||||
// the interval pref to 0.
|
||||
yield forceSaveState();
|
||||
registerCleanupFunction(() => promiseWindowClosed(win));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ add_task(function* test_dont_save_passwords() {
|
||||
yield setInputValue(browser, {id: "passwd", value: PASS});
|
||||
|
||||
// Close and restore the tab.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
browser = tab.linkedBrowser;
|
||||
yield promiseTabRestored(tab);
|
||||
@ -46,7 +46,6 @@ add_task(function* test_dont_save_passwords() {
|
||||
ok(!state.includes(PASS), "password has not been written to file " + key)
|
||||
);
|
||||
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ add_task(function test_restore_nonstandard_input_values() {
|
||||
yield setFormElementValues(browser, {value: expectedValue});
|
||||
|
||||
// Remove tab and check collected form data.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
let undoItems = JSON.parse(ss.getClosedTabData(window));
|
||||
let savedFormData = undoItems[0].state.formdata;
|
||||
|
||||
|
@ -1,21 +1,20 @@
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
"use strict";
|
||||
|
||||
var tab1 = gBrowser.addTab("data:text/plain;charset=utf-8,foo");
|
||||
add_task(function* () {
|
||||
let tab1 = gBrowser.addTab("data:text/plain;charset=utf-8,foo");
|
||||
gBrowser.pinTab(tab1);
|
||||
|
||||
promiseBrowserLoaded(tab1.linkedBrowser).then(() => {
|
||||
var tab2 = gBrowser.addTab();
|
||||
gBrowser.pinTab(tab2);
|
||||
yield promiseBrowserLoaded(tab1.linkedBrowser);
|
||||
let tab2 = gBrowser.addTab();
|
||||
gBrowser.pinTab(tab2);
|
||||
|
||||
is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 is at the first position");
|
||||
gBrowser.removeTab(tab1);
|
||||
tab1 = undoCloseTab();
|
||||
ok(tab1.pinned, "pinned tab 1 has been restored as a pinned tab");
|
||||
is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 has been restored to the first position");
|
||||
is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 is at the first position");
|
||||
yield promiseRemoveTab(tab1);
|
||||
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
tab1 = undoCloseTab();
|
||||
ok(tab1.pinned, "pinned tab 1 has been restored as a pinned tab");
|
||||
is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 has been restored to the first position");
|
||||
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
});
|
||||
|
@ -1,36 +1,19 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests that an about:blank tab with no history will not be saved into
|
||||
// session store and thus, it will not show up in Recently Closed Tabs.
|
||||
|
||||
let tab;
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
"use strict";
|
||||
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", 0);
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
add_task(function* () {
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
is(ss.getClosedTabCount(window), 0, "should be no closed tabs");
|
||||
is(tab.linkedBrowser.currentURI.spec, "about:blank",
|
||||
"we will be removing an about:blank tab");
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
|
||||
let r = `rand-${Math.random()}`;
|
||||
ss.setTabValue(tab, "foobar", r);
|
||||
|
||||
tab = gBrowser.addTab();
|
||||
}
|
||||
|
||||
function onTabOpen(aEvent) {
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
|
||||
|
||||
// Let other listeners react to the TabOpen event before removing the tab.
|
||||
executeSoon(function() {
|
||||
is(gBrowser.browsers[1].currentURI.spec, "about:blank",
|
||||
"we will be removing an about:blank tab");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
is(ss.getClosedTabCount(window), 0, "should still be no closed tabs");
|
||||
|
||||
executeSoon(finish);
|
||||
});
|
||||
}
|
||||
yield promiseRemoveTab(tab);
|
||||
let closedTabData = ss.getClosedTabData(window);
|
||||
ok(!closedTabData.contains(r), "tab not stored in _closedTabs");
|
||||
});
|
||||
|
@ -30,15 +30,16 @@ function test() {
|
||||
ok(tab.hidden, "newly created tab is now hidden");
|
||||
|
||||
// close and restore hidden tab
|
||||
gBrowser.removeTab(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
promiseRemoveTab(tab).then(() => {
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
whenTabIsLoaded(tab, function () {
|
||||
is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "restored tab has correct url");
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
whenTabIsLoaded(tab, function () {
|
||||
is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "restored tab has correct url");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ add_task(function* test() {
|
||||
"CSP should block the script loaded by the clicked data URI");
|
||||
|
||||
// close the tab
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
// open new tab and recover the state
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
|
@ -1,18 +1,10 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// Tests that an about:privatebrowsing tab with no history will not
|
||||
// be saved into session store and thus, it will not show up in
|
||||
// Recently Closed Tabs.
|
||||
|
||||
add_task(function* () {
|
||||
while (ss.getClosedTabCount(window)) {
|
||||
ss.forgetClosedTab(window, 0);
|
||||
}
|
||||
|
||||
is(ss.getClosedTabCount(window), 0, "should be no closed tabs");
|
||||
|
||||
let tab = gBrowser.addTab("about:privatebrowsing");
|
||||
let browser = tab.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser);
|
||||
@ -20,6 +12,10 @@ add_task(function* () {
|
||||
is(gBrowser.browsers[1].currentURI.spec, "about:privatebrowsing",
|
||||
"we will be removing an about:privatebrowsing tab");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
is(ss.getClosedTabCount(window), 0, "should still be no closed tabs");
|
||||
let r = `rand-${Math.random()}`;
|
||||
ss.setTabValue(tab, "foobar", r);
|
||||
|
||||
yield promiseRemoveTab(tab);
|
||||
let closedTabData = ss.getClosedTabData(window);
|
||||
ok(!closedTabData.contains(r), "tab not stored in _closedTabs");
|
||||
});
|
||||
|
242
browser/components/sessionstore/test/browser_async_remove_tab.js
Normal file
@ -0,0 +1,242 @@
|
||||
"use strict";
|
||||
|
||||
function* createTabWithRandomValue(url) {
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser);
|
||||
|
||||
// Set a random value.
|
||||
let r = `rand-${Math.random()}`;
|
||||
ss.setTabValue(tab, "foobar", r);
|
||||
|
||||
// Flush to ensure there are no scheduled messages.
|
||||
TabState.flush(browser);
|
||||
|
||||
return {tab, r};
|
||||
}
|
||||
|
||||
function isValueInClosedData(rval) {
|
||||
return ss.getClosedTabData(window).includes(rval);
|
||||
}
|
||||
|
||||
function restoreClosedTabWithValue(rval) {
|
||||
let closedTabData = JSON.parse(ss.getClosedTabData(window));
|
||||
let index = closedTabData.findIndex(function (data) {
|
||||
return (data.state.extData && data.state.extData.foobar) == rval;
|
||||
});
|
||||
|
||||
if (index == -1) {
|
||||
throw new Error("no closed tab found for given rval");
|
||||
}
|
||||
|
||||
return ss.undoCloseTab(window, index);
|
||||
}
|
||||
|
||||
function promiseNewLocationAndHistoryEntryReplaced(browser, snippet) {
|
||||
return ContentTask.spawn(browser, snippet, function* (snippet) {
|
||||
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
let shistory = webNavigation.sessionHistory;
|
||||
|
||||
// Evaluate the snippet that the changes the location.
|
||||
eval(snippet);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let listener = {
|
||||
OnHistoryReplaceEntry() {
|
||||
shistory.removeSHistoryListener(this);
|
||||
resolve();
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISHistoryListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
shistory.addSHistoryListener(listener);
|
||||
|
||||
/* Keep the weak shistory listener alive. */
|
||||
addEventListener("unload", function () {
|
||||
try {
|
||||
shistory.removeSHistoryListener(listener);
|
||||
} catch (e) { /* Will most likely fail. */ }
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function promiseHistoryEntryReplacedNonRemote(browser) {
|
||||
let {listeners} = promiseHistoryEntryReplacedNonRemote;
|
||||
|
||||
return new Promise(resolve => {
|
||||
let shistory = browser.webNavigation.sessionHistory;
|
||||
|
||||
let listener = {
|
||||
OnHistoryReplaceEntry() {
|
||||
shistory.removeSHistoryListener(this);
|
||||
resolve();
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISHistoryListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
shistory.addSHistoryListener(listener);
|
||||
listeners.set(browser, listener);
|
||||
});
|
||||
}
|
||||
promiseHistoryEntryReplacedNonRemote.listeners = new WeakMap();
|
||||
|
||||
add_task(function* dont_save_empty_tabs() {
|
||||
let {tab, r} = yield createTabWithRandomValue("about:blank");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// No tab state worth saving.
|
||||
ok(!isValueInClosedData(r), "closed tab not saved");
|
||||
yield promise;
|
||||
|
||||
// Still no tab state worth saving.
|
||||
ok(!isValueInClosedData(r), "closed tab not saved");
|
||||
});
|
||||
|
||||
add_task(function* save_worthy_tabs_remote() {
|
||||
let {tab, r} = yield createTabWithRandomValue("https://example.com/");
|
||||
ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// Tab state deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
yield promise;
|
||||
|
||||
// Tab state still deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
});
|
||||
|
||||
add_task(function* save_worthy_tabs_nonremote() {
|
||||
let {tab, r} = yield createTabWithRandomValue("about:robots");
|
||||
ok(!tab.linkedBrowser.isRemoteBrowser, "browser is not remote");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// Tab state deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
yield promise;
|
||||
|
||||
// Tab state still deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
});
|
||||
|
||||
add_task(function* save_worthy_tabs_remote_final() {
|
||||
let {tab, r} = yield createTabWithRandomValue("about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
ok(browser.isRemoteBrowser, "browser is remote");
|
||||
|
||||
// Replace about:blank with a new remote page.
|
||||
let snippet = 'webNavigation.loadURI("https://example.com/", null, null, null, null)';
|
||||
yield promiseNewLocationAndHistoryEntryReplaced(browser, snippet);
|
||||
|
||||
// Remotness shouldn't have changed.
|
||||
ok(browser.isRemoteBrowser, "browser is still remote");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// No tab state worth saving (that we know about yet).
|
||||
ok(!isValueInClosedData(r), "closed tab not saved");
|
||||
yield promise;
|
||||
|
||||
// Turns out there is a tab state worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
});
|
||||
|
||||
add_task(function* save_worthy_tabs_nonremote_final() {
|
||||
let {tab, r} = yield createTabWithRandomValue("about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
ok(browser.isRemoteBrowser, "browser is remote");
|
||||
|
||||
// Replace about:blank with a non-remote entry.
|
||||
browser.loadURI("about:robots");
|
||||
ok(!browser.isRemoteBrowser, "browser is not remote anymore");
|
||||
|
||||
// Wait until the new entry replaces about:blank.
|
||||
yield promiseHistoryEntryReplacedNonRemote(browser);
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// No tab state worth saving (that we know about yet).
|
||||
ok(!isValueInClosedData(r), "closed tab not saved");
|
||||
yield promise;
|
||||
|
||||
// Turns out there is a tab state worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
});
|
||||
|
||||
add_task(function* dont_save_empty_tabs_final() {
|
||||
let {tab, r} = yield createTabWithRandomValue("https://example.com/");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Replace the current page with an about:blank entry.
|
||||
let snippet = 'content.location.replace("about:blank")';
|
||||
yield promiseNewLocationAndHistoryEntryReplaced(browser, snippet);
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// Tab state deemed worth saving (yet).
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
yield promise;
|
||||
|
||||
// Turns out we don't want to save the tab state.
|
||||
ok(!isValueInClosedData(r), "closed tab not saved");
|
||||
});
|
||||
|
||||
add_task(function* undo_worthy_tabs() {
|
||||
let {tab, r} = yield createTabWithRandomValue("https://example.com/");
|
||||
ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// Tab state deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
|
||||
// Restore the closed tab before receiving its final message.
|
||||
tab = restoreClosedTabWithValue(r);
|
||||
|
||||
// Wait for the final update message.
|
||||
yield promise;
|
||||
|
||||
// Check we didn't add the tab back to the closed list.
|
||||
ok(!isValueInClosedData(r), "tab no longer closed");
|
||||
|
||||
// Cleanup.
|
||||
yield promiseRemoveTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* forget_worthy_tabs_remote() {
|
||||
let {tab, r} = yield createTabWithRandomValue("https://example.com/");
|
||||
ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
|
||||
|
||||
// Remove the tab before the update arrives.
|
||||
let promise = promiseRemoveTab(tab);
|
||||
|
||||
// Tab state deemed worth saving.
|
||||
ok(isValueInClosedData(r), "closed tab saved");
|
||||
|
||||
// Forget the closed tab.
|
||||
ss.forgetClosedTab(window, 0);
|
||||
|
||||
// Wait for the final update message.
|
||||
yield promise;
|
||||
|
||||
// Check we didn't add the tab back to the closed list.
|
||||
ok(!isValueInClosedData(r), "we forgot about the tab");
|
||||
});
|
@ -14,7 +14,7 @@ add_task(function flush_on_tabclose() {
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
yield modifySessionStorage(browser, {test: "on-tab-close"});
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(storage["http://example.com"].test, "on-tab-close",
|
||||
@ -59,7 +59,7 @@ add_task(function flush_on_duplicate() {
|
||||
"sessionStorage data has been flushed when duplicating tabs");
|
||||
|
||||
yield promiseTabRestored(tab2);
|
||||
gBrowser.removeTab(tab2);
|
||||
yield promiseRemoveTab(tab2);
|
||||
[{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(storage["http://example.com"].test, "on-duplicate",
|
||||
"sessionStorage data has been flushed when duplicating tabs");
|
||||
@ -128,7 +128,7 @@ add_task(function flush_on_tabclose_racy() {
|
||||
// Flush all data contained in the content script but send it using
|
||||
// asynchronous messages.
|
||||
TabState.flushAsync(browser);
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(storage["http://example.com"].test, "on-tab-close-racy",
|
||||
|
@ -71,8 +71,8 @@ add_task(function* test_open_and_close() {
|
||||
|
||||
// Now close stuff, this should add closeAt
|
||||
yield promiseWindowClosed(newWin);
|
||||
gBrowser.removeTab(newTab1);
|
||||
gBrowser.removeTab(newTab2);
|
||||
yield promiseRemoveTab(newTab1);
|
||||
yield promiseRemoveTab(newTab2);
|
||||
|
||||
state = CLOSED_STATE = JSON.parse(ss.getBrowserState());
|
||||
|
||||
|
@ -20,7 +20,7 @@ add_task(function* test() {
|
||||
let tab = win.gBrowser.addTab("about:mozilla");
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
TabState.flush(tab.linkedBrowser);
|
||||
win.gBrowser.removeTab(win.gBrowser.tabs[0]);
|
||||
yield promiseRemoveTab(win.gBrowser.tabs[0]);
|
||||
|
||||
// Make sure our window is still tracked by sessionstore
|
||||
// and the window state is as expected.
|
||||
|
@ -30,7 +30,7 @@ add_task(function test_formdata() {
|
||||
yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
|
||||
|
||||
// Remove the tab.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
});
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ add_task(function test_nested() {
|
||||
yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m", frame: 0});
|
||||
|
||||
// Remove the tab and check that we stored form data correctly.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(JSON.stringify(formdata), JSON.stringify(FORM_DATA),
|
||||
"formdata for iframe stored correctly");
|
||||
@ -156,7 +156,7 @@ add_task(function test_design_mode() {
|
||||
yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m"});
|
||||
|
||||
// Close and restore the tab.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
browser = tab.linkedBrowser;
|
||||
yield promiseTabRestored(tab);
|
||||
@ -167,7 +167,7 @@ add_task(function test_design_mode() {
|
||||
is(html, expected, "editable document has been restored correctly");
|
||||
|
||||
// Close and restore the tab.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
browser = tab.linkedBrowser;
|
||||
yield promiseTabRestored(tab);
|
||||
@ -232,7 +232,7 @@ add_task(function test_ccNumbers() {
|
||||
yield setInputValue(browser, {id: "txt", value: formValue});
|
||||
|
||||
// Remove the tab.
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
}
|
||||
|
||||
// Test that valid CC numbers are not collected.
|
||||
|
@ -32,7 +32,7 @@ add_task(function() {
|
||||
yield promise;
|
||||
|
||||
info("Close then un-close page, 4 loads should take place");
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
let newTab = ss.undoCloseTab(window, 0);
|
||||
yield waitForLoadsInBrowser(newTab.linkedBrowser, 4);
|
||||
|
||||
@ -77,7 +77,7 @@ add_task(function() {
|
||||
yield promise;
|
||||
|
||||
info("iframe: Close then un-close page, 5 loads should take place");
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
let newTab = ss.undoCloseTab(window, 0);
|
||||
yield waitForLoadsInBrowser(newTab.linkedBrowser, 5);
|
||||
|
||||
|
@ -59,7 +59,7 @@ add_task(function nested_page_style() {
|
||||
yield promiseBrowserLoaded(browser);
|
||||
|
||||
yield enableSubDocumentStyleSheetsForSet(browser, "alternate");
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
let [{state: {pageStyle}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
let expected = JSON.stringify({children: [{pageStyle: "alternate"}]});
|
||||
|
@ -15,7 +15,7 @@ add_task(function test_load_start() {
|
||||
// Load a new URI but remove the tab before it has finished loading.
|
||||
browser.loadURI("about:mozilla");
|
||||
yield promiseContentMessage(browser, "ss-test:OnHistoryReplaceEntry");
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
// Undo close the tab.
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
|
@ -129,7 +129,7 @@ add_task(function purge_domain() {
|
||||
add_task(function respect_privacy_level() {
|
||||
let tab = gBrowser.addTab(URL + "&secure");
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
|
||||
@ -142,7 +142,7 @@ add_task(function respect_privacy_level() {
|
||||
|
||||
tab = gBrowser.addTab(URL + "&secure");
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
[{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
|
||||
@ -158,7 +158,7 @@ add_task(function respect_privacy_level() {
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
yield promiseTabRestored(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
|
||||
// With privacy_level=2 the |tab| shouldn't have any sessionStorage data.
|
||||
[{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
@ -166,7 +166,7 @@ add_task(function respect_privacy_level() {
|
||||
|
||||
// Restore the default privacy level and close the duplicated tab.
|
||||
Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
|
||||
gBrowser.removeTab(tab2);
|
||||
yield promiseRemoveTab(tab2);
|
||||
|
||||
// With privacy_level=0 the duplicated |tab2| should persist all data.
|
||||
[{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
|
||||
|
@ -76,7 +76,7 @@ add_task(function history() {
|
||||
}
|
||||
} finally {
|
||||
if (tab) {
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -93,7 +93,7 @@ add_task(function close_tab() {
|
||||
let statistics = yield promiseStats();
|
||||
|
||||
info("Now closing a tab");
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
tab = null;
|
||||
let statistics2 = yield promiseStats();
|
||||
|
||||
@ -108,7 +108,7 @@ add_task(function close_tab() {
|
||||
|
||||
} finally {
|
||||
if (tab) {
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -202,7 +202,7 @@ add_task(function dom_storage() {
|
||||
|
||||
} finally {
|
||||
if (tab) {
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -235,7 +235,7 @@ add_task(function formdata() {
|
||||
}
|
||||
} finally {
|
||||
if (tab) {
|
||||
gBrowser.removeTab(tab);
|
||||
yield promiseRemoveTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -65,8 +65,10 @@ let historyListener = {
|
||||
])
|
||||
};
|
||||
|
||||
docShell.QueryInterface(Ci.nsIWebNavigation).
|
||||
let {sessionHistory} = docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
if (sessionHistory) {
|
||||
sessionHistory.addSHistoryListener(historyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* This frame script is only loaded for sessionstore mochitests. It enables us
|
||||
|
@ -527,3 +527,7 @@ for (let name of FORM_HELPERS) {
|
||||
let msg = "ss-test:" + name;
|
||||
this[name] = (browser, data) => sendMessage(browser, msg, data);
|
||||
}
|
||||
|
||||
function promiseRemoveTab(tab) {
|
||||
return BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
@ -61,7 +61,8 @@ let WindowMessageHandler = {
|
||||
// Function: isDocumentLoaded
|
||||
// Checks if the currently active document is loaded.
|
||||
isDocumentLoaded: function WMH_isDocumentLoaded(cx) {
|
||||
let isLoaded = (content.document.readyState != "uninitialized" &&
|
||||
let isLoaded = (content &&
|
||||
content.document.readyState != "uninitialized" &&
|
||||
!webProgress.isLoadingDocument);
|
||||
|
||||
sendAsyncMessage(cx.name, {isLoaded: isLoaded});
|
||||
@ -71,7 +72,8 @@ let WindowMessageHandler = {
|
||||
// Function: isImageDocument
|
||||
// Checks if the currently active document is an image document or not.
|
||||
isImageDocument: function WMH_isImageDocument(cx) {
|
||||
let isImageDocument = (content.document instanceof Ci.nsIImageDocument);
|
||||
let isImageDocument = (content &&
|
||||
content.document instanceof Ci.nsIImageDocument);
|
||||
|
||||
sendAsyncMessage(cx.name, {isImageDocument: isImageDocument});
|
||||
},
|
||||
|
@ -89,7 +89,9 @@ let FavIcons = {
|
||||
tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
|
||||
}
|
||||
|
||||
tabImage = PlacesUtils.getImageURLForResolution(window, tabImage);
|
||||
if (tabImage) {
|
||||
tabImage = PlacesUtils.getImageURLForResolution(window, tabImage);
|
||||
}
|
||||
|
||||
callback(tabImage);
|
||||
},
|
||||
|
@ -24,19 +24,20 @@ function onTabViewWindowLoaded() {
|
||||
is(groupItems.length, 1, "There is only one group");
|
||||
is(groupItems[0].getChildren().length, 3, "The group has three tab items");
|
||||
|
||||
gBrowser.removeTab(tabTwo);
|
||||
ok(TabView.isVisible(), "Tab View is still visible after removing a tab");
|
||||
is(groupItems[0].getChildren().length, 2, "The group has two tab items");
|
||||
BrowserTestUtils.removeTab(tabTwo).then(() => {
|
||||
ok(TabView.isVisible(), "Tab View is still visible after removing a tab");
|
||||
is(groupItems[0].getChildren().length, 2, "The group has two tab items");
|
||||
|
||||
restoreTab(function (tabTwo) {
|
||||
ok(TabView.isVisible(), "Tab View is still visible after restoring a tab");
|
||||
is(groupItems[0].getChildren().length, 3, "The group still has three tab items");
|
||||
restoreTab(function (tabTwo) {
|
||||
ok(TabView.isVisible(), "Tab View is still visible after restoring a tab");
|
||||
is(groupItems[0].getChildren().length, 3, "The group still has three tab items");
|
||||
|
||||
// clean up and finish
|
||||
hideTabView(function () {
|
||||
gBrowser.removeTab(tabOne);
|
||||
gBrowser.removeTab(tabTwo);
|
||||
finish();
|
||||
// clean up and finish
|
||||
hideTabView(function () {
|
||||
gBrowser.removeTab(tabOne);
|
||||
gBrowser.removeTab(tabTwo);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -56,18 +56,19 @@ function test() {
|
||||
assertNumberOfTabs(2);
|
||||
|
||||
afterAllTabsLoaded(function () {
|
||||
win.gBrowser.removeTab(tab);
|
||||
assertNumberOfTabs(1);
|
||||
assertNumberOfPinnedTabs(0);
|
||||
BrowserTestUtils.removeTab(tab).then(() => {
|
||||
assertNumberOfTabs(1);
|
||||
assertNumberOfPinnedTabs(0);
|
||||
|
||||
restoreTab(function () {
|
||||
prefix = 'unpinned-restored';
|
||||
assertValidPrerequisites();
|
||||
assertGroupItemPreserved();
|
||||
restoreTab(function () {
|
||||
prefix = 'unpinned-restored';
|
||||
assertValidPrerequisites();
|
||||
assertGroupItemPreserved();
|
||||
|
||||
createBlankTab();
|
||||
afterAllTabsLoaded(testUndoCloseWithSelectedBlankPinnedTab, win);
|
||||
}, 0, win);
|
||||
createBlankTab();
|
||||
afterAllTabsLoaded(testUndoCloseWithSelectedBlankPinnedTab, win);
|
||||
}, 0, win);
|
||||
});
|
||||
}, win);
|
||||
}
|
||||
|
||||
|
@ -70,17 +70,24 @@ function test() {
|
||||
let groupItem = getGroupItem(1);
|
||||
let tabItem = groupItem.getChild(0);
|
||||
|
||||
// Wait until the tab has been removed but close it ourselves.
|
||||
let promise = BrowserTestUtils.removeTab(tabItem.tab, {dontRemove: true});
|
||||
|
||||
// Close the tab.
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
tabItem.$close[0], {}, TabView.getContentWindow());
|
||||
assertNumberOfTabsInGroup(groupItem, 1);
|
||||
|
||||
restoreTab(function () {
|
||||
assertNumberOfTabsInGroup(groupItem, 2);
|
||||
promise.then(() => {
|
||||
assertNumberOfTabsInGroup(groupItem, 1);
|
||||
|
||||
activateFirstGroupItem();
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
hideTabView(finishTest);
|
||||
restoreTab(function () {
|
||||
assertNumberOfTabsInGroup(groupItem, 2);
|
||||
|
||||
activateFirstGroupItem();
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
hideTabView(finishTest);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -661,7 +661,7 @@ this.BrowserUITelemetry = {
|
||||
"copyvideourl", "copyaudiourl", "saveimage", "shareimage", "sendimage",
|
||||
"setDesktopBackground", "viewimageinfo", "viewimagedesc", "savevideo",
|
||||
"sharevideo", "saveaudio", "video-saveimage", "sendvideo", "sendaudio",
|
||||
"ctp-play", "ctp-hide", "sharepage", "savepage", "markpageMenu",
|
||||
"ctp-play", "ctp-hide", "sharepage", "savepage", "pocket", "markpageMenu",
|
||||
"viewbgimage", "undo", "cut", "copy", "paste", "delete", "selectall",
|
||||
"keywordfield", "searchselect", "shareselect", "frame", "showonlythisframe",
|
||||
"openframeintab", "openframe", "reloadframe", "bookmarkframe", "saveframe",
|
||||
|
@ -155,6 +155,7 @@ HiddenBrowser.prototype = {
|
||||
this._hiddenFrame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
||||
this._browser.permanentKey = {};
|
||||
this._browser.setAttribute("type", "content");
|
||||
this._browser.setAttribute("src", CUSTOMIZATION_URL);
|
||||
this._browser.style.width = "400px";
|
||||
|
@ -523,6 +523,12 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
list-style-image: url("chrome://browser/skin/readinglist/readinglist-icon.svg");
|
||||
}
|
||||
|
||||
#panelMenu_pocket,
|
||||
#menu_pocket,
|
||||
#BMB_pocket {
|
||||
list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
|
||||
}
|
||||
|
||||
#menu_openDownloads {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
|
@ -568,6 +568,24 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-p
|
||||
list-style-image: url("chrome://browser/skin/readinglist/readinglist-icon.svg");
|
||||
}
|
||||
|
||||
#panelMenu_pocket,
|
||||
#menu_pocket,
|
||||
#BMB_pocket {
|
||||
list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#panelMenu_pocket,
|
||||
#menu_pocket,
|
||||
#BMB_pocket {
|
||||
list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16@2x.png");
|
||||
}
|
||||
|
||||
#panelMenu_pocket > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- PRIMARY TOOLBAR BUTTONS ----- */
|
||||
|
||||
toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
|
@ -2297,6 +2297,12 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
-moz-image-region: auto;
|
||||
}
|
||||
|
||||
#panelMenu_pocket,
|
||||
#menu_pocket,
|
||||
#BMB_pocket {
|
||||
list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
|
||||
}
|
||||
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
|
||||
.KUI-panel {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "nsIDOMXULSelectCntrlItemEl.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsLayoutStylesheetCache.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
@ -1601,6 +1602,10 @@ nsXULElement::LoadSrc()
|
||||
slots->mFrameLoader = nsFrameLoader::Create(this, false);
|
||||
NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
|
||||
|
||||
(new AsyncEventDispatcher(this,
|
||||
NS_LITERAL_STRING("XULFrameLoaderCreated"),
|
||||
/* aBubbles */ true))->RunDOMEventWhenSafe();
|
||||
|
||||
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::prerendered,
|
||||
NS_LITERAL_STRING("true"), eIgnoreCase)) {
|
||||
nsresult rv = slots->mFrameLoader->SetIsPrerendered();
|
||||
|
Before Width: | Height: | Size: 954 B After Width: | Height: | Size: 681 B |
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 493 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 931 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.3 KiB |
@ -72,9 +72,9 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/enabled_confirmation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/img_check"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
@ -339,5 +339,27 @@ this.BrowserTestUtils = {
|
||||
synthesizeMouseAtPoint(offsetX, offsetY, event, browser)
|
||||
{
|
||||
return BrowserTestUtils.synthesizeMouse(null, offsetX, offsetY, event, browser);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the given tab from its parent tabbrowser and
|
||||
* waits until its final message has reached the parent.
|
||||
*/
|
||||
removeTab(tab, options = {}) {
|
||||
let dontRemove = options && options.dontRemove;
|
||||
|
||||
return new Promise(resolve => {
|
||||
let {messageManager: mm, frameLoader} = tab.linkedBrowser;
|
||||
mm.addMessageListener("SessionStore:update", function onMessage(msg) {
|
||||
if (msg.targetFrameLoader == frameLoader && msg.data.isFinal) {
|
||||
mm.removeMessageListener("SessionStore:update", onMessage);
|
||||
resolve();
|
||||
}
|
||||
}, true);
|
||||
|
||||
if (!dontRemove && !tab.closing) {
|
||||
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -880,6 +880,8 @@ this.PlacesUtils = {
|
||||
* Set the POST data associated with a bookmark, if any.
|
||||
* Used by POST keywords.
|
||||
* @param aBookmarkId
|
||||
*
|
||||
* @deprecated Use PlacesUtils.keywords.insert() API instead.
|
||||
*/
|
||||
setPostDataForBookmark(aBookmarkId, aPostData) {
|
||||
if (!aPostData)
|
||||
@ -923,6 +925,8 @@ this.PlacesUtils = {
|
||||
* Get the POST data associated with a bookmark, if any.
|
||||
* @param aBookmarkId
|
||||
* @returns string of POST data if set for aBookmarkId. null otherwise.
|
||||
*
|
||||
* @deprecated Use PlacesUtils.keywords.fetch() API instead.
|
||||
*/
|
||||
getPostDataForBookmark(aBookmarkId) {
|
||||
let stmt = PlacesUtils.history.DBConnection.createStatement(
|
||||
|
@ -533,18 +533,24 @@ interface nsINavBookmarksService : nsISupports
|
||||
*
|
||||
* Use an empty keyword to clear the keyword associated with the URI.
|
||||
* In both of these cases, succeeds but does nothing if the URL/keyword is not found.
|
||||
*
|
||||
* @deprecated Use PlacesUtils.keywords.insert() API instead.
|
||||
*/
|
||||
void setKeywordForBookmark(in long long aItemId, in AString aKeyword);
|
||||
|
||||
/**
|
||||
* Retrieves the keyword for the given bookmark. Will be void string
|
||||
* (null in JS) if no such keyword is found.
|
||||
*
|
||||
* @deprecated Use PlacesUtils.keywords.fetch() API instead.
|
||||
*/
|
||||
AString getKeywordForBookmark(in long long aItemId);
|
||||
|
||||
/**
|
||||
* Returns the URI associated with the given keyword. Empty if no such
|
||||
* keyword is found.
|
||||
*
|
||||
* @deprecated Use PlacesUtils.keywords.fetch() API instead.
|
||||
*/
|
||||
nsIURI getURIForKeyword(in AString keyword);
|
||||
|
||||
|
@ -2445,6 +2445,8 @@ nsNavBookmarks::GetURIForKeyword(const nsAString& aUserCasedKeyword,
|
||||
NS_ENSURE_TRUE(!aUserCasedKeyword.IsEmpty(), NS_ERROR_INVALID_ARG);
|
||||
*aURI = nullptr;
|
||||
|
||||
PLACES_WARN_DEPRECATED();
|
||||
|
||||
// Shortcuts are always lowercased internally.
|
||||
nsAutoString keyword(aUserCasedKeyword);
|
||||
ToLowerCase(keyword);
|
||||
|
@ -402,11 +402,6 @@
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<field name="_permanentKey">({})</field>
|
||||
|
||||
<property name="permanentKey" readonly="true"
|
||||
onget="return this._permanentKey;"/>
|
||||
|
||||
<property name="outerWindowID" readonly="true">
|
||||
<getter><![CDATA[
|
||||
return this.contentWindow
|
||||
@ -1096,8 +1091,7 @@
|
||||
"_docShell",
|
||||
"_webBrowserFind",
|
||||
"_contentWindow",
|
||||
"_webNavigation",
|
||||
"_permanentKey"
|
||||
"_webNavigation"
|
||||
];
|
||||
|
||||
if (this.isRemoteBrowser) {
|
||||
|
@ -134,9 +134,12 @@
|
||||
readonly="true"/>
|
||||
<property name="contentDocument" readonly="true"
|
||||
onget="return this.webNavigation.document;"/>
|
||||
<property name="docShell"
|
||||
onget="return this.boxObject.docShell;"
|
||||
readonly="true"/>
|
||||
<property name="docShell" readonly="true">
|
||||
<getter><![CDATA[
|
||||
let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
|
||||
return frameLoader ? frameLoader.docShell : null;
|
||||
]]></getter>
|
||||
</property>
|
||||
<property name="currentURI"
|
||||
readonly="true"
|
||||
onget="return this.webNavigation.currentURI;"/>
|
||||
|
@ -85,9 +85,12 @@
|
||||
|
||||
<binding id="iframe" role="outerdoc">
|
||||
<implementation>
|
||||
<property name="docShell"
|
||||
readonly="true"
|
||||
onget="return this.boxObject.docShell"/>
|
||||
<property name="docShell" readonly="true">
|
||||
<getter><![CDATA[
|
||||
let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
|
||||
return frameLoader ? frameLoader.docShell : null;
|
||||
]]></getter>
|
||||
</property>
|
||||
<property name="contentWindow"
|
||||
readonly="true"
|
||||
onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);"/>
|
||||
|
@ -4746,6 +4746,10 @@ BreakpointActor.prototype = {
|
||||
actorPrefix: "breakpoint",
|
||||
condition: null,
|
||||
|
||||
disconnect: function () {
|
||||
this.removeScripts();
|
||||
},
|
||||
|
||||
hasScript: function (aScript) {
|
||||
return this.scripts.has(aScript);
|
||||
},
|
||||
|
@ -49,6 +49,16 @@ function waitForPage(pages) {
|
||||
});
|
||||
}
|
||||
|
||||
function swapDocShells(browser1, browser2) {
|
||||
// Swap frameLoaders.
|
||||
browser1.swapDocShells(browser2);
|
||||
|
||||
// Swap permanentKeys.
|
||||
let tmp = browser1.permanentKey;
|
||||
browser1.permanentKey = browser2.permanentKey;
|
||||
browser2.permanentKey = tmp;
|
||||
}
|
||||
|
||||
// Test that opening a page creates a port, sends the load event and then
|
||||
// navigating to a new page sends the unload event. Going back should create a
|
||||
// new port
|
||||
@ -193,7 +203,7 @@ add_task(function* browser_switch() {
|
||||
port1.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom nom", "Should have the right cookie");
|
||||
|
||||
browser1.swapDocShells(browser2);
|
||||
swapDocShells(browser1, browser2);
|
||||
is(port1.browser, browser2, "Should have noticed the swap");
|
||||
is(port2.browser, browser1, "Should have noticed the swap");
|
||||
|
||||
@ -210,7 +220,7 @@ add_task(function* browser_switch() {
|
||||
port1.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom nom", "Should have the right cookie");
|
||||
|
||||
browser1.swapDocShells(browser2);
|
||||
swapDocShells(browser1, browser2);
|
||||
is(port1.browser, browser1, "Should have noticed the swap");
|
||||
is(port2.browser, browser2, "Should have noticed the swap");
|
||||
|
||||
|