Merge m-c to graphics

MozReview-Commit-ID: 6ocpYm7MBCV
This commit is contained in:
Kartikaya Gupta 2016-12-19 13:35:32 -05:00
commit 108f572510
700 changed files with 22008 additions and 22769 deletions

View File

@ -25,7 +25,6 @@ EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
mParent(aParent), mStartIdx(UINT32_MAX),
mStateFlagsCopy(mParent->mStateFlags),
mEventTree(aNoEvents ? kNoEventTree : nullptr),
mQueueEvents(!aNoEvents)
{
#ifdef DEBUG
@ -33,7 +32,7 @@ TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
#endif
#ifdef A11Y_LOG
if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
logging::MsgBegin("EVENTS_TREE", "reordering tree before");
logging::AccessibleInfo("reordering for", mParent);
Controller()->RootEventTree().Log();
@ -119,7 +118,7 @@ TreeMutation::Done()
#endif
#ifdef A11Y_LOG
if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
if (mQueueEvents && logging::IsEnabled(logging::eEventTree)) {
logging::MsgBegin("EVENTS_TREE", "reordering tree after");
logging::AccessibleInfo("reordering for", mParent);
Controller()->RootEventTree().Log();

View File

@ -47,7 +47,6 @@ private:
Accessible* mParent;
uint32_t mStartIdx;
uint32_t mStateFlagsCopy;
EventTree* mEventTree;
/*
* True if mutation events should be queued.

View File

@ -842,6 +842,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
size_t newDocCount = newChildDocs.Length();
for (size_t i = 0; i < newDocCount; i++) {
DocAccessible* childDoc = newChildDocs[i];
if (childDoc->IsDefunct()) {
continue;
}
Accessible* parent = childDoc->Parent();
DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
uint64_t id = reinterpret_cast<uintptr_t>(parent->UniqueID());

View File

@ -61,7 +61,7 @@
#include "nsIObserverService.h"
#include "nsLayoutUtils.h"
#include "nsPluginFrame.h"
#include "nsSVGPathGeometryFrame.h"
#include "SVGGeometryFrame.h"
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
#include "nsTreeUtils.h"
@ -1173,8 +1173,8 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
if (!newAcc) {
if (content->IsSVGElement()) {
nsSVGPathGeometryFrame* pathGeometryFrame = do_QueryFrame(frame);
if (pathGeometryFrame) {
SVGGeometryFrame* geometryFrame = do_QueryFrame(frame);
if (geometryFrame) {
// A graphic elements: rect, circle, ellipse, line, path, polygon,
// polyline and image. A 'use' and 'text' graphic elements require
// special support.

View File

@ -451,16 +451,6 @@ pref("full-screen-api.ignore-widgets", true);
pref("media.volume.steps", 10);
#ifdef ENABLE_MARIONETTE
//Enable/disable marionette server, set listening port
pref("marionette.defaultPrefs.enabled", true);
pref("marionette.defaultPrefs.port", 2828);
#ifndef MOZ_WIDGET_GONK
// On desktop builds, we need to force the socket to listen on localhost only
pref("marionette.force-local", true);
#endif
#endif
#ifdef MOZ_UPDATER
// When we're applying updates, we can't let anything hang us on
// quit+restart. The user has no recourse.
@ -817,8 +807,7 @@ pref("network.sntp.pools", // Servers separated by ';'.
pref("network.sntp.port", 123);
pref("network.sntp.timeout", 30); // In seconds.
// Allow ADB to run for this many hours before disabling
// (only applies when marionette is disabled)
// Allow ADB to run for this many hours before disabling.
// 0 disables the timer.
pref("b2g.adb.timeout-hours", 12);

View File

@ -166,19 +166,6 @@ var AdbController = {
(!(this.lockEnabled && this.locked) || usbFuncActive);
let useDisableAdbTimer = true;
try {
if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
// Marionette is enabled. Marionette requires that adb be on (and also
// requires that remote debugging be off). The fact that marionette
// is enabled also implies that we're doing a non-production build, so
// we want adb enabled all of the time.
enableAdb = true;
useDisableAdbTimer = false;
}
} catch (e) {
// This means that the pref doesn't exist. Which is fine. We just leave
// enableAdb alone.
}
// Check wakelock to prevent adb from disconnecting when phone is locked
let lockFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);

View File

@ -12,7 +12,6 @@ export GONK_PRODUCT=generic
ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug
ENABLE_MARIONETTE=1
# Enable dump() from JS.
export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"

View File

@ -13,7 +13,6 @@ export GONK_PRODUCT=generic
ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
ac_add_options --enable-debug-symbols
# ac_add_options --enable-profiling
ENABLE_MARIONETTE=1
# Enable dump() from JS.
export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"

View File

@ -23,7 +23,6 @@ no_sccache=
#B2G options
ac_add_options --enable-application=b2g
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
GAIADIR=$topsrcdir/gaia

View File

@ -21,7 +21,6 @@ export MOZ_TELEMETRY_REPORTING=1
ac_add_options --enable-application=b2g
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP

View File

@ -17,7 +17,6 @@ export MOZ_TELEMETRY_REPORTING=1
# B2G Options
ac_add_options --enable-application=b2g
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP

View File

@ -19,7 +19,6 @@ no_sccache=
. "$topsrcdir/build/mozconfig.cache"
# graphene options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common.override"

View File

@ -19,7 +19,6 @@ no_sccache=
. "$topsrcdir/build/mozconfig.cache"
# graphene options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/graphene/config/horizon-mozconfigs/common.override"

View File

@ -16,7 +16,6 @@ export MOZILLA_OFFICIAL=1
# graphene Stuff
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP

View File

@ -12,8 +12,6 @@ export MOZILLA_OFFICIAL=1
. $topsrcdir/build/win32/mozconfig.vs-latest
# graphene Options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/graphene/config/mozconfigs/common.override"

View File

@ -19,7 +19,6 @@ no_sccache=
. "$topsrcdir/build/mozconfig.cache"
# graphene options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/graphene/config/mozconfigs/common.override"

View File

@ -19,7 +19,6 @@ no_sccache=
. "$topsrcdir/build/mozconfig.cache"
# graphene options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/graphene/config/mozconfigs/common.override"

View File

@ -16,7 +16,6 @@ export MOZILLA_OFFICIAL=1
# graphene Stuff
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP

View File

@ -12,8 +12,6 @@ export MOZILLA_OFFICIAL=1
. $topsrcdir/build/win32/mozconfig.vs-latest
# graphene Options
ENABLE_MARIONETTE=1
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
. "$topsrcdir/b2g/grapheneconfig/mozconfigs/common.override"

View File

@ -47,10 +47,6 @@ pref("b2g.nativeWindowGeometry.fullscreen", false);
pref("media.useAudioChannelService", false);
#ifdef ENABLE_MARIONETTE
pref("b2g.is_mulet", true);
#endif
// Most DevTools prefs are set from the shared file
// devtools/client/preferences/devtools.js, but this one is currently set
// per-app or per-channel.

View File

@ -41,10 +41,6 @@ ifdef MOZ_DEBUG
DEFINES += -DMOZ_DEBUG=1
endif
ifdef ENABLE_MARIONETTE
DEFINES += -DENABLE_MARIONETTE=1
endif
MOZ_PACKAGER_MINIFY=1
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))

View File

@ -768,12 +768,6 @@ bin/libfreebl_32int64_3.so
@RESPATH@/chrome/chrome.manifest
@RESPATH@/components/B2GComponents.manifest
@BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@
#if defined(ENABLE_MARIONETTE) || !defined(MOZ_WIDGET_GONK)
@RESPATH@/chrome/marionette@JAREXT@
@RESPATH@/chrome/marionette.manifest
@RESPATH@/components/marionette.manifest
@RESPATH@/components/marionette.js
#endif
@RESPATH@/components/AlertsService.js
@RESPATH@/components/ContentPermissionPrompt.js
@RESPATH@/components/DirectoryProvider.js

View File

@ -89,8 +89,7 @@ SSE2Check()
}
#endif
#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) \
&& !(defined(XP_LINUX) && defined(MOZ_SANDBOX))
#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
#define MOZ_BROWSER_CAN_BE_CONTENTPROC
#include "../../ipc/contentproc/plugin-container.cpp"
#endif

View File

@ -754,9 +754,6 @@ pref("gecko.handlerService.schemes.ircs.2.uriTemplate", "chrome://browser-region
pref("gecko.handlerService.schemes.ircs.3.name", "chrome://browser-region/locale/region.properties");
pref("gecko.handlerService.schemes.ircs.3.uriTemplate", "chrome://browser-region/locale/region.properties");
// By default, we don't want protocol/content handlers to be registered from a different host, see bug 402287
pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
pref("browser.EULA.version", 3);
@ -1555,3 +1552,6 @@ pref("browser.crashReports.unsubmittedCheck.autoSubmit", false);
// controlling validation are located in /services/sync/services-sync.js
pref("services.sync.validation.enabled", true);
#endif
// Preferences for the form autofill system extension
pref("browser.formautofill.enabled", false);

View File

@ -559,6 +559,8 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
visibility: collapse;
}
#urlbar[pageproxystate="invalid"] > #identity-box > #blocked-permissions-container,
#urlbar[pageproxystate="invalid"] > #identity-box > #notification-popup-box,
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels {
visibility: collapse;
}
@ -567,10 +569,6 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
pointer-events: none;
}
#urlbar[pageproxystate="invalid"] > #identity-box > #notification-popup-box {
pointer-events: auto;
}
#identity-icon-labels {
max-width: 18em;
}

View File

@ -2368,7 +2368,22 @@ function BrowserPageInfo(documentURL, initialTab, imageElement, frameOuterWindow
"chrome,toolbar,dialog=no,resizable", args);
}
function URLBarSetURI(aURI) {
/**
* Sets the URI to display in the location bar.
*
* @param aURI [optional]
* nsIURI to set. If this is unspecified, the current URI will be used.
* @param aOptions [optional]
* An object with the following properties:
* {
* isForLocationChange:
* Set to true to indicate that the function was invoked to respond
* to a location change event, rather than to reset the current URI
* value. This is useful to avoid calling PopupNotifications.jsm
* multiple times.
* }
*/
function URLBarSetURI(aURI, aOptions = {}) {
var value = gBrowser.userTypedValue;
var valid = false;
@ -2401,7 +2416,7 @@ function URLBarSetURI(aURI) {
gURLBar.value = value;
gURLBar.valueIsTyped = !valid;
SetPageProxyState(valid ? "valid" : "invalid");
SetPageProxyState(valid ? "valid" : "invalid", aOptions);
}
function losslessDecodeURI(aURI) {
@ -2500,7 +2515,26 @@ function UpdatePageProxyState()
SetPageProxyState("invalid");
}
function SetPageProxyState(aState)
/**
* Updates the user interface to indicate whether the URI in the location bar is
* different than the loaded page, because it's being edited or because a search
* result is currently selected and is displayed in the location bar.
*
* @param aState
* The string "valid" indicates that the security indicators and other
* related user interface elments should be shown because the URI in the
* location bar matches the loaded page. The string "invalid" indicates
* that the URI in the location bar is different than the loaded page.
* @param aOptions [optional]
* An object with the following properties:
* {
* isForLocationChange:
* Set to true to indicate that the function was invoked to respond
* to a location change event. This is useful to avoid calling
* PopupNotifications.jsm multiple times.
* }
*/
function SetPageProxyState(aState, aOptions = {})
{
if (!gURLBar)
return;
@ -2515,6 +2549,15 @@ function SetPageProxyState(aState)
} else if (aState == "invalid") {
gURLBar.removeEventListener("input", UpdatePageProxyState, false);
}
// Only need to call anchorVisibilityChange if the PopupNotifications object
// for this window has already been initialized (i.e. its getter no
// longer exists). If this is the result of a locations change, then we will
// already invoke PopupNotifications.locationChange separately.
if (!Object.getOwnPropertyDescriptor(window, "PopupNotifications").get &&
!aOptions.isForLocationChange) {
PopupNotifications.anchorVisibilityChange();
}
}
function PageProxyClickHandler(aEvent)
@ -4508,7 +4551,7 @@ var XULBrowserWindow = {
this.reloadCommand.removeAttribute("disabled");
}
URLBarSetURI(aLocationURI);
URLBarSetURI(aLocationURI, { isForLocationChange: true });
BookmarkingUI.onLocationChange();
@ -5307,7 +5350,7 @@ var gHomeButton = {
if (homeButton) {
var homePage = this.getHomePage();
homePage = homePage.replace(/\|/g, ', ');
if (homePage.toLowerCase() == "about:home")
if (["about:home", "about:newtab"].includes(homePage.toLowerCase()))
homeButton.setAttribute("tooltiptext", homeButton.getAttribute("aboutHomeOverrideTooltip"));
else
homeButton.setAttribute("tooltiptext", homePage);

View File

@ -409,14 +409,20 @@ Sanitizer.prototype = {
let refObj = {};
TelemetryStopwatch.start("FX_SANITIZE_FORMDATA", refObj);
try {
// Clear undo history of all searchBars
// Clear undo history of all search bars.
let windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let currentWindow = windows.getNext();
let currentDocument = currentWindow.document;
// searchBar.textbox may not exist due to the search bar binding
// not having been constructed yet if the search bar is in the
// overflow or menu panel. It won't have a value or edit history in
// that case.
let searchBar = currentDocument.getElementById("searchbar");
if (searchBar)
if (searchBar && searchBar.textbox)
searchBar.textbox.reset();
let tabBrowser = currentWindow.gBrowser;
if (!tabBrowser) {
// No tab browser? This means that it's too early during startup (typically,

View File

@ -365,6 +365,8 @@ support-files =
refresh_meta.sjs
[browser_relatedTabs.js]
[browser_remoteTroubleshoot.js]
skip-if = !updater
reason = depends on UpdateUtils .Locale
support-files =
test_remoteTroubleshoot.html
[browser_remoteWebNavigation_postdata.js]

View File

@ -16,5 +16,7 @@ skip-if = (os == "linux" && (debug || asan))
skip-if = (os == "linux" && (debug || asan))
[browser_popupNotification_checkbox.js]
skip-if = (os == "linux" && (debug || asan))
[browser_popupNotification_no_anchors.js]
skip-if = (os == "linux" && (debug || asan))
[browser_reshow_in_background.js]
skip-if = (os == "linux" && (debug || asan))

View File

@ -8,11 +8,7 @@ add_task(function* test_displayURI() {
gBrowser,
url: "https://test1.example.com/",
}, function*(browser) {
let popupShownPromise = new Promise((resolve, reject) => {
onPopupEvent("popupshown", function() {
resolve(this);
});
});
let popupShownPromise = waitForNotificationPanel();
yield ContentTask.spawn(browser, null, function*() {
content.navigator.geolocation.getCurrentPosition(function(pos) {
// Do nothing

View File

@ -13,7 +13,6 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
var tests = [
@ -110,7 +109,8 @@ var tests = [
// Note: test 4 to 6 share a tab.
{ id: "Test#4",
run: function* () {
let tab = gBrowser.addTab("about:blank");
let tab = gBrowser.addTab("http://example.com/");
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
isnot(gBrowser.selectedTab, tab, "new tab isn't selected");
wrongBrowserNotificationObject.browser = gBrowser.getBrowserForTab(tab);
let promiseTopic = promiseTopicObserved("PopupNotifications-backgroundShow");

View File

@ -9,7 +9,6 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
var tests = [
@ -58,8 +57,7 @@ var tests = [
{ id: "Test#3",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.addOptions({
persistence: 2
@ -69,7 +67,7 @@ var tests = [
onShown: function* (popup) {
this.complete = false;
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/")
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
// Next load will remove the notification
this.complete = true;
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.org/");
@ -85,8 +83,7 @@ var tests = [
{ id: "Test#4",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
// Set a timeout of 10 minutes that should never be hit
this.notifyObj.addOptions({
@ -115,8 +112,7 @@ var tests = [
{ id: "Test#5",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.addOptions({
persistWhileVisible: true
@ -223,28 +219,4 @@ var tests = [
window.locationbar.visible = true;
}
},
// Test that dismissed popupnotifications can be opened on about:blank
// (where the rest of the identity block is disabled)
{ id: "Test#11",
run: function() {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notifyObj.addOptions({dismissed: true});
this.notification = showNotification(this.notifyObj);
EventUtils.synthesizeMouse(document.getElementById("geo-notification-icon"), 0, 0, {});
},
onShown: function(popup) {
checkPopup(popup, this.notifyObj);
dismissNotification(popup);
},
onHidden: function(popup) {
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
}
];

View File

@ -9,7 +9,6 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
var tests = [
@ -66,7 +65,7 @@ var tests = [
},
// Test that multiple notification icons are removed when switching tabs
{ id: "Test#3",
run: function() {
run: function* () {
// show the notification on old tab.
this.notifyObjOld = new BasicNotification(this.id);
this.notifyObjOld.anchorID = "default-notification-icon";
@ -74,7 +73,7 @@ var tests = [
// switch tab
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
// show the notification on new tab.
this.notifyObjNew = new BasicNotification(this.id);
@ -170,10 +169,7 @@ var tests = [
{ id: "Test#7",
run: function* () {
let oldSelectedTab = gBrowser.selectedTab;
let newTab = gBrowser.addTab("about:blank");
gBrowser.selectedTab = newTab;
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
let newTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
gBrowser.selectedTab = oldSelectedTab;
let browser = gBrowser.getBrowserForTab(newTab);
@ -199,9 +195,7 @@ var tests = [
run: function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
let originalTab = gBrowser.selectedTab;
let bgTab = gBrowser.addTab("about:blank");
gBrowser.selectedTab = bgTab;
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
let bgTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let anchor = document.createElement("box");
anchor.id = "test26-anchor";
anchor.className = "notification-anchor-icon";

View File

@ -9,14 +9,13 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
var tests = [
// Popup Notifications main actions should catch exceptions from callbacks
{ id: "Test#1",
run: function() {
this.testNotif = new ErrorNotification();
this.testNotif = new ErrorNotification(this.id);
showNotification(this.testNotif);
},
onShown: function(popup) {
@ -30,7 +29,7 @@ var tests = [
// Popup Notifications secondary actions should catch exceptions from callbacks
{ id: "Test#2",
run: function() {
this.testNotif = new ErrorNotification();
this.testNotif = new ErrorNotification(this.id);
showNotification(this.testNotif);
},
onShown: function(popup) {
@ -97,30 +96,36 @@ var tests = [
},
// Moving a tab to a new window should remove non-swappable notifications.
{ id: "Test#5",
run: function() {
gBrowser.selectedTab = gBrowser.addTab("about:blank");
run: function* () {
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let notifyObj = new BasicNotification(this.id);
let shown = waitForNotificationPanel();
showNotification(notifyObj);
let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
whenDelayedStartupFinished(win, function() {
let anchor = win.document.getElementById("default-notification-icon");
win.PopupNotifications._reshowNotifications(anchor);
ok(win.PopupNotifications.panel.childNodes.length == 0,
"no notification displayed in new window");
ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
ok(notifyObj.removedCallbackTriggered, "the removed callback was triggered");
win.close();
goNext();
});
yield shown;
let promiseWin = BrowserTestUtils.waitForNewWindow();
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
let win = yield promiseWin;
let anchor = win.document.getElementById("default-notification-icon");
win.PopupNotifications._reshowNotifications(anchor);
ok(win.PopupNotifications.panel.childNodes.length == 0,
"no notification displayed in new window");
ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
ok(notifyObj.removedCallbackTriggered, "the removed callback was triggered");
yield BrowserTestUtils.closeWindow(win);
yield waitForWindowReadyForPopupNotifications(window);
goNext();
}
},
// Moving a tab to a new window should preserve swappable notifications.
{ id: "Test#6",
run: function* () {
let originalBrowser = gBrowser.selectedBrowser;
let originalWindow = window;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let notifyObj = new BasicNotification(this.id);
let originalCallback = notifyObj.options.eventCallback;
notifyObj.options.eventCallback = function(eventName) {
@ -128,9 +133,14 @@ var tests = [
return eventName == "swapping";
};
let shown = waitForNotificationPanel();
let notification = showNotification(notifyObj);
let win = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
yield whenDelayedStartupFinished(win);
yield shown;
let promiseWin = BrowserTestUtils.waitForNewWindow();
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
let win = yield promiseWin;
yield waitForWindowReadyForPopupNotifications(win);
yield new Promise(resolve => {
let callback = notification.options.eventCallback;
@ -146,16 +156,9 @@ var tests = [
checkPopup(win.PopupNotifications.panel, notifyObj);
ok(notifyObj.swappingCallbackTriggered, "the swapping callback was triggered");
yield BrowserTestUtils.closeWindow(win);
// These are the same checks that PopupNotifications.jsm makes before it
// allows a notification to open. Do not go to the next test until we are
// sure that its attempt to display a notification will not fail.
yield BrowserTestUtils.waitForCondition(() => originalBrowser.docShellIsActive,
"The browser should be active");
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
yield BrowserTestUtils.waitForCondition(() => fm.activeWindow == originalWindow,
"The window should be active")
yield BrowserTestUtils.closeWindow(win);
yield waitForWindowReadyForPopupNotifications(window);
goNext();
}

View File

@ -9,7 +9,6 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
var gNotification;
@ -65,17 +64,21 @@ var tests = [
},
// The anchor icon should be shown for notifications in background windows.
{ id: "Test#3",
run: function() {
run: function* () {
let notifyObj = new BasicNotification(this.id);
notifyObj.options.dismissed = true;
let win = gBrowser.replaceTabWithWindow(gBrowser.addTab("about:blank"));
whenDelayedStartupFinished(win, function() {
showNotification(notifyObj);
let anchor = document.getElementById("default-notification-icon");
is(anchor.getAttribute("showing"), "true", "the anchor is shown");
win.close();
goNext();
});
let win = yield BrowserTestUtils.openNewBrowserWindow();
// Open the notification in the original window, now in the background.
showNotification(notifyObj);
let anchor = document.getElementById("default-notification-icon");
is(anchor.getAttribute("showing"), "true", "the anchor is shown");
yield BrowserTestUtils.closeWindow(win);
yield waitForWindowReadyForPopupNotifications(window);
goNext();
}
},
// Test that persistent doesn't allow the notification to persist after
@ -83,8 +86,7 @@ var tests = [
{ id: "Test#4",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.addOptions({
persistent: true
@ -115,8 +117,7 @@ var tests = [
{ id: "Test#5",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.addOptions({
persistent: true
@ -152,9 +153,7 @@ var tests = [
},
onShown: function* (popup) {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
info("Waiting for the new tab to load.");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
},
onHidden: function(popup) {
ok(true, "Should have hidden the notification after tab switch");
@ -179,27 +178,37 @@ var tests = [
{ id: "Test#7",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let shown = waitForNotificationPanel();
let notifyObj = new BasicNotification(this.id);
notifyObj.options.persistent = true;
this.notification = showNotification(notifyObj);
let win = gBrowser.replaceTabWithWindow(gBrowser.addTab("about:blank"));
whenDelayedStartupFinished(win, () => {
ok(notifyObj.shownCallbackTriggered, "Should have triggered the shown callback");
let anchor = win.document.getElementById("default-notification-icon");
win.PopupNotifications._reshowNotifications(anchor);
ok(win.PopupNotifications.panel.childNodes.length == 0,
"no notification displayed in new window");
ok(PopupNotifications.isPanelOpen, "Should be still showing the popup in the first window");
win.close();
let id = PopupNotifications.panel.firstChild.getAttribute("popupid");
ok(id.endsWith("Test#7"), "Should have found the notification from Test7");
ok(PopupNotifications.isPanelOpen, "Should have shown the popup again after getting back to the window");
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
goNext();
});
yield shown;
ok(notifyObj.shownCallbackTriggered, "Should have triggered the shown callback");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let promiseWin = BrowserTestUtils.waitForNewWindow();
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
let win = yield promiseWin;
let anchor = win.document.getElementById("default-notification-icon");
win.PopupNotifications._reshowNotifications(anchor);
ok(win.PopupNotifications.panel.childNodes.length == 0,
"no notification displayed in new window");
yield BrowserTestUtils.closeWindow(win);
yield waitForWindowReadyForPopupNotifications(window);
let id = PopupNotifications.panel.firstChild.getAttribute("popupid");
ok(id.endsWith("Test#7"), "Should have found the notification from Test7");
ok(PopupNotifications.isPanelOpen, "Should have shown the popup again after getting back to the window");
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
goNext();
}
},
// Test that only the first persistent notification is shown on update

View File

@ -9,7 +9,6 @@ function test() {
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
goNext();
}
function checkCheckbox(checkbox, label, checked = false, hidden = false) {

View File

@ -0,0 +1,153 @@
/* 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/. */
function test() {
waitForExplicitFinish();
ok(PopupNotifications, "PopupNotifications object exists");
ok(PopupNotifications.panel, "PopupNotifications panel exists");
setup();
}
var tests = [
// Test that popupnotifications are anchored to the identity icon on
// about:blank, where anchor icons are hidden.
{ id: "Test#1",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notification = showNotification(this.notifyObj);
},
onShown: function(popup) {
checkPopup(popup, this.notifyObj);
is(document.getElementById("geo-notification-icon").boxObject.width, 0,
"geo anchor shouldn't be visible");
is(popup.anchorNode.id, "identity-icon",
"notification anchored to identity icon");
dismissNotification(popup);
},
onHidden: function(popup) {
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
},
// Test that popupnotifications are anchored to the identity icon after
// navigation to about:blank.
{ id: "Test#2",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notifyObj.addOptions({
persistence: 1,
});
this.notification = showNotification(this.notifyObj);
},
onShown: function* (popup) {
yield promiseTabLoadEvent(gBrowser.selectedTab, "about:blank");
checkPopup(popup, this.notifyObj);
is(document.getElementById("geo-notification-icon").boxObject.width, 0,
"geo anchor shouldn't be visible");
is(popup.anchorNode.id, "identity-icon",
"notification anchored to identity icon");
dismissNotification(popup);
},
onHidden: function(popup) {
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
},
// Test that dismissed popupnotifications cannot be opened on about:blank, but
// can be opened after navigation.
{ id: "Test#3",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notifyObj.addOptions({
dismissed: true,
persistence: 1,
});
this.notification = showNotification(this.notifyObj);
is(document.getElementById("geo-notification-icon").boxObject.width, 0,
"geo anchor shouldn't be visible");
yield promiseTabLoadEvent(gBrowser.selectedTab, "http://example.com/");
isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
"geo anchor should be visible");
EventUtils.synthesizeMouse(document.getElementById("geo-notification-icon"), 0, 0, {});
},
onShown: function(popup) {
checkPopup(popup, this.notifyObj);
dismissNotification(popup);
},
onHidden: function(popup) {
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
}
},
// Test that popupnotifications are anchored to the identity icon while
// editing the URL in the location bar, and restored to their anchors when the
// URL is reverted.
{ id: "Test#4",
run: function* () {
this.oldSelectedTab = gBrowser.selectedTab;
yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let shownInitially = waitForNotificationPanel();
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notifyObj.addOptions({
persistent: true,
});
this.notification = showNotification(this.notifyObj);
yield shownInitially;
checkPopup(PopupNotifications.panel, this.notifyObj);
let shownAgain = waitForNotificationPanel();
// This will cause the popup to hide and show again.
gURLBar.select();
EventUtils.synthesizeKey("*", {});
// Keep the URL bar empty, so we don't show the awesomebar.
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
yield shownAgain;
is(document.getElementById("geo-notification-icon").boxObject.width, 0,
"geo anchor shouldn't be visible");
is(PopupNotifications.panel.anchorNode.id, "identity-icon",
"notification anchored to identity icon");
let shownLastTime = waitForNotificationPanel();
// This will cause the popup to hide and show again.
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield shownLastTime;
checkPopup(PopupNotifications.panel, this.notifyObj);
let hidden = new Promise(resolve => onPopupEvent("popuphidden", resolve));
this.notification.remove();
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.selectedTab = this.oldSelectedTab;
yield hidden;
goNext();
}
},
];

View File

@ -9,8 +9,11 @@ add_task(function* test_background_notifications_dont_reshow_in_foreground() {
// Our initial tab will be A. Let's open two more tabs B and C, but keep
// A selected. Then, we'll trigger a PopupNotification in C, and then make
// it reshow.
let tabB = gBrowser.addTab("about:blank");
let tabC = gBrowser.addTab("about:blank");
let tabB = gBrowser.addTab("http://example.com/");
yield BrowserTestUtils.browserLoaded(tabB.linkedBrowser);
let tabC = gBrowser.addTab("http://example.com/");
yield BrowserTestUtils.browserLoaded(tabC.linkedBrowser);
let seenEvents = [];

View File

@ -7,21 +7,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
function whenDelayedStartupFinished(aWindow, aCallback) {
return new Promise(resolve => {
info("Waiting for delayed startup to finish");
Services.obs.addObserver(function observer(aSubject, aTopic) {
if (aWindow == aSubject) {
Services.obs.removeObserver(observer, aTopic);
if (aCallback) {
executeSoon(aCallback);
}
resolve();
}
}, "browser-delayed-startup-finished", false);
});
}
/**
* Allows waiting for an observer notification once.
*
@ -43,6 +28,23 @@ function promiseTopicObserved(topic)
return deferred.promise;
}
/**
* Called after opening a new window or switching windows, this will wait until
* we are sure that an attempt to display a notification will not fail.
*/
function* waitForWindowReadyForPopupNotifications(win)
{
// These are the same checks that PopupNotifications.jsm makes before it
// allows a notification to open.
yield BrowserTestUtils.waitForCondition(
() => win.gBrowser.selectedBrowser.docShellIsActive,
"The browser should be active"
);
yield BrowserTestUtils.waitForCondition(
() => Services.focus.activeWindow == win,
"The window should be active"
);
}
/**
* Waits for a load (or custom) event to finish in a given tab. If provided
@ -70,10 +72,10 @@ function promiseTabLoadEvent(tab, url)
const PREF_SECURITY_DELAY_INITIAL = Services.prefs.getIntPref("security.notification_enable_delay");
function setup() {
// Disable transitions as they slow the test down and we want to click the
// mouse buttons in a predictable location.
BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/")
.then(goNext);
registerCleanupFunction(() => {
gBrowser.removeTab(gBrowser.selectedTab);
PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL;
});
}
@ -173,7 +175,8 @@ BasicNotification.prototype.addOptions = function(options) {
this.options[name] = value;
};
function ErrorNotification() {
function ErrorNotification(testId) {
BasicNotification.call(this, testId);
this.mainAction.callback = () => {
this.mainActionClicked = true;
throw new Error("Oops!");
@ -184,8 +187,7 @@ function ErrorNotification() {
};
}
ErrorNotification.prototype = new BasicNotification();
ErrorNotification.prototype.constructor = ErrorNotification;
ErrorNotification.prototype = BasicNotification.prototype;
function checkPopup(popup, notifyObj) {
info("Checking notification " + notifyObj.id);
@ -257,6 +259,14 @@ function onPopupEvent(eventName, callback, condition) {
PopupNotifications.panel.addEventListener(eventName, listener, false);
}
function waitForNotificationPanel() {
return new Promise(resolve => {
onPopupEvent("popupshown", function() {
resolve(this);
});
});
}
function triggerMainCommand(popup) {
let notifications = popup.childNodes;
ok(notifications.length > 0, "at least one notification displayed");

View File

@ -38,6 +38,7 @@ var gMenuBuilder = {
// to be displayed. We always clear all the items again when
// popuphidden fires.
build(contextData) {
let firstItem = true;
let xulMenu = contextData.menu;
xulMenu.addEventListener("popuphidden", this);
this.xulMenu = xulMenu;
@ -72,6 +73,13 @@ var gMenuBuilder = {
rootElement.setAttribute("image", resolvedURL);
}
if (firstItem) {
firstItem = false;
const separator = xulMenu.ownerDocument.createElement("menuseparator");
this.itemsToCleanUp.add(separator);
xulMenu.append(separator);
}
xulMenu.appendChild(rootElement);
this.itemsToCleanUp.add(rootElement);
}
@ -252,13 +260,8 @@ global.actionContextMenu = function(contextData) {
gMenuBuilder.buildActionContextMenu(contextData);
};
function contextMenuObserver(subject, topic, data) {
subject = subject.wrappedJSObject;
gMenuBuilder.build(subject);
}
function getContexts(contextData) {
let contexts = new Set(["all"]);
let contexts = new Set();
if (contextData.inFrame) {
contexts.add("frame");
@ -300,10 +303,16 @@ function getContexts(contextData) {
contexts.add("browser_action");
}
if (contexts.size == 1) {
if (contexts.size === 0) {
contexts.add("page");
}
if (contextData.onTab) {
contexts.add("tab");
} else {
contexts.add("all");
}
return contexts;
}
@ -517,14 +526,53 @@ MenuItem.prototype = {
},
};
// While any extensions are active, this Tracker registers to observe/listen
// for contex-menu events from both content and chrome.
const contextMenuTracker = {
register() {
Services.obs.addObserver(this, "on-build-contextmenu", false);
for (const window of WindowListManager.browserWindows()) {
this.onWindowOpen(window);
}
WindowListManager.addOpenListener(this.onWindowOpen);
},
unregister() {
Services.obs.removeObserver(this, "on-build-contextmenu");
for (const window of WindowListManager.browserWindows()) {
const menu = window.document.getElementById("tabContextMenu");
menu.removeEventListener("popupshowing", this);
}
WindowListManager.removeOpenListener(this.onWindowOpen);
},
observe(subject, topic, data) {
subject = subject.wrappedJSObject;
gMenuBuilder.build(subject);
},
onWindowOpen(window) {
const menu = window.document.getElementById("tabContextMenu");
menu.addEventListener("popupshowing", contextMenuTracker);
},
handleEvent(event) {
const menu = event.target;
if (menu.id === "tabContextMenu") {
const trigger = menu.triggerNode;
const tab = trigger.localName === "tab" ? trigger : TabManager.activeTab;
const pageUrl = tab.linkedBrowser.currentURI.spec;
gMenuBuilder.build({menu, tab, pageUrl, onTab: true});
}
},
};
var gExtensionCount = 0;
/* eslint-disable mozilla/balanced-listeners */
extensions.on("startup", (type, extension) => {
gContextMenuMap.set(extension, new Map());
if (++gExtensionCount == 1) {
Services.obs.addObserver(contextMenuObserver,
"on-build-contextmenu",
false);
contextMenuTracker.register();
}
});
@ -532,8 +580,7 @@ extensions.on("shutdown", (type, extension) => {
gContextMenuMap.delete(extension);
gRootItems.delete(extension);
if (--gExtensionCount == 0) {
Services.obs.removeObserver(contextMenuObserver,
"on-build-contextmenu");
contextMenuTracker.unregister();
}
});
/* eslint-enable mozilla/balanced-listeners */

View File

@ -31,8 +31,8 @@
{
"id": "ContextType",
"type": "string",
"enum": ["all", "page", "frame", "selection", "link", "editable", "password", "image", "video", "audio", "launcher", "browser_action", "page_action"],
"description": "The different contexts a menu can appear in. Specifying 'all' is equivalent to the combination of all other contexts except for 'launcher'. The 'launcher' context is only supported by apps and is used to add menu items to the context menu that appears when clicking on the app icon in the launcher/taskbar/dock/etc. Different platforms might put limitations on what is actually supported in a launcher context menu."
"enum": ["all", "page", "frame", "selection", "link", "editable", "password", "image", "video", "audio", "launcher", "browser_action", "page_action", "tab"],
"description": "The different contexts a menu can appear in. Specifying 'all' is equivalent to the combination of all other contexts except for 'tab'."
},
{
"id": "ItemType",

View File

@ -34,8 +34,8 @@ support-files =
[browser_ext_commands_onCommand.js]
[browser_ext_contentscript_connect.js]
[browser_ext_contextMenus.js]
[browser_ext_contextMenus_actionMenus.js]
[browser_ext_contextMenus_checkboxes.js]
[browser_ext_contextMenus_chrome.js]
[browser_ext_contextMenus_icons.js]
[browser_ext_contextMenus_onclick.js]
[browser_ext_contextMenus_radioGroups.js]

View File

@ -1,64 +0,0 @@
/* 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";
add_task(function* () {
const manifest = {
page_action: {},
browser_action: {},
permissions: ["contextMenus"],
};
async function background() {
const contexts = ["page_action", "browser_action"];
const parentId = browser.contextMenus.create({contexts, title: "parent"});
await browser.contextMenus.create({contexts, parentId, title: "click A"});
await browser.contextMenus.create({contexts, parentId, title: "click B"});
for (let i = 1; i < 9; i++) {
await browser.contextMenus.create({contexts, title: `click ${i}`});
}
browser.contextMenus.onClicked.addListener((info, tab) => {
browser.test.sendMessage("click", {info, tab});
});
const [tab] = await browser.tabs.query({active: true});
await browser.pageAction.show(tab.id);
browser.test.sendMessage("ready", tab.id);
}
const extension = ExtensionTestUtils.loadExtension({manifest, background});
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
yield extension.startup();
const tabId = yield extension.awaitMessage("ready");
for (const kind of ["page", "browser"]) {
const menu = yield openActionContextMenu(extension, kind);
const [submenu, second, , , , last, separator] = menu.children;
is(submenu.tagName, "menu", "Correct submenu type");
is(submenu.label, "parent", "Correct submenu title");
const popup = yield openActionSubmenu(submenu);
is(popup, submenu.firstChild, "Correct submenu opened");
is(popup.children.length, 2, "Correct number of submenu items");
is(second.tagName, "menuitem", "Second menu item type is correct");
is(second.label, "click 1", "Second menu item title is correct");
is(last.label, "click 5", "Last menu item title is correct");
is(separator.tagName, "menuseparator", "Separator after last menu item");
yield closeActionContextMenu(popup.firstChild);
const {info, tab} = yield extension.awaitMessage("click");
is(info.pageUrl, "http://example.com/", "Click info pageUrl is correct");
is(tab.id, tabId, "Click event tab ID is correct");
}
yield BrowserTestUtils.removeTab(tab);
yield extension.unload();
});

View File

@ -0,0 +1,129 @@
/* 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";
add_task(function* test_actionContextMenus() {
const manifest = {
page_action: {},
browser_action: {},
permissions: ["contextMenus"],
};
async function background() {
const contexts = ["page_action", "browser_action"];
const parentId = browser.contextMenus.create({contexts, title: "parent"});
await browser.contextMenus.create({contexts, parentId, title: "click A"});
await browser.contextMenus.create({contexts, parentId, title: "click B"});
for (let i = 1; i < 9; i++) {
await browser.contextMenus.create({contexts, title: `click ${i}`});
}
browser.contextMenus.onClicked.addListener((info, tab) => {
browser.test.sendMessage("click", {info, tab});
});
const [tab] = await browser.tabs.query({active: true});
await browser.pageAction.show(tab.id);
browser.test.sendMessage("ready", tab.id);
}
const extension = ExtensionTestUtils.loadExtension({manifest, background});
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
yield extension.startup();
const tabId = yield extension.awaitMessage("ready");
for (const kind of ["page", "browser"]) {
const menu = yield openActionContextMenu(extension, kind);
const [submenu, second, , , , last, separator] = menu.children;
is(submenu.tagName, "menu", "Correct submenu type");
is(submenu.label, "parent", "Correct submenu title");
const popup = yield openSubmenu(submenu);
is(popup, submenu.firstChild, "Correct submenu opened");
is(popup.children.length, 2, "Correct number of submenu items");
is(second.tagName, "menuitem", "Second menu item type is correct");
is(second.label, "click 1", "Second menu item title is correct");
is(last.label, "click 5", "Last menu item title is correct");
is(separator.tagName, "menuseparator", "Separator after last menu item");
yield closeActionContextMenu(popup.firstChild);
const {info, tab} = yield extension.awaitMessage("click");
is(info.pageUrl, "http://example.com/", "Click info pageUrl is correct");
is(tab.id, tabId, "Click event tab ID is correct");
}
yield BrowserTestUtils.removeTab(tab);
yield extension.unload();
});
add_task(function* test_tabContextMenu() {
const first = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["contextMenus"],
},
async background() {
await browser.contextMenus.create({title: "alpha", contexts: ["tab"]});
await browser.contextMenus.create({title: "beta", contexts: ["tab"]});
browser.contextMenus.onClicked.addListener((info, tab) => {
browser.test.sendMessage("click", {info, tab});
});
const [tab] = await browser.tabs.query({active: true});
browser.test.sendMessage("ready", tab.id);
},
});
const second = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["contextMenus"],
},
async background() {
await browser.contextMenus.create({title: "gamma", contexts: ["tab"]});
browser.test.sendMessage("ready");
},
});
const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
yield first.startup();
yield second.startup();
const tabId = yield first.awaitMessage("ready");
yield second.awaitMessage("ready");
const menu = yield openTabContextMenu();
const [separator, submenu, gamma] = Array.from(menu.children).slice(-3);
is(separator.tagName, "menuseparator", "Separator before first extension item");
is(submenu.tagName, "menu", "Correct submenu type");
is(submenu.label, "Generated extension", "Correct submenu title");
is(gamma.tagName, "menuitem", "Third menu item type is correct");
is(gamma.label, "gamma", "Third menu item label is correct");
const popup = yield openSubmenu(submenu);
is(popup, submenu.firstChild, "Correct submenu opened");
is(popup.children.length, 2, "Correct number of submenu items");
const [alpha, beta] = popup.children;
is(alpha.tagName, "menuitem", "First menu item type is correct");
is(alpha.label, "alpha", "First menu item label is correct");
is(beta.tagName, "menuitem", "Second menu item type is correct");
is(beta.label, "beta", "Second menu item label is correct");
yield closeTabContextMenu(beta);
const click = yield first.awaitMessage("click");
is(click.info.pageUrl, "http://example.com/", "Click info pageUrl is correct");
is(click.tab.id, tabId, "Click event tab ID is correct");
yield BrowserTestUtils.removeTab(tab);
yield first.unload();
yield second.unload();
});

View File

@ -26,6 +26,33 @@ function createHiddenBrowser(url) {
let extension;
let dummy = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/file_dummy.html";
let headers = {
request: {
add: {
"X-WebRequest-request": "text",
"X-WebRequest-request-binary": "binary",
},
modify: {
"user-agent": "WebRequest",
},
remove: [
"accept-encoding",
],
},
response: {
add: {
"X-WebRequest-response": "text",
"X-WebRequest-response-binary": "binary",
},
modify: {
"server": "WebRequest",
"content-type": "text/html; charset=utf-8",
},
remove: [
"connection",
],
},
};
add_task(function* setup() {
// SelfSupport has a tendency to fire when running this test alone, without
@ -41,6 +68,7 @@ add_task(function* test_newWindow() {
let expect = {
"file_dummy.html": {
type: "main_frame",
headers,
},
};
// NOTE: When running solo, favicon will be loaded at some point during
@ -63,6 +91,7 @@ add_task(function* test_newTab() {
let expect = {
"file_dummy.html": {
type: "main_frame",
headers,
},
};
extension.sendMessage("set-expected", {expect, ignore: ["favicon.ico"]});
@ -77,6 +106,7 @@ add_task(function* test_subframe() {
let expect = {
"file_dummy.html": {
type: "main_frame",
headers,
},
};
// test a content subframe attached to hidden window

View File

@ -10,7 +10,8 @@
* promisePopupShown promisePopupHidden
* openContextMenu closeContextMenu
* openExtensionContextMenu closeExtensionContextMenu
* openActionContextMenu openActionSubmenu closeActionContextMenu
* openActionContextMenu openSubmenu closeActionContextMenu
* openTabContextMenu closeTabContextMenu
* imageBuffer getListStyleImage getPanelForNode
* awaitExtensionPanel awaitPopupResize
* promiseContentDimensions alterContent
@ -262,20 +263,16 @@ function* closeExtensionContextMenu(itemToSelect) {
yield popupHiddenPromise;
}
function* openActionContextMenu(extension, kind, win = window) {
const menu = win.document.getElementById("toolbar-context-menu");
const id = `${makeWidgetId(extension.id)}-${kind}-action`;
const button = win.document.getElementById(id);
SetPageProxyState("valid");
function* openChromeContextMenu(menuId, target, win = window) {
const node = win.document.querySelector(target);
const menu = win.document.getElementById(menuId);
const shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
EventUtils.synthesizeMouseAtCenter(button, {type: "contextmenu"}, win);
EventUtils.synthesizeMouseAtCenter(node, {type: "contextmenu"}, win);
yield shown;
return menu;
}
function* openActionSubmenu(submenuItem, win = window) {
function* openSubmenu(submenuItem, win = window) {
const submenu = submenuItem.firstChild;
const shown = BrowserTestUtils.waitForEvent(submenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(submenuItem, {}, win);
@ -283,8 +280,8 @@ function* openActionSubmenu(submenuItem, win = window) {
return submenu;
}
function closeActionContextMenu(itemToSelect, win = window) {
const menu = win.document.getElementById("toolbar-context-menu");
function closeChromeContextMenu(menuId, itemToSelect, win = window) {
const menu = win.document.getElementById(menuId);
const hidden = BrowserTestUtils.waitForEvent(menu, "popuphidden");
if (itemToSelect) {
EventUtils.synthesizeMouseAtCenter(itemToSelect, {}, win);
@ -294,6 +291,25 @@ function closeActionContextMenu(itemToSelect, win = window) {
return hidden;
}
function openActionContextMenu(extension, kind, win = window) {
// See comment from clickPageAction below.
SetPageProxyState("valid");
const id = `#${makeWidgetId(extension.id)}-${kind}-action`;
return openChromeContextMenu("toolbar-context-menu", id, win);
}
function closeActionContextMenu(itemToSelect, win = window) {
return closeChromeContextMenu("toolbar-context-menu", itemToSelect, win);
}
function openTabContextMenu(win = window) {
return openChromeContextMenu("tabContextMenu", ".tabbrowser-tab[selected]", win);
}
function closeTabContextMenu(itemToSelect, win = window) {
return closeChromeContextMenu("tabContextMenu", itemToSelect, win);
}
function getPageActionPopup(extension, win = window) {
let panelId = makeWidgetId(extension.id) + "-panel";
return win.document.getElementById(panelId);

View File

@ -30,7 +30,6 @@ const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_SELECTED_ACTION = "browser.feeds.handler";
const PREF_SELECTED_READER = "browser.feeds.handler.default";
const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external";
const PREF_ALLOW_DIFFERENT_HOST = "gecko.handlerService.allowRegisterFromDifferentHost";
const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
@ -156,11 +155,8 @@ const Utils = {
}
// We also reject handlers registered from a different host (see bug 402287)
// The pref allows us to test the feature
let pb = Services.prefs;
if (!pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST) &&
(!["http:", "https:"].includes(aContentWindow.location.protocol) ||
aContentWindow.location.hostname != uri.host)) {
if (!["http:", "https:"].includes(aContentWindow.location.protocol) ||
aContentWindow.location.hostname != uri.host) {
throw this.getSecurityError(
"Permission denied to add " + uri.spec + " as a content or protocol handler",
aContentWindow);

View File

@ -1,5 +1,6 @@
import os
import shutil
import time
from marionette_harness import MarionetteTestCase
@ -343,21 +344,22 @@ class TestFirefoxRefresh(MarionetteTestCase):
if self.reset_profile_path:
# Remove ourselves from profiles.ini
profileLeafName = os.path.basename(os.path.normpath(self.reset_profile_path))
self.runCode("""
let [salt, name] = arguments[0].split(".");
let name = arguments[0];
let profile = global.profSvc.getProfileByName(name);
profile.remove(false)
global.profSvc.flush();
""", script_args=[profileLeafName])
""", script_args=[self.profileNameToRemove])
# And delete all the files.
shutil.rmtree(self.reset_profile_path, ignore_errors=False, onerror=handleRemoveReadonly)
def doReset(self):
profileName = "marionette-test-profile-" + str(int(time.time() * 1000))
self.profileNameToRemove = profileName
self.runCode("""
// Ensure the current (temporary) profile is in profiles.ini:
let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
let profileName = "marionette-test-profile-" + Date.now();
let profileName = arguments[1];
let myProfile = global.profSvc.createProfile(profD, profileName);
global.profSvc.flush()
@ -375,7 +377,7 @@ class TestFirefoxRefresh(MarionetteTestCase):
env.set("MOZ_RESET_PROFILE_RESTART", "1");
env.set("XRE_PROFILE_PATH", arguments[0]);
env.set("XRE_PROFILE_NAME", profileName);
""", script_args=[self.marionette.instance.profile.profile])
""", script_args=[self.marionette.instance.profile.profile, profileName])
profileLeafName = os.path.basename(os.path.normpath(self.marionette.instance.profile.profile))

View File

@ -4,6 +4,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OfflineAppCacheHelper",
"resource:///modules/offlineAppCache.jsm");
@ -177,5 +178,28 @@ this.SiteDataManager = {
Services.cookies.removeAll();
OfflineAppCacheHelper.clear();
this.updateSites();
},
getSites() {
return Promise.all([this._updateQuotaPromise, this._updateDiskCachePromise])
.then(() => {
let list = [];
for (let [origin, site] of this._sites) {
let cache = null;
let usage = site.quotaUsage;
for (cache of site.appCacheList) {
usage += cache.usage;
}
for (cache of site.diskCacheList) {
usage += cache.dataSize;
}
list.push({
usage,
status: site.status,
uri: NetUtil.newURI(origin)
});
}
return list;
});
}
};

View File

@ -60,6 +60,8 @@ var gAdvancedPane = {
SiteDataManager.updateSites();
setEventListener("clearSiteDataButton", "command",
gAdvancedPane.clearSiteData);
setEventListener("siteDataSettings", "command",
gAdvancedPane.showSiteDataSettings);
}
setEventListener("layers.acceleration.disabled", "change",
@ -339,6 +341,10 @@ var gAdvancedPane = {
gSubDialog.open("chrome://browser/content/preferences/connection.xul");
},
showSiteDataSettings: function() {
gSubDialog.open("chrome://browser/content/preferences/siteDataSettings.xul");
},
updateTotalSiteDataSize: function() {
SiteDataManager.getTotalUsage()
.then(usage => {

View File

@ -338,6 +338,11 @@
<button id="clearSiteDataButton" icon="clear"
label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
</hbox>
<vbox align="end">
<button id="siteDataSettings"
label="&siteDataSettings.label;"
accesskey="&siteDataSettings.accesskey;"/>
</vbox>
</groupbox>
</tabpanel>

View File

@ -245,10 +245,17 @@ var gMainPane = {
{
let homePref = document.getElementById("browser.startup.homepage");
// If the pref is set to about:home, set the value to "" to show the
// placeholder text (about:home title).
if (homePref.value.toLowerCase() == "about:home")
// If the pref is set to about:home or about:newtab, set the value to ""
// to show the placeholder text (about:home title) rather than
// exposing those URLs to users.
let defaultBranch = Services.prefs.getDefaultBranch("");
let defaultValue = defaultBranch.getComplexValue("browser.startup.homepage",
Ci.nsIPrefLocalizedString).data;
let currentValue = homePref.value.toLowerCase();
if (currentValue == "about:home" ||
(currentValue == defaultValue && currentValue == "about:newtab")) {
return "";
}
// If the pref is actually "", show about:blank. The actual home page
// loading code treats them the same, and we don't want the placeholder text

View File

@ -6,6 +6,7 @@ support-files =
[browser_advanced_siteData.js]
[browser_advanced_update.js]
skip-if = !updater
[browser_basic_rebuild_fonts_test.js]
[browser_bug410900.js]
[browser_bug705422.js]

View File

@ -27,5 +27,9 @@ browser.jar:
content/browser/preferences/sanitize.js
content/browser/preferences/selectBookmark.xul
content/browser/preferences/selectBookmark.js
content/browser/preferences/siteDataSettings.xul
content/browser/preferences/siteDataSettings.js
content/browser/preferences/siteDataSettings.css
content/browser/preferences/siteListItem.xml
content/browser/preferences/translation.xul
content/browser/preferences/translation.js

View File

@ -0,0 +1,15 @@
/* 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/. */
#sitesList {
min-height: 20em;
}
#sitesList > richlistitem {
-moz-binding: url("chrome://browser/content/preferences/siteListItem.xml#siteListItem");
}
.item-box {
padding: 5px 8px;
}

View File

@ -0,0 +1,69 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* 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/. */
const { interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
"resource:///modules/SiteDataManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
"resource://gre/modules/DownloadUtils.jsm");
"use strict";
let gSiteDataSettings = {
// Array of meatdata of sites. Each array element is object holding:
// - uri: uri of site; instance of nsIURI
// - status: persistent-storage permission status
// - usage: disk usage which site uses
_sites: null,
_list: null,
init() {
this._list = document.getElementById("sitesList");
SiteDataManager.getSites().then(sites => {
this._sites = sites;
this._sortSites(this._sites, "decending");
this._buildSitesList(this._sites);
});
},
/**
* Sort sites by usages
*
* @param sites {Array}
* @param order {String} indicate to sort in the "decending" or "ascending" order
*/
_sortSites(sites, order) {
sites.sort((a, b) => {
if (order === "ascending") {
return a.usage - b.usage;
}
return b.usage - a.usage;
});
},
_buildSitesList(sites) {
// Clear old entries.
while (this._list.childNodes.length > 1) {
this._list.removeChild(this._list.lastChild);
}
let prefStrBundle = document.getElementById("bundlePreferences");
for (let data of sites) {
let statusStrId = data.status === Ci.nsIPermissionManager.ALLOW_ACTION ? "important" : "default";
let size = DownloadUtils.convertByteUnits(data.usage);
let item = document.createElement("richlistitem");
item.setAttribute("data-origin", data.uri.spec);
item.setAttribute("host", data.uri.host);
item.setAttribute("status", prefStrBundle.getString(statusStrId));
item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size));
this._list.appendChild(item);
}
}
};

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/preferences/siteDataSettings.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/siteDataSettings.dtd" >
<window id="SiteDataSettingsDialog" windowtype="Browser:SiteDataSettings"
class="windowDialog" title="&window.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
style="width: 45em;"
onload="gSiteDataSettings.init();"
persist="screenX screenY width height">
<script src="chrome://browser/content/preferences/siteDataSettings.js"/>
<stringbundle id="bundlePreferences"
src="chrome://browser/locale/preferences/preferences.properties"/>
<vbox flex="1">
<description>&settings.description;</description>
<separator class="thin"/>
<richlistbox id="sitesList" orient="vertical" flex="1">
<listheader>
<treecol flex="4" width="50" label="&hostCol.label;"/>
<treecol flex="2" width="50" label="&statusCol.label;"/>
<treecol flex="1" width="50" label="&usageCol.label;"/>
</listheader>
</richlistbox>
</vbox>
</window>

View File

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<!-- 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/. -->
<!-- import-globals-from siteDataSettings.js -->
<!DOCTYPE overlay [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
<!ENTITY % applicationsDTD SYSTEM "chrome://browser/locale/preferences/siteDataSettings.dtd">
%brandDTD;
%applicationsDTD;
]>
<bindings id="siteListItemBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="siteListItem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<content>
<xul:hbox flex="1">
<xul:hbox flex="4" width="50" class="item-box" align="center" xbl:inherits="tooltiptext=host">
<xul:label flex="1" crop="end" xbl:inherits="value=host"/>
</xul:hbox>
<xul:hbox flex="2" width="50" class="item-box" align="center" xbl:inherits="tooltiptext=status">
<xul:label flex="1" crop="end" xbl:inherits="value=status"/>
</xul:hbox>
<xul:hbox flex="1" width="50" class="item-box" align="center" xbl:inherits="tooltiptext=usage">
<xul:label flex="1" crop="end" xbl:inherits="value=usage"/>
</xul:hbox>
</xul:hbox>
</content>
</binding>
</bindings>

View File

@ -881,10 +881,8 @@ var SessionStoreInternal = {
if (activePageData) {
if (activePageData.title) {
tab.label = activePageData.title;
tab.crop = "end";
} else if (activePageData.url != "about:blank") {
tab.label = activePageData.url;
tab.crop = "center";
}
} else if (tab.hasAttribute("customizemode")) {
win.gCustomizeMode.setTab(tab);

View File

@ -1,4 +1,6 @@
[DEFAULT]
[browser_bug538331.js]
skip-if = !updater
reason = test depends on update channel
[browser_contentpermissionprompt.js]

View File

@ -160,20 +160,15 @@ function loadJSONAsync(file, options) {
// Returns a promise that is resolved with the AddonInstall for that URL.
function addonInstallForURL(url, hash) {
let deferred = Promise.defer();
AddonManager.getInstallForURL(url, install => deferred.resolve(install),
"application/x-xpinstall", hash);
return deferred.promise;
return AddonManager.getInstallForURL(url, null, "application/x-xpinstall", hash);
}
// Returns a promise that is resolved with an Array<Addon> of the installed
// experiment addons.
function installedExperimentAddons() {
let deferred = Promise.defer();
AddonManager.getAddonsByTypes(["experiment"], (addons) => {
deferred.resolve(addons.filter(a => !a.appDisabled));
return AddonManager.getAddonsByTypes(["experiment"]).then(addons => {
return addons.filter(a => !a.appDisabled);
});
return deferred.promise;
}
// Takes an Array<Addon> and returns a promise that is resolved when the
@ -2025,18 +2020,14 @@ Experiments.ExperimentEntry.prototype = {
return Promise.resolve(null);
}
let deferred = Promise.defer();
AddonManager.getAddonByID(this._addonId, (addon) => {
return AddonManager.getAddonByID(this._addonId).then(addon => {
if (addon && addon.appDisabled) {
// Don't return PreviousExperiments.
addon = null;
return null;
}
deferred.resolve(addon);
return addon;
});
return deferred.promise;
},
_logTermination: function(terminationKind, terminationReason) {

View File

@ -6,7 +6,25 @@
/* exported startup, shutdown, install, uninstall */
function startup() {}
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillParent",
"resource://formautofill/FormAutofillParent.jsm");
function startup() {
// Besides this pref, we'll need dom.forms.autocomplete.experimental enabled
// as well to make sure form autocomplete works correctly.
if (!Services.prefs.getBoolPref("browser.formautofill.enabled")) {
return;
}
FormAutofillParent.init();
Services.mm.loadFrameScript("chrome://formautofill/content/FormAutofillContent.js", true);
}
function shutdown() {}
function install() {}
function uninstall() {}

View File

@ -3,13 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implements a service used by DOM content to request Form Autofill.
* Form Autofill frame script.
*/
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
/**
* Handles profile autofill for a DOM Form element.
* @param {HTMLFormElement} form Form that need to be auto filled
@ -130,5 +131,3 @@ FormAutofillHandler.prototype = {
}
},
};
this.EXPORTED_SYMBOLS = ["FormAutofillHandler"];

View File

@ -3,5 +3,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[features/formautofill@mozilla.org] chrome.jar:
% resource formautofill %content/
content/ (content/*)
% resource formautofill %res/
res/ (*.jsm)
% content formautofill %content/
content/ (content/*)

View File

@ -20,3 +20,6 @@ BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
JAR_MANIFESTS += ['jar.mn']
with Files('**'):
BUG_COMPONENT = ('Toolkit', 'Form Manager')

View File

@ -2,7 +2,7 @@
* Provides infrastructure for automated formautofill components tests.
*/
/* exported importAutofillModule, getTempFile */
/* exported getTempFile */
"use strict";
@ -18,11 +18,18 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
// Register the resource path of formautofill
let resHandler = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsISubstitutingProtocolHandler);
let dataURI = NetUtil.newURI(do_get_file(".", true));
resHandler.setSubstitution("formautofill", dataURI);
// Load our bootstrap extension manifest so we can access our chrome/resource URIs.
const EXTENSION_ID = "formautofill@mozilla.org";
let extensionDir = Services.dirsvc.get("GreD", Ci.nsIFile);
extensionDir.append("browser");
extensionDir.append("features");
extensionDir.append(EXTENSION_ID);
// If the unpacked extension doesn't exist, use the packed version.
if (!extensionDir.exists()) {
extensionDir = extensionDir.parent;
extensionDir.append(EXTENSION_ID + ".xpi");
}
Components.manager.addBootstrappedManifestLocation(extensionDir);
// While the previous test file should have deleted all the temporary files it
// used, on Windows these might still be pending deletion on the physical file
@ -30,6 +37,17 @@ resHandler.setSubstitution("formautofill", dataURI);
// with a file that is still pending deletion highly unlikely.
let gFileCounter = Math.floor(Math.random() * 1000000);
function loadFormAutofillContent() {
let facGlobal = {};
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScriptWithOptions("chrome://formautofill/content/FormAutofillContent.js", {
target: facGlobal,
});
return facGlobal;
}
/**
* Returns a reference to a temporary file, that is guaranteed not to exist, and
* to have never been created before.
@ -64,10 +82,13 @@ function getTempFile(leafName) {
}
add_task(function* test_common_initialize() {
Services.prefs.setBoolPref("browser.formautofill.enabled", true);
Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
loadFormAutofillContent();
// Clean up after every test.
do_register_cleanup(() => {
Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", false);
Services.prefs.clearUserPref("browser.formautofill.enabled");
Services.prefs.clearUserPref("dom.forms.autocomplete.experimental");
});
});

View File

@ -1,10 +0,0 @@
/**
* Cleans up the testing environment.
*/
/* global resHandler */
"use strict";
// Unregister the resource path of formautofill.
resHandler.setSubstitution("formautofill", null);

View File

@ -4,7 +4,7 @@
"use strict";
let {FormAutofillHandler} = Cu.import("resource://formautofill/FormAutofillContent.jsm");
let {FormAutofillHandler} = loadFormAutofillContent();
const TESTCASES = [
{

View File

@ -4,7 +4,7 @@
"use strict";
let {FormAutofillHandler} = Cu.import("resource://formautofill/FormAutofillContent.jsm");
let {FormAutofillHandler} = loadFormAutofillContent();
const TESTCASES = [
{

View File

@ -1,10 +1,8 @@
[DEFAULT]
firefox-appdir = browser
head = head.js
tail = tail.js
tail =
support-files =
../../content/FormAutofillContent.jsm
../../content/FormAutofillParent.jsm
../../content/ProfileStorage.jsm
[test_autofillFormFields.js]
[test_collectFormFields.js]

View File

@ -61,6 +61,8 @@
<!ENTITY siteData.label "Site Data">
<!ENTITY clearSiteData.label "Clear All Data">
<!ENTITY clearSiteData.accesskey "l">
<!ENTITY siteDataSettings.label "Settings…">
<!ENTITY siteDataSettings.accesskey "i">
<!-- LOCALIZATION NOTE:
The entities limitCacheSizeBefore.label and limitCacheSizeAfter.label appear on a single

View File

@ -173,6 +173,9 @@ totalSiteDataSize=Your stored site data is currently using %1$S %2$S of disk spa
clearSiteDataPromptTitle=Clear all cookies and site data
clearSiteDataPromptText=Selecting Clear Now will clear all cookies and site data stored by Firefox. This may sign you out of websites and remove offline web content.
clearSiteDataNow=Clear Now
important=Important
default=Default
siteUsage=%1$S %2$S
syncUnlink.title=Do you want to unlink your device?
syncUnlink.label=This device will no longer be associated with your Sync account. All of your personal data, both on this device and in your Sync account, will remain intact.

View File

@ -0,0 +1,9 @@
<!-- 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/. -->
<!ENTITY window.title "Settings - Site Data">
<!ENTITY settings.description "The following websites asked to store site data in your disk. You can specify which websites are allowed to store site data. Default site data is temporary and could be deleted automatically.">
<!ENTITY hostCol.label "Site">
<!ENTITY statusCol.label "Status">
<!ENTITY usageCol.label "Storage">

View File

@ -82,6 +82,7 @@
locale/browser/preferences/sync.dtd (%chrome/browser/preferences/sync.dtd)
locale/browser/preferences/tabs.dtd (%chrome/browser/preferences/tabs.dtd)
locale/browser/preferences/search.dtd (%chrome/browser/preferences/search.dtd)
locale/browser/preferences/siteDataSettings.dtd (%chrome/browser/preferences/siteDataSettings.dtd)
locale/browser/preferences/translation.dtd (%chrome/browser/preferences/translation.dtd)
locale/browser/syncBrand.dtd (%chrome/browser/syncBrand.dtd)
locale/browser/syncSetup.dtd (%chrome/browser/syncSetup.dtd)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 928 B

View File

@ -31,7 +31,6 @@ browser.jar:
skin/classic/browser/reload-stop-go.png
skin/classic/browser/reload-stop-go@2x.png
skin/classic/browser/searchbar.css
skin/classic/browser/Security-broken.png
skin/classic/browser/setDesktopBackground.css
skin/classic/browser/slowStartup-16.png
skin/classic/browser/Toolbar.png

View File

@ -398,7 +398,7 @@ if __name__ == "__main__":
# by looking at an MSVC install, but we don't really have that here.
# Force things on.
extra_cflags2 = []
extra_cxxflags2 = ['-fms-compatibility-version=19.00.23918', '-Xclang', '-std=c++14']
extra_cxxflags2 = ['-fms-compatibility-version=19.00.24213', '-Xclang', '-std=c++14']
build_one_stage(
[cc] + extra_cflags,

View File

@ -370,12 +370,12 @@ def check_compiler(compiler, language, target):
if info.type == 'clang-cl' and info.language_version != 201402:
append_flag('-std=c++14')
# We force clang-cl to emulate Visual C++ 2015 Update 2 with fallback to
# We force clang-cl to emulate Visual C++ 2015 Update 3 with fallback to
# cl.exe.
if info.type == 'clang-cl' and info.version != '19.00.23918':
if info.type == 'clang-cl' and info.version != '19.00.24213':
# Those flags are direct clang-cl flags that don't need -Xclang, add
# them directly.
flags.append('-fms-compatibility-version=19.00.23918')
flags.append('-fms-compatibility-version=19.00.24213')
flags.append('-fallback')
# Check compiler target
@ -716,11 +716,11 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
'Only clang/llvm 3.6 or newer is supported.')
if info.type == 'msvc':
if info.version < '19.00.23918':
if info.version < '19.00.24213':
raise FatalCheckError(
'This version (%s) of the MSVC compiler is not '
'supported.\n'
'You must install Visual C++ 2015 Update 2 or newer in '
'You must install Visual C++ 2015 Update 3 or newer in '
'order to build.\n'
'See https://developer.mozilla.org/en/'
'Windows_Build_Prerequisites' % info.version)

View File

@ -31,7 +31,7 @@ let promise = require("promise");
let defer = require("devtools/shared/defer");
const Services = require("Services");
const {Task} = require("devtools/shared/task");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
const CHROME_URL_ROOT = TEST_DIR + "/";

View File

@ -55,7 +55,7 @@ loader.lazyRequireGetter(this, "system",
loader.lazyRequireGetter(this, "getPreferenceFront",
"devtools/shared/fronts/preference", true);
loader.lazyRequireGetter(this, "KeyShortcuts",
"devtools/client/shared/key-shortcuts", true);
"devtools/client/shared/key-shortcuts");
loader.lazyRequireGetter(this, "ZoomKeys",
"devtools/client/shared/zoom-keys");
loader.lazyRequireGetter(this, "settleAll",

View File

@ -16,7 +16,7 @@ const NS_XHTML = "http://www.w3.org/1999/xhtml";
const SCROLL_REPEAT_MS = 100;
const EventEmitter = require("devtools/shared/event-emitter");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
// Some margin may be required for visible element detection.
const SCROLL_MARGIN = 1;

View File

@ -838,4 +838,4 @@ BoxModelView.prototype = {
}
};
exports.BoxModelView = BoxModelView;
module.exports = BoxModelView;

View File

@ -12,7 +12,7 @@ const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const promise = require("promise");
const defer = require("devtools/shared/defer");
const Services = require("Services");
const {OutputParser} = require("devtools/client/shared/output-parser");
const OutputParser = require("devtools/client/shared/output-parser");
const {PrefObserver} = require("devtools/client/shared/prefs");
const {createChild} = require("devtools/client/inspector/shared/utils");
const {gDevTools} = require("devtools/client/framework/devtools");
@ -25,8 +25,8 @@ const {
} = require("devtools/client/inspector/shared/node-types");
const StyleInspectorMenu = require("devtools/client/inspector/shared/style-inspector-menu");
const TooltipsOverlay = require("devtools/client/inspector/shared/tooltips-overlay");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const {BoxModelView} = require("devtools/client/inspector/components/box-model");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const BoxModelView = require("devtools/client/inspector/components/box-model");
const clipboardHelper = require("devtools/shared/platform/clipboard");
const STYLE_INSPECTOR_PROPERTIES = "devtools/shared/locales/styleinspector.properties";

View File

@ -9,7 +9,7 @@ const {Task} = require("devtools/shared/task");
const {KeyCodes} = require("devtools/client/shared/keycodes");
const EventEmitter = require("devtools/shared/event-emitter");
const {AutocompletePopup} = require("devtools/client/shared/autocomplete-popup");
const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
const Services = require("Services");
// Maximum number of selector suggestions shown in the panel.

View File

@ -13,7 +13,7 @@ var promise = require("promise");
var defer = require("devtools/shared/defer");
var EventEmitter = require("devtools/shared/event-emitter");
const {executeSoon} = require("devtools/shared/DevToolsUtils");
var {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
var KeyShortcuts = require("devtools/client/shared/key-shortcuts");
var {Task} = require("devtools/shared/task");
const {initCssProperties} = require("devtools/shared/fronts/css-properties");
const nodeConstants = require("devtools/shared/dom-node-constants");
@ -568,7 +568,7 @@ Inspector.prototype = {
this.computedview = new ComputedViewTool(this, this.panelWin);
if (Services.prefs.getBoolPref("devtools.layoutview.enabled")) {
const {LayoutView} = this.browserRequire("devtools/client/inspector/layout/layout");
const LayoutView = this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
}

View File

@ -258,4 +258,4 @@ LayoutView.prototype = {
};
exports.LayoutView = LayoutView;
module.exports = LayoutView;

View File

@ -14,8 +14,8 @@ const EventEmitter = require("devtools/shared/event-emitter");
const {LocalizationHelper} = require("devtools/shared/l10n");
const {PluralForm} = require("devtools/shared/plural-form");
const {template} = require("devtools/shared/gcli/templater");
const {AutocompletePopup} = require("devtools/client/shared/autocomplete-popup");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const {scrollIntoViewIfNeeded} = require("devtools/client/shared/scroll");
const {UndoStack} = require("devtools/client/shared/undo");
const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");

View File

@ -7,7 +7,7 @@
"use strict";
const promise = require("promise");
const {Rule} = require("devtools/client/inspector/rules/models/rule");
const Rule = require("devtools/client/inspector/rules/models/rule");
const {promiseWarn} = require("devtools/client/inspector/shared/utils");
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
@ -409,4 +409,4 @@ UserProperties.prototype = {
}
};
exports.ElementStyle = ElementStyle;
module.exports = ElementStyle;

View File

@ -683,4 +683,4 @@ Rule.prototype = {
}
};
exports.Rule = Rule;
module.exports = Rule;

View File

@ -12,11 +12,11 @@ const {Task} = require("devtools/shared/task");
const {Tools} = require("devtools/client/definitions");
const {l10n} = require("devtools/shared/inspector/css-logic");
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const {OutputParser} = require("devtools/client/shared/output-parser");
const OutputParser = require("devtools/client/shared/output-parser");
const {PrefObserver} = require("devtools/client/shared/prefs");
const {ElementStyle} = require("devtools/client/inspector/rules/models/element-style");
const {Rule} = require("devtools/client/inspector/rules/models/rule");
const {RuleEditor} = require("devtools/client/inspector/rules/views/rule-editor");
const ElementStyle = require("devtools/client/inspector/rules/models/element-style");
const Rule = require("devtools/client/inspector/rules/models/rule");
const RuleEditor = require("devtools/client/inspector/rules/views/rule-editor");
const {gDevTools} = require("devtools/client/framework/devtools");
const {getCssProperties} = require("devtools/shared/fronts/css-properties");
const {
@ -30,9 +30,9 @@ const StyleInspectorMenu = require("devtools/client/inspector/shared/style-inspe
const TooltipsOverlay = require("devtools/client/inspector/shared/tooltips-overlay");
const {createChild, promiseWarn, throttle} = require("devtools/client/inspector/shared/utils");
const EventEmitter = require("devtools/shared/event-emitter");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const clipboardHelper = require("devtools/shared/platform/clipboard");
const {AutocompletePopup} = require("devtools/client/shared/autocomplete-popup");
const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
const HTML_NS = "http://www.w3.org/1999/xhtml";
const PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles";

View File

@ -6,7 +6,7 @@
const {l10n} = require("devtools/shared/inspector/css-logic");
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const {Rule} = require("devtools/client/inspector/rules/models/rule");
const Rule = require("devtools/client/inspector/rules/models/rule");
const {InplaceEditor, editableField, editableItem} =
require("devtools/client/shared/inplace-editor");
const {TextPropertyEditor} =
@ -618,4 +618,4 @@ RuleEditor.prototype = {
}
};
exports.RuleEditor = RuleEditor;
module.exports = RuleEditor;

View File

@ -9,7 +9,7 @@
// This is more of a unit test than a mochitest-browser test, but can't be
// tested with an xpcshell test as the output-parser requires the DOM to work.
const {OutputParser} = require("devtools/client/shared/output-parser");
const OutputParser = require("devtools/client/shared/output-parser");
const {initCssProperties, getCssProperties} = require("devtools/shared/fronts/css-properties");
const COLOR_CLASS = "color-class";

View File

@ -86,7 +86,6 @@ function AutocompletePopup(toolboxDoc, options = {}) {
this.selectedIndex = -1;
}
exports.AutocompletePopup = AutocompletePopup;
AutocompletePopup.prototype = {
_document: null,
@ -592,3 +591,5 @@ AutocompletePopup.prototype = {
return this._document.defaultView;
},
};
module.exports = AutocompletePopup;

View File

@ -104,7 +104,7 @@ define(function (require, exports, module) {
props.push(Caption({
object: objectLink({
object: object
}, `${object.ownPropertyLength - max} more…`)
}, `${propertiesLength - max} more…`)
}));
}

View File

@ -7,7 +7,7 @@
"use strict";
const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
/**
* A generic search box component for use across devtools

View File

@ -31,6 +31,7 @@ window.onload = Task.async(function* () {
yield testProxy();
yield testArrayBuffer();
yield testSharedArrayBuffer();
yield testApplicationCache();
// Test property iterator
yield testMaxProps();
@ -288,6 +289,43 @@ window.onload = Task.async(function* () {
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
}
function testApplicationCache() {
// Test object: `window.applicationCache`
const testName = "testApplicationCache";
// Test that correct rep is chosen
const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering
const defaultOutput =
"OfflineResourceList { status: 0, onchecking: null, onerror: null, 7 more… }";
const modeTests = [
{
mode: undefined,
expectedOutput: defaultOutput,
},
{
mode: MODE.TINY,
expectedOutput: "OfflineResourceList",
},
{
mode: MODE.SHORT,
expectedOutput: defaultOutput,
},
{
mode: MODE.LONG,
expectedOutput: "OfflineResourceList { status: 0, onchecking: null, " +
"onerror: null, onnoupdate: null, ondownloading: null, onprogress: null, " +
"onupdateready: null, oncached: null, onobsolete: null, mozItems: [] }",
}
];
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
}
function testMaxProps() {
// Test object: `{a: "a", b: "b", c: "c"}`;
const testName = "testMaxProps";
@ -878,6 +916,108 @@ window.onload = Task.async(function* () {
}
}
};
case "testApplicationCache":
return {
"type": "object",
"actor": "server2.conn1.child2/obj45",
"class": "OfflineResourceList",
"ownPropertyLength": 0,
"preview": {
"kind": "Object",
"ownProperties": {},
"ownPropertiesLength": 0,
"safeGetterValues": {
"status": {
"getterValue": 0,
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onchecking": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onerror": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onnoupdate": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"ondownloading": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onprogress": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onupdateready": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"oncached": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"onobsolete": {
"getterValue": {
"type": "null"
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
},
"mozItems": {
"getterValue": {
"type": "object",
"actor": "server2.conn1.child2/obj46",
"class": "DOMStringList",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "ArrayLike",
"length": 0
}
},
"getterPrototypeLevel": 1,
"enumerable": true,
"writable": true
}
}
}
};
}
}
});

View File

@ -248,4 +248,5 @@ KeyShortcuts.prototype = {
this.eventEmitter.off(key, listener);
},
};
exports.KeyShortcuts = KeyShortcuts;
module.exports = KeyShortcuts;

View File

@ -27,7 +27,7 @@ const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
* border radius, cubic-bezier etc.).
*
* Usage:
* const {OutputParser} = require("devtools/client/shared/output-parser");
* const OutputParser = require("devtools/client/shared/output-parser");
*
* let parser = new OutputParser(document, supportsType);
*
@ -52,8 +52,6 @@ function OutputParser(document, {supportsType, isValidOnClient}) {
this._onAngleSwatchMouseDown = this._onAngleSwatchMouseDown.bind(this);
}
exports.OutputParser = OutputParser;
OutputParser.prototype = {
/**
* Parse a CSS property value given a property name.
@ -693,3 +691,5 @@ OutputParser.prototype = {
return defaults;
}
};
module.exports = OutputParser;

Some files were not shown because too many files have changed in this diff Show More