diff --git a/addon-sdk/source/lib/sdk/addon/window.js b/addon-sdk/source/lib/sdk/addon/window.js
index 4c163a6ead15..557397411cbb 100644
--- a/addon-sdk/source/lib/sdk/addon/window.js
+++ b/addon-sdk/source/lib/sdk/addon/window.js
@@ -7,59 +7,75 @@ module.metadata = {
"stability": "experimental"
};
-const { Ci, Cc } = require("chrome");
-const { make: makeWindow, getHiddenWindow } = require("../window/utils");
-const { create: makeFrame, getDocShell } = require("../frame/utils");
-const { defer } = require("../core/promise");
+const { Ci, Cc, Cu } = require("chrome");
const { when: unload } = require("../system/unload");
-const cfxArgs = require("../test/options");
+const prefs = require("../preferences/service");
-var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
- createInstance(Ci.nsIPrincipal);
+if (!prefs.get("extensions.usehiddenwindow", false)) {
+ const {HiddenFrame} = require("resource:///modules/HiddenFrame.jsm", {});
+ let hiddenFrame = new HiddenFrame();
+ exports.window = hiddenFrame.getWindow();
+ exports.ready = hiddenFrame.get();
-var hiddenWindow = getHiddenWindow();
+ // Still destroy frame on unload to claim memory back early.
+ // NOTE: this doesn't seem to work and just doesn't get called. :-\
+ unload(function() {
+ hiddenFrame.destroy();
+ hiddenFrame = null;
+ });
+} else {
+ const { make: makeWindow, getHiddenWindow } = require("../window/utils");
+ const { create: makeFrame, getDocShell } = require("../frame/utils");
+ const { defer } = require("../core/promise");
+ const cfxArgs = require("../test/options");
-if (cfxArgs.parseable) {
- console.info("hiddenWindow document.documentURI:" +
- hiddenWindow.document.documentURI);
- console.info("hiddenWindow document.readyState:" +
- hiddenWindow.document.readyState);
+ var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
+ createInstance(Ci.nsIPrincipal);
+
+ var hiddenWindow = getHiddenWindow();
+
+ if (cfxArgs.parseable) {
+ console.info("hiddenWindow document.documentURI:" +
+ hiddenWindow.document.documentURI);
+ console.info("hiddenWindow document.readyState:" +
+ hiddenWindow.document.readyState);
+ }
+
+ // Once Bug 565388 is fixed and shipped we'll be able to make invisible,
+ // permanent docShells. Meanwhile we create hidden top level window and
+ // use it's docShell.
+ var frame = makeFrame(hiddenWindow.document, {
+ nodeName: "iframe",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ allowJavascript: true,
+ allowPlugins: true
+ })
+ var docShell = getDocShell(frame);
+ var eventTarget = docShell.chromeEventHandler;
+
+ // We need to grant docShell system principals in order to load XUL document
+ // from data URI into it.
+ docShell.createAboutBlankContentViewer(addonPrincipal);
+
+ // Get a reference to the DOM window of the given docShell and load
+ // such document into that would allow us to create XUL iframes, that
+ // are necessary for hidden frames etc..
+ var window = docShell.contentViewer.DOMDocument.defaultView;
+ window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,";
+
+ // Create a promise that is delivered once add-on window is interactive,
+ // used by add-on runner to defer add-on loading until window is ready.
+ var { promise, resolve } = defer();
+ eventTarget.addEventListener("DOMContentLoaded", function(event) {
+ resolve();
+ }, {once: true});
+
+ exports.ready = promise;
+ exports.window = window;
+
+ // Still close window on unload to claim memory back early.
+ unload(function() {
+ window.close()
+ frame.remove();
+ });
}
-
-// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
-// permanent docShells. Meanwhile we create hidden top level window and
-// use it's docShell.
-var frame = makeFrame(hiddenWindow.document, {
- nodeName: "iframe",
- namespaceURI: "http://www.w3.org/1999/xhtml",
- allowJavascript: true,
- allowPlugins: true
-})
-var docShell = getDocShell(frame);
-var eventTarget = docShell.chromeEventHandler;
-
-// We need to grant docShell system principals in order to load XUL document
-// from data URI into it.
-docShell.createAboutBlankContentViewer(addonPrincipal);
-
-// Get a reference to the DOM window of the given docShell and load
-// such document into that would allow us to create XUL iframes, that
-// are necessary for hidden frames etc..
-var window = docShell.contentViewer.DOMDocument.defaultView;
-window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,";
-
-// Create a promise that is delivered once add-on window is interactive,
-// used by add-on runner to defer add-on loading until window is ready.
-var { promise, resolve } = defer();
-eventTarget.addEventListener("DOMContentLoaded", function(event) {
- resolve();
-}, {once: true});
-
-exports.ready = promise;
-exports.window = window;
-
-// Still close window on unload to claim memory back early.
-unload(function() {
- window.close()
- frame.remove();
-});
diff --git a/addon-sdk/source/lib/sdk/net/xhr.js b/addon-sdk/source/lib/sdk/net/xhr.js
index 415b9cbf44de..fd4fcd62915d 100644
--- a/addon-sdk/source/lib/sdk/net/xhr.js
+++ b/addon-sdk/source/lib/sdk/net/xhr.js
@@ -8,8 +8,9 @@ module.metadata = {
};
const { deprecateFunction } = require("../util/deprecate");
-const { Cc, Ci } = require("chrome");
-const XMLHttpRequest = require("../addon/window").window.XMLHttpRequest;
+const { Ci, Cu } = require("chrome");
+
+Cu.importGlobalProperties(["XMLHttpRequest"]);
Object.defineProperties(XMLHttpRequest.prototype, {
mozBackgroundRequest: {
diff --git a/addon-sdk/source/lib/sdk/panel/utils.js b/addon-sdk/source/lib/sdk/panel/utils.js
index 2f92a9ff9841..5a39ff68f362 100644
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -13,7 +13,7 @@ const { Services } = require("resource://gre/modules/Services.jsm");
const { setTimeout } = require("../timers");
const { platform } = require("../system");
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
- getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
+ getScreenPixelsPerCSSPixel } = require("../window/utils");
const { create: createFrame, swapFrameLoaders, getDocShell } = require("../frame/utils");
const { window: addonWindow } = require("../addon/window");
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 7ca5d3e888b3..b46b62bc80d0 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -426,6 +426,8 @@ pref("browser.link.open_newwindow.disabled_in_fullscreen", true);
pref("browser.link.open_newwindow.disabled_in_fullscreen", false);
#endif
+pref("browser.photon.structure.enabled", false);
+
// Tabbed browser
pref("browser.tabs.closeWindowWithLastTab", true);
pref("browser.tabs.insertRelatedAfterCurrent", true);
diff --git a/browser/base/content/aboutDialog.js b/browser/base/content/aboutDialog.js
index b6177715c8b4..e1eec77053f1 100644
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -52,6 +52,17 @@ function init(aEvent) {
let arch = bundle.GetStringFromName(archResource);
versionField.textContent += ` (${arch})`;
+ // Show a release notes link if we have a URL.
+ let relNotesLink = document.getElementById("releasenotes");
+ let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL");
+ if (relNotesPrefType != Services.prefs.PREF_INVALID) {
+ let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
+ if (relNotesURL != "about:blank") {
+ relNotesLink.href = relNotesURL;
+ relNotesLink.hidden = false;
+ }
+ }
+
if (AppConstants.MOZ_UPDATER) {
gAppUpdater = new appUpdater();
diff --git a/browser/base/content/aboutDialog.xul b/browser/base/content/aboutDialog.xul
index cbb07a5e11af..661f2c6419ac 100644
--- a/browser/base/content/aboutDialog.xul
+++ b/browser/base/content/aboutDialog.xul
@@ -45,10 +45,8 @@
-#expand
-#ifndef NIGHTLY_BUILD
-#expand
-#endif
+#expand
+
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 95b2335d1e7b..146d7b0d0a44 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -26,6 +26,7 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
title="&mainWindow.title;"
@@ -719,6 +720,8 @@
tooltiptext="&urlbar.microphoneBlocked.tooltip;"/>
+
+
diff --git a/browser/base/content/content.js b/browser/base/content/content.js
index 6abc4d4a12e4..a62715541f0b 100644
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -355,7 +355,9 @@ var AboutNetAndCertErrorListener = {
// If the difference is more than a day.
if (Math.abs(difference) > 60 * 60 * 24) {
- let formatter = new Intl.DateTimeFormat();
+ let formatter = Services.intl.createDateTimeFormat(undefined, {
+ dateStyle: "short"
+ });
let systemDate = formatter.format(new Date());
// negative difference means local time is behind server time
let actualDate = formatter.format(new Date(Date.now() - difference * 1000));
@@ -385,7 +387,9 @@ var AboutNetAndCertErrorListener = {
let systemDate = new Date();
if (buildDate > systemDate) {
- let formatter = new Intl.DateTimeFormat();
+ let formatter = Services.intl.createDateTimeFormat(undefined, {
+ dateStyle: "short"
+ });
content.document.getElementById("wrongSystemTimeWithoutReference_URL")
.textContent = content.document.location.hostname;
diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc
index ae8e04bea092..da3a34ef62eb 100644
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -74,7 +74,6 @@
-
diff --git a/browser/base/content/test/general/browser_aboutCertError.js b/browser/base/content/test/general/browser_aboutCertError.js
index 47235c4b0123..480b969d7d5b 100644
--- a/browser/base/content/test/general/browser_aboutCertError.js
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -151,7 +151,9 @@ add_task(function* checkWrongSystemTimeWarning() {
});
}
- let formatter = new Intl.DateTimeFormat();
+ let formatter = Services.intl.createDateTimeFormat(undefined, {
+ dateStyle: "short"
+ });
// pretend we have a positively skewed (ahead) system time
let serverDate = new Date("2015/10/27");
diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js b/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js
index 4c1ac10cfcdc..c71c720eb599 100644
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_checkbox.js
@@ -160,6 +160,23 @@ var tests = [
gNotification.remove();
}
},
+
+ // Test no checkbox hides warning label
+ { id: "no_checkbox",
+ run() {
+ this.notifyObj = new BasicNotification(this.id);
+ this.notifyObj.options.checkbox = null;
+ gNotification = showNotification(this.notifyObj);
+ },
+ onShown(popup) {
+ checkPopup(popup, this.notifyObj);
+ let notification = popup.childNodes[0];
+ checkCheckbox(notification.checkbox, "", false, true);
+ checkMainAction(notification);
+ triggerMainCommand(popup);
+ },
+ onHidden() { },
+ },
];
// Test checkbox disabling the main action in different combinations
diff --git a/browser/branding/aurora/pref/firefox-branding.js b/browser/branding/aurora/pref/firefox-branding.js
index 9f005b857085..df0d1613ebed 100644
--- a/browser/branding/aurora/pref/firefox-branding.js
+++ b/browser/branding/aurora/pref/firefox-branding.js
@@ -22,6 +22,8 @@ pref("app.update.url.manual", "https://www.mozilla.org/firefox/aurora/");
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "https://www.mozilla.org/firefox/aurora/");
+pref("app.releaseNotesURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/releasenotes/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=whatsnew");
+
// The number of days a binary is permitted to be old
// without checking for an update. This assumes that
// app.update.checkInstallTime is true.
diff --git a/browser/branding/official/pref/firefox-branding.js b/browser/branding/official/pref/firefox-branding.js
index 82ef1c891a87..f864b97b2276 100644
--- a/browser/branding/official/pref/firefox-branding.js
+++ b/browser/branding/official/pref/firefox-branding.js
@@ -20,6 +20,8 @@ pref("app.update.url.manual", "https://www.mozilla.org/firefox/");
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "https://www.mozilla.org/%LOCALE%/firefox/notes");
+pref("app.releaseNotesURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/releasenotes/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=whatsnew");
+
// The number of days a binary is permitted to be old
// without checking for an update. This assumes that
// app.update.checkInstallTime is true.
diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul
index d0ae3d72cf7c..53c0e8faff5f 100644
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -485,3 +485,13 @@
+
+
diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js
index 09b476f84c02..23a8ed1b7459 100644
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -11,6 +11,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyPreferenceGetter(this, "gPhotonStructure",
+ "browser.photon.structure.enabled", false);
+
/**
* Maintains the state and dispatches events for the main menu panel.
*/
@@ -31,7 +34,7 @@ const PanelUI = {
multiView: "PanelUI-multiView",
helpView: "PanelUI-helpView",
menuButton: "PanelUI-menu-button",
- panel: "PanelUI-popup",
+ panel: gPhotonStructure ? "PanelUI-photon-popup" : "PanelUI-popup",
notificationPanel: "PanelUI-notification-popup",
scroller: "PanelUI-contents-scroller",
footer: "PanelUI-footer"
diff --git a/browser/components/feeds/FeedWriter.js b/browser/components/feeds/FeedWriter.js
index c8a3bf4b10e2..c6af2bb3db1c 100644
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -189,9 +189,11 @@ FeedWriter.prototype = {
__dateFormatter: null,
get _dateFormatter() {
if (!this.__dateFormatter) {
- const dtOptions = { year: "numeric", month: "long", day: "numeric",
- hour: "numeric", minute: "numeric" };
- this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
+ const dtOptions = {
+ timeStyle: "short",
+ dateStyle: "long"
+ };
+ this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__dateFormatter;
},
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index ad0c794f1b74..35c8c65177be 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2315,6 +2315,11 @@ const ContentPermissionIntegration = {
case "desktop-notification": {
return new PermissionUI.DesktopNotificationPermissionPrompt(request);
}
+ case "persistent-storage": {
+ if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
+ return new PermissionUI.PersistentStoragePermissionPrompt(request);
+ }
+ }
}
return undefined;
},
diff --git a/browser/components/places/content/places.js b/browser/components/places/content/places.js
index 048465f98f7a..5c8adaeff77b 100644
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -10,6 +10,7 @@
Components.utils.import("resource://gre/modules/AppConstants.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/TelemetryStopwatch.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MigrationUtils",
"resource:///modules/MigrationUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@@ -411,8 +412,10 @@ var PlacesOrganizer = {
populateRestoreMenu: function PO_populateRestoreMenu() {
let restorePopup = document.getElementById("fileRestorePopup");
- const dtOptions = { year: "numeric", month: "long", day: "numeric" };
- let dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
+ const dtOptions = {
+ dateStyle: "long"
+ };
+ let dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
// Remove existing menu items. Last item is the restoreFromFile item.
while (restorePopup.childNodes.length > 1)
diff --git a/browser/components/places/content/treeView.js b/browser/components/places/content/treeView.js
index 12367d922ab2..416300a301fa 100644
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
const PTV_interfaces = [Ci.nsITreeView,
Ci.nsINavHistoryResultObserver,
@@ -499,8 +500,8 @@ PlacesTreeView.prototype = {
__todayFormatter: null,
get _todayFormatter() {
if (!this.__todayFormatter) {
- const dtOptions = { hour: "numeric", minute: "numeric" };
- this.__todayFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
+ const dtOptions = { timeStyle: "short" };
+ this.__todayFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__todayFormatter;
},
@@ -508,9 +509,11 @@ PlacesTreeView.prototype = {
__dateFormatter: null,
get _dateFormatter() {
if (!this.__dateFormatter) {
- const dtOptions = { year: "numeric", month: "numeric", day: "numeric",
- hour: "numeric", minute: "numeric" };
- this.__dateFormatter = new Intl.DateTimeFormat(undefined, dtOptions);
+ const dtOptions = {
+ dateStyle: "short",
+ timeStyle: "short"
+ };
+ this.__dateFormatter = Services.intl.createDateTimeFormat(undefined, dtOptions);
}
return this.__dateFormatter;
},
diff --git a/browser/components/places/tests/chrome/test_treeview_date.xul b/browser/components/places/tests/chrome/test_treeview_date.xul
index e7aad3ef52d0..38a9db04ca87 100644
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -124,18 +124,21 @@
case "date":
let timeObj = new Date(node.time / 1000);
// Default is short date format.
- let dtOptions = { year: 'numeric', month: 'numeric', day: 'numeric',
- hour: 'numeric', minute: 'numeric' };
+ let dtOptions = {
+ dateStyle: "short",
+ timeStyle: "short"
+ };
+
// For today's visits we don't show date portion.
if (node.uri == "http://at.midnight.com/" ||
node.uri == "http://after.midnight.com/") {
- dtOptions = { hour: 'numeric', minute: 'numeric' };
+ dtOptions.dateStyle = undefined;
} else if (node.uri != "http://before.midnight.com/") {
// Avoid to test spurious uris, due to how the test works
// a redirecting uri could be put in the tree while we test.
break;
}
- let timeStr = timeObj.toLocaleString(undefined, dtOptions);
+ let timeStr = Services.intl.createDateTimeFormat(undefined, dtOptions).format(timeObj);
is(text, timeStr, "Date format is correct");
break;
diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index 775a15616169..6d0281b59a7a 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -213,6 +213,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
+
@@ -229,12 +230,13 @@ These should match what Safari and other Apple applications use on OS X Lion. --
+
-
+
diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
index e645e1fe29c0..4a045bd850bf 100644
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -496,6 +496,14 @@ geolocation.shareWithSite3=Will you allow %S to access your location?
geolocation.shareWithFile3=Will you allow this local file to access your location?
geolocation.remember=Remember this decision
+# Persistent storage UI
+persistentStorage.allow=Allow
+persistentStorage.allow.accesskey=A
+persistentStorage.dontAllow=Don’t Allow
+persistentStorage.dontAllow.accesskey=n
+persistentStorage.allowWithSite=Will you allow %S to store data in persistent storage?
+persistentStorage.remember=Remember this decision
+
webNotifications.allow=Allow Notifications
webNotifications.allow.accesskey=A
webNotifications.notNow=Not Now
diff --git a/browser/locales/en-US/chrome/browser/sitePermissions.properties b/browser/locales/en-US/chrome/browser/sitePermissions.properties
index 15a5cc02d746..8de5b26c1572 100644
--- a/browser/locales/en-US/chrome/browser/sitePermissions.properties
+++ b/browser/locales/en-US/chrome/browser/sitePermissions.properties
@@ -36,3 +36,4 @@ permission.popup.label = Open Pop-up Windows
permission.geo.label = Access Your Location
permission.indexedDB.label = Maintain Offline Storage
permission.focus-tab-by-prompt.label = Switch to this Tab
+permission.persistent-storage.label = Store Data in Persistent Storage
diff --git a/browser/locales/shipped-locales b/browser/locales/shipped-locales
index cd336176dc1e..39bd1cfd099a 100644
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -63,6 +63,7 @@ mk
ml
mr
ms
+my
nb-NO
nl
nn-NO
diff --git a/browser/modules/ExtensionsUI.jsm b/browser/modules/ExtensionsUI.jsm
index 21ad6009aa6e..ce08cde2225b 100644
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -341,10 +341,11 @@ this.ExtensionsUI = {
showPermissionsPrompt(browser, strings, icon, histkey) {
function eventCallback(topic) {
- if (topic == "showing") {
- let doc = this.browser.ownerDocument;
- doc.getElementById("addon-webext-perm-header").innerHTML = strings.header;
-
+ let doc = this.browser.ownerDocument;
+ if (topic == "shown") {
+ doc.getElementById("addon-webext-permissions-notification")
+ .description.innerHTML = strings.header;
+ } else if (topic == "showing") {
let textEl = doc.getElementById("addon-webext-perm-text");
textEl.innerHTML = strings.text;
textEl.hidden = !strings.text;
@@ -397,7 +398,12 @@ this.ExtensionsUI = {
},
];
- win.PopupNotifications.show(browser, "addon-webext-permissions", "",
+ // Get the text value of strings.header to pre-populate the header. This will get
+ // overwritten with the HTML version later.
+ let escapeHeader = browser.ownerDocument.createElement("div");
+ escapeHeader.innerHTML = strings.header;
+ win.PopupNotifications.show(browser, "addon-webext-permissions",
+ escapeHeader.textContent,
"addons-notification-icon",
action, secondaryActions, popupOptions);
});
diff --git a/browser/modules/HiddenFrame.jsm b/browser/modules/HiddenFrame.jsm
index 1d9533ff842f..eb023052f968 100644
--- a/browser/modules/HiddenFrame.jsm
+++ b/browser/modules/HiddenFrame.jsm
@@ -14,11 +14,27 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,";
+const gAllHiddenFrames = new WeakSet();
+
+let cleanupRegistered = false;
+function ensureCleanupRegistered() {
+ if (!cleanupRegistered) {
+ cleanupRegistered = true;
+ Services.obs.addObserver(function() {
+ for (let hiddenFrame of ChromeUtils.nondeterministicGetWeakSetKeys(gAllHiddenFrames)) {
+ hiddenFrame.destroy();
+ }
+ }, "xpcom-shutdown", false);
+ }
+}
+
+
/**
* An hidden frame object. It takes care of creating a windowless browser and
* passing the window containing a blank XUL back.
*/
-function HiddenFrame() {}
+function HiddenFrame() {
+}
HiddenFrame.prototype = {
_frame: null,
@@ -41,6 +57,16 @@ HiddenFrame.prototype = {
return this._deferred.promise;
},
+ /**
+ * Fetch a sync ref to the window inside the frame (needed for the add-on SDK).
+ */
+ getWindow() {
+ this.get();
+ this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
+ return this._browser.getInterface(Ci.nsIDOMWindow);
+ },
+
+
destroy() {
if (this._browser) {
if (this._listener) {
@@ -51,14 +77,17 @@ HiddenFrame.prototype = {
this._frame = null;
this._deferred = null;
+ gAllHiddenFrames.delete(this);
this._browser.close();
this._browser = null;
}
},
_create() {
+ ensureCleanupRegistered();
this._browser = Services.appShell.createWindowlessBrowser(true);
this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
+ gAllHiddenFrames.add(this);
this._webProgress = this._browser.getInterface(Ci.nsIWebProgress);
this._listener = {
QueryInterface: XPCOMUtils.generateQI([
diff --git a/browser/modules/PermissionUI.jsm b/browser/modules/PermissionUI.jsm
index ceffb26bad51..f6c1a767429f 100644
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -598,3 +598,75 @@ DesktopNotificationPermissionPrompt.prototype = {
PermissionUI.DesktopNotificationPermissionPrompt =
DesktopNotificationPermissionPrompt;
+
+/**
+ * Creates a PermissionPrompt for a nsIContentPermissionRequest for
+ * the persistent-storage API.
+ *
+ * @param request (nsIContentPermissionRequest)
+ * The request for a permission from content.
+ */
+function PersistentStoragePermissionPrompt(request) {
+ this.request = request;
+}
+
+PersistentStoragePermissionPrompt.prototype = {
+ __proto__: PermissionPromptForRequestPrototype,
+
+ get permissionKey() {
+ return "persistent-storage";
+ },
+
+ get popupOptions() {
+ let checkbox = {
+ // In PB mode, we don't want the "always remember" checkbox
+ show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
+ };
+ if (checkbox.show) {
+ checkbox.checked = true;
+ checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
+ }
+ let learnMoreURL =
+ Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
+ return {
+ checkbox,
+ learnMoreURL
+ };
+ },
+
+ get notificationID() {
+ return "persistent-storage";
+ },
+
+ get anchorID() {
+ return "persistent-storage-notification-icon";
+ },
+
+ get message() {
+ let hostPort = "<>";
+ try {
+ hostPort = this.principal.URI.hostPort;
+ } catch (ex) {}
+ return gBrowserBundle.formatStringFromName(
+ "persistentStorage.allowWithSite", [hostPort], 1);
+ },
+
+ get promptActions() {
+ return [
+ {
+ label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
+ accessKey:
+ gBrowserBundle.GetStringFromName("persistentStorage.allow.accesskey"),
+ action: Ci.nsIPermissionManager.ALLOW_ACTION
+ },
+ {
+ label: gBrowserBundle.GetStringFromName("persistentStorage.dontAllow"),
+ accessKey:
+ gBrowserBundle.GetStringFromName("persistentStorage.dontAllow.accesskey"),
+ action: Ci.nsIPermissionManager.DENY_ACTION
+ }
+ ];
+ }
+};
+
+PermissionUI.PersistentStoragePermissionPrompt = PersistentStoragePermissionPrompt;
diff --git a/browser/modules/SitePermissions.jsm b/browser/modules/SitePermissions.jsm
index 20b6b478b1d3..19c28d625469 100644
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -614,8 +614,16 @@ var gPermissionObject = {
exactHostMatch: true,
states: [ SitePermissions.UNKNOWN, SitePermissions.ALLOW ],
},
+ "persistent-storage": {
+ exactHostMatch: true
+ }
};
+// Delete this entry while being pre-off
+// or the persistent-storage permission would appear in Page info's Permission section
+if (!Services.prefs.getBoolPref("browser.storageManager.enabled")) {
+ delete gPermissionObject["persistent-storage"];
+}
+
XPCOMUtils.defineLazyPreferenceGetter(SitePermissions, "temporaryPermissionExpireTime",
"privacy.temporary_permission_expire_time_ms", 3600 * 1000);
-
diff --git a/browser/modules/test/browser/browser_PermissionUI_prompts.js b/browser/modules/test/browser/browser_PermissionUI_prompts.js
index c1e57b464618..c456e113f2d0 100644
--- a/browser/modules/test/browser/browser_PermissionUI_prompts.js
+++ b/browser/modules/test/browser/browser_PermissionUI_prompts.js
@@ -20,6 +20,11 @@ add_task(function* test_desktop_notification_permission_prompt() {
yield testPrompt(PermissionUI.DesktopNotificationPermissionPrompt);
});
+// Tests that PersistentStoragePermissionPrompt works as expected
+add_task(function* test_persistent_storage_permission_prompt() {
+ yield testPrompt(PermissionUI.PersistentStoragePermissionPrompt);
+});
+
function* testPrompt(Prompt) {
yield BrowserTestUtils.withNewTab({
gBrowser,
diff --git a/browser/modules/test/unit/test_SitePermissions.js b/browser/modules/test/unit/test_SitePermissions.js
index 144f6cb8cd41..c60f55081078 100644
--- a/browser/modules/test/unit/test_SitePermissions.js
+++ b/browser/modules/test/unit/test_SitePermissions.js
@@ -9,7 +9,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
add_task(function* testPermissionsListing() {
Assert.deepEqual(SitePermissions.listPermissions().sort(),
["camera", "cookie", "desktop-notification", "focus-tab-by-prompt", "geo", "image",
- "indexedDB", "install", "microphone", "popup", "screen"],
+ "indexedDB", "install", "microphone", "persistent-storage", "popup", "screen"],
"Correct list of all permissions");
});
@@ -72,7 +72,8 @@ add_task(function* testExactHostMatch() {
let uri = Services.io.newURI("https://example.com");
let subUri = Services.io.newURI("https://test1.example.com");
- let exactHostMatched = ["desktop-notification", "focus-tab-by-prompt", "camera", "microphone", "screen", "geo"];
+ let exactHostMatched = ["desktop-notification", "focus-tab-by-prompt", "camera",
+ "microphone", "screen", "geo", "persistent-storage"];
let nonExactHostMatched = ["image", "cookie", "popup", "install", "indexedDB"];
let permissions = SitePermissions.listPermissions();
diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css
index 1a8b85a4b29e..4bb32c6c36ee 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -793,8 +793,18 @@ menuitem.bookmark-item {
font-weight: bold;
}
-.addon-webext-perm-header {
- font-size: 1.3em;
+html|*.addon-webext-perm-list {
+ margin-block-end: 0;
+ padding-inline-start: 10px;
+}
+
+.addon-webext-perm-text {
+ margin-inline-start: 0;
+}
+
+.popup-notification-description[popupid="addon-webext-permissions"] {
+ margin: 0;
+ padding: 0;
}
.addon-webext-name {
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index d4835a8f0cb4..6608dd73a3d8 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -3031,8 +3031,18 @@ menulist.translate-infobar-element > .menulist-dropmarker {
font-weight: bold;
}
-.addon-webext-perm-header {
- font-size: 1.3em;
+html|*.addon-webext-perm-list {
+ margin-block-end: 0;
+ padding-inline-start: 10px;
+}
+
+.addon-webext-perm-text {
+ margin-inline-start: 0;
+}
+
+.popup-notification-description[popupid="addon-webext-permissions"] {
+ margin: 0;
+ padding: 0;
}
.addon-webext-name {
diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css
index 918e9656c5de..cd422cf677e4 100644
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -37,6 +37,15 @@
list-style-image: url(chrome://browser/skin/notification-icons.svg#focus-tab-by-prompt);
}
+.popup-notification-icon[popupid="persistent-storage"],
+.persistent-storage-icon {
+ list-style-image: url(chrome://browser/skin/notification-icons.svg#persistent-storage);
+}
+
+.persistent-storage-icon.blocked-permission-icon {
+ list-style-image: url(chrome://browser/skin/notification-icons.svg#persistent-storage-blocked);
+}
+
.popup-notification-icon[popupid="web-notifications"],
.desktop-notification-icon {
list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);
diff --git a/browser/themes/shared/notification-icons.svg b/browser/themes/shared/notification-icons.svg
index a9fb232c9fe1..004eb40edc09 100644
--- a/browser/themes/shared/notification-icons.svg
+++ b/browser/themes/shared/notification-icons.svg
@@ -66,6 +66,7 @@
+
@@ -111,6 +112,8 @@
+
+
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index 547dc41edc23..f91403def4e6 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2074,8 +2074,18 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
font-weight: bold;
}
-.addon-webext-perm-header {
- font-size: 1.3em;
+html|*.addon-webext-perm-list {
+ margin-block-end: 0;
+ padding-inline-start: 10px;
+}
+
+.addon-webext-perm-text {
+ margin-inline-start: 0;
+}
+
+.popup-notification-description[popupid="addon-webext-permissions"] {
+ margin: 0;
+ padding: 0;
}
.addon-webext-name {
diff --git a/build/virtualenv_packages.txt b/build/virtualenv_packages.txt
index 74118d26785f..a1066a10ec0c 100644
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -1,4 +1,3 @@
-altgraph.pth:python/altgraph
marionette_driver.pth:testing/marionette/client
marionette_harness.pth:testing/marionette/harness
browsermobproxy.pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
@@ -16,7 +15,6 @@ optional:setup.py:python/psutil:build_ext:--inplace
optional:psutil.pth:python/psutil
which.pth:python/which
ply.pth:other-licenses/ply/
-macholib.pth:python/macholib
mock.pth:python/mock-1.0.0
py.pth:python/py
pytest.pth:python/pytest
@@ -32,7 +30,6 @@ objdir:build
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
pyasn1.pth:python/pyasn1
pyasn1_modules.pth:python/pyasn1-modules
-bitstring.pth:python/bitstring
redo.pth:python/redo
requests.pth:python/requests
rsa.pth:python/rsa
diff --git a/devtools/client/aboutdebugging/aboutdebugging.css b/devtools/client/aboutdebugging/aboutdebugging.css
index e37477814f1e..f6840594775e 100644
--- a/devtools/client/aboutdebugging/aboutdebugging.css
+++ b/devtools/client/aboutdebugging/aboutdebugging.css
@@ -214,3 +214,78 @@ button {
.error-page .error-page-details {
color: gray;
}
+
+.addon-target-container {
+ background: #fff;
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0.12);
+ list-style-type: none;
+ margin: 0 0 8px;
+ padding: 4px 16px;
+ transition: box-shadow 150ms;
+}
+
+.addon-target-container:hover {
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.24);
+}
+
+.addon-target-container .target {
+ align-items: center;
+ display: flex;
+ margin: 0;
+ padding: 16px 0;
+}
+
+.addon-target-actions {
+ border-top: 1px solid rgba(0, 0, 0, 0.2);
+}
+
+.addon-target-container .target-icon {
+ margin-inline-end: 16px;
+}
+
+.addon-target-container .name {
+ align-self: center;
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.addon-target-button {
+ background: none;
+ border: none;
+ color: #0087ff;
+ font-size: 14px;
+ margin: 12px;
+ min-width: auto;
+ padding: 4px;
+ transition: color 150ms;
+}
+
+.addon-target-button:active,
+.addon-target-button:hover,
+.addon-target-button:enabled:hover:active {
+ background: none;
+}
+
+.addon-target-button:disabled {
+ color: #999;
+ opacity: 1;
+}
+
+.addon-target-button:enabled:focus,
+.addon-target-button:enabled:hover {
+ background: none;
+ color: #0052cc;
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+.addon-target-button:enabled:hover:active {
+ color: #003399;
+ text-decoration: none;
+}
+
+.addon-target-button:first-of-type {
+ /* Subtract the start padding so the button is still a bigger click target but
+ * lines up with the icon. */
+ margin-inline-start: -4px;
+}
diff --git a/devtools/client/aboutdebugging/components/addons/target.js b/devtools/client/aboutdebugging/components/addons/target.js
index 8e0432e418b4..bd7a888f7b4b 100644
--- a/devtools/client/aboutdebugging/components/addons/target.js
+++ b/devtools/client/aboutdebugging/components/addons/target.js
@@ -59,27 +59,29 @@ module.exports = createClass({
const canBeReloaded = target.temporarilyInstalled;
return dom.li(
- { className: "target-container", "data-addon-id": target.addonID },
- dom.img({
- className: "target-icon",
- role: "presentation",
- src: target.icon
- }),
+ { className: "addon-target-container", "data-addon-id": target.addonID },
dom.div({ className: "target" },
- dom.div({ className: "target-name", title: target.name }, target.name)
+ dom.img({
+ className: "target-icon",
+ role: "presentation",
+ src: target.icon
+ }),
+ dom.span({ className: "target-name", title: target.name }, target.name)
+ ),
+ dom.div({className: "addon-target-actions"},
+ dom.button({
+ className: "debug-button addon-target-button",
+ onClick: this.debug,
+ disabled: debugDisabled,
+ }, Strings.GetStringFromName("debug")),
+ dom.button({
+ className: "reload-button addon-target-button",
+ onClick: this.reload,
+ disabled: !canBeReloaded,
+ title: !canBeReloaded ?
+ Strings.GetStringFromName("reloadDisabledTooltip") : ""
+ }, Strings.GetStringFromName("reload"))
),
- dom.button({
- className: "debug-button",
- onClick: this.debug,
- disabled: debugDisabled,
- }, Strings.GetStringFromName("debug")),
- dom.button({
- className: "reload-button",
- onClick: this.reload,
- disabled: !canBeReloaded,
- title: !canBeReloaded ?
- Strings.GetStringFromName("reloadDisabledTooltip") : ""
- }, Strings.GetStringFromName("reload"))
);
}
});
diff --git a/devtools/client/netmonitor/src/request-list-context-menu.js b/devtools/client/netmonitor/src/request-list-context-menu.js
index 9ddd0b845de7..aa5dc82147b0 100644
--- a/devtools/client/netmonitor/src/request-list-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-context-menu.js
@@ -7,8 +7,7 @@
const Services = require("Services");
const { Curl } = require("devtools/client/shared/curl");
const { gDevTools } = require("devtools/client/framework/devtools");
-const Menu = require("devtools/client/framework/menu");
-const MenuItem = require("devtools/client/framework/menu-item");
+const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
const FileSaver = require("devtools/client/shared/file-saver");
const clipboardHelper = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
@@ -48,66 +47,65 @@ RequestListContextMenu.prototype = {
* Since visible attribute only accept boolean value but the method call may
* return undefined, we use !! to force convert any object to boolean
*/
- open({ screenX = 0, screenY = 0 } = {}) {
+ open(event = {}) {
let selectedRequest = this.selectedRequest;
+ let menu = [];
+ let copySubmenu = [];
- let menu = new Menu();
- let copySubmenu = new Menu();
-
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-url",
label: L10N.getStr("netmonitor.context.copyUrl"),
accesskey: L10N.getStr("netmonitor.context.copyUrl.accesskey"),
visible: !!selectedRequest,
click: () => this.copyUrl(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-url-params",
label: L10N.getStr("netmonitor.context.copyUrlParams"),
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
visible: !!(selectedRequest && getUrlQuery(selectedRequest.url)),
click: () => this.copyUrlParams(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-post-data",
label: L10N.getStr("netmonitor.context.copyPostData"),
accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
visible: !!(selectedRequest && selectedRequest.requestPostData),
click: () => this.copyPostData(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-as-curl",
label: L10N.getStr("netmonitor.context.copyAsCurl"),
accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
visible: !!selectedRequest,
click: () => this.copyAsCurl(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
type: "separator",
visible: !!selectedRequest,
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-request-headers",
label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
visible: !!(selectedRequest && selectedRequest.requestHeaders),
click: () => this.copyRequestHeaders(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "response-list-context-copy-response-headers",
label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
visible: !!(selectedRequest && selectedRequest.responseHeaders),
click: () => this.copyResponseHeaders(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-response",
label: L10N.getStr("netmonitor.context.copyResponse"),
accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
@@ -116,9 +114,9 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent.content.text &&
selectedRequest.responseContent.content.text.length !== 0),
click: () => this.copyResponse(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-image-as-data-uri",
label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
@@ -126,37 +124,37 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.copyImageAsDataUri(),
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
type: "separator",
visible: !!selectedRequest,
- }));
+ });
- copySubmenu.append(new MenuItem({
+ copySubmenu.push({
id: "request-list-context-copy-all-as-har",
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
visible: this.sortedRequests.size > 0,
click: () => this.copyAllAsHar(),
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
label: L10N.getStr("netmonitor.context.copy"),
accesskey: L10N.getStr("netmonitor.context.copy.accesskey"),
visible: !!selectedRequest,
submenu: copySubmenu,
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-context-save-all-as-har",
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"),
visible: this.sortedRequests.size > 0,
click: () => this.saveAllAsHar(),
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-context-save-image-as",
label: L10N.getStr("netmonitor.context.saveImageAs"),
accesskey: L10N.getStr("netmonitor.context.saveImageAs.accesskey"),
@@ -164,46 +162,44 @@ RequestListContextMenu.prototype = {
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.saveImageAs(),
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
type: "separator",
visible: !!(NetMonitorController.supportsCustomRequest &&
selectedRequest && !selectedRequest.isCustom),
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-context-resend",
label: L10N.getStr("netmonitor.context.editAndResend"),
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
visible: !!(NetMonitorController.supportsCustomRequest &&
selectedRequest && !selectedRequest.isCustom),
click: this.cloneSelectedRequest,
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
type: "separator",
visible: !!selectedRequest,
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-context-newtab",
label: L10N.getStr("netmonitor.context.newTab"),
accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"),
visible: !!selectedRequest,
click: () => this.openRequestInTab()
- }));
+ });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-context-perf",
label: L10N.getStr("netmonitor.context.perfTools"),
accesskey: L10N.getStr("netmonitor.context.perfTools.accesskey"),
- visible: !!NetMonitorController.supportsPerfStats,
click: () => this.openStatistics(true)
- }));
+ });
- menu.popup(screenX, screenY, { doc: window.parent.document });
- return menu;
+ return showMenu(event, menu);
},
/**
diff --git a/devtools/client/netmonitor/src/request-list-header-context-menu.js b/devtools/client/netmonitor/src/request-list-header-context-menu.js
index ab8bf8652142..ad1433480b49 100644
--- a/devtools/client/netmonitor/src/request-list-header-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-header-context-menu.js
@@ -4,8 +4,7 @@
"use strict";
-const Menu = require("devtools/client/framework/menu");
-const MenuItem = require("devtools/client/framework/menu-item");
+const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
const { HEADERS } = require("./constants");
const { L10N } = require("./utils/l10n");
@@ -30,12 +29,12 @@ class RequestListHeaderContextMenu {
/**
* Handle the context menu opening.
*/
- open({ screenX = 0, screenY = 0 } = {}) {
- let menu = new Menu();
+ open(event = {}) {
+ let menu = [];
let onlyOneColumn = this.visibleColumns.length === 1;
for (let [column, shown] of this.columns) {
- menu.append(new MenuItem({
+ menu.push({
id: `request-list-header-${column}-toggle`,
label: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`),
type: "checkbox",
@@ -43,19 +42,18 @@ class RequestListHeaderContextMenu {
click: () => this.toggleColumn(column),
// We don't want to allow hiding the last visible column
disabled: onlyOneColumn && shown,
- }));
+ });
}
- menu.append(new MenuItem({ type: "separator" }));
+ menu.push({ type: "separator" });
- menu.append(new MenuItem({
+ menu.push({
id: "request-list-header-reset-columns",
label: L10N.getStr("netmonitor.toolbar.resetColumns"),
click: () => this.resetColumns(),
- }));
+ });
- menu.popup(screenX, screenY, { doc: window.parent.document });
- return menu;
+ return showMenu(event, menu);
}
}
diff --git a/devtools/client/netmonitor/src/utils/menu.js b/devtools/client/netmonitor/src/utils/menu.js
new file mode 100644
index 000000000000..051a9e85679d
--- /dev/null
+++ b/devtools/client/netmonitor/src/utils/menu.js
@@ -0,0 +1,36 @@
+/* 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";
+
+const Menu = require("devtools/client/framework/menu");
+const MenuItem = require("devtools/client/framework/menu-item");
+
+function showMenu(evt, items) {
+ if (items.length === 0) {
+ return;
+ }
+
+ let menu = new Menu();
+ items.forEach((item) => {
+ let menuItem = new MenuItem(item);
+ let subItems = item.submenu;
+
+ if (subItems) {
+ let subMenu = new Menu();
+ subItems.forEach((subItem) => {
+ subMenu.append(new MenuItem(subItem));
+ });
+ menuItem.submenu = subMenu;
+ }
+
+ menu.append(menuItem);
+ });
+
+ menu.popup(evt.screenX, evt.screenY, { doc: window.parent.document });
+}
+
+module.exports = {
+ showMenu,
+};
diff --git a/devtools/client/netmonitor/src/utils/moz.build b/devtools/client/netmonitor/src/utils/moz.build
index 32a74d0fae7c..e871828b3778 100644
--- a/devtools/client/netmonitor/src/utils/moz.build
+++ b/devtools/client/netmonitor/src/utils/moz.build
@@ -11,6 +11,7 @@ DevToolsModules(
'format-utils.js',
'l10n.js',
'mdn-utils.js',
+ 'menu.js',
'prefs.js',
'request-utils.js',
'sort-predicates.js',
diff --git a/devtools/client/netmonitor/webpack.config.js b/devtools/client/netmonitor/webpack.config.js
index 6a165e571fe6..dd3603e86ea6 100644
--- a/devtools/client/netmonitor/webpack.config.js
+++ b/devtools/client/netmonitor/webpack.config.js
@@ -53,6 +53,7 @@ let webpackConfig = {
"devtools/client/framework/menu": "devtools-modules/client/framework/menu",
"devtools/client/framework/menu-item": "devtools-modules/client/framework/menu-item",
"devtools/client/locales": path.join(__dirname, "../locales/en-US"),
+ "devtools/client/netmonitor/src/utils/menu": "devtools-launchpad/src/components/shared/menu",
"devtools/client/shared/components/reps/reps": "devtools-reps",
"devtools/client/shared/components/search-box": "devtools-modules/client/shared/components/search-box",
"devtools/client/shared/components/splitter/split-box": "devtools-splitter",
diff --git a/dom/canvas/test/imagebitmap_extensions_prepareSources.js b/dom/canvas/test/imagebitmap_extensions_prepareSources.js
index db077a098b05..3cf018ecc94d 100644
--- a/dom/canvas/test/imagebitmap_extensions_prepareSources.js
+++ b/dom/canvas/test/imagebitmap_extensions_prepareSources.js
@@ -11,7 +11,7 @@ var gGroundTruthImageData;
function prepareSources() {
gVideo = document.createElement("video");
- gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous";
+ gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.crossOrigin = "anonymous";
gVideo.autoplay = "true"
diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini
index 7865ad43130a..4477d71f0ec8 100644
--- a/dom/canvas/test/mochitest.ini
+++ b/dom/canvas/test/mochitest.ini
@@ -39,6 +39,9 @@ support-files =
offscreencanvas_mask.svg
offscreencanvas_neuter.js
offscreencanvas_serviceworker_inner.html
+ crossorigin/image.png
+ crossorigin/video.sjs
+ ../../media/test/320x240.ogv
[test_2d.clearRect.image.offscreen.html]
[test_2d.clip.winding.html]
diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html
index b3d3c08ad4df..17f050e330b1 100644
--- a/dom/canvas/test/test_imagebitmap.html
+++ b/dom/canvas/test/test_imagebitmap.html
@@ -6,7 +6,7 @@
-
+
@@ -226,7 +226,7 @@ function testSecurityErrors() {
reject();
}
- uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg";
+ uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg";
uncleanVideo.play();
});
}
diff --git a/dom/canvas/test/test_imagebitmap_cropping.html b/dom/canvas/test/test_imagebitmap_cropping.html
index be7cd086f3c1..56ccbf62e2cc 100644
--- a/dom/canvas/test/test_imagebitmap_cropping.html
+++ b/dom/canvas/test/test_imagebitmap_cropping.html
@@ -135,7 +135,7 @@ var gJPEGBlob;
function prepareSources() {
gVideo = document.createElement("video");
- gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous";
+ gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous";
gVideo.crossOrigin = "anonymous";
gVideo.autoplay = "true"
diff --git a/dom/html/reftests/reftest-stylo.list b/dom/html/reftests/reftest-stylo.list
index 09aa9eff5da5..29a5a2ae55b0 100644
--- a/dom/html/reftests/reftest-stylo.list
+++ b/dom/html/reftests/reftest-stylo.list
@@ -44,7 +44,7 @@ fails == 596455-2b.html 596455-2b.html
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
# The vast majority of the fuzziness comes from Linux and WinXP.)
== bug917595-iframe-1.html bug917595-iframe-1.html
-fails == bug917595-exif-rotated.jpg bug917595-exif-rotated.jpg
+== bug917595-exif-rotated.jpg bug917595-exif-rotated.jpg
# Test support for SVG-as-image in