DevTools API

  • Revision slug: Tools/DevToolsAPI
  • Revision title: DevTools API
  • Revision id: 326981
  • Created:
  • Creator: Paul
  • Is current revision? No
  • Comment

Revision Content

{{ warning("The DevTools API is not available yet. The DevTools API is still WIP. If you notice any inconsistency, please let Paul know.") }}

Introduction

The DevTools API provides a way to register and access developer tools in Firefox.

In term of User Interface, each registered tool lives in its own tab (we call one tab a panel). These tabs are located in a box we call a Toolbox. A toolbox can be hosted in a browser tab (at the bottom or on the side), or in its own window (we say that the toolbox is undocked). A Toolbox (and all the tools it contains) is linked to a Target, which the object the tools are debugging. A target is usually a web page (a tab), but can be other things (a chrome window, a remote tab,…).

In term of code, each tool has to provide a ToolDefinition object. A definition is a JS light object that exposes different informations about the tool (like its name and its icon), and a build method that will be used later-on to start an instance of this tool. The gDevTools global object provides methods to register a tool definition and to access tool instances. An instance of a tool is called a ToolPanel. The ToolPanel is built only when the tool is selected (not when the toolbox is opened). There is no way to "close/destroy" a ToolPanel. The only way to close a toolbox is to close its containing toolbox. All these objects implement the EventEmitter interface.

API

gDevTools

Method Description
void registerTool(toolDefinition) Register a new tool, and build a new panel in each exisiting toolbox.
void unregisterTool(toolId) Unregister a tool. Destroy any open panel.
Map(toolId,toolDefinition) getToolDefinitions() Get a copy of the internal toolID:toolDefinition Map.
Toolbox openToolbox(target, host=null, toolId=null) Open a toolbox for the specified target. If host is unspecified, Toolbox will decide where to open the toolbox (below the tab, on the side or in its own window). If tooldId is unspecified, Toolbox will decide which to open by default.
void closeToolbox(target) Close a toolbox.
Toolbox openToolboxForTab(tab, toolId=null) Open a toolbox for a specified tab. A tab target is built internally.
void toggleToolboxForTab(tab, toolId=null) Toggle the toolbox for a specified tab.
Map(Target,Toolbox) getToolboxes() Get a copy of the internal target:toolbox Map.
Toolbox getToolboxForTarget(target) Retrieve the toolbox for a specified target.
ToolPanel getPanelForTarget(tooldId, target) Retrieve the instance of a tool for a specified target.
Events Description
tool-registered a tool has been registered. [toolId]
tool-unregistered a tool has been unregistered. [toolId]
toolbox-ready a toolbox has been opened.[Toolbox]
toolbox-destroyed a toolbox has been closed. [xul:tab]
{tooldId}-ready a tool has been activated. [Toolbox, ToolPanel]

Toolbox

Method Description
Map(toolId, toolPanel) getToolPanels() Get a copy of the internal toolId:panel Map.
Target target  
HostType hostType Where the toolbox lives.
toolId currentToolId The toolId of the selected tool.
void selectTool(toolId) Select a tool.
Node getNotificationBox() Retrieve the surrounding notificationbox (useful to show notify the user even if a tool is not visible).
void destroy() Close the toolbox.
Events Description
ready the toolbox is ready to use.
{toolId}-ready a tool is ready to use.
host-changed the location of the toolbox changed.
destroyed The toolbox has been closed
select{{notimplemented_inline()}} A tool has been selected. [toolId]

ToolDefinition

Method Description
String id A unique id. Must not contained white spaces (it will be used as an id).
String icon The url of the icon.
String label Tool's name. Showed in Firefox' tool menu and in the Toolbox' tab.
String key Main keybinding key.
Number ordinal The position of the tool's tab within the toolbox (default is 99).
String modifiers Main keybinding modifiers.
String accesskey Menu accesskey.
Boolean isTargetSupported(Target) If the target is not supported, the toolbox will hide the tab.
String url A tool lives in its own iframe. Toolbox will load this URL.
ToolPanel build(iframeWindow, Toolbox) This function is called when the user select the tool tab. It is called only once ToolDefinition.url is loaded.

TargetType

FIXME:

HostType

FIXME

ToolPanel

