mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1306037: Support options_ui in embedded WebExtensions. r=aswan
MozReview-Commit-ID: KZVPz52qrTS --HG-- extra : rebase_source : 302bdead12c6bf36e30ed3782c6cb4526f1ef1c7
This commit is contained in:
parent
534d31c7d0
commit
7fe3c9e28a
@ -2,10 +2,20 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function add_tasks(task) {
|
||||
add_task(task.bind(null, {embedded: false}));
|
||||
|
||||
add_task(task.bind(null, {embedded: true}));
|
||||
}
|
||||
|
||||
function* loadExtension(options) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
|
||||
embedded: options.embedded,
|
||||
|
||||
manifest: Object.assign({
|
||||
"permissions": ["tabs"],
|
||||
}, options.manifest),
|
||||
@ -37,10 +47,12 @@ function* loadExtension(options) {
|
||||
return extension;
|
||||
}
|
||||
|
||||
add_task(function* test_inline_options() {
|
||||
add_tasks(function* test_inline_options(extraOptions) {
|
||||
info(`Test options opened inline (${JSON.stringify(extraOptions)})`);
|
||||
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
let extension = yield loadExtension({
|
||||
let extension = yield loadExtension(Object.assign({}, extraOptions, {
|
||||
manifest: {
|
||||
applications: {gecko: {id: "inline_options@tests.mozilla.org"}},
|
||||
"options_ui": {
|
||||
@ -123,7 +135,7 @@ add_task(function* test_inline_options() {
|
||||
browser.test.notifyFail("options-ui");
|
||||
});
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
yield extension.awaitFinish("options-ui");
|
||||
yield extension.unload();
|
||||
@ -131,10 +143,12 @@ add_task(function* test_inline_options() {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* test_tab_options() {
|
||||
add_tasks(function* test_tab_options(extraOptions) {
|
||||
info(`Test options opened in a tab (${JSON.stringify(extraOptions)})`);
|
||||
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
|
||||
let extension = yield loadExtension({
|
||||
let extension = yield loadExtension(Object.assign({}, extraOptions, {
|
||||
manifest: {
|
||||
applications: {gecko: {id: "tab_options@tests.mozilla.org"}},
|
||||
"options_ui": {
|
||||
@ -221,7 +235,7 @@ add_task(function* test_tab_options() {
|
||||
browser.test.notifyFail("options-ui-tab");
|
||||
});
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
yield extension.awaitFinish("options-ui-tab");
|
||||
yield extension.unload();
|
||||
@ -229,8 +243,10 @@ add_task(function* test_tab_options() {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* test_options_no_manifest() {
|
||||
let extension = yield loadExtension({
|
||||
add_tasks(function* test_options_no_manifest(extraOptions) {
|
||||
info(`Test with no manifest key (${JSON.stringify(extraOptions)})`);
|
||||
|
||||
let extension = yield loadExtension(Object.assign({}, extraOptions, {
|
||||
manifest: {
|
||||
applications: {gecko: {id: "no_options@tests.mozilla.org"}},
|
||||
},
|
||||
@ -256,7 +272,7 @@ add_task(function* test_options_no_manifest() {
|
||||
browser.test.notifyFail("options-no-manifest");
|
||||
});
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
yield extension.awaitFinish("options-no-manifest");
|
||||
yield extension.unload();
|
||||
|
@ -611,12 +611,20 @@ SpecialPowersObserverAPI.prototype = {
|
||||
// they're run on a bare archive rather than a running instance,
|
||||
// as the add-on manager runs them.
|
||||
let extensionData = new ExtensionData(extension.rootURI);
|
||||
extensionData.readManifest().then(() => {
|
||||
return extensionData.initAllLocales();
|
||||
}).then(() => {
|
||||
if (extensionData.errors.length) {
|
||||
return Promise.reject("Extension contains packaging errors");
|
||||
extensionData.readManifest().then(
|
||||
() => {
|
||||
return extensionData.initAllLocales().then(() => {
|
||||
if (extensionData.errors.length) {
|
||||
return Promise.reject("Extension contains packaging errors");
|
||||
}
|
||||
});
|
||||
},
|
||||
() => {
|
||||
// readManifest() will throw if we're loading an embedded
|
||||
// extension, so don't worry about locale errors in that
|
||||
// case.
|
||||
}
|
||||
).then(() => {
|
||||
return extension.startup();
|
||||
}).then(() => {
|
||||
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionStarted", args: []});
|
||||
|
@ -1360,6 +1360,52 @@ this.Extension = class extends ExtensionData {
|
||||
|
||||
provide(files, ["manifest.json"], manifest);
|
||||
|
||||
if (data.embedded) {
|
||||
// Package this as a webextension embedded inside a legacy
|
||||
// extension.
|
||||
|
||||
let xpiFiles = {
|
||||
"install.rdf": `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest"
|
||||
em:id="${manifest.applications.gecko.id}"
|
||||
em:name="${manifest.name}"
|
||||
em:type="2"
|
||||
em:version="${manifest.version}"
|
||||
em:description=""
|
||||
em:hasEmbeddedWebExtension="true"
|
||||
em:bootstrap="true">
|
||||
|
||||
<!-- Firefox -->
|
||||
<em:targetApplication>
|
||||
<Description
|
||||
em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
|
||||
em:minVersion="51.0a1"
|
||||
em:maxVersion="*"/>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
||||
`,
|
||||
|
||||
"bootstrap.js": `
|
||||
function install() {}
|
||||
function uninstall() {}
|
||||
function shutdown() {}
|
||||
|
||||
function startup(data) {
|
||||
data.webExtension.startup();
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
for (let [path, data] of Object.entries(files)) {
|
||||
xpiFiles[`webextension/${path}`] = data;
|
||||
}
|
||||
|
||||
files = xpiFiles;
|
||||
}
|
||||
|
||||
return this.generateZipFile(files);
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1019,7 @@ var loadManifestFromWebManifest = Task.async(function*(aUri) {
|
||||
* @throws if the install manifest in the RDF stream is corrupt or could not
|
||||
* be read
|
||||
*/
|
||||
function loadManifestFromRDF(aUri, aStream) {
|
||||
let loadManifestFromRDF = Task.async(function*(aUri, aStream) {
|
||||
function getPropertyArray(aDs, aSource, aProperty) {
|
||||
let values = [];
|
||||
let targets = aDs.GetTargets(aSource, EM_R(aProperty), true);
|
||||
@ -1156,6 +1156,7 @@ function loadManifestFromRDF(aUri, aStream) {
|
||||
addon.bootstrap = getRDFProperty(ds, root, "bootstrap") == "true";
|
||||
addon.multiprocessCompatible = getRDFProperty(ds, root, "multiprocessCompatible") == "true";
|
||||
addon.hasEmbeddedWebExtension = getRDFProperty(ds, root, "hasEmbeddedWebExtension") == "true";
|
||||
|
||||
if (addon.optionsType &&
|
||||
addon.optionsType != AddonManager.OPTIONS_TYPE_DIALOG &&
|
||||
addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE &&
|
||||
@ -1163,6 +1164,19 @@ function loadManifestFromRDF(aUri, aStream) {
|
||||
addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE_INFO) {
|
||||
throw new Error("Install manifest specifies unknown type: " + addon.optionsType);
|
||||
}
|
||||
|
||||
if (addon.hasEmbeddedWebExtension) {
|
||||
let uri = NetUtil.newURI("webextension/manifest.json", null, aUri);
|
||||
let embeddedAddon = yield loadManifestFromWebManifest(uri);
|
||||
if (embeddedAddon.optionsURL) {
|
||||
if (addon.optionsType || addon.optionsURL)
|
||||
logger.warn(`Addon ${addon.id} specifies optionsType or optionsURL ` +
|
||||
`in both install.rdf and manifest.json`);
|
||||
|
||||
addon.optionsURL = embeddedAddon.optionsURL;
|
||||
addon.optionsType = embeddedAddon.optionsType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Some add-on types are always restartless.
|
||||
@ -1280,7 +1294,7 @@ function loadManifestFromRDF(aUri, aStream) {
|
||||
addon.icons = {};
|
||||
|
||||
return addon;
|
||||
}
|
||||
});
|
||||
|
||||
function defineSyncGUID(aAddon) {
|
||||
// Define .syncGUID as a lazy property which is also settable
|
||||
@ -1344,7 +1358,7 @@ var loadManifestFromDir = Task.async(function*(aDir, aInstallLocation) {
|
||||
return size;
|
||||
}
|
||||
|
||||
function loadFromRDF(aUri) {
|
||||
function* loadFromRDF(aUri) {
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(aUri.file, -1, -1, false);
|
||||
@ -1352,7 +1366,7 @@ var loadManifestFromDir = Task.async(function*(aDir, aInstallLocation) {
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(fis, 4096);
|
||||
try {
|
||||
var addon = loadManifestFromRDF(aUri, bis);
|
||||
var addon = yield loadManifestFromRDF(aUri, bis);
|
||||
} finally {
|
||||
bis.close();
|
||||
fis.close();
|
||||
@ -1400,7 +1414,7 @@ var loadManifestFromDir = Task.async(function*(aDir, aInstallLocation) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addon = loadFromRDF(uri);
|
||||
addon = yield loadFromRDF(uri);
|
||||
}
|
||||
|
||||
addon._sourceBundle = aDir.clone();
|
||||
@ -1424,13 +1438,13 @@ var loadManifestFromDir = Task.async(function*(aDir, aInstallLocation) {
|
||||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
var loadManifestFromZipReader = Task.async(function*(aZipReader, aInstallLocation) {
|
||||
function loadFromRDF(aUri) {
|
||||
function* loadFromRDF(aUri) {
|
||||
let zis = aZipReader.getInputStream(entry);
|
||||
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(zis, 4096);
|
||||
try {
|
||||
var addon = loadManifestFromRDF(aUri, bis);
|
||||
var addon = yield loadManifestFromRDF(aUri, bis);
|
||||
} finally {
|
||||
bis.close();
|
||||
zis.close();
|
||||
@ -1470,7 +1484,7 @@ var loadManifestFromZipReader = Task.async(function*(aZipReader, aInstallLocatio
|
||||
|
||||
let addon = isWebExtension ?
|
||||
yield loadManifestFromWebManifest(uri) :
|
||||
loadFromRDF(uri);
|
||||
yield loadFromRDF(uri);
|
||||
|
||||
addon._sourceBundle = aZipReader.file;
|
||||
addon._installLocation = aInstallLocation;
|
||||
@ -7324,7 +7338,7 @@ AddonWrapper.prototype = {
|
||||
|
||||
let addon = addonFor(this);
|
||||
if (addon.optionsURL) {
|
||||
if (this.isWebExtension) {
|
||||
if (this.isWebExtension || this.hasEmbeddedWebExtension) {
|
||||
// The internal object's optionsURL property comes from the addons
|
||||
// DB and should be a relative URL. However, extensions with
|
||||
// options pages installed before bug 1293721 was fixed got absolute
|
||||
|
Loading…
Reference in New Issue
Block a user