mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-11 21:58:41 +02:00
***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8
This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:
ChromeUtils.import("resource://gre/modules/Services.jsm");
is approximately the same as the following, in the new model:
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs
This was done using the followng script:
https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16750
--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
657 lines
21 KiB
JavaScript
657 lines
21 KiB
JavaScript
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set sts=2 sw=2 et tw=80: */
|
|
"use strict";
|
|
|
|
var {ExtensionParent} = ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm");
|
|
|
|
var {
|
|
IconDetails,
|
|
watchExtensionProxyContextLoad,
|
|
} = ExtensionParent;
|
|
|
|
var {
|
|
promiseDocumentLoaded,
|
|
} = ExtensionUtils;
|
|
|
|
const WEBEXT_PANELS_URL = "chrome://browser/content/webext-panels.xul";
|
|
|
|
class BaseDevToolsPanel {
|
|
constructor(context, panelOptions) {
|
|
const toolbox = context.devToolsToolbox;
|
|
if (!toolbox) {
|
|
// This should never happen when this constructor is called with a valid
|
|
// devtools extension context.
|
|
throw Error("Missing mandatory toolbox");
|
|
}
|
|
|
|
this.context = context;
|
|
this.extension = context.extension;
|
|
this.toolbox = toolbox;
|
|
this.viewType = "devtools_panel";
|
|
this.panelOptions = panelOptions;
|
|
this.id = panelOptions.id;
|
|
|
|
this.unwatchExtensionProxyContextLoad = null;
|
|
|
|
// References to the panel browser XUL element and the toolbox window global which
|
|
// contains the devtools panel UI.
|
|
this.browser = null;
|
|
this.browserContainerWindow = null;
|
|
}
|
|
|
|
async createBrowserElement(window) {
|
|
const {toolbox} = this;
|
|
const {extension} = this.context;
|
|
const {url} = this.panelOptions || {url: "about:blank"};
|
|
|
|
this.browser = await window.getBrowser({
|
|
extension,
|
|
extensionUrl: url,
|
|
browserStyle: false,
|
|
viewType: "devtools_panel",
|
|
browserInsertedData: {
|
|
devtoolsToolboxInfo: {
|
|
toolboxPanelId: this.id,
|
|
inspectedWindowTabId: getTargetTabIdForToolbox(toolbox),
|
|
},
|
|
},
|
|
});
|
|
|
|
let hasTopLevelContext = false;
|
|
|
|
// Listening to new proxy contexts.
|
|
this.unwatchExtensionProxyContextLoad = watchExtensionProxyContextLoad(this, context => {
|
|
// Keep track of the toolbox and target associated to the context, which is
|
|
// needed by the API methods implementation.
|
|
context.devToolsToolbox = toolbox;
|
|
|
|
if (!hasTopLevelContext) {
|
|
hasTopLevelContext = true;
|
|
|
|
// Resolve the promise when the root devtools_panel context has been created.
|
|
if (this._resolveTopLevelContext) {
|
|
this._resolveTopLevelContext(context);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.browser.loadURI(url, {triggeringPrincipal: this.context.principal});
|
|
}
|
|
|
|
destroyBrowserElement() {
|
|
const {browser, unwatchExtensionProxyContextLoad} = this;
|
|
if (unwatchExtensionProxyContextLoad) {
|
|
this.unwatchExtensionProxyContextLoad = null;
|
|
unwatchExtensionProxyContextLoad();
|
|
}
|
|
|
|
if (browser) {
|
|
browser.remove();
|
|
this.browser = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Represents an addon devtools panel in the main process.
|
|
*
|
|
* @param {ExtensionChildProxyContext} context
|
|
* A devtools extension proxy context running in a main process.
|
|
* @param {object} options
|
|
* @param {string} options.id
|
|
* The id of the addon devtools panel.
|
|
* @param {string} options.icon
|
|
* The icon of the addon devtools panel.
|
|
* @param {string} options.title
|
|
* The title of the addon devtools panel.
|
|
* @param {string} options.url
|
|
* The url of the addon devtools panel, relative to the extension base URL.
|
|
*/
|
|
class ParentDevToolsPanel extends BaseDevToolsPanel {
|
|
constructor(context, panelOptions) {
|
|
super(context, panelOptions);
|
|
|
|
this.visible = false;
|
|
this.destroyed = false;
|
|
|
|
this.context.callOnClose(this);
|
|
|
|
this.onToolboxPanelSelect = this.onToolboxPanelSelect.bind(this);
|
|
this.onToolboxHostWillChange = this.onToolboxHostWillChange.bind(this);
|
|
this.onToolboxHostChanged = this.onToolboxHostChanged.bind(this);
|
|
|
|
this.waitTopLevelContext = new Promise(resolve => {
|
|
this._resolveTopLevelContext = resolve;
|
|
});
|
|
|
|
this.panelAdded = false;
|
|
this.addPanel();
|
|
}
|
|
|
|
addPanel() {
|
|
const {icon, title} = this.panelOptions;
|
|
const extensionName = this.context.extension.name;
|
|
|
|
this.toolbox.addAdditionalTool({
|
|
id: this.id,
|
|
extensionId: this.context.extension.id,
|
|
url: WEBEXT_PANELS_URL,
|
|
icon: icon,
|
|
label: title,
|
|
tooltip: `DevTools Panel added by "${extensionName}" add-on.`,
|
|
isTargetSupported: target => target.isLocalTab,
|
|
build: (window, toolbox) => {
|
|
if (toolbox !== this.toolbox) {
|
|
throw new Error("Unexpected toolbox received on addAdditionalTool build property");
|
|
}
|
|
|
|
const destroy = this.buildPanel(window);
|
|
|
|
return {toolbox, destroy};
|
|
},
|
|
});
|
|
|
|
this.panelAdded = true;
|
|
}
|
|
|
|
buildPanel(window) {
|
|
const {toolbox} = this;
|
|
|
|
this.createBrowserElement(window);
|
|
|
|
// Store the last panel's container element (used to restore it when the toolbox
|
|
// host is switched between docked and undocked).
|
|
this.browserContainerWindow = window;
|
|
|
|
toolbox.on("select", this.onToolboxPanelSelect);
|
|
toolbox.on("host-will-change", this.onToolboxHostWillChange);
|
|
toolbox.on("host-changed", this.onToolboxHostChanged);
|
|
|
|
// Return a cleanup method that is when the panel is destroyed, e.g.
|
|
// - when addon devtool panel has been disabled by the user from the toolbox preferences,
|
|
// its ParentDevToolsPanel instance is still valid, but the built devtools panel is removed from
|
|
// the toolbox (and re-built again if the user re-enables it from the toolbox preferences panel)
|
|
// - when the creator context has been destroyed, the ParentDevToolsPanel close method is called,
|
|
// it removes the tool definition from the toolbox, which will call this destroy method.
|
|
return () => {
|
|
this.destroyBrowserElement();
|
|
this.browserContainerWindow = null;
|
|
toolbox.off("select", this.onToolboxPanelSelect);
|
|
toolbox.off("host-will-change", this.onToolboxHostWillChange);
|
|
toolbox.off("host-changed", this.onToolboxHostChanged);
|
|
};
|
|
}
|
|
|
|
onToolboxHostWillChange() {
|
|
// NOTE: Using a content iframe here breaks the devtools panel
|
|
// switching between docked and undocked mode,
|
|
// because of a swapFrameLoader exception (see bug 1075490),
|
|
// destroy the browser and recreate it after the toolbox host has been
|
|
// switched is a reasonable workaround to fix the issue on release and beta
|
|
// Firefox versions (at least until the underlying bug can be fixed).
|
|
if (this.browser) {
|
|
// Fires a panel.onHidden event before destroying the browser element because
|
|
// the toolbox hosts is changing.
|
|
if (this.visible) {
|
|
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelHidden", {
|
|
toolboxPanelId: this.id,
|
|
});
|
|
}
|
|
|
|
this.destroyBrowserElement();
|
|
}
|
|
}
|
|
|
|
async onToolboxHostChanged() {
|
|
if (this.browserContainerWindow) {
|
|
this.createBrowserElement(this.browserContainerWindow);
|
|
|
|
// Fires a panel.onShown event once the browser element has been recreated
|
|
// after the toolbox hosts has been changed (needed to provide the new window
|
|
// object to the extension page that has created the devtools panel).
|
|
if (this.visible) {
|
|
await this.waitTopLevelContext;
|
|
|
|
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsPanelShown", {
|
|
toolboxPanelId: this.id,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async onToolboxPanelSelect(id) {
|
|
if (!this.waitTopLevelContext || !this.panelAdded) {
|
|
return;
|
|
}
|
|
|
|
// Wait that the panel is fully loaded and emit show.
|
|
await this.waitTopLevelContext;
|
|
|
|
if (!this.visible && id === this.id) {
|
|
this.visible = true;
|
|
} else if (this.visible && id !== this.id) {
|
|
this.visible = false;
|
|
}
|
|
|
|
const extensionMessage = `Extension:DevToolsPanel${this.visible ? "Shown" : "Hidden"}`;
|
|
this.context.parentMessageManager.sendAsyncMessage(extensionMessage, {
|
|
toolboxPanelId: this.id,
|
|
});
|
|
}
|
|
|
|
close() {
|
|
const {toolbox} = this;
|
|
|
|
if (!toolbox) {
|
|
throw new Error("Unable to destroy a closed devtools panel");
|
|
}
|
|
|
|
// Explicitly remove the panel if it is registered and the toolbox is not
|
|
// closing itself.
|
|
if (this.panelAdded && toolbox.isToolRegistered(this.id)) {
|
|
this.destroyBrowserElement();
|
|
toolbox.removeAdditionalTool(this.id);
|
|
}
|
|
|
|
this.waitTopLevelContext = null;
|
|
this._resolveTopLevelContext = null;
|
|
this.context = null;
|
|
this.toolbox = null;
|
|
this.browser = null;
|
|
this.browserContainerWindow = null;
|
|
}
|
|
|
|
destroyBrowserElement() {
|
|
super.destroyBrowserElement();
|
|
|
|
// If the panel has been removed or disabled (e.g. from the toolbox preferences
|
|
// or during the toolbox switching between docked and undocked),
|
|
// we need to re-initialize the waitTopLevelContext Promise.
|
|
this.waitTopLevelContext = new Promise(resolve => {
|
|
this._resolveTopLevelContext = resolve;
|
|
});
|
|
}
|
|
}
|
|
|
|
class DevToolsSelectionObserver extends EventEmitter {
|
|
constructor(context) {
|
|
if (!context.devToolsToolbox) {
|
|
// This should never happen when this constructor is called with a valid
|
|
// devtools extension context.
|
|
throw Error("Missing mandatory toolbox");
|
|
}
|
|
|
|
super();
|
|
context.callOnClose(this);
|
|
|
|
this.toolbox = context.devToolsToolbox;
|
|
this.onSelected = this.onSelected.bind(this);
|
|
this.initialized = false;
|
|
}
|
|
|
|
on(...args) {
|
|
this.lazyInit();
|
|
super.on.apply(this, args);
|
|
}
|
|
|
|
once(...args) {
|
|
this.lazyInit();
|
|
super.once.apply(this, args);
|
|
}
|
|
|
|
async lazyInit() {
|
|
if (!this.initialized) {
|
|
this.initialized = true;
|
|
this.toolbox.on("selection-changed", this.onSelected);
|
|
}
|
|
}
|
|
|
|
close() {
|
|
if (this.destroyed) {
|
|
throw new Error("Unable to close a destroyed DevToolsSelectionObserver");
|
|
}
|
|
|
|
if (this.initialized) {
|
|
this.toolbox.off("selection-changed", this.onSelected);
|
|
}
|
|
|
|
this.toolbox = null;
|
|
this.destroyed = true;
|
|
}
|
|
|
|
onSelected() {
|
|
this.emit("selectionChanged");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Represents an addon devtools inspector sidebar in the main process.
|
|
*
|
|
* @param {ExtensionChildProxyContext} context
|
|
* A devtools extension proxy context running in a main process.
|
|
* @param {object} options
|
|
* @param {string} options.id
|
|
* The id of the addon devtools sidebar.
|
|
* @param {string} options.title
|
|
* The title of the addon devtools sidebar.
|
|
*/
|
|
class ParentDevToolsInspectorSidebar extends BaseDevToolsPanel {
|
|
constructor(context, panelOptions) {
|
|
super(context, panelOptions);
|
|
|
|
this.visible = false;
|
|
this.destroyed = false;
|
|
|
|
this.context.callOnClose(this);
|
|
|
|
this.onSidebarSelect = this.onSidebarSelect.bind(this);
|
|
this.onSidebarCreated = this.onSidebarCreated.bind(this);
|
|
this.onExtensionPageMount = this.onExtensionPageMount.bind(this);
|
|
this.onExtensionPageUnmount = this.onExtensionPageUnmount.bind(this);
|
|
this.onToolboxHostWillChange = this.onToolboxHostWillChange.bind(this);
|
|
this.onToolboxHostChanged = this.onToolboxHostChanged.bind(this);
|
|
|
|
this.toolbox.once(`extension-sidebar-created-${this.id}`, this.onSidebarCreated);
|
|
this.toolbox.on("inspector-sidebar-select", this.onSidebarSelect);
|
|
this.toolbox.on("host-will-change", this.onToolboxHostWillChange);
|
|
this.toolbox.on("host-changed", this.onToolboxHostChanged);
|
|
|
|
// Set by setObject if the sidebar has not been created yet.
|
|
this._initializeSidebar = null;
|
|
|
|
// Set by _updateLastObjectValueGrip to keep track of the last
|
|
// object value grip (to release the previous selected actor
|
|
// on the remote debugging server when the actor changes).
|
|
this._lastObjectValueGrip = null;
|
|
|
|
this.toolbox.registerInspectorExtensionSidebar(this.id, {
|
|
title: panelOptions.title,
|
|
});
|
|
}
|
|
|
|
close() {
|
|
if (this.destroyed) {
|
|
throw new Error("Unable to close a destroyed DevToolsSelectionObserver");
|
|
}
|
|
|
|
if (this.extensionSidebar) {
|
|
this.extensionSidebar.off("extension-page-mount", this.onExtensionPageMount);
|
|
this.extensionSidebar.off("extension-page-unmount", this.onExtensionPageUnmount);
|
|
}
|
|
|
|
if (this.browser) {
|
|
this.destroyBrowserElement();
|
|
this.browser = null;
|
|
this.containerEl = null;
|
|
}
|
|
|
|
// Release the last selected actor on the remote debugging server.
|
|
this._updateLastObjectValueGrip(null);
|
|
|
|
this.toolbox.off(`extension-sidebar-created-${this.id}`, this.onSidebarCreated);
|
|
this.toolbox.off("inspector-sidebar-select", this.onSidebarSelect);
|
|
this.toolbox.off("host-changed", this.onToolboxHostChanged);
|
|
this.toolbox.off("host-will-change", this.onToolboxHostWillChange);
|
|
|
|
this.toolbox.unregisterInspectorExtensionSidebar(this.id);
|
|
this.extensionSidebar = null;
|
|
this._lazySidebarInit = null;
|
|
|
|
this.destroyed = true;
|
|
}
|
|
|
|
onToolboxHostWillChange() {
|
|
if (this.browser) {
|
|
this.destroyBrowserElement();
|
|
}
|
|
}
|
|
|
|
onToolboxHostChanged() {
|
|
if (this.containerEl && this.panelOptions.url) {
|
|
this.createBrowserElement(this.containerEl.contentWindow);
|
|
}
|
|
}
|
|
|
|
onExtensionPageMount(containerEl) {
|
|
this.containerEl = containerEl;
|
|
|
|
// Wait the webext-panel.xul page to have been loaded in the
|
|
// inspector sidebar panel.
|
|
promiseDocumentLoaded(containerEl.contentDocument).then(() => {
|
|
this.createBrowserElement(containerEl.contentWindow);
|
|
});
|
|
}
|
|
|
|
onExtensionPageUnmount() {
|
|
this.containerEl = null;
|
|
this.destroyBrowserElement();
|
|
}
|
|
|
|
onSidebarCreated(sidebar) {
|
|
this.extensionSidebar = sidebar;
|
|
|
|
sidebar.on("extension-page-mount", this.onExtensionPageMount);
|
|
sidebar.on("extension-page-unmount", this.onExtensionPageUnmount);
|
|
|
|
const {_lazySidebarInit} = this;
|
|
this._lazySidebarInit = null;
|
|
|
|
if (typeof _lazySidebarInit === "function") {
|
|
_lazySidebarInit();
|
|
}
|
|
}
|
|
|
|
onSidebarSelect(id) {
|
|
if (!this.extensionSidebar) {
|
|
return;
|
|
}
|
|
|
|
if (!this.visible && id === this.id) {
|
|
this.visible = true;
|
|
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsInspectorSidebarShown", {
|
|
inspectorSidebarId: this.id,
|
|
});
|
|
} else if (this.visible && id !== this.id) {
|
|
this.visible = false;
|
|
this.context.parentMessageManager.sendAsyncMessage("Extension:DevToolsInspectorSidebarHidden", {
|
|
inspectorSidebarId: this.id,
|
|
});
|
|
}
|
|
}
|
|
|
|
setPage(extensionPageURL) {
|
|
this.panelOptions.url = extensionPageURL;
|
|
|
|
if (this.extensionSidebar) {
|
|
if (this.browser) {
|
|
// Just load the new extension page url in the existing browser, if
|
|
// it already exists.
|
|
this.browser.loadURI(this.panelOptions.url, {
|
|
triggeringPrincipal: this.context.extension.principal,
|
|
});
|
|
} else {
|
|
// The browser element doesn't exist yet, but the sidebar has been
|
|
// already created (e.g. because the inspector was already selected
|
|
// in a open toolbox and the extension has been installed/reloaded/updated).
|
|
this.extensionSidebar.setExtensionPage(WEBEXT_PANELS_URL);
|
|
}
|
|
} else {
|
|
// Defer the sidebar.setExtensionPage call.
|
|
this._setLazySidebarInit(
|
|
() => this.extensionSidebar.setExtensionPage(WEBEXT_PANELS_URL));
|
|
}
|
|
}
|
|
|
|
setObject(object, rootTitle) {
|
|
delete this.panelOptions.url;
|
|
|
|
this._updateLastObjectValueGrip(null);
|
|
|
|
// Nest the object inside an object, as the value of the `rootTitle` property.
|
|
if (rootTitle) {
|
|
object = {[rootTitle]: object};
|
|
}
|
|
|
|
if (this.extensionSidebar) {
|
|
this.extensionSidebar.setObject(object);
|
|
} else {
|
|
// Defer the sidebar.setObject call.
|
|
this._setLazySidebarInit(() => this.extensionSidebar.setObject(object));
|
|
}
|
|
}
|
|
|
|
_setLazySidebarInit(cb) {
|
|
this._lazySidebarInit = cb;
|
|
}
|
|
|
|
setObjectValueGrip(objectValueGrip, rootTitle) {
|
|
delete this.panelOptions.url;
|
|
|
|
this._updateLastObjectValueGrip(objectValueGrip);
|
|
|
|
if (this.extensionSidebar) {
|
|
this.extensionSidebar.setObjectValueGrip(objectValueGrip, rootTitle);
|
|
} else {
|
|
// Defer the sidebar.setObjectValueGrip call.
|
|
this._setLazySidebarInit(() => {
|
|
this.extensionSidebar.setObjectValueGrip(objectValueGrip, rootTitle);
|
|
});
|
|
}
|
|
}
|
|
|
|
_updateLastObjectValueGrip(newObjectValueGrip = null) {
|
|
const {_lastObjectValueGrip} = this;
|
|
|
|
this._lastObjectValueGrip = newObjectValueGrip;
|
|
|
|
const oldActor = _lastObjectValueGrip && _lastObjectValueGrip.actor;
|
|
const newActor = newObjectValueGrip && newObjectValueGrip.actor;
|
|
|
|
// Release the previously active actor on the remote debugging server.
|
|
if (oldActor && oldActor !== newActor) {
|
|
this.toolbox.target.client.release(oldActor);
|
|
}
|
|
}
|
|
}
|
|
|
|
const sidebarsById = new Map();
|
|
|
|
this.devtools_panels = class extends ExtensionAPI {
|
|
getAPI(context) {
|
|
// Lazily retrieved inspectedWindow actor front per child context
|
|
// (used by Sidebar.setExpression).
|
|
let waitForInspectedWindowFront;
|
|
|
|
// TODO - Bug 1448878: retrieve a more detailed callerInfo object,
|
|
// like the filename and lineNumber of the actual extension called
|
|
// in the child process.
|
|
const callerInfo = {
|
|
addonId: context.extension.id,
|
|
url: context.extension.baseURI.spec,
|
|
};
|
|
|
|
// An incremental "per context" id used in the generated devtools panel id.
|
|
let nextPanelId = 0;
|
|
|
|
const toolboxSelectionObserver = new DevToolsSelectionObserver(context);
|
|
|
|
function newBasePanelId() {
|
|
return `${context.extension.id}-${context.contextId}-${nextPanelId++}`;
|
|
}
|
|
|
|
return {
|
|
devtools: {
|
|
panels: {
|
|
elements: {
|
|
onSelectionChanged: new EventManager({
|
|
context,
|
|
name: "devtools.panels.elements.onSelectionChanged",
|
|
register: fire => {
|
|
const listener = (eventName) => {
|
|
fire.async();
|
|
};
|
|
toolboxSelectionObserver.on("selectionChanged", listener);
|
|
return () => {
|
|
toolboxSelectionObserver.off("selectionChanged", listener);
|
|
};
|
|
},
|
|
}).api(),
|
|
createSidebarPane(title) {
|
|
const id = `devtools-inspector-sidebar-${makeWidgetId(newBasePanelId())}`;
|
|
|
|
const parentSidebar = new ParentDevToolsInspectorSidebar(context, {title, id});
|
|
sidebarsById.set(id, parentSidebar);
|
|
|
|
context.callOnClose({
|
|
close() {
|
|
sidebarsById.delete(id);
|
|
},
|
|
});
|
|
|
|
// Resolved to the devtools sidebar id into the child addon process,
|
|
// where it will be used to identify the messages related
|
|
// to the panel API onShown/onHidden events.
|
|
return Promise.resolve(id);
|
|
},
|
|
// The following methods are used internally to allow the sidebar API
|
|
// piece that is running in the child process to asks the parent process
|
|
// to execute the sidebar methods.
|
|
Sidebar: {
|
|
setPage(sidebarId, extensionPageURL) {
|
|
const sidebar = sidebarsById.get(sidebarId);
|
|
return sidebar.setPage(extensionPageURL);
|
|
},
|
|
setObject(sidebarId, jsonObject, rootTitle) {
|
|
const sidebar = sidebarsById.get(sidebarId);
|
|
return sidebar.setObject(jsonObject, rootTitle);
|
|
},
|
|
async setExpression(sidebarId, evalExpression, rootTitle) {
|
|
const sidebar = sidebarsById.get(sidebarId);
|
|
|
|
if (!waitForInspectedWindowFront) {
|
|
waitForInspectedWindowFront = getInspectedWindowFront(context);
|
|
}
|
|
|
|
const front = await waitForInspectedWindowFront;
|
|
const evalOptions = Object.assign({
|
|
evalResultAsGrip: true,
|
|
}, getToolboxEvalOptions(context));
|
|
const evalResult = await front.eval(callerInfo, evalExpression, evalOptions);
|
|
|
|
let jsonObject;
|
|
|
|
if (evalResult.exceptionInfo) {
|
|
jsonObject = evalResult.exceptionInfo;
|
|
|
|
return sidebar.setObject(jsonObject, rootTitle);
|
|
}
|
|
|
|
return sidebar.setObjectValueGrip(evalResult.valueGrip, rootTitle);
|
|
},
|
|
},
|
|
},
|
|
create(title, icon, url) {
|
|
// Get a fallback icon from the manifest data.
|
|
if (icon === "" && context.extension.manifest.icons) {
|
|
const iconInfo = IconDetails.getPreferredIcon(context.extension.manifest.icons,
|
|
context.extension, 128);
|
|
icon = iconInfo ? iconInfo.icon : "";
|
|
}
|
|
|
|
icon = context.extension.baseURI.resolve(icon);
|
|
url = context.extension.baseURI.resolve(url);
|
|
|
|
const id = `webext-devtools-panel-${makeWidgetId(newBasePanelId())}`;
|
|
|
|
new ParentDevToolsPanel(context, {title, icon, url, id});
|
|
|
|
// Resolved to the devtools panel id into the child addon process,
|
|
// where it will be used to identify the messages related
|
|
// to the panel API onShown/onHidden events.
|
|
return Promise.resolve(id);
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
};
|