Bug 1327971 - Add support to show list of frames on key-press of "Alt+Down" on the "iframes" button. r=Honza
authorabhinav <abhinav.koppula@gmail.com>
Sun, 10 Sep 2017 15:41:35 +0530
changeset 430044 cb9cbed526b99b5256d62095e14e452683ff65d4
parent 430043 2ac5c1345f1353b685a8e18abe31134e0c0712cf
child 430045 3051cf9176df1af2095f353ef05ec99417022657
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1327971
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1327971 - Add support to show list of frames on key-press of "Alt+Down" on the "iframes" button. r=Honza MozReview-Commit-ID: EZFG4br17mC
devtools/client/framework/components/toolbox-toolbar.js
devtools/client/framework/test/browser_toolbox_window_title_frame_select.js
devtools/client/framework/toolbox.js
devtools/client/locales/en-US/toolbox.properties
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -101,30 +101,40 @@ function renderToolboxButtons({toolboxBu
   });
 
   if (visibleButtons.length === 0) {
     return null;
   }
 
   return div({id: `toolbox-buttons-${isStart ? "start" : "end"}`},
     ...visibleButtons.map(command => {
-      const {id, description, onClick, isChecked, className: buttonClass} = command;
+      const {
+        id,
+        description,
+        onClick,
+        isChecked,
+        className: buttonClass,
+        onKeyDown
+      } = command;
       return button({
         id,
         title: description,
         className: (
           "command-button command-button-invertable devtools-button "
           + buttonClass + (isChecked ? " checked" : "")
         ),
         onClick: (event) => {
           onClick(event);
           focusButton(id);
         },
         onFocus: () => focusButton(id),
-        tabIndex: id === focusedButton ? "0" : "-1"
+        tabIndex: id === focusedButton ? "0" : "-1",
+        onKeyDown: (event) => {
+          onKeyDown(event);
+        }
       });
     }),
     isStart ? div({className: "devtools-separator"}) : null
   );
 }
 
 /**
  * The options button is a ToolboxTab just like in the ToolboxTabs component. However
--- a/devtools/client/framework/test/browser_toolbox_window_title_frame_select.js
+++ b/devtools/client/framework/test/browser_toolbox_window_title_frame_select.js
@@ -11,16 +11,18 @@
  * Check that the detached devtools window title is not updated when switching
  * the selected frame. Also check that frames command button has 'open'
  * attribute set when the list of frames is opened.
  */
 
 var {Toolbox} = require("devtools/client/framework/toolbox");
 const URL = URL_ROOT + "browser_toolbox_window_title_frame_select_page.html";
 const IFRAME_URL = URL_ROOT + "browser_toolbox_window_title_changes_page.html";
+const {LocalizationHelper} = require("devtools/shared/l10n");
+const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
 
 add_task(function* () {
   Services.prefs.setBoolPref("devtools.command-button-frames.enabled", true);
 
   yield addTab(URL);
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   let toolbox = yield gDevTools.showToolbox(target, null,
     Toolbox.HostType.BOTTOM);
@@ -36,19 +38,22 @@ add_task(function* () {
 
   is(getTitle(), `Developer Tools - Page title - ${URL}`,
     "Devtools title correct after switching to detached window host");
 
   // Wait for tick to avoid unexpected 'popuphidden' event, which
   // blocks the frame popup menu opened below. See also bug 1276873
   yield waitForTick();
 
+  let btn = toolbox.doc.getElementById("command-button-frames");
+
+  yield testShortcutToOpenFrames(btn, toolbox);
+
   // Open frame menu and wait till it's available on the screen.
   // Also check 'open' attribute on the command button.
-  let btn = toolbox.doc.getElementById("command-button-frames");
   ok(!btn.classList.contains("checked"), "The checked class must not be present");
   let menu = toolbox.showFramesMenu({target: btn});
   yield once(menu, "open");
 
   ok(btn.classList.contains("checked"), "The checked class must be set");
 
   // Verify that the frame list menu is populated
   let frames = menu.items;
@@ -87,8 +92,30 @@ add_task(function* () {
   Services.prefs.clearUserPref("devtools.toolbox.sideEnabled");
   Services.prefs.clearUserPref("devtools.command-button-frames.enabled");
   finish();
 });
 
 function getTitle() {
   return Services.wm.getMostRecentWindow("devtools:toolbox").document.title;
 }
+
+function* testShortcutToOpenFrames(btn, toolbox) {
+  info("Tests if shortcut Alt+Down opens the frames");
+  // focus the button so that keyPress can be performed
+  btn.focus();
+  // perform keyPress - Alt+Down
+  let shortcut = L10N.getStr("toolbox.showFrames.key");
+  synthesizeKeyShortcut(shortcut, toolbox.win);
+
+  // wait for 200 ms for UI to render
+  yield wait(200);
+
+  // btn should now have the checked class set
+  ok(btn.classList.contains("checked"), "The checked class must be set");
+
+  // pressing Esc should hide the menu again
+  synthesizeKeyShortcut("Esc", toolbox.win);
+  yield wait(200);
+
+  // btn shouldn't have the checked class set
+  ok(!btn.classList.contains("checked"), "The checked class must not be set");
+}
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -112,16 +112,18 @@ function Toolbox(target, selectedTool, h
   this.frameMap = new Map();
   this.selectedFrameId = null;
 
   this._toolRegistered = this._toolRegistered.bind(this);
   this._toolUnregistered = this._toolUnregistered.bind(this);
   this._refreshHostTitle = this._refreshHostTitle.bind(this);
   this._toggleNoAutohide = this._toggleNoAutohide.bind(this);
   this.showFramesMenu = this.showFramesMenu.bind(this);
+  this.handleKeyDownOnFramesButton = this.handleKeyDownOnFramesButton.bind(this);
+  this.showFramesMenuOnKeyDown = this.showFramesMenuOnKeyDown.bind(this);
   this._updateFrames = this._updateFrames.bind(this);
   this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
   this.destroy = this.destroy.bind(this);
   this.highlighterUtils = getHighlighterUtils(this);
   this._highlighterReady = this._highlighterReady.bind(this);
   this._highlighterHidden = this._highlighterHidden.bind(this);
   this._applyCacheSettings = this._applyCacheSettings.bind(this);
   this._applyServiceWorkersTestingSettings =
@@ -690,28 +692,43 @@ Toolbox.prototype = {
    *                      the button based on the target. If the target don't support
    *                      the button feature, this method should return false.
    * @property {Function} isChecked - Optional function called to known if the button
    *                      is toggled or not. The function should return true when
    *                      the button should be displayed as toggled on.
    */
   _createButtonState: function (options) {
     let isCheckedValue = false;
-    const { id, className, description, onClick, isInStartContainer, setup, teardown,
-            isTargetSupported, isChecked } = options;
+    const {
+      id,
+      className,
+      description,
+      onClick,
+      isInStartContainer,
+      setup,
+      teardown,
+      isTargetSupported,
+      isChecked,
+      onKeyDown
+    } = options;
     const toolbox = this;
     const button = {
       id,
       className,
       description,
       onClick(event) {
         if (typeof onClick == "function") {
           onClick(event, toolbox);
         }
       },
+      onKeyDown(event) {
+        if (typeof onKeyDown == "function") {
+          onKeyDown(event, toolbox);
+        }
+      },
       isTargetSupported,
       get isChecked() {
         if (typeof isChecked == "function") {
           return isChecked(toolbox);
         }
         return isCheckedValue;
       },
       set isChecked(value) {
@@ -1208,17 +1225,18 @@ Toolbox.prototype = {
    */
   _buildFrameButton() {
     this.frameButton = this._createButtonState({
       id: "command-button-frames",
       description: L10N.getStr("toolbox.frames.tooltip"),
       onClick: this.showFramesMenu,
       isTargetSupported: target => {
         return target.activeTab && target.activeTab.traits.frames;
-      }
+      },
+      onKeyDown: this.handleKeyDownOnFramesButton
     });
 
     return this.frameButton;
   },
 
   /**
    * Button that disables/enables auto-hiding XUL pop-ups. When enabled, XUL
    * pop-ups will not automatically close when they lose focus.
@@ -2057,16 +2075,33 @@ Toolbox.prototype = {
     let screenX = target.ownerDocument.defaultView.mozInnerScreenX;
     let screenY = target.ownerDocument.defaultView.mozInnerScreenY;
     menu.popup(rect.left + screenX, rect.bottom + screenY, this);
 
     return menu;
   },
 
   /**
+   * Handle keyDown event on 'frames' button to show available frames
+   */
+  handleKeyDownOnFramesButton: function (event) {
+    this.shortcuts.on(L10N.getStr("toolbox.showFrames.key"),
+      this.showFramesMenuOnKeyDown);
+  },
+
+  /**
+   * Show 'frames' menu on key down
+   */
+  showFramesMenuOnKeyDown: function (name, event) {
+    if (event.target.id == "command-button-frames") {
+      this.showFramesMenu(event);
+    }
+  },
+
+  /**
    * Select a frame by sending 'switchToFrame' packet to the backend.
    */
   onSelectFrame: function (frameId) {
     // Send packet to the backend to select specified frame and
     // wait for 'frameUpdate' event packet to update the UI.
     let packet = {
       to: this._target.form.actor,
       type: "switchToFrame",
--- a/devtools/client/locales/en-US/toolbox.properties
+++ b/devtools/client/locales/en-US/toolbox.properties
@@ -159,16 +159,20 @@ toolbox.minimize.key=CmdOrCtrl+Shift+U
 # Key shortcut used to move the toolbox in bottom or side of the browser window
 toolbox.toggleHost.key=CmdOrCtrl+Shift+D
 
 # LOCALIZATION NOTE (toolbox.frames.tooltip): This is the label for
 # the iframes menu list that appears only when the document has some.
 # It allows you to switch the context of the whole toolbox.
 toolbox.frames.tooltip=Select an iframe as the currently targeted document
 
+# LOCALIZATION NOTE (toolbox.showFrames.key)
+# Key shortcut used to show frames menu when 'frames' button is focused
+toolbox.showFrames.key=Alt+Down
+
 # LOCALIZATION NOTE (toolbox.noautohide.tooltip): This is the label for
 # the button to force the popups/panels to stay visible on blur.
 # This is only visible in the browser toolbox as it is meant for
 # addon developers and Firefox contributors.
 toolbox.noautohide.tooltip=Disable popup auto hide
 
 # LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for
 # the close button the developer tools toolbox.