Bug 1192642 - Add a left host type for the toolbox. r=pbro draft
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 06 Jun 2018 13:54:20 -0400
changeset 804907 172b8dff313d497159f9336e8c168eeb9e8cfd39
parent 804906 97c439edf8ac893ad5133296148775e1db84ff80
push id112489
push userbmo:gl@mozilla.com
push dateWed, 06 Jun 2018 18:01:11 +0000
reviewerspbro
bugs1192642
milestone62.0a1
Bug 1192642 - Add a left host type for the toolbox. r=pbro MozReview-Commit-ID: HANEObGHtjr
browser/components/extensions/test/browser/browser_ext_devtools_panel.js
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
devtools/client/debugger/debugger-view.js
devtools/client/debugger/new/test/mochitest/browser_dbg-layout-changes.js
devtools/client/debugger/test/mochitest/browser_dbg_host-layout.js
devtools/client/framework/devtools.js
devtools/client/framework/test/browser_keybindings_02.js
devtools/client/framework/test/browser_keybindings_03.js
devtools/client/framework/test/browser_toolbox_hosts.js
devtools/client/framework/test/browser_toolbox_hosts_size.js
devtools/client/framework/test/browser_toolbox_hosts_telemetry.js
devtools/client/framework/test/browser_toolbox_select_event.js
devtools/client/framework/test/browser_toolbox_telemetry_close.js
devtools/client/framework/toolbox-host-manager.js
devtools/client/framework/toolbox-hosts.js
devtools/client/framework/toolbox.js
devtools/client/inspector/inspector.js
devtools/client/inspector/test/browser_inspector_highlighter-rulers_03.js
devtools/client/inspector/test/browser_inspector_pane-toggle-01.js
devtools/client/inspector/test/browser_inspector_pane-toggle-04.js
devtools/client/locales/en-US/toolbox.properties
devtools/client/netmonitor/test/browser_net_prefs-reload.js
devtools/client/preferences/devtools-client.js
devtools/client/shadereditor/shadereditor.js
devtools/client/shared/test/browser_html_tooltip_rtl.js
devtools/client/webconsole/test/mochitest/browser_webconsole_split.js
devtools/docs/frontend/telemetry.md
--- a/browser/components/extensions/test/browser/browser_ext_devtools_panel.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_panel.js
@@ -501,18 +501,18 @@ add_task(async function test_devtools_pa
     hasDevToolsAPINamespace,
   } = await extension.awaitMessage("devtools_panel_loaded");
 
   is(panelShownURL, panelLoadedURL, "Got the expected panel URL on the first load");
   ok(hasDevToolsAPINamespace, "The devtools panel has the devtools API on the first load");
 
   const originalToolboxHostType = toolbox.hostType;
 
