зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1364945 - Fix runtime.openOptionsPage on Firefox for Android. r=mixedpuppy,sebastian
MozReview-Commit-ID: Envx19jlCjY --HG-- extra : rebase_source : 7b1ae9bd2809ac0b75130d740c2f28388cd63d43
This commit is contained in:
Родитель
db2aefdf08
Коммит
f7b58974c2
|
@ -95,22 +95,34 @@ var ContextMenus = {
|
|||
Addons.uninstall(this.target.addon);
|
||||
this.target = null;
|
||||
}
|
||||
};
|
||||
|
||||
function sendEMPong() {
|
||||
Services.obs.notifyObservers(window, "EM-pong");
|
||||
}
|
||||
|
||||
function init() {
|
||||
async function init() {
|
||||
window.addEventListener("popstate", onPopState);
|
||||
|
||||
AddonManager.addInstallListener(Addons);
|
||||
AddonManager.addAddonListener(Addons);
|
||||
Addons.init();
|
||||
|
||||
await Addons.init();
|
||||
showAddons();
|
||||
ContextMenus.init();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(sendEMPong, "EM-ping");
|
||||
|
||||
// The addons list has been loaded and rendered, send a notification
|
||||
// if the openOptionsPage is waiting to be able to select an addon details page.
|
||||
Services.obs.notifyObservers(window, "EM-loaded");
|
||||
}
|
||||
|
||||
function uninit() {
|
||||
AddonManager.removeInstallListener(Addons);
|
||||
AddonManager.removeAddonListener(Addons);
|
||||
|
||||
Services.obs.removeObserver(sendEMPong, "EM-ping");
|
||||
}
|
||||
|
||||
function openLink(url) {
|
||||
|
@ -118,6 +130,15 @@ function openLink(url) {
|
|||
BrowserApp.addTab(url, { selected: true, parentId: BrowserApp.selectedTab.id });
|
||||
}
|
||||
|
||||
function openOptionsInTab(url) {
|
||||
let BrowserApp = gChromeWin.BrowserApp;
|
||||
BrowserApp.selectOrAddTab(url, {
|
||||
startsWith: true,
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id
|
||||
});
|
||||
}
|
||||
|
||||
function onPopState(aEvent) {
|
||||
// Called when back/forward is used to change the state of the page
|
||||
if (aEvent.state) {
|
||||
|
@ -138,6 +159,16 @@ function onPopState(aEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
function showAddonDetails(addonId) {
|
||||
const listItem = Addons._getElementForAddon(addonId);
|
||||
if (listItem) {
|
||||
Addons.showDetails(listItem);
|
||||
history.pushState({ id: addonId }, document.title);
|
||||
} else {
|
||||
throw new Error(`Addon not found: ${addonId}`);
|
||||
}
|
||||
}
|
||||
|
||||
function showAddons() {
|
||||
// Hide the addon options and show the addons list
|
||||
let details = document.querySelector("#addons-details");
|
||||
|
@ -278,30 +309,30 @@ var Addons = {
|
|||
return element;
|
||||
},
|
||||
|
||||
init: function init() {
|
||||
let self = this;
|
||||
AddonManager.getAllAddons(function(aAddons) {
|
||||
// Clear all content before filling the addons
|
||||
let list = document.getElementById("addons-list");
|
||||
list.innerHTML = "";
|
||||
init: async function init() {
|
||||
const aAddons = await AddonManager.getAllAddons();
|
||||
|
||||
aAddons.sort(function(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
for (let i = 0; i < aAddons.length; i++) {
|
||||
// Don't create item for system add-ons.
|
||||
if (aAddons[i].isSystem)
|
||||
continue;
|
||||
// Clear all content before filling the addons
|
||||
let list = document.getElementById("addons-list");
|
||||
list.innerHTML = "";
|
||||
|
||||
let item = self._createItemForAddon(aAddons[i]);
|
||||
list.appendChild(item);
|
||||
}
|
||||
|
||||
// Add a "Browse all Firefox Add-ons" item to the bottom of the list.
|
||||
let browseItem = self._createBrowseItem();
|
||||
list.appendChild(browseItem);
|
||||
aAddons.sort(function(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
for (let i = 0; i < aAddons.length; i++) {
|
||||
// Don't create item for system add-ons.
|
||||
if (aAddons[i].isSystem)
|
||||
continue;
|
||||
|
||||
let item = this._createItemForAddon(aAddons[i]);
|
||||
list.appendChild(item);
|
||||
}
|
||||
|
||||
// Add a "Browse all Firefox Add-ons" item to the bottom of the list.
|
||||
let browseItem = this._createBrowseItem();
|
||||
list.appendChild(browseItem);
|
||||
|
||||
document.getElementById("uninstall-btn").addEventListener("click", Addons.uninstallCurrent.bind(this));
|
||||
document.getElementById("cancel-btn").addEventListener("click", Addons.cancelUninstall.bind(this));
|
||||
document.getElementById("disable-btn").addEventListener("click", Addons.disable.bind(this));
|
||||
|
@ -372,6 +403,14 @@ var Addons = {
|
|||
detailItem.setAttribute("optionsURL", addon.optionsURL);
|
||||
this.createWebExtensionOptions(optionsBox, addon.optionsURL, addon.optionsBrowserStyle);
|
||||
break;
|
||||
case AddonManager.OPTIONS_TYPE_TAB:
|
||||
// Keep the usual layout for any options related the legacy (or system) add-ons
|
||||
// when the options are opened in a new tab from a single button in the addon
|
||||
// details page.
|
||||
optionsBox.classList.add("inner");
|
||||
|
||||
this.createOptionsInTabButton(optionsBox, addon);
|
||||
break;
|
||||
case AddonManager.OPTIONS_TYPE_INLINE:
|
||||
// Keep the usual layout for any options related the legacy (or system) add-ons.
|
||||
optionsBox.classList.add("inner");
|
||||
|
@ -383,6 +422,30 @@ var Addons = {
|
|||
showAddonOptions();
|
||||
},
|
||||
|
||||
createOptionsInTabButton: function(destination, addon) {
|
||||
let frame = destination.querySelector("iframe#addon-options");
|
||||
let button = destination.querySelector("button#open-addon-options");
|
||||
|
||||
if (frame) {
|
||||
// Remove any existent options frame (e.g. when the addon updates
|
||||
// contains the open_in_tab options for the first time).
|
||||
|
||||
frame.remove();
|
||||
}
|
||||
|
||||
if (!button) {
|
||||
button = document.createElement("button");
|
||||
button.setAttribute("id", "open-addon-options");
|
||||
button.textContent = gStringBundle.GetStringFromName("addon.options");
|
||||
destination.appendChild(button);
|
||||
}
|
||||
|
||||
button.onclick = async () => {
|
||||
const {optionsURL} = addon;
|
||||
openOptionsInTab(optionsURL);
|
||||
};
|
||||
},
|
||||
|
||||
createWebExtensionOptions: async function(destination, optionsURL, browserStyle) {
|
||||
let originalHeight;
|
||||
let frame = document.createElement("iframe");
|
||||
|
|
|
@ -1399,6 +1399,45 @@ var BrowserApp = {
|
|||
return tab;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open or select a tab with the "about:addons" page and optionally
|
||||
* switch to the details page related to a defined addonId.
|
||||
*
|
||||
* @param {string} addonId
|
||||
*/
|
||||
openAddonManager: function openAddonManager({addonId}) {
|
||||
if (addonId) {
|
||||
let emWindow;
|
||||
|
||||
function receivePong(subject, topic, data) {
|
||||
emWindow = subject;
|
||||
};
|
||||
|
||||
Services.obs.addObserver(receivePong, "EM-pong");
|
||||
Services.obs.notifyObservers(null, "EM-ping");
|
||||
Services.obs.removeObserver(receivePong, "EM-pong");
|
||||
|
||||
if (emWindow) {
|
||||
// "about:addons" has been already loaded in a tab.
|
||||
emWindow.showAddonDetails(addonId);
|
||||
} else {
|
||||
// Wait for "about:addons" to be fully loaded.
|
||||
function waitAboutAddons(subject, topic, data) {
|
||||
Services.obs.removeObserver(waitAboutAddons, "EM-loaded");
|
||||
emWindow = subject;
|
||||
|
||||
emWindow.showAddonDetails(addonId);
|
||||
}
|
||||
Services.obs.addObserver(waitAboutAddons, "EM-loaded");
|
||||
}
|
||||
}
|
||||
|
||||
BrowserApp.selectOrAddTab("about:addons", {
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id,
|
||||
});
|
||||
},
|
||||
|
||||
// This method updates the state in BrowserApp after a tab has been selected
|
||||
// in the Java UI.
|
||||
_handleTabSelected: function _handleTabSelected(aTab) {
|
||||
|
|
|
@ -48,6 +48,25 @@ extensions.on("page-shutdown", (type, context) => {
|
|||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
global.openOptionsPage = (extension) => {
|
||||
let window = windowTracker.topWindow;
|
||||
if (!window) {
|
||||
return Promise.reject({message: "No browser window available"});
|
||||
}
|
||||
|
||||
let {BrowserApp} = window;
|
||||
|
||||
if (extension.manifest.options_ui.open_in_tab) {
|
||||
BrowserApp.selectOrAddTab(extension.manifest.options_ui.page, {
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id,
|
||||
});
|
||||
} else {
|
||||
BrowserApp.openAddonManager({addonId: extension.id});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
extensions.registerModules({
|
||||
browserAction: {
|
||||
|
|
|
@ -61,6 +61,25 @@ async function navigateBack() {
|
|||
content.window.history.back();
|
||||
}
|
||||
|
||||
function waitDOMContentLoaded(checkUrlCb) {
|
||||
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
return new Promise(resolve => {
|
||||
let listener = (event) => {
|
||||
if (checkUrlCb(event.target.defaultView.location.href)) {
|
||||
BrowserApp.deck.removeEventListener("DOMContentLoaded", listener);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
BrowserApp.deck.addEventListener("DOMContentLoaded", listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitAboutAddonsLoaded() {
|
||||
return waitDOMContentLoaded(url => url === "about:addons");
|
||||
}
|
||||
|
||||
add_task(async function test_options_ui_iframe_height() {
|
||||
let addonID = "test-options-ui@mozilla.org";
|
||||
|
||||
|
@ -113,34 +132,20 @@ add_task(async function test_options_ui_iframe_height() {
|
|||
|
||||
await extension.startup();
|
||||
|
||||
let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let BrowserApp = chromeWin.BrowserApp;
|
||||
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
let waitAboutAddonsLoaded = new Promise(resolve => {
|
||||
let listener = (event) => {
|
||||
if (event.target.defaultView.location.href === "about:addons") {
|
||||
BrowserApp.deck.removeEventListener("DOMContentLoaded", listener);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
BrowserApp.deck.addEventListener("DOMContentLoaded", listener);
|
||||
});
|
||||
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
|
||||
|
||||
BrowserApp.selectOrAddTab("about:addons", {
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id,
|
||||
});
|
||||
|
||||
await waitAboutAddonsLoaded;
|
||||
await onceAboutAddonsLoaded;
|
||||
|
||||
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
|
||||
"about:addons is the currently selected tab");
|
||||
|
||||
let aboutAddonsWindow = BrowserApp.selectedTab.browser.contentWindow;
|
||||
|
||||
is(aboutAddonsWindow.location.href, "about:addons");
|
||||
|
||||
await ContentTask.spawn(BrowserApp.selectedTab.browser, addonID, waitAboutAddonsRendered);
|
||||
|
||||
await ContentTask.spawn(BrowserApp.selectedTab.browser, addonID, navigateToAddonDetails);
|
||||
|
@ -190,6 +195,81 @@ add_task(async function test_options_ui_iframe_height() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_options_ui_open_aboutaddons_details() {
|
||||
let addonID = "test-options-ui-open-addon-details@mozilla.org";
|
||||
|
||||
function background() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "runtime.openOptionsPage") {
|
||||
browser.test.fail(`Received unexpected test message: ${msg}`);
|
||||
return;
|
||||
}
|
||||
|
||||
browser.runtime.openOptionsPage();
|
||||
});
|
||||
}
|
||||
|
||||
function optionsScript() {
|
||||
browser.test.sendMessage("options-page-loaded", window.location.href);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
background,
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: addonID},
|
||||
},
|
||||
name: "Options UI open addon details Extension",
|
||||
description: "Longer addon description",
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
},
|
||||
},
|
||||
files: {
|
||||
"options.js": optionsScript,
|
||||
"options.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Options page</h1>
|
||||
<script src="options.js"><\/script>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
|
||||
|
||||
BrowserApp.selectOrAddTab("about:addons", {
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id,
|
||||
});
|
||||
|
||||
await onceAboutAddonsLoaded;
|
||||
|
||||
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
|
||||
"about:addons is the currently selected tab");
|
||||
|
||||
info("Wait runtime.openOptionsPage to open the about:addond details in the existent tab");
|
||||
extension.sendMessage("runtime.openOptionsPage");
|
||||
await extension.awaitMessage("options-page-loaded");
|
||||
|
||||
is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
|
||||
"about:addons is still the currently selected tab once the options has been loaded");
|
||||
|
||||
BrowserApp.closeTab(BrowserApp.selectedTab);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
Загрузка…
Ссылка в новой задаче