Method Description
Target target FIXME
Target destroy() FIXME
Events Description
ready FIXME

EventEmitter

Method Description
on(eventName, listener) FIXME
off(eventName, listener) FIXME
once(eventName, listener) FIXME
emit(eventName, ...extraArgs) FIXME
listener function(eventName, ...extraArgs) {} FIXME

ToolSidebar {{notimplemented_inline()}}

To build a sidebar in your tool, first, add a xul:tabbox where you want the sidebar to live:

    <splitter class="devtools-side-splitter"/>
    <tabbox id="mytool-sidebar" class="devtools-sidebar-tabs" hidden="true">
      <tabs/>
      <tabpanels flex="1"/>
    </tabbox>
 
A sidebar is composed of tabs. Each tab will hold an iframe. For example, in the Inspector, there are 3 tabs (Computed View, Rule View, Layout View). The user can select the tab he wants to see.
 
If the availability of the tabs depends on some tool-related conditions, we might want to not let the user select a tab. This API provides methods to hide the tabstripe. For example, in the Web Console, there are 2 views (Network View and Object View). These views are only available in certain conditions controlled by the WebConsole code. So it's up the WebConsole the hide and show the sidebar, and select the correct tab.
 
If the loaded document exposes a window.setPanel(ToolPanel) function, the sidebar will call it once the document is loaded.
 
Method Description
new ToolSidebar(xul:tabbox, ToolPanel, showTabstripe) ToolSidebar object
void addTab(tabId, url) Add a tab in the sidebar
void select(tabId) Select a tab
void hide() Hide the sidebar
void show() Show the sidebar
void toggle() Toggle the sidebar
void getIframeForTab(tabId) Get the iframe containing the tab content
Events Description
new-tab-registered A new tab has been added
{tabId}-ready Tab is loaded and can be used
{tabId}-selected Tab has been selected and is visible
{tabId}-unselected Tab has been unselected and is not visible

Examples

Register a tool

gDevTools.registerTool({
  // FIXME: missing key related properties.
  id: "inspector",
  icon: "chrome://browser/skin/devtools/inspector-icon.png",
  url: "chrome://browser/content/devtools/inspector/inspector.xul",
  get label() {
    let strings = Services.strings.createBundle("chrome://browser/locale/devtools/inspector.properties");
    return strings.GetStringFromName("inspector.label");
  },

  isTargetSupported: function(target) {
    switch (target.type) {
      case DevTools.TargetType.TAB:
        return true;
      case DevTools.TargetType.REMOTE:
      case DevTools.TargetType.CHROME:
      default:
        return false;
    }
  },

  build: function(iframeWindow, toolbox, node) {
    return new InspectorPanel(iframeWindow, toolbox, node);
  }
});

Open a tool, or select it if the toolbox is already open:

let tab = gBrowser.selectedTab;
let inspector = gDevTools.getPanelForTarget("inspector", tab);
if (inspector && inspector.isReady) {
  inspector.selection.setNode(this.target);
} else {
  let toolbox = gDevTools.openToolForTab(tab, "inspector");
  toolbox.once("inspector-ready", function(event, panel) {
    let inspector = gDevTools.getPanelForTarget("inspector", tab);
    inspector.selection.setNode(this.target, "browser-context-menu");
  }.bind(this));
}

Revision Source