-  info("Switch the toolbox from docked on bottom to docked on side");
-  toolbox.switchHost("side");
+  info("Switch the toolbox from docked on bottom to docked on right");
+  toolbox.switchHost("right");
 
   info("Wait for the panel to emit hide, show and load messages once docked on side");
   await extension.awaitMessage("devtools_panel_hidden");
   const dockedOnSideShownURL = await extension.awaitMessage("devtools_panel_shown");
 
   is(dockedOnSideShownURL, panelShownURL,
      "Got the expected panel url once the panel shown event has been emitted on toolbox host changed");
 
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
@@ -46,17 +46,17 @@ var DevTools = {
         Services.prefs.clearUserPref("devtools.toolbox.footer.height");
         await gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "bottom");
         await new Promise(resolve => setTimeout(resolve, 1000));
       },
     },
     sideToolbox: {
       selectors: [selectToolbox],
       async applyConfig() {
-        await gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "side");
+        await gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "right");
         await new Promise(resolve => setTimeout(resolve, 500));
       },
     },
     undockedToolbox: {
       selectors: [selectToolbox],
       windowType: "devtools:toolbox",
       async applyConfig() {
         await gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "window");
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -174,17 +174,17 @@ var DebuggerView = {
   },
 
   /**
    * Destroys the UI for all the displayed panes.
    */
   _destroyPanes: function () {
     dumpn("Destroying the DebuggerView panes");
 
-    if (gHostType != "side") {
+    if (gHostType != "right" && gHostType != "left") {
       Prefs.workersAndSourcesWidth = this._workersAndSourcesPane.getAttribute("width");
       Prefs.instrumentsWidth = this._instrumentsPane.getAttribute("width");
     }
 
     this._workersAndSourcesPane = null;
     this._instrumentsPane = null;
     this._instrumentsPaneToggleButton = null;
   },
@@ -698,17 +698,17 @@ var DebuggerView = {
       this.controller.dispatch(actions.fetchEventListeners());
     }
   },
 
   /**
    * Handles a host change event issued by the parent toolbox.
    *
    * @param string aType
-   *        The host type, either "bottom", "side" or "window".
+   *        The host type, either "bottom", "left", "right" or "window".
    */
   handleHostChanged: function (hostType) {
     this._hostType = hostType;
     this.updateLayoutMode();
   },
 
   /**
    * Resize handler for this container's window.
@@ -718,17 +718,19 @@ var DebuggerView = {
     setNamedTimeout(
       "resize-events", RESIZE_REFRESH_RATE, () => this.updateLayoutMode());
   },
 
   /**
    * Set the layout to "vertical" or "horizontal" depending on the host type.
    */
   updateLayoutMode: function () {
-    if (this._isSmallWindowHost() || this._hostType == "side") {
+    if (this._isSmallWindowHost() ||
+        this._hostType == "left" ||
+        this._hostType == "right") {
       this._setLayoutMode("vertical");
     } else {
       this._setLayoutMode("horizontal");
     }
   },
 
   /**
    * Check if the current host is in window mode and is
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-layout-changes.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-layout-changes.js
@@ -11,17 +11,17 @@ var gDefaultHostType = Services.prefs.ge
 
 add_task(async function() {
   // test is too slow on some platforms due to the number of test cases
   const dbg = await initDebugger("doc-iframes.html");
 
   const layouts = [
     ["vertical", "window:small"],
     ["horizontal", "bottom"],
-    ["vertical", "side"],
+    ["vertical", "right"],
     ["horizontal", "window:big"]
   ];
 
   for (const layout of layouts) {
     const [orientation, host] = layout;
     await testLayout(dbg, orientation, host);
   }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_host-layout.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_host-layout.js
@@ -12,22 +12,22 @@
 
 var gDefaultHostType = Services.prefs.getCharPref("devtools.toolbox.host");
 
 function test() {
   // test is too slow on some platforms due to the number of test cases
   requestLongerTimeout(3);
 
   (async function() {
-    await testHosts(["bottom", "side", "window:big"], ["horizontal", "vertical", "horizontal"]);
-    await testHosts(["side", "bottom", "side"], ["vertical", "horizontal", "vertical"]);
-    await testHosts(["bottom", "side", "bottom"], ["horizontal", "vertical", "horizontal"]);
-    await testHosts(["side", "window:big", "side"], ["vertical", "horizontal", "vertical"]);
-    await testHosts(["window:big", "side", "window:big"], ["horizontal", "vertical", "horizontal"]);
-    await testHosts(["window:small", "bottom", "side"], ["vertical", "horizontal", "vertical"]);
+    await testHosts(["bottom", "right", "window:big"], ["horizontal", "vertical", "horizontal"]);
+    await testHosts(["right", "bottom", "right"], ["vertical", "horizontal", "vertical"]);
+    await testHosts(["bottom", "right", "bottom"], ["horizontal", "vertical", "horizontal"]);
+    await testHosts(["right", "window:big", "right"], ["vertical", "horizontal", "vertical"]);
+    await testHosts(["window:big", "right", "window:big"], ["horizontal", "vertical", "horizontal"]);
+    await testHosts(["window:small", "bottom", "right"], ["vertical", "horizontal", "vertical"]);
     await testHosts(["window:small", "window:big", "window:small"], ["vertical", "horizontal", "vertical"]);
     finish();
   })();
 }
 
 async function testHosts(aHostTypes, aLayoutTypes) {
   let [firstHost, secondHost, thirdHost] = aHostTypes;
   let [firstLayout, secondLayout, thirdLayout] = aLayoutTypes;
--- a/devtools/client/framework/devtools.js
+++ b/devtools/client/framework/devtools.js
@@ -436,17 +436,17 @@ DevTools.prototype = {
    * If |hostType| is specified then the toolbox will be displayed using the
    * specified HostType.
    *
    * @param {Target} target
    *         The target the toolbox will debug
    * @param {string} toolId
    *        The id of the tool to show
    * @param {Toolbox.HostType} hostType
-   *        The type of host (bottom, window, side)
+   *        The type of host (bottom, window, left, right)
    * @param {object} hostOptions
    *        Options for host specifically
    * @param {Number} startTime
    *        Optional, indicates the time at which the user event related to this toolbox
    *        opening started. This is a `Cu.now()` timing.
    *
    * @return {Toolbox} toolbox
    *        The toolbox that was opened
--- a/devtools/client/framework/test/browser_keybindings_02.js
+++ b/devtools/client/framework/test/browser_keybindings_02.js
@@ -19,18 +19,18 @@ function getZoomValue() {
 }
 
 add_task(async function() {
   info("Create a test tab and open the toolbox");
   const tab = await addTab(URL);
   const target = TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, "webconsole");
 
-  const {SIDE, BOTTOM} = Toolbox.HostType;
-  for (const type of [SIDE, BOTTOM, SIDE]) {
+  const {RIGHT, BOTTOM} = Toolbox.HostType;
+  for (const type of [RIGHT, BOTTOM, RIGHT]) {
     info("Switch to host type " + type);
     await toolbox.switchHost(type);
 
     info("Try to use the toolbox shortcuts");
     await checkKeyBindings(toolbox);
   }
 
   Services.prefs.clearUserPref("devtools.toolbox.zoomValue");
--- a/devtools/client/framework/test/browser_keybindings_03.js
+++ b/devtools/client/framework/test/browser_keybindings_03.js
@@ -18,30 +18,30 @@ const L10N = new LocalizationHelper("dev
 add_task(async function() {
   info("Create a test tab and open the toolbox");
   const tab = await addTab(URL);
   const target = TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, "webconsole");
 
   const shortcut = L10N.getStr("toolbox.toggleHost.key");
 
-  const {SIDE, BOTTOM, WINDOW} = Toolbox.HostType;
-  checkHostType(toolbox, BOTTOM, SIDE);
+  const {RIGHT, BOTTOM, WINDOW} = Toolbox.HostType;
+  checkHostType(toolbox, BOTTOM, RIGHT);
 
-  info("Switching from bottom to side");
+  info("Switching from bottom to right");
   let onHostChanged = toolbox.once("host-changed");
   synthesizeKeyShortcut(shortcut, toolbox.win);
   await onHostChanged;
-  checkHostType(toolbox, SIDE, BOTTOM);
+  checkHostType(toolbox, RIGHT, BOTTOM);
 
-  info("Switching from side to bottom");
+  info("Switching from right to bottom");
   onHostChanged = toolbox.once("host-changed");
   synthesizeKeyShortcut(shortcut, toolbox.win);
   await onHostChanged;
-  checkHostType(toolbox, BOTTOM, SIDE);
+  checkHostType(toolbox, BOTTOM, RIGHT);
 
   info("Switching to window");
   await toolbox.switchHost(WINDOW);
   checkHostType(toolbox, WINDOW, BOTTOM);
 
   info("Switching from window to bottom");
   onHostChanged = toolbox.once("host-changed");
   synthesizeKeyShortcut(shortcut, toolbox.win);
--- a/devtools/client/framework/test/browser_toolbox_hosts.js
+++ b/devtools/client/framework/test/browser_toolbox_hosts.js
@@ -1,29 +1,30 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 var {Toolbox} = require("devtools/client/framework/toolbox");
-var {SIDE, BOTTOM, WINDOW} = Toolbox.HostType;
+var {LEFT, RIGHT, BOTTOM, WINDOW} = Toolbox.HostType;
 var toolbox, target;
 
 const URL = "data:text/html;charset=utf8,test for opening toolbox in different hosts";
 
 add_task(async function runTest() {
   info("Create a test tab and open the toolbox");
   const tab = await addTab(URL);
   target = TargetFactory.forTab(tab);
   toolbox = await gDevTools.showToolbox(target, "webconsole");
 
   await testBottomHost();
-  await testSidebarHost();
+  await testLeftHost();
+  await testRightHost();
   await testWindowHost();
   await testToolSelect();
   await testDestroy();
   await testRememberHost();
   await testPreviousHost();
 
   await toolbox.destroy();
 
@@ -37,19 +38,34 @@ function testBottomHost() {
   // test UI presence
   const nbox = gBrowser.getNotificationBox();
   const iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   ok(iframe, "toolbox bottom iframe exists");
 
   checkToolboxLoaded(iframe);
 }
 
-async function testSidebarHost() {
-  await toolbox.switchHost(SIDE);
-  checkHostType(toolbox, SIDE);
+async function testLeftHost() {
+  await toolbox.switchHost(LEFT);
+  checkHostType(toolbox, LEFT);
+
+  // test UI presence
+  const nbox = gBrowser.getNotificationBox();
+  const bottom = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
+  ok(!bottom, "toolbox bottom iframe doesn't exist");
+
+  const iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
+  ok(iframe, "toolbox side iframe exists");
+
+  checkToolboxLoaded(iframe);
+}
+
+async function testRightHost() {
+  await toolbox.switchHost(RIGHT);
+  checkHostType(toolbox, RIGHT);
 
   // test UI presence
   const nbox = gBrowser.getNotificationBox();
   const bottom = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   ok(!bottom, "toolbox bottom iframe doesn't exist");
 
   const iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   ok(iframe, "toolbox side iframe exists");
@@ -90,50 +106,54 @@ function testRememberHost() {
   const win = Services.wm.getMostRecentWindow("devtools:toolbox");
   ok(win, "toolbox separate window exists");
 }
 
 async function testPreviousHost() {
   // last host was the window - make sure it's the same when re-opening
   is(toolbox.hostType, WINDOW, "host remembered");
 
-  info("Switching to side");
-  await toolbox.switchHost(SIDE);
-  checkHostType(toolbox, SIDE, WINDOW);
+  info("Switching to left");
+  await toolbox.switchHost(LEFT);
+  checkHostType(toolbox, LEFT, WINDOW);
+
+  info("Switching to right");
+  await toolbox.switchHost(RIGHT);
+  checkHostType(toolbox, RIGHT, LEFT);
 
   info("Switching to bottom");
   await toolbox.switchHost(BOTTOM);
-  checkHostType(toolbox, BOTTOM, SIDE);
+  checkHostType(toolbox, BOTTOM, RIGHT);
 
-  info("Switching from bottom to side");
+  info("Switching from bottom to right");
   await toolbox.switchToPreviousHost();
-  checkHostType(toolbox, SIDE, BOTTOM);
+  checkHostType(toolbox, RIGHT, BOTTOM);
 
-  info("Switching from side to bottom");
+  info("Switching from right to bottom");
   await toolbox.switchToPreviousHost();
-  checkHostType(toolbox, BOTTOM, SIDE);
+  checkHostType(toolbox, BOTTOM, RIGHT);
 
   info("Switching to window");
   await toolbox.switchHost(WINDOW);
   checkHostType(toolbox, WINDOW, BOTTOM);
 
   info("Switching from window to bottom");
   await toolbox.switchToPreviousHost();
   checkHostType(toolbox, BOTTOM, WINDOW);
 
   info("Forcing the previous host to match the current (bottom)");
   Services.prefs.setCharPref("devtools.toolbox.previousHost", BOTTOM);
 
-  info("Switching from bottom to side (since previous=current=bottom");
+  info("Switching from bottom to right (since previous=current=bottom");
   await toolbox.switchToPreviousHost();
-  checkHostType(toolbox, SIDE, BOTTOM);
+  checkHostType(toolbox, RIGHT, BOTTOM);
 
-  info("Forcing the previous host to match the current (side)");
-  Services.prefs.setCharPref("devtools.toolbox.previousHost", SIDE);
-  info("Switching from side to bottom (since previous=current=side");
+  info("Forcing the previous host to match the current (right)");
+  Services.prefs.setCharPref("devtools.toolbox.previousHost", RIGHT);
+  info("Switching from right to bottom (since previous=current=side");
   await toolbox.switchToPreviousHost();
-  checkHostType(toolbox, BOTTOM, SIDE);
+  checkHostType(toolbox, BOTTOM, RIGHT);
 }
 
 function checkToolboxLoaded(iframe) {
   const tabs = iframe.contentDocument.querySelector(".toolbox-tabs");
   ok(tabs, "toolbox UI has been loaded into iframe");
 }
--- a/devtools/client/framework/test/browser_toolbox_hosts_size.js
+++ b/devtools/client/framework/test/browser_toolbox_hosts_size.js
@@ -22,17 +22,17 @@ add_task(async function() {
   const toolbox = await gDevTools.showToolbox(TargetFactory.forTab(tab));
 
   is(nbox.clientHeight, nboxHeight, "Opening the toolbox hasn't changed the height of the nbox");
   is(nbox.clientWidth, nboxWidth, "Opening the toolbox hasn't changed the width of the nbox");
 
   let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   is(iframe.clientHeight, nboxHeight - 25, "The iframe fits within the available space");
 
-  await toolbox.switchHost(Toolbox.HostType.SIDE);
+  await toolbox.switchHost(Toolbox.HostType.RIGHT);
   iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   iframe.style.minWidth = "1px"; // Disable the min width set in css
   is(iframe.clientWidth, nboxWidth - 25, "The iframe fits within the available space");
 
   await cleanup(toolbox);
 });
 
 add_task(async function() {
@@ -47,17 +47,17 @@ add_task(async function() {
   const toolbox = await gDevTools.showToolbox(TargetFactory.forTab(tab));
 
   is(nbox.clientHeight, nboxHeight, "Opening the toolbox hasn't changed the height of the nbox");
   is(nbox.clientWidth, nboxWidth, "Opening the toolbox hasn't changed the width of the nbox");
 
   let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   is(iframe.clientHeight, 100, "The iframe is resized properly");
 
-  await toolbox.switchHost(Toolbox.HostType.SIDE);
+  await toolbox.switchHost(Toolbox.HostType.RIGHT);
   iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   iframe.style.minWidth = "1px"; // Disable the min width set in css
   is(iframe.clientWidth, 100, "The iframe is resized properly");
 
   await cleanup(toolbox);
 });
 
 async function cleanup(toolbox) {
--- a/devtools/client/framework/test/browser_toolbox_hosts_telemetry.js
+++ b/devtools/client/framework/test/browser_toolbox_hosts_telemetry.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* import-globals-from head.js */
 
 "use strict";
 
 const {Toolbox} = require("devtools/client/framework/toolbox");
-const {SIDE, BOTTOM, WINDOW} = Toolbox.HostType;
+const {LEFT, RIGHT, BOTTOM, WINDOW} = Toolbox.HostType;
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_hosts_telemetry.js";
 
 add_task(async function() {
   startTelemetry();
 
   info("Create a test tab and open the toolbox");
   const tab = await addTab(URL);
@@ -19,23 +19,27 @@ add_task(async function() {
   const toolbox = await gDevTools.showToolbox(target, "webconsole");
 
   await changeToolboxHost(toolbox);
   await checkResults();
 });
 
 async function changeToolboxHost(toolbox) {
   info("Switch toolbox host");
-  await toolbox.switchHost(SIDE);
+  await toolbox.switchHost(RIGHT);
   await toolbox.switchHost(WINDOW);
   await toolbox.switchHost(BOTTOM);
-  await toolbox.switchHost(SIDE);
+  await toolbox.switchHost(LEFT);
+  await toolbox.switchHost(RIGHT);
   await toolbox.switchHost(WINDOW);
   await toolbox.switchHost(BOTTOM);
+  await toolbox.switchHost(LEFT);
+  await toolbox.switchHost(RIGHT);
 }
 
 function checkResults() {
   // Check for:
   //   - 3 "bottom" entries.
-  //   - 2 "side" entries.
+  //   - 2 "left" entries.
+  //   - 3 "right" entries.
   //   - 2 "window" entries.
-  checkTelemetry("DEVTOOLS_TOOLBOX_HOST", "", [3, 2, 2, 0, 0, 0, 0, 0, 0, 0], "array");
+  checkTelemetry("DEVTOOLS_TOOLBOX_HOST", "", [3, 3, 2, 0, 2, 0, 0, 0, 0, 0], "array");
 }
--- a/devtools/client/framework/test/browser_toolbox_select_event.js
+++ b/devtools/client/framework/test/browser_toolbox_select_event.js
@@ -20,17 +20,17 @@ add_task(async function() {
   await testSelectEvent("webconsole");
   await testSelectEvent("styleeditor");
 
   await testToolSelectEvent("inspector");
   await testToolSelectEvent("webconsole");
   await testToolSelectEvent("styleeditor");
   await toolbox.destroy();
 
-  toolbox = await openToolboxForTab(tab, "webconsole", "side");
+  toolbox = await openToolboxForTab(tab, "webconsole", "right");
   await testSelectEvent("inspector");
   await testSelectEvent("webconsole");
   await testSelectEvent("styleeditor");
   await testSelectEvent("inspector");
   await testSelectEvent("webconsole");
   await testSelectEvent("styleeditor");
   await toolbox.destroy();
 
--- a/devtools/client/framework/test/browser_toolbox_telemetry_close.js
+++ b/devtools/client/framework/test/browser_toolbox_telemetry_close.js
@@ -2,26 +2,26 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { Toolbox } = require("devtools/client/framework/toolbox");
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
 const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
-const { SIDE, BOTTOM } = Toolbox.HostType;
+const { RIGHT, BOTTOM } = Toolbox.HostType;
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
-      host: "side",
+      host: "right",
       width: "1440"
     }
   },
   {
     timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
@@ -36,17 +36,17 @@ const DATA = [
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
   const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
-  await openAndCloseToolbox("webconsole", SIDE);
+  await openAndCloseToolbox("webconsole", RIGHT);
   await openAndCloseToolbox("webconsole", BOTTOM);
 
   checkResults();
 });
 
 async function openAndCloseToolbox(toolId, host) {
   const tab = await addTab(URL);
   const target = TargetFactory.forTab(tab);
--- a/devtools/client/framework/toolbox-host-manager.js
+++ b/devtools/client/framework/toolbox-host-manager.js
@@ -153,20 +153,20 @@ ToolboxHostManager.prototype = {
 
   async switchHost(hostType) {
     if (hostType == "previous") {
       // Switch to the last used host for the toolbox UI.
       // This is determined by the devtools.toolbox.previousHost pref.
       hostType = Services.prefs.getCharPref(PREVIOUS_HOST);
 
       // Handle the case where the previous host happens to match the current
-      // host. If so, switch to bottom if it's not already used, and side if not.
+      // host. If so, switch to bottom if it's not already used, and right side if not.
       if (hostType === this.hostType) {
         if (hostType === Toolbox.HostType.BOTTOM) {
-          hostType = Toolbox.HostType.SIDE;
+          hostType = Toolbox.HostType.RIGHT;
         } else {
           hostType = Toolbox.HostType.BOTTOM;
         }
       }
     }
     const iframe = this.host.frame;
     const newHost = this.createHost(hostType);
     const newIframe = await newHost.create();
--- a/devtools/client/framework/toolbox-hosts.js
+++ b/devtools/client/framework/toolbox-hosts.js
@@ -25,23 +25,16 @@ const MIN_PAGE_SIZE = 25;
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
  *
  * create() - create the UI and emit a 'ready' event when the UI is ready to use
  * destroy() - destroy the host's UI
  */
 
-exports.Hosts = {
-  "bottom": BottomHost,
-  "side": SidebarHost,
-  "window": WindowHost,
-  "custom": CustomHost
-};
-
 /**
  * Host object for the dock on the bottom of the browser
  */
 function BottomHost(hostTab) {
   this.hostTab = hostTab;
 
   EventEmitter.decorate(this);
 }
@@ -123,98 +116,119 @@ BottomHost.prototype = {
       this._splitter = null;
     }
 
     return promise.resolve(null);
   }
 };
 
 /**
- * Host object for the in-browser sidebar
+ * Base Host object for the in-browser sidebar
  */
-function SidebarHost(hostTab) {
-  this.hostTab = hostTab;
+class SidebarHost {
+  constructor(hostTab, hostType) {
+    this.hostTab = hostTab;
+    this.type = hostType;
+    this.widthPref = "devtools.toolbox.sidebar.width";
 
-  EventEmitter.decorate(this);
-}
-
-SidebarHost.prototype = {
-  type: "side",
-
-  widthPref: "devtools.toolbox.sidebar.width",
+    EventEmitter.decorate(this);
+  }
 
   /**
    * Create a box in the sidebar of the host tab.
    */
-  create: async function() {
+  async create() {
     await gDevToolsBrowser.loadBrowserStyleSheet(this.hostTab.ownerGlobal);
-
     const gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     const ownerDocument = gBrowser.ownerDocument;
+    this._browser = gBrowser.getBrowserContainer(this.hostTab.linkedBrowser);
     this._sidebar = gBrowser.getSidebarContainer(this.hostTab.linkedBrowser);
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-side-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
     this.frame.flex = 1; // Required to be able to shrink when the window shrinks
     this.frame.className = "devtools-toolbox-side-iframe";
 
     this.frame.width = Math.min(
       Services.prefs.getIntPref(this.widthPref),
       this._sidebar.clientWidth - MIN_PAGE_SIZE
     );
 
-    this._sidebar.appendChild(this._splitter);
-    this._sidebar.appendChild(this.frame);
+    if (this.hostType == "right") {
+      this._sidebar.appendChild(this._splitter);
+      this._sidebar.appendChild(this.frame);
+    } else {
+      this._sidebar.insertBefore(this.frame, this._browser);
+      this._sidebar.insertBefore(this._splitter, this._browser);
+    }
 
     this.frame.tooltip = "aHTMLTooltip";
     this.frame.setAttribute("src", "about:blank");
 
     const frame = await new Promise(resolve => {
       const domHelper = new DOMHelpers(this.frame.contentWindow);
       const frameLoad = () => {
         this.emit("ready", this.frame);
         resolve(this.frame);
       };
       domHelper.onceDOMReady(frameLoad);
       focusTab(this.hostTab);
     });
 
     return frame;
-  },
+  }
 
   /**
    * Raise the host.
    */
-  raise: function() {
+  raise() {
     focusTab(this.hostTab);
-  },
+  }
 
   /**
    * Set the toolbox title.
    * Nothing to do for this host type.
    */
-  setTitle: function() {},
+  setTitle() {}
 
   /**
    * Destroy the sidebar.
    */
-  destroy: function() {
+  destroy() {
     if (!this._destroyed) {
       this._destroyed = true;
 
       Services.prefs.setIntPref(this.widthPref, this.frame.width);
       this._sidebar.removeChild(this._splitter);
       this._sidebar.removeChild(this.frame);
     }
 
     return promise.resolve(null);
   }
-};
+}
+
+/**
+ * Host object for the in-browser left sidebar
+ */
+class LeftHost extends SidebarHost {
+  constructor(hostTab) {
+    super(hostTab, "left");
+  }
+}
+
+/**
+ * Host object for the in-browser right sidebar
+ */
+class RightHost extends SidebarHost {
+  constructor(hostTab) {
+    super(hostTab, "right");
+  }
+}
 
 /**
  * Host object for the toolbox in a separate window
  */
 function WindowHost() {
   this._boundUnload = this._boundUnload.bind(this);
 
   EventEmitter.decorate(this);
@@ -364,8 +378,17 @@ CustomHost.prototype = {
 /**
  *  Switch to the given tab in a browser and focus the browser window
  */
 function focusTab(tab) {
   const browserWindow = tab.ownerDocument.defaultView;
   browserWindow.focus();
   browserWindow.gBrowser.selectedTab = tab;
 }
+
+exports.Hosts = {
+  "bottom": BottomHost,
+  "left": LeftHost,
+  "right": RightHost,
+  "window": WindowHost,
+  "custom": CustomHost
+};
+
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -206,17 +206,18 @@ function Toolbox(target, selectedTool, h
 exports.Toolbox = Toolbox;
 
 /**
  * The toolbox can be 'hosted' either embedded in a browser window
  * or in a separate window.
  */
 Toolbox.HostType = {
   BOTTOM: "bottom",
-  SIDE: "side",
+  RIGHT: "right",
+  LEFT: "left",
   WINDOW: "window",
   CUSTOM: "custom"
 };
 
 Toolbox.prototype = {
   _URL: "about:devtools-toolbox",
 
   _prefs: {
@@ -686,28 +687,30 @@ Toolbox.prototype = {
     this._sourceMapURLService = new SourceMapURLService(this, sourceMaps);
     return this._sourceMapURLService;
   },
 
   // Return HostType id for telemetry
   _getTelemetryHostId: function() {
     switch (this.hostType) {
       case Toolbox.HostType.BOTTOM: return 0;
-      case Toolbox.HostType.SIDE: return 1;
+      case Toolbox.HostType.RIGHT: return 1;
       case Toolbox.HostType.WINDOW: return 2;
       case Toolbox.HostType.CUSTOM: return 3;
+      case Toolbox.HostType.LEFT: return 4;
       default: return 9;
     }
   },
 
   // Return HostType string for telemetry
   _getTelemetryHostString: function() {
     switch (this.hostType) {
       case Toolbox.HostType.BOTTOM: return "bottom";
-      case Toolbox.HostType.SIDE: return "side";
+      case Toolbox.HostType.LEFT: return "left";
+      case Toolbox.HostType.RIGHT: return "right";
       case Toolbox.HostType.WINDOW: return "window";
       case Toolbox.HostType.CUSTOM: return "other";
       default: return "bottom";
     }
   },
 
   _pingTelemetry: function() {
     this.telemetry.toolOpened("toolbox");
@@ -1069,17 +1072,18 @@ Toolbox.prototype = {
     this.component.setCanCloseToolbox(this.hostType !== Toolbox.HostType.WINDOW);
 
     const sideEnabled = Services.prefs.getBoolPref(this._prefs.SIDE_ENABLED);
 
     const hostTypes = [];
     for (const type in Toolbox.HostType) {
       const position = Toolbox.HostType[type];
       if (position == Toolbox.HostType.CUSTOM ||
-          (!sideEnabled && position == Toolbox.HostType.SIDE)) {
+          (!sideEnabled &&
+            (position == Toolbox.HostType.LEFT || position == Toolbox.HostType.RIGHT))) {
         continue;
       }
 
       hostTypes.push({
         position,
         switchHost: this.switchHost.bind(this, position)
       });
     }
@@ -1243,17 +1247,18 @@ Toolbox.prototype = {
    * window. When devtools is free floating, then the target window should not
    * pop in front of the viewer when the picker is clicked.
    *
    * Note: Toggle picker can be overwritten by panel other than the inspector to
    * allow for custom picker behaviour.
    */
   _onPickerClick: function() {
     const focus = this.hostType === Toolbox.HostType.BOTTOM ||
-                this.hostType === Toolbox.HostType.SIDE;
+                  this.hostType === Toolbox.HostType.LEFT ||
+                  this.hostType === Toolbox.HostType.RIGHT;
     const currentPanel = this.getCurrentPanel();
     if (currentPanel.togglePicker) {
       currentPanel.togglePicker(focus);
     } else {
       this.highlighterUtils.togglePicker(focus);
     }
   },
 
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -504,17 +504,19 @@ Inspector.prototype = {
    * @return {Boolean} true if the inspector should be in landscape mode.
    */
   useLandscapeMode: function() {
     if (!this.panelDoc) {
       return true;
     }
 
     const { clientWidth } = this.panelDoc.getElementById("inspector-splitter-box");
-    return this.is3PaneModeEnabled && this.toolbox.hostType == Toolbox.HostType.SIDE ?
+    return this.is3PaneModeEnabled &&
+           (this.toolbox.hostType == Toolbox.HostType.LEFT ||
+            this.toolbox.hostType == Toolbox.HostType.RIGHT) ?
       clientWidth > SIDE_PORTAIT_MODE_WIDTH_THRESHOLD :
       clientWidth > PORTRAIT_MODE_WIDTH_THRESHOLD;
   },
 
   /**
    * Build Splitter located between the main and side area of
    * the Inspector panel.
    */
--- a/devtools/client/inspector/test/browser_inspector_highlighter-rulers_03.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-rulers_03.js
@@ -53,10 +53,10 @@ async function hasRightLabelsContent(hig
   const windowText = windowHeight + "px \u00D7 " + windowWidth + "px";
 
   is(dimensionText, windowText, "Dimension text was created successfully");
 }
 
 async function resizeInspector(highlighterFront, inspector, testActor) {
   info("Docking the toolbox to the side of the browser to change the window size");
   const toolbox = inspector.toolbox;
-  await toolbox.switchHost(Toolbox.HostType.SIDE);
+  await toolbox.switchHost(Toolbox.HostType.RIGHT);
 }
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-01.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-01.js
@@ -15,15 +15,15 @@ add_task(async function() {
   const { inspector, toolbox } = await openInspectorForURL("about:blank", "bottom");
 
   const button = inspector.panelDoc.querySelector(".sidebar-toggle");
   ok(button, "The toggle button exists in the DOM");
   ok(button.getAttribute("title"), "The title tooltip has initial state");
   ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state");
   ok(!!button.getClientRects().length, "The button is visible");
 
-  info("Switch the host to side type");
-  await toolbox.switchHost("side");
+  info("Switch the host to the right");
+  await toolbox.switchHost("right");
 
   ok(!!button.getClientRects().length, "The button is still visible");
   ok(button.classList.contains("pane-collapsed"),
     "The button is still in collapsed state");
 });
--- a/devtools/client/inspector/test/browser_inspector_pane-toggle-04.js
+++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-04.js
@@ -9,18 +9,18 @@
 
 add_task(async function() {
   info("Switch to 2 pane inspector to test the 3 pane toggle button behavior");
   await pushPref("devtools.inspector.three-pane-enabled", false);
 
   const { inspector, toolbox } = await openInspectorForURL("about:blank");
   const { panelDoc: doc } = inspector;
 
-  info("Switch the host to side type");
-  await toolbox.switchHost("side");
+  info("Switch the host to the right");
+  await toolbox.switchHost("right");
 
   const button = doc.querySelector(".sidebar-toggle");
   const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth;
 
   info("Click on the toggle button to toggle ON 3 pane inspector");
   let onRuleViewAdded = inspector.once("ruleview-added");
   EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView);
   await onRuleViewAdded;
--- a/devtools/client/locales/en-US/toolbox.properties
+++ b/devtools/client/locales/en-US/toolbox.properties
@@ -121,17 +121,18 @@ toolbox.showFrames.key=Alt+Down
 # LOCALIZATION NOTE (toolbox.meatballMenu.button.tooltip): This is the tooltip
 # for the "..." button on the developer tools toolbox.
 toolbox.meatballMenu.button.tooltip=Customize Developer Tools and get help
 
 # LOCALIZATION NOTE (toolbox.meatballMenu.dock.*.label): These labels are shown
 # in the "..." menu in the toolbox and represent the different arrangements for
 # docking (or undocking) the developer tools toolbox.
 toolbox.meatballMenu.dock.bottom.label=Dock to bottom
-toolbox.meatballMenu.dock.side.label=Dock to side
+toolbox.meatballMenu.dock.left.label=Dock to left
+toolbox.meatballMenu.dock.right.label=Dock to right
 toolbox.meatballMenu.dock.separateWindow.label=Separate window
 
 # LOCALIZATION NOTE (toolbox.meatballMenu.{splitconsole,hideconsole}.label):
 # These are the labels in the "..." menu in the toolbox for toggling the split
 # console window.
 # The keyboard shortcut will be shown to the side of the label.
 toolbox.meatballMenu.splitconsole.label=Show split console
 toolbox.meatballMenu.hideconsole.label=Hide split console
--- a/devtools/client/netmonitor/test/browser_net_prefs-reload.js
+++ b/devtools/client/netmonitor/test/browser_net_prefs-reload.js
@@ -208,20 +208,20 @@ add_task(async function() {
 
     // Revalidate.
     validateFirstPrefValues(true);
   }
 
   async function testSide() {
     await restartNetMonitorAndSetupEnv();
 
-    info("Moving toolbox to the side...");
+    info("Moving toolbox to the right...");
 
-    await monitor.toolbox.switchHost("side");
-    info("Testing prefs reload for a side host.");
+    await monitor.toolbox.switchHost("right");
+    info("Testing prefs reload for a right host.");
     storeFirstPrefValues();
 
     // Validate and modify frontend while toolbox is on the side.
     validateFirstPrefValues(false);
     modifyFrontend(false);
 
     await restartNetMonitorAndSetupEnv();
 
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -4,17 +4,17 @@
 
 // Enable DevTools WebIDE by default
 pref("devtools.webide.enabled", true);
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
-pref("devtools.toolbox.previousHost", "side");
+pref("devtools.toolbox.previousHost", "right");
 pref("devtools.toolbox.selectedTool", "webconsole");
 pref("devtools.toolbox.sideEnabled", true);
 pref("devtools.toolbox.zoomValue", "1");
 pref("devtools.toolbox.splitconsoleEnabled", false);
 pref("devtools.toolbox.splitconsoleHeight", 100);
 pref("devtools.toolbox.tabsOrder", "");
 
 // Toolbox Button preferences
--- a/devtools/client/shadereditor/shadereditor.js
+++ b/devtools/client/shadereditor/shadereditor.js
@@ -121,17 +121,17 @@ var EventsHandler = {
   _onReloadCommand() {
     gFront.setup({ reload: true });
   },
 
   /**
    * Handles a host change event on the parent toolbox.
    */
   _onHostChanged: function() {
-    if (gToolbox.hostType == "side") {
+    if (gToolbox.hostType == "right" || gToolbox.hostType == "left") {
       $("#shaders-pane").removeAttribute("height");
     }
   },
 
   _onTabWillNavigate: function({isFrameSwitching}) {
     // Make sure the backend is prepared to handle WebGL contexts.
     if (!isFrameSwitching) {
       gFront.setup({ reload: false });
@@ -260,17 +260,18 @@ var ShadersListView = extend(WidgetMetho
 
     // Make sure there's always a selected item available.
     if (!this.selectedItem) {
       this.selectedIndex = 0;
     }
 
     // Prevent this container from growing indefinitely in height when the
     // toolbox is docked to the side.
-    if (gToolbox.hostType == "side" && this.itemCount == SHADERS_AUTOGROW_ITEMS) {
+    if ((gToolbox.hostType == "left" || gToolbox.hostType == "right") &&
+        this.itemCount == SHADERS_AUTOGROW_ITEMS) {
       this._pane.setAttribute("height", this._pane.getBoundingClientRect().height);
     }
   },
 
   /**
    * Returns whether a program was already added to this programs container.
    *
    * @param object programActor
--- a/devtools/client/shared/test/browser_html_tooltip_rtl.js
+++ b/devtools/client/shared/test/browser_html_tooltip_rtl.js
@@ -17,17 +17,17 @@ loadHelperScript("helper_html_tooltip.js
 
 const TOOLBOX_WIDTH = 500;
 const TOOLTIP_WIDTH = 150;
 const TOOLTIP_HEIGHT = 30;
 
 add_task(async function() {
   await pushPref("devtools.toolbox.sidebar.width", TOOLBOX_WIDTH);
 
-  const [,, doc] = await createHost("side", TEST_URI);
+  const [,, doc] = await createHost("right", TEST_URI);
 
   info("Test a tooltip is not closed when clicking inside itself");
 
   const tooltip = new HTMLTooltip(doc, {useXulWrapper: false});
   const div = doc.createElementNS(HTML_NS, "div");
   div.textContent = "tooltip";
   div.style.cssText = "box-sizing: border-box; border: 1px solid black";
   tooltip.setContent(div, {width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT});
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_split.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_split.js
@@ -20,18 +20,18 @@ add_task(async function() {
   await addTab(TEST_URI);
   await testConsoleLoadOnDifferentPanel();
   await testKeyboardShortcuts();
   await checkAllTools();
 
   info("Testing host types");
   checkHostType(Toolbox.HostType.BOTTOM);
   await checkToolboxUI();
-  await toolbox.switchHost(Toolbox.HostType.SIDE);
-  checkHostType(Toolbox.HostType.SIDE);
+  await toolbox.switchHost(Toolbox.HostType.RIGHT);
+  checkHostType(Toolbox.HostType.RIGHT);
   await checkToolboxUI();
   await toolbox.switchHost(Toolbox.HostType.WINDOW);
 
   // checkHostType, below,  will open the meatball menu to read the "Split
   // console" menu item label. However, if we've just opened a new window then
   // on some platforms when we switch focus to the new window we might end up
   // triggering the auto-close behavior on the menu popup. To avoid that, wait
   // a moment before querying the menu.
--- a/devtools/docs/frontend/telemetry.md
+++ b/devtools/docs/frontend/telemetry.md
@@ -343,17 +343,17 @@ const { SIDE, BOTTOM } = Toolbox.HostTyp
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
-      host: "side",
+      host: "right",
       width: "1440"
     }
   },
   {
     timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",