mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1784292 - Anchor extension popups to the unified extensions button. r=mconley,mixedpuppy
Differential Revision: https://phabricator.services.mozilla.com/D154408
This commit is contained in:
parent
1160e6a61a
commit
cb31c16d87
@ -270,8 +270,6 @@ var gXPInstallObserver = {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorID = "addons-notification-icon";
|
||||
|
||||
// Make notifications persistent
|
||||
var options = {
|
||||
displayURI: installInfo.originatingURI,
|
||||
@ -279,6 +277,14 @@ var gXPInstallObserver = {
|
||||
hideClose: true,
|
||||
};
|
||||
|
||||
if (gUnifiedExtensions.isEnabled) {
|
||||
options.popupOptions = {
|
||||
position: "bottomcenter topright",
|
||||
x: 2,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
|
||||
let acceptInstallation = () => {
|
||||
for (let install of installInfo.installs) {
|
||||
install.install();
|
||||
@ -422,7 +428,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
"addon-install-confirmation",
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
[secondaryAction],
|
||||
options
|
||||
@ -496,7 +502,6 @@ var gXPInstallObserver = {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorID = "addons-notification-icon";
|
||||
var messageString, action;
|
||||
var brandShortName = brandBundle.getString("brandShortName");
|
||||
|
||||
@ -509,6 +514,14 @@ var gXPInstallObserver = {
|
||||
timeout: Date.now() + 30000,
|
||||
};
|
||||
|
||||
if (gUnifiedExtensions.isEnabled) {
|
||||
options.popupOptions = {
|
||||
position: "bottomcenter topright",
|
||||
x: 2,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
|
||||
switch (aTopic) {
|
||||
case "addon-install-disabled": {
|
||||
notificationID = "xpinstall-disabled";
|
||||
@ -550,7 +563,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
secondaryActions,
|
||||
options
|
||||
@ -597,7 +610,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
null,
|
||||
null,
|
||||
options
|
||||
@ -728,7 +741,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
[dontAllowAction, neverAllowAction],
|
||||
options
|
||||
@ -793,7 +806,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
[secondaryAction],
|
||||
options
|
||||
@ -876,7 +889,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
null,
|
||||
options
|
||||
@ -950,7 +963,7 @@ var gXPInstallObserver = {
|
||||
browser,
|
||||
notificationID,
|
||||
messageString,
|
||||
anchorID,
|
||||
gUnifiedExtensions.getPopupAnchorID(browser, window),
|
||||
action,
|
||||
secondaryActions,
|
||||
options
|
||||
@ -1291,22 +1304,46 @@ var gUnifiedExtensions = {
|
||||
return;
|
||||
}
|
||||
|
||||
const unifiedExtensionsEnabled = Services.prefs.getBoolPref(
|
||||
"extensions.unifiedExtensions.enabled",
|
||||
false
|
||||
);
|
||||
|
||||
if (unifiedExtensionsEnabled) {
|
||||
if (this.isEnabled) {
|
||||
MozXULElement.insertFTLIfNeeded("preview/unifiedExtensions.ftl");
|
||||
|
||||
this._button = document.getElementById("unified-extensions-button");
|
||||
// TODO: Bug 1778684 - Auto-hide button when there is no active extension.
|
||||
this._button.hidden = !unifiedExtensionsEnabled;
|
||||
this._button.hidden = false;
|
||||
}
|
||||
|
||||
this._initialized = true;
|
||||
},
|
||||
|
||||
get isEnabled() {
|
||||
return Services.prefs.getBoolPref(
|
||||
"extensions.unifiedExtensions.enabled",
|
||||
false
|
||||
);
|
||||
},
|
||||
|
||||
getPopupAnchorID(aBrowser, aWindow) {
|
||||
if (this.isEnabled) {
|
||||
const anchorID = "unified-extensions-button";
|
||||
const attr = anchorID + "popupnotificationanchor";
|
||||
|
||||
if (!aBrowser[attr]) {
|
||||
// A hacky way of setting the popup anchor outside the usual url bar
|
||||
// icon box, similar to how it was done for CFR.
|
||||
// See: https://searchfox.org/mozilla-central/rev/847b64cc28b74b44c379f9bff4f415b97da1c6d7/toolkit/modules/PopupNotifications.jsm#42
|
||||
aBrowser[attr] = aWindow.document.getElementById(
|
||||
anchorID
|
||||
// Anchor on the toolbar icon to position the popup right below the
|
||||
// button.
|
||||
).firstElementChild;
|
||||
}
|
||||
|
||||
return anchorID;
|
||||
}
|
||||
|
||||
return "addons-notification-icon";
|
||||
},
|
||||
|
||||
get button() {
|
||||
return this._button;
|
||||
},
|
||||
|
@ -403,3 +403,4 @@ https_first_disabled = true
|
||||
[browser_unified_extensions.js]
|
||||
[browser_unified_extensions_accessibility.js]
|
||||
[browser_unified_extensions_context_menu.js]
|
||||
[browser_unified_extensions_doorhangers.js]
|
||||
|
@ -0,0 +1,100 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
loadTestSubscript("head_unified_extensions.js");
|
||||
|
||||
let win;
|
||||
|
||||
add_setup(async function() {
|
||||
// Only load a new window with the unified extensions feature enabled once to
|
||||
// speed up the execution of this test file.
|
||||
win = await promiseEnableUnifiedExtensions();
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
});
|
||||
|
||||
const verifyPermissionsPrompt = async (win, expectedAnchorID) => {
|
||||
const ext = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
optional_permissions: ["history"],
|
||||
},
|
||||
|
||||
background: async () => {
|
||||
await browser.tabs.create({
|
||||
url: browser.runtime.getURL("content.html"),
|
||||
active: true,
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"content.html": `<!DOCTYPE html><script src="content.js"></script>`,
|
||||
"content.js": async () => {
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
browser.test.assertEq(
|
||||
msg,
|
||||
"grant-permission",
|
||||
"expected message to grant permission"
|
||||
);
|
||||
|
||||
const granted = await new Promise(resolve => {
|
||||
browser.test.withHandlingUserInput(() => {
|
||||
resolve(
|
||||
browser.permissions.request({ permissions: ["history"] })
|
||||
);
|
||||
});
|
||||
});
|
||||
browser.test.assertTrue(granted, "permission request succeeded");
|
||||
|
||||
browser.test.sendMessage("ok");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser: win.gBrowser }, async () => {
|
||||
await ext.startup();
|
||||
await ext.awaitMessage("ready");
|
||||
|
||||
const popupPromise = promisePopupNotificationShown(
|
||||
"addon-webext-permissions",
|
||||
win
|
||||
);
|
||||
ext.sendMessage("grant-permission");
|
||||
const panel = await popupPromise;
|
||||
const notification = win.PopupNotifications.getNotification(
|
||||
"addon-webext-permissions"
|
||||
);
|
||||
ok(notification, "expected notification");
|
||||
is(
|
||||
// We access the parent element because the anchor is on the icon, not on
|
||||
// the unified extensions button itself.
|
||||
notification.anchorElement.id ||
|
||||
notification.anchorElement.parentElement.id,
|
||||
expectedAnchorID,
|
||||
"expected the right anchor ID"
|
||||
);
|
||||
|
||||
panel.button.click();
|
||||
await ext.awaitMessage("ok");
|
||||
|
||||
await ext.unload();
|
||||
});
|
||||
};
|
||||
|
||||
add_task(async function test_permissions_prompt_with_pref_enabled() {
|
||||
await verifyPermissionsPrompt(win, "unified-extensions-button");
|
||||
});
|
||||
|
||||
add_task(async function test_permissions_prompt_with_pref_disabled() {
|
||||
const anotherWindow = await promiseDisableUnifiedExtensions();
|
||||
|
||||
await verifyPermissionsPrompt(anotherWindow, "addons-notification-icon");
|
||||
|
||||
await BrowserTestUtils.closeWindow(anotherWindow);
|
||||
});
|
@ -421,7 +421,7 @@ var ExtensionsUI = {
|
||||
return false;
|
||||
}
|
||||
|
||||
let popupOptions = {
|
||||
let options = {
|
||||
hideClose: true,
|
||||
popupIconURL: icon || DEFAULT_EXTENSION_ICON,
|
||||
popupIconClass: icon ? "" : "addon-warning-icon",
|
||||
@ -454,14 +454,25 @@ var ExtensionsUI = {
|
||||
},
|
||||
];
|
||||
|
||||
if (browser.ownerGlobal.gUnifiedExtensions.isEnabled) {
|
||||
options.popupOptions = {
|
||||
position: "bottomcenter topright",
|
||||
x: 2,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
|
||||
window.PopupNotifications.show(
|
||||
browser,
|
||||
"addon-webext-permissions",
|
||||
strings.header,
|
||||
"addons-notification-icon",
|
||||
browser.ownerGlobal.gUnifiedExtensions.getPopupAnchorID(
|
||||
browser,
|
||||
window
|
||||
),
|
||||
action,
|
||||
secondaryActions,
|
||||
popupOptions
|
||||
options
|
||||
);
|
||||
});
|
||||
|
||||
@ -472,7 +483,7 @@ var ExtensionsUI = {
|
||||
|
||||
showDefaultSearchPrompt(target, strings, icon) {
|
||||
return new Promise(resolve => {
|
||||
let popupOptions = {
|
||||
let options = {
|
||||
hideClose: true,
|
||||
popupIconURL: icon || DEFAULT_EXTENSION_ICON,
|
||||
persistent: true,
|
||||
@ -503,14 +514,26 @@ var ExtensionsUI = {
|
||||
];
|
||||
|
||||
let { browser, window } = getTabBrowser(target);
|
||||
|
||||
if (browser.ownerGlobal.gUnifiedExtensions.isEnabled) {
|
||||
options.popupOptions = {
|
||||
position: "bottomcenter topright",
|
||||
x: 2,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
|
||||
window.PopupNotifications.show(
|
||||
browser,
|
||||
"addon-webext-defaultsearch",
|
||||
strings.text,
|
||||
"addons-notification-icon",
|
||||
browser.ownerGlobal.gUnifiedExtensions.getPopupAnchorID(
|
||||
browser,
|
||||
window
|
||||
),
|
||||
action,
|
||||
secondaryActions,
|
||||
popupOptions
|
||||
options
|
||||
);
|
||||
});
|
||||
},
|
||||
|
@ -528,6 +528,9 @@ PopupNotifications.prototype = {
|
||||
* extraAttr:
|
||||
* An optional string value which will be given to the
|
||||
* extraAttr attribute on the notification's anchorElement
|
||||
* popupOptions:
|
||||
* An optional object containing popup options passed to
|
||||
* `openPopup()` when defined.
|
||||
* @returns the Notification object corresponding to the added notification.
|
||||
*/
|
||||
show: function PopupNotifications_show(
|
||||
@ -1336,7 +1339,14 @@ PopupNotifications.prototype = {
|
||||
this._popupshownListener = this._popupshownListener.bind(this);
|
||||
target.addEventListener("popupshown", this._popupshownListener, true);
|
||||
|
||||
this.panel.openPopup(anchorElement, "bottomcenter topleft", 0, 0);
|
||||
let popupOptions = notificationsToShow.findLast(
|
||||
n => n.options?.popupOptions
|
||||
)?.options?.popupOptions;
|
||||
if (popupOptions) {
|
||||
this.panel.openPopup(anchorElement, popupOptions);
|
||||
} else {
|
||||
this.panel.openPopup(anchorElement, "bottomcenter topleft", 0, 0);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -61,7 +61,9 @@ function getObserverTopic(aNotificationId) {
|
||||
async function waitForProgressNotification(
|
||||
aPanelOpen = false,
|
||||
aExpectedCount = 1,
|
||||
wantDisabled = true
|
||||
wantDisabled = true,
|
||||
expectedAnchorID = "addons-notification-icon",
|
||||
win = window
|
||||
) {
|
||||
let notificationId = PROGRESS_NOTIFICATION;
|
||||
info("Waiting for " + notificationId + " notification");
|
||||
@ -87,7 +89,7 @@ async function waitForProgressNotification(
|
||||
panelEventPromise = Promise.resolve();
|
||||
} else {
|
||||
panelEventPromise = new Promise(resolve => {
|
||||
PopupNotifications.panel.addEventListener(
|
||||
win.PopupNotifications.panel.addEventListener(
|
||||
"popupshowing",
|
||||
function() {
|
||||
resolve();
|
||||
@ -102,14 +104,14 @@ async function waitForProgressNotification(
|
||||
await waitForTick();
|
||||
|
||||
info("Saw a notification");
|
||||
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
||||
ok(win.PopupNotifications.isPanelOpen, "Panel should be open");
|
||||
is(
|
||||
PopupNotifications.panel.childNodes.length,
|
||||
win.PopupNotifications.panel.childNodes.length,
|
||||
aExpectedCount,
|
||||
"Should be the right number of notifications"
|
||||
);
|
||||
if (PopupNotifications.panel.childNodes.length) {
|
||||
let nodes = Array.from(PopupNotifications.panel.childNodes);
|
||||
if (win.PopupNotifications.panel.childNodes.length) {
|
||||
let nodes = Array.from(win.PopupNotifications.panel.childNodes);
|
||||
let notification = nodes.find(
|
||||
n => n.id == notificationId + "-notification"
|
||||
);
|
||||
@ -119,9 +121,16 @@ async function waitForProgressNotification(
|
||||
wantDisabled,
|
||||
"The install button should be disabled?"
|
||||
);
|
||||
|
||||
let n = win.PopupNotifications.getNotification(PROGRESS_NOTIFICATION);
|
||||
is(
|
||||
n?.anchorElement?.id || n?.anchorElement?.parentElement?.id,
|
||||
expectedAnchorID,
|
||||
"expected the right anchor ID"
|
||||
);
|
||||
}
|
||||
|
||||
return PopupNotifications.panel;
|
||||
return win.PopupNotifications.panel;
|
||||
}
|
||||
|
||||
function acceptAppMenuNotificationWhenShown(
|
||||
@ -205,7 +214,12 @@ function acceptAppMenuNotificationWhenShown(
|
||||
});
|
||||
}
|
||||
|
||||
async function waitForNotification(aId, aExpectedCount = 1) {
|
||||
async function waitForNotification(
|
||||
aId,
|
||||
aExpectedCount = 1,
|
||||
expectedAnchorID = "addons-notification-icon",
|
||||
win = window
|
||||
) {
|
||||
info("Waiting for " + aId + " notification");
|
||||
|
||||
let topic = getObserverTopic(aId);
|
||||
@ -228,14 +242,14 @@ async function waitForNotification(aId, aExpectedCount = 1) {
|
||||
}
|
||||
|
||||
let panelEventPromise = new Promise(resolve => {
|
||||
PopupNotifications.panel.addEventListener(
|
||||
win.PopupNotifications.panel.addEventListener(
|
||||
"PanelUpdated",
|
||||
function eventListener(e) {
|
||||
// Skip notifications that are not the one that we are supposed to be looking for
|
||||
if (!e.detail.includes(aId)) {
|
||||
return;
|
||||
}
|
||||
PopupNotifications.panel.removeEventListener(
|
||||
win.PopupNotifications.panel.removeEventListener(
|
||||
"PanelUpdated",
|
||||
eventListener
|
||||
);
|
||||
@ -249,20 +263,27 @@ async function waitForNotification(aId, aExpectedCount = 1) {
|
||||
await waitForTick();
|
||||
|
||||
info("Saw a " + aId + " notification");
|
||||
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
||||
ok(win.PopupNotifications.isPanelOpen, "Panel should be open");
|
||||
is(
|
||||
PopupNotifications.panel.childNodes.length,
|
||||
win.PopupNotifications.panel.childNodes.length,
|
||||
aExpectedCount,
|
||||
"Should be the right number of notifications"
|
||||
);
|
||||
if (PopupNotifications.panel.childNodes.length) {
|
||||
let nodes = Array.from(PopupNotifications.panel.childNodes);
|
||||
if (win.PopupNotifications.panel.childNodes.length) {
|
||||
let nodes = Array.from(win.PopupNotifications.panel.childNodes);
|
||||
let notification = nodes.find(n => n.id == aId + "-notification");
|
||||
ok(notification, "Should have seen the " + aId + " notification");
|
||||
}
|
||||
await SimpleTest.promiseFocus(PopupNotifications.window);
|
||||
|
||||
return PopupNotifications.panel;
|
||||
let n = win.PopupNotifications.getNotification(aId);
|
||||
is(
|
||||
n?.anchorElement?.id || n?.anchorElement?.parentElement?.id,
|
||||
expectedAnchorID,
|
||||
"expected the right anchor ID"
|
||||
);
|
||||
}
|
||||
await SimpleTest.promiseFocus(win.PopupNotifications.window);
|
||||
|
||||
return win.PopupNotifications.panel;
|
||||
}
|
||||
|
||||
function waitForNotificationClose() {
|
||||
@ -431,6 +452,7 @@ var TESTS = [
|
||||
await addon.uninstall();
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
},
|
||||
|
||||
async function test_blockedInstallDomain() {
|
||||
@ -1198,7 +1220,10 @@ var TESTS = [
|
||||
|
||||
async function test_failedSecurity() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [[PREF_INSTALL_REQUIREBUILTINCERTS, false]],
|
||||
set: [
|
||||
[PREF_INSTALL_REQUIREBUILTINCERTS, false],
|
||||
["extensions.postDownloadThirdPartyPrompt", false],
|
||||
],
|
||||
});
|
||||
|
||||
setupRedirect({
|
||||
@ -1334,7 +1359,6 @@ var TESTS = [
|
||||
await addon.uninstall();
|
||||
|
||||
await removeTabAndWaitForNotificationClose();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
},
|
||||
|
||||
async function test_incognito_checkbox_new_window() {
|
||||
@ -1428,9 +1452,52 @@ var TESTS = [
|
||||
|
||||
await addon.uninstall();
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
},
|
||||
|
||||
async function test_blockedInstallDomain_with_unified_extensions() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.unifiedExtensions.enabled", true]],
|
||||
});
|
||||
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await SimpleTest.promiseFocus(win);
|
||||
await new Promise(resolve => {
|
||||
win.requestIdleCallback(resolve);
|
||||
});
|
||||
await TestUtils.waitForCondition(
|
||||
() => win.gUnifiedExtensions._initialized,
|
||||
"Wait gUnifiedExtensions to have been initialized"
|
||||
);
|
||||
|
||||
let progressPromise = waitForProgressNotification(
|
||||
false,
|
||||
1,
|
||||
true,
|
||||
"unified-extensions-button",
|
||||
win
|
||||
);
|
||||
let notificationPromise = waitForNotification(
|
||||
"addon-install-failed",
|
||||
1,
|
||||
"unified-extensions-button",
|
||||
win
|
||||
);
|
||||
let triggers = encodeURIComponent(
|
||||
JSON.stringify({
|
||||
XPI: TESTROOT2 + "webmidi_permission.xpi",
|
||||
})
|
||||
);
|
||||
BrowserTestUtils.openNewForegroundTab(
|
||||
win.gBrowser,
|
||||
TESTROOT + "installtrigger.html?" + triggers
|
||||
);
|
||||
await progressPromise;
|
||||
await notificationPromise;
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
},
|
||||
];
|
||||
|
||||
var gTestStart = null;
|
||||
|
Loading…
Reference in New Issue
Block a user