mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 1221141 - Support installing addon from local directory in about:debugging. r=janx
--HG-- rename : devtools/client/locales/en-US/aboutdebugging.properties => devtools/client/aboutdebugging/moz.build
This commit is contained in:
parent
5be55f54e9
commit
5cf2eb0e19
@ -12,7 +12,8 @@ h2, h3, h4 {
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
#body {
|
||||
@ -80,3 +81,12 @@ label {
|
||||
.target-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.addon-controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.addon-options {
|
||||
flex: 1;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const { loader } = Components.utils.import(
|
||||
"resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
@ -23,6 +24,12 @@ loader.lazyRequireGetter(this, "WorkersComponent",
|
||||
"devtools/client/aboutdebugging/components/workers", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
loader.lazyImporter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/aboutdebugging.properties");
|
||||
|
||||
var AboutDebugging = {
|
||||
_prefListeners: [],
|
||||
|
||||
@ -83,6 +90,10 @@ var AboutDebugging = {
|
||||
updateCheckbox();
|
||||
});
|
||||
|
||||
// Link buttons to their associated actions.
|
||||
let loadAddonButton = document.getElementById("load-addon-from-file");
|
||||
loadAddonButton.addEventListener("click", this.loadAddonFromFile);
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
@ -98,6 +109,29 @@ var AboutDebugging = {
|
||||
});
|
||||
},
|
||||
|
||||
loadAddonFromFile() {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(window,
|
||||
Strings.GetStringFromName("selectAddonFromFile"),
|
||||
Ci.nsIFilePicker.modeOpen);
|
||||
let res = fp.show();
|
||||
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
|
||||
return;
|
||||
}
|
||||
let file = fp.file;
|
||||
// AddonManager.installTemporaryAddon accepts either
|
||||
// addon directory or final xpi file.
|
||||
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
|
||||
file = file.parent;
|
||||
}
|
||||
try {
|
||||
AddonManager.installTemporaryAddon(file);
|
||||
} catch(e) {
|
||||
alert("Error while installing the addon:\n" + e.message + "\n");
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
destroy() {
|
||||
let telemetry = this._telemetry;
|
||||
telemetry.toolClosed("aboutdebugging");
|
||||
|
@ -34,8 +34,13 @@
|
||||
<div class="header">
|
||||
<h1 class="header-name">&aboutDebugging.addons;</h1>
|
||||
</div>
|
||||
<input id="enable-addon-debugging" type="checkbox" data-pref="devtools.chrome.enabled"/>
|
||||
<label for="enable-addon-debugging" title="&aboutDebugging.addonDebugging.tooltip;">&aboutDebugging.addonDebugging.label;</label>
|
||||
<div class="addon-controls">
|
||||
<div class="addon-options">
|
||||
<input id="enable-addon-debugging" type="checkbox" data-pref="devtools.chrome.enabled"/>
|
||||
<label for="enable-addon-debugging" title="&aboutDebugging.addonDebugging.tooltip;">&aboutDebugging.addonDebugging.label;</label>
|
||||
</div>
|
||||
<button id="load-addon-from-file">&aboutDebugging.loadTemporaryAddon;</button>
|
||||
</div>
|
||||
<div id="addons"></div>
|
||||
</div>
|
||||
<div id="tab-workers" class="tab">
|
||||
|
13
devtools/client/aboutdebugging/moz.build
Normal file
13
devtools/client/aboutdebugging/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += [
|
||||
'components',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser.ini'
|
||||
]
|
7
devtools/client/aboutdebugging/test/addons/unpacked/bootstrap.js
vendored
Normal file
7
devtools/client/aboutdebugging/test/addons/unpacked/bootstrap.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
function startup() {
|
||||
Services.obs.notifyObservers(null, "test-devtools", null);
|
||||
}
|
||||
function shutdown() {}
|
||||
function install() {}
|
||||
function uninstall() {}
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
|
||||
<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="test-devtools@mozilla.org"
|
||||
em:name="test-devtools"
|
||||
em:version="1.0"
|
||||
em:type="2"
|
||||
em:creator="Mozilla">
|
||||
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>44.0a1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
8
devtools/client/aboutdebugging/test/browser.ini
Normal file
8
devtools/client/aboutdebugging/test/browser.ini
Normal file
@ -0,0 +1,8 @@
|
||||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
head.js
|
||||
addons/
|
||||
|
||||
[browser_addons_install.js]
|
@ -0,0 +1,61 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
var {AddonManager} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
|
||||
const ADDON_ID = "test-devtools@mozilla.org";
|
||||
const ADDON_NAME = "test-devtools";
|
||||
|
||||
add_task(function *() {
|
||||
let { tab, document } = yield openAboutDebugging("addons");
|
||||
|
||||
// Mock the file picker to select a test addon
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(null);
|
||||
let file = get_supports_file("addons/unpacked/install.rdf");
|
||||
MockFilePicker.returnFiles = [file.file];
|
||||
|
||||
// Wait for a message sent by the addon's bootstrap.js file
|
||||
let promise = new Promise(done => {
|
||||
Services.obs.addObserver(function listener() {
|
||||
Services.obs.removeObserver(listener, "test-devtools", false);
|
||||
ok(true, "Addon installed and running its bootstrap.js file");
|
||||
done();
|
||||
}, "test-devtools", false);
|
||||
});
|
||||
// Trigger the file picker by clicking on the button
|
||||
document.getElementById("load-addon-from-file").click();
|
||||
|
||||
// Wait for the addon execution
|
||||
yield promise;
|
||||
|
||||
// Check that the addon appears in the UI
|
||||
let names = [...document.querySelectorAll("#addons .target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
ok(names.includes(ADDON_NAME), "The addon name appears in the list of addons: " + names);
|
||||
|
||||
// Now uninstall this addon
|
||||
yield new Promise(done => {
|
||||
AddonManager.getAddonByID(ADDON_ID, addon => {
|
||||
let listener = {
|
||||
onUninstalled: function(aUninstalledAddon) {
|
||||
if (aUninstalledAddon != addon) {
|
||||
return;
|
||||
}
|
||||
AddonManager.removeAddonListener(listener);
|
||||
done();
|
||||
}
|
||||
};
|
||||
AddonManager.addAddonListener(listener);
|
||||
addon.uninstall();
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure that the UI removes the addon from the list
|
||||
names = [...document.querySelectorAll("#addons .target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
ok(!names.includes(ADDON_NAME), "After uninstall, the addon name disappears from the list of addons: " + names);
|
||||
|
||||
yield closeAboutDebugging(tab);
|
||||
});
|
78
devtools/client/aboutdebugging/test/head.js
Normal file
78
devtools/client/aboutdebugging/test/head.js
Normal file
@ -0,0 +1,78 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
|
||||
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const Services = require("Services");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
DevToolsUtils.testing = true;
|
||||
|
||||
const CHROME_ROOT = gTestPath.substr(0, gTestPath.lastIndexOf("/") + 1);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
DevToolsUtils.testing = false;
|
||||
});
|
||||
|
||||
function openAboutDebugging() {
|
||||
info("opening about:debugging");
|
||||
return addTab("about:debugging").then(tab => {
|
||||
let browser = tab.linkedBrowser;
|
||||
return {
|
||||
tab,
|
||||
document: browser.contentDocument,
|
||||
window: browser.contentWindow
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function closeAboutDebugging(tab) {
|
||||
info("Closing about:debugging");
|
||||
return removeTab(tab);
|
||||
}
|
||||
|
||||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
return new Promise(done => {
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
targetWindow.focus();
|
||||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
done(tab);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
function removeTab(aTab, aWindow) {
|
||||
info("Removing tab.");
|
||||
|
||||
return new Promise(done => {
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
let tabContainer = targetBrowser.tabContainer;
|
||||
|
||||
tabContainer.addEventListener("TabClose", function onClose(aEvent) {
|
||||
tabContainer.removeEventListener("TabClose", onClose, false);
|
||||
info("Tab removed and finished closing.");
|
||||
done();
|
||||
}, false);
|
||||
|
||||
targetBrowser.removeTab(aTab);
|
||||
});
|
||||
}
|
||||
|
||||
function get_supports_file(path) {
|
||||
let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIChromeRegistry);
|
||||
let fileurl = cr.convertChromeURL(Services.io.newURI(CHROME_ROOT + path, null, null));
|
||||
return fileurl.QueryInterface(Ci.nsIFileURL);
|
||||
}
|
@ -6,4 +6,5 @@
|
||||
<!ENTITY aboutDebugging.addons "Add-ons">
|
||||
<!ENTITY aboutDebugging.addonDebugging.label "Enable add-on debugging">
|
||||
<!ENTITY aboutDebugging.addonDebugging.tooltip "Turning this on will allow you to debug add-ons and various other parts of the browser chrome">
|
||||
<!ENTITY aboutDebugging.loadTemporaryAddon "Load Temporary Add-on">
|
||||
<!ENTITY aboutDebugging.workers "Workers">
|
||||
|
@ -5,6 +5,7 @@
|
||||
debug = Debug
|
||||
|
||||
extensions = Extensions
|
||||
selectAddonFromFile = Select Add-on Directory or XPI File
|
||||
serviceWorkers = Service Workers
|
||||
sharedWorkers = Shared Workers
|
||||
otherWorkers = Other Workers
|
||||
|
@ -7,7 +7,7 @@
|
||||
include('../templates.mozbuild')
|
||||
|
||||
DIRS += [
|
||||
'aboutdebugging/components',
|
||||
'aboutdebugging',
|
||||
'animationinspector',
|
||||
'canvasdebugger',
|
||||
'commandline',
|
||||
|
Loading…
Reference in New Issue
Block a user