Bug 1226877 - fixing keyboard navigation around hidden devtools panels/controls. r=bgrins draft
authorYura Zenevich <yzenevich@mozilla.com>
Mon, 11 Jul 2016 13:08:16 -0400
changeset 386326 6743122ba7614273d724c74f99695fe247f308fa
parent 386302 214884d507ee369c1cf14edb26527c4f9a97bf48
child 525082 6c77d6509119988c9bcdcd456fecf417706768c9
push id22672
push useryura.zenevich@gmail.com
push dateMon, 11 Jul 2016 17:08:45 +0000
reviewersbgrins
bugs1226877
milestone50.0a1
Bug 1226877 - fixing keyboard navigation around hidden devtools panels/controls. r=bgrins MozReview-Commit-ID: KJoE2R5fcWG
devtools/client/framework/test/browser_new_activation_workflow.js
devtools/client/framework/toolbox.js
devtools/client/framework/toolbox.xul
devtools/client/netmonitor/netmonitor.css
devtools/client/themes/toolbars.css
--- a/devtools/client/framework/test/browser_new_activation_workflow.js
+++ b/devtools/client/framework/test/browser_new_activation_workflow.js
@@ -26,32 +26,45 @@ function loadWebConsole(aTab) {
     checkToolLoading();
   });
 }
 
 function checkToolLoading() {
   is(toolbox.currentToolId, "webconsole", "The web console is selected");
   ok(toolbox.isReady, "toolbox is ready");
 
+  testVisibility(true);
+
   selectAndCheckById("jsdebugger").then(function () {
+    testVisibility(false);
     selectAndCheckById("styleeditor").then(function () {
+      testVisibility(false);
       testToggle();
     });
   });
 }
 
 function selectAndCheckById(id) {
   let doc = toolbox.frame.contentDocument;
 
   return toolbox.selectTool(id).then(function () {
     let tab = doc.getElementById("toolbox-tab-" + id);
     is(tab.hasAttribute("selected"), true, "The " + id + " tab is selected");
   });
 }
 
+function testVisibility(webconsoleVisible) {
+  ok(toolbox.webconsolePanel.hasAttribute("hidden") !== webconsoleVisible,
+    "Web console has correct visibility");
+  ok(toolbox.doc.getElementById("toolbox-deck").hasAttribute(
+    "hidden") === webconsoleVisible, "Web console has correct visibility");
+  (webconsoleVisible ? is : isnot)(toolbox.doc.activeElement.id,
+    "toolbox-panel-iframe-webconsole", "Web console has correct focus state");
+}
+
 function testToggle() {
   toolbox.once("destroyed", () => {
     // Cannot reuse a target after it's destroyed.
     target = TargetFactory.forTab(gBrowser.selectedTab);
     gDevTools.showToolbox(target, "styleeditor").then(function (aToolbox) {
       toolbox = aToolbox;
       is(toolbox.currentToolId, "styleeditor", "The style editor is selected");
       finishUp();
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -627,26 +627,26 @@ Toolbox.prototype = {
    */
   _refreshConsoleDisplay: function () {
     let deck = this.doc.getElementById("toolbox-deck");
     let webconsolePanel = this.webconsolePanel;
     let splitter = this.doc.getElementById("toolbox-console-splitter");
     let openedConsolePanel = this.currentToolId === "webconsole";
 
     if (openedConsolePanel) {
-      deck.setAttribute("collapsed", "true");
+      deck.setAttribute("hidden", "true");
       splitter.setAttribute("hidden", "true");
-      webconsolePanel.removeAttribute("collapsed");
+      webconsolePanel.removeAttribute("hidden");
     } else {
-      deck.removeAttribute("collapsed");
+      deck.removeAttribute("hidden");
       if (this.splitConsole) {
-        webconsolePanel.removeAttribute("collapsed");
+        webconsolePanel.removeAttribute("hidden");
         splitter.removeAttribute("hidden");
       } else {
-        webconsolePanel.setAttribute("collapsed", "true");
+        webconsolePanel.setAttribute("hidden", "true");
         splitter.setAttribute("hidden", "true");
       }
     }
   },
 
   /**
    * Adds the keys and commands to the Toolbox Window in window mode.
    */
@@ -1410,16 +1410,19 @@ Toolbox.prototype = {
   },
 
   /**
    * Focus split console's input line
    */
   focusConsoleInput: function () {
     let consolePanel = this.getPanel("webconsole");
     if (consolePanel) {
+      if (!this.isSplitConsoleFocused()) {
+        this.focusTool("webconsole");
+      }
       consolePanel.focusInput();
     }
   },
 
   /**
    * If the console is split and we are focusing an element outside
    * of the console, then store the newly focused element, so that
    * it can be restored once the split console closes.
@@ -1462,16 +1465,21 @@ Toolbox.prototype = {
   closeSplitConsole: function () {
     this._splitConsole = false;
     Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false);
     this._refreshConsoleDisplay();
     this.emit("split-console");
 
     if (this._lastFocusedElement) {
       this._lastFocusedElement.focus();
+    } else if (this.doc.activeElement) {
+      // Do not let the focus remain on a hidden frame, move it to the previous
+      // active frame in the deck.
+      Services.focus.moveFocus(this.win, this.doc.activeElement,
+        Services.focus.MOVEFOCUS_BACKWARD, 0);
     }
     return promise.resolve();
   },
 
   /**
    * Toggles the split state of the webconsole.  If the webconsole panel
    * is already selected then this command is ignored.
    *
--- a/devtools/client/framework/toolbox.xul
+++ b/devtools/client/framework/toolbox.xul
@@ -71,13 +71,13 @@
     </toolbar>
     <vbox flex="1" class="theme-body">
       <!-- Set large flex to allow the toolbox-panel-webconsole to have a
            height set to a small value without flexing to fill up extra
            space. There must be a flex on both to ensure that the console
            panel itself is sized properly -->
       <box id="toolbox-deck" flex="1000" minheight="75" />
       <splitter id="toolbox-console-splitter" class="devtools-horizontal-splitter" hidden="true" />
-      <box minheight="75" flex="1" id="toolbox-panel-webconsole" collapsed="true" />
+      <box minheight="75" flex="1" id="toolbox-panel-webconsole" hidden="true" />
     </vbox>
     <tooltip id="aHTMLTooltip" page="true" />
   </vbox>
 </window>
--- a/devtools/client/netmonitor/netmonitor.css
+++ b/devtools/client/netmonitor/netmonitor.css
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #toolbar-labels {
   overflow: hidden;
 }
 
+#details-pane.pane-collapsed,
 #details-pane-toggle[disabled] {
   display: none;
 }
 
 #custom-pane {
   overflow: auto;
 }
 
@@ -31,14 +32,13 @@
   /* workaround for textbox not supporting the @crop attribute */
   text-overflow: ellipsis;
 }
 
 /* Responsive sidebar */
 @media (max-width: 700px) {
   #toolbar-spacer,
   #details-pane-toggle,
-  #details-pane.pane-collapsed,
   .requests-menu-waterfall,
   #requests-menu-network-summary-button > .toolbarbutton-text {
     display: none;
   }
 }
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -823,23 +823,22 @@
   border-bottom-color: var(--theme-splitter-color);
 }
 
 #toolbox-tabs {
   margin: 0;
 }
 
 .toolbox-panel {
-  display: -moz-box;
-  -moz-box-flex: 1;
-  visibility: collapse;
+  display: none;
 }
 
 .toolbox-panel[selected] {
-  visibility: visible;
+  display: -moz-box;
+  -moz-box-flex: 1;
 }
 
 .devtools-tab {
   -moz-appearance: none;
   -moz-binding: url("chrome://global/content/bindings/general.xml#control-item");
   -moz-box-align: center;
   min-width: 32px;
   min-height: 24px;