<p>{{ warning("The DevTools API is not available yet. The DevTools API is still WIP. If you notice any inconsistency, please let Paul know.") }}</p>
<h2 id="Introduction">Introduction</h2>
<p>The DevTools API provides a way to register and access developer tools in Firefox.</p>
<p>In term of User Interface, each registered tool lives in its own tab (we call one tab a <strong>panel</strong>). These tabs are located in a box we call a <strong>Toolbox</strong>. A toolbox can be <em>hosted</em> in a browser tab (at the bottom or on the side), or in its own window (we say that the toolbox is <em>undocked</em>). A Toolbox (and all the tools it contains) is linked to a <strong>Target</strong>, which the object the tools are debugging. A target is usually a web page (a tab), but can be other things (a chrome window, a remote tab,…).</p>
<p>In term of code, each tool has to provide a <strong>ToolDefinition</strong> object. A definition is a JS light object that exposes different informations about the tool (like its name and its icon), and a <em>build</em> method that will be used later-on to start an instance of this tool. The <strong> gDevTools</strong> global object provides methods to register a tool definition and to access tool instances. An instance of a tool is called a <strong>ToolPanel</strong>. The ToolPanel is built only when the tool is selected (not when the toolbox is opened). There is no way to "close/destroy" a ToolPanel. The only way to close a toolbox is to close its containing toolbox. All these objects implement the <strong>EventEmitter</strong> interface.</p>
<h2 id="API">API</h2>
<h3 id="gDevTools">gDevTools</h3>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>void&nbsp;registerTool(toolDefinition)</code></td>
      <td>Register a new tool, and build a new panel in each exisiting toolbox.</td>
    </tr>
    <tr>
      <td><code>void&nbsp;unregisterTool(toolId)</code></td>
      <td>Unregister a tool. Destroy any open panel.</td>
    </tr>
    <tr>
      <td><code>Map(toolId,toolDefinition)&nbsp;getToolDefinitions()</code></td>
      <td>Get a copy of the internal toolID:toolDefinition Map.</td>
    </tr>
    <tr>
      <td><code>Toolbox&nbsp;openToolbox(target,&nbsp;host=null,&nbsp;toolId=null)</code></td>
      <td>Open a toolbox for the specified target. If host is unspecified, Toolbox will decide where to open the toolbox (below the tab, on the side or in its own window). If tooldId is unspecified, Toolbox will decide which to open by default.</td>
    </tr>
    <tr>
      <td><code>void&nbsp;closeToolbox(target)</code></td>
      <td>Close a toolbox.</td>
    </tr>
    <tr>
      <td><code>Toolbox&nbsp;openToolboxForTab(tab,&nbsp;toolId=null)</code></td>
      <td>Open a toolbox for a specified tab. A tab target is built internally.</td>
    </tr>
    <tr>
      <td><code>void&nbsp;toggleToolboxForTab(tab,&nbsp;toolId=null)</code></td>
      <td>Toggle the toolbox for a specified tab.</td>
    </tr>
    <tr>
      <td><code>Map(Target,Toolbox)&nbsp;getToolboxes()</code></td>
      <td>Get a copy of the internal target:toolbox Map.</td>
    </tr>
    <tr>
      <td><code>Toolbox&nbsp;getToolboxForTarget(target)</code></td>
      <td>Retrieve the toolbox for a specified target.</td>
    </tr>
    <tr>
      <td><code>ToolPanel&nbsp;getPanelForTarget(tooldId,&nbsp;target)</code></td>
      <td>Retrieve the instance of a tool for a specified target.</td>
    </tr>
    <tr>
      <th>Events</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>tool-registered</code></td>
      <td>a tool has been registered. <code>[toolId]</code></td>
    </tr>
    <tr>
      <td><code>tool-unregistered</code></td>
      <td>a tool has been unregistered. <code>[toolId]</code></td>
    </tr>
    <tr>
      <td><code>toolbox-ready</code></td>
      <td>a toolbox has been opened.<code>[Toolbox]</code></td>
    </tr>
    <tr>
      <td><code>toolbox-destroyed</code></td>
      <td>a toolbox has been closed.<code> [xul:tab]</code></td>
    </tr>
    <tr>
      <td><code>{tooldId}-ready</code></td>
      <td>a tool has been activated. <code>[Toolbox, ToolPanel]</code></td>
    </tr>
  </tbody>
</table>
<h3 id="Toolbox">Toolbox</h3>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>Map(toolId,&nbsp;toolPanel)&nbsp;getToolPanels()</code></td>
      <td>Get a copy of the internal toolId:panel Map.</td>
    </tr>
    <tr>
      <td><code>Target&nbsp;target</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>HostType&nbsp;hostType</code></td>
      <td>Where the toolbox lives.</td>
    </tr>
    <tr>
      <td><code>toolId&nbsp;currentToolId</code></td>
      <td>The toolId of the selected tool.</td>
    </tr>
    <tr>
      <td><code>void&nbsp;selectTool(toolId)</code></td>
      <td>Select a tool.</td>
    </tr>
    <tr>
      <td><code>Node&nbsp;getNotificationBox()</code></td>
      <td>Retrieve the surrounding notificationbox (useful to show notify the user even if a tool is not visible).</td>
    </tr>
    <tr>
      <td><code>void&nbsp;destroy()</code></td>
      <td>Close the toolbox.</td>
    </tr>
    <tr>
      <th>Events</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>ready</code></td>
      <td>the toolbox is ready to use.</td>
    </tr>
    <tr>
      <td><code>{toolId}-ready</code></td>
      <td>a tool is ready to use.</td>
    </tr>
    <tr>
      <td><code>host-changed</code></td>
      <td>the location of the toolbox changed.</td>
    </tr>
    <tr>
      <td><code>destroyed</code></td>
      <td>The toolbox has been closed</td>
    </tr>
    <tr>
      <td><code>select</code>{{notimplemented_inline()}}</td>
      <td>A tool has been selected. <code>[toolId]</code></td>
    </tr>
  </tbody>
</table>
<h3 id="ToolDefinition">ToolDefinition</h3>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>String&nbsp;id</code></td>
      <td>A unique id. Must not contained white spaces (it will be used as an id).</td>
    </tr>
    <tr>
      <td><code>String&nbsp;icon</code></td>
      <td>The url of the icon.</td>
    </tr>
    <tr>
      <td><code>String&nbsp;label</code></td>
      <td>Tool's name. Showed in Firefox' tool menu and in the Toolbox' tab.</td>
    </tr>
    <tr>
      <td><code>String&nbsp;key</code></td>
      <td>Main keybinding key.</td>
    </tr>
    <tr>
      <td><code>Number ordinal</code></td>
      <td>The position of the tool's tab within the toolbox (default is 99).</td>
    </tr>
    <tr>
      <td><code>String&nbsp;modifiers</code></td>
      <td>Main keybinding modifiers.</td>
    </tr>
    <tr>
      <td><code>String&nbsp;accesskey</code></td>
      <td>Menu accesskey.</td>
    </tr>
    <tr>
      <td><code>Boolean&nbsp;isTargetSupported(Target)</code></td>
      <td>If the target is not supported, the toolbox will hide the tab.</td>
    </tr>
    <tr>
      <td><code>String&nbsp;url</code></td>
      <td>A tool lives in its own iframe. Toolbox will load this URL.</td>
    </tr>
    <tr>
      <td><code>ToolPanel&nbsp;build(iframeWindow,&nbsp;Toolbox)</code></td>
      <td>This function is called when the user select the tool tab. It is called only once <em>ToolDefinition.url</em> is loaded.</td>
    </tr>
  </tbody>
</table>
<h3 id="TargetType">TargetType</h3>
<p>FIXME:</p>
<h3 id="HostType">HostType</h3>
<p>FIXME</p>
<h3 id="ToolPanel">ToolPanel</h3>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>Target&nbsp;target</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <td><code>Target&nbsp;destroy()</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <th>Events</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>ready</code></td>
      <td>FIXME</td>
    </tr>
  </tbody>
</table>
<h3 id="EventEmitter">EventEmitter</h3>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>on(eventName,&nbsp;listener)</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <td><code>off(eventName,&nbsp;listener)</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <td><code>once(eventName,&nbsp;listener)</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <td><code>emit(eventName,&nbsp;...extraArgs)</code></td>
      <td>FIXME</td>
    </tr>
    <tr>
      <td><code>listener&nbsp;function(eventName,&nbsp;...extraArgs)&nbsp;{}</code></td>
      <td>FIXME</td>
    </tr>
  </tbody>
</table>
<h3 id="ToolSidebar_.7B.7Bnotimplemented_inline().7D.7D">ToolSidebar {{notimplemented_inline()}}</h3>
<p>To build a sidebar in your tool, first, add a xul:tabbox where you want the sidebar to live:</p>
<pre class="line">
<code class="brush: html">    <span class="nt">&lt;splitter</span> <span class="na">class=</span><span class="s">"devtools-side-splitter"</span><span class="nt">/&gt;</span></code>
<code>    <span class="nt">&lt;tabbox</span> <span class="na">id=</span><span class="s">"mytool-sidebar"</span> <span class="na">class=</span><span class="s">"devtools-sidebar-tabs"</span> <span class="na">hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span></code>
<code>      <span class="nt">&lt;tabs/&gt;</span></code>
<code>      <span class="nt">&lt;tabpanels</span> <span class="na">flex=</span><span class="s">"1"</span><span class="nt">/&gt;</span></code>
<code>    <span class="nt">&lt;/tabbox&gt;</span></code></pre>
<div class="line">
  &nbsp;</div>
<div class="line">
  A sidebar is composed of tabs. Each tab will hold an iframe. For example, in the Inspector, there are 3 tabs (Computed View, Rule View, Layout View). The user can select the tab he wants to see.</div>
<div class="line">
  &nbsp;</div>
<div class="line">
  If the availability of the tabs depends on some tool-related conditions, we might want to not let the user select a tab. This API provides methods to hide the tabstripe. For example, in the Web Console, there are 2 views (Network View and Object View). These views are only available in certain conditions controlled by the WebConsole code. So it's up the WebConsole the hide and show the sidebar, and select the correct tab.</div>
<div class="line">
  &nbsp;</div>
<div class="line">
  If the loaded document exposes a <code>window.setPanel(ToolPanel)</code> function, the sidebar will call it once the document is loaded.</div>
<div class="line">
  &nbsp;</div>
<table class="standard-table">
  <tbody>
    <tr>
      <th>Method</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>new ToolSidebar(xul:tabbox, ToolPanel, showTabstripe)</code></td>
      <td>ToolSidebar object</td>
    </tr>
    <tr>
      <td><code>void addTab(tabId, url)</code></td>
      <td>Add a tab in the sidebar</td>
    </tr>
    <tr>
      <td><code>void select(tabId)</code></td>
      <td>Select a tab</td>
    </tr>
    <tr>
      <td><code>void hide()</code></td>
      <td>Hide the sidebar</td>
    </tr>
    <tr>
      <td><code>void show()</code></td>
      <td>Show the sidebar</td>
    </tr>
    <tr>
      <td><code>void toggle()</code></td>
      <td>Toggle the sidebar</td>
    </tr>
    <tr>
      <td><code>void getIframeForTab(tabId)</code></td>
      <td>Get the iframe containing the tab content</td>
    </tr>
    <tr>
      <th>Events</th>
      <th>Description</th>
    </tr>
    <tr>
      <td><code>new-tab-registered</code></td>
      <td>A new tab has been added</td>
    </tr>
    <tr>
      <td><code>{tabId}-ready</code></td>
      <td>Tab is loaded and can be used</td>
    </tr>
    <tr>
      <td><code>{tabId}-selected</code></td>
      <td>Tab has been selected and is visible</td>
    </tr>
    <tr>
      <td><code>{tabId}-unselected</code></td>
      <td>Tab has been unselected and is not visible</td>
    </tr>
  </tbody>
</table>
<h2 id="Examples">Examples</h2>
<p>Register a tool</p>
<pre class="brush: js">
gDevTools.registerTool({
  // FIXME: missing key related properties.
  id: "inspector",
  icon: "chrome://browser/skin/devtools/inspector-icon.png",
  url: "chrome://browser/content/devtools/inspector/inspector.xul",
  get label() {
    let strings = Services.strings.createBundle("chrome://browser/locale/devtools/inspector.properties");
    return strings.GetStringFromName("inspector.label");
  },

  isTargetSupported: function(target) {
    switch (target.type) {
      case DevTools.TargetType.TAB:
        return true;
      case DevTools.TargetType.REMOTE:
      case DevTools.TargetType.CHROME:
      default:
        return false;
    }
  },

  build: function(iframeWindow, toolbox, node) {
    return new InspectorPanel(iframeWindow, toolbox, node);
  }
});
</pre>
<p>Open a tool, or select it if the toolbox is already open:</p>
<pre class="brush: js">
let tab = gBrowser.selectedTab;
let inspector = gDevTools.getPanelForTarget("inspector", tab);
if (inspector &amp;&amp; inspector.isReady) {
  inspector.selection.setNode(this.target);
} else {
  let toolbox = gDevTools.openToolForTab(tab, "inspector");
  toolbox.once("inspector-ready", function(event, panel) {
    let inspector = gDevTools.getPanelForTarget("inspector", tab);
    inspector.selection.setNode(this.target, "browser-context-menu");
  }.bind(this));
}
</pre>
Revert to this revision