Bug 820735 - [toolbox] Tools shortcuts should work from the toolbox window, r=paul a=bbajaj
authorGirish Sharma <scrapmachines@gmail.com>
Sun, 13 Jan 2013 14:22:03 +0530
changeset 127215 71752eb1fec1b6a7aec59c78ced38c6ac2b331df
parent 127214 91d5f962e5530190aa958f30e41186b8e0120e3e
child 127216 1059001a53f598c7c51fc20c3e0b1d1aa5b86a44
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaul, bbajaj
bugs820735
milestone20.0a2
Bug 820735 - [toolbox] Tools shortcuts should work from the toolbox window, r=paul a=bbajaj
browser/devtools/framework/Toolbox.jsm
browser/devtools/framework/test/Makefile.in
browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -256,31 +256,65 @@ Toolbox.prototype = {
         this.isReady = true;
 
         let closeButton = this.doc.getElementById("toolbox-close");
         closeButton.addEventListener("command", this.destroy, true);
 
         this._buildDockButtons();
         this._buildTabs();
         this._buildButtons();
+        this._addKeysToWindow();
 
         this.selectTool(this._defaultToolId).then(function(panel) {
           this.emit("ready");
           deferred.resolve();
         }.bind(this));
       }.bind(this);
 
       iframe.addEventListener("DOMContentLoaded", domReady, true);
       iframe.setAttribute("src", this._URL);
     }.bind(this));
 
     return deferred.promise;
   },
 
   /**
+   * Adds the keys and commands to the Toolbox Window in window mode.
+   */
+  _addKeysToWindow: function TBOX__addKeysToWindow() {
+    if (this.hostType != Toolbox.HostType.WINDOW) {
+      return;
+    }
+    let doc = this.doc.defaultView.parent.document;
+    for (let [id, toolDefinition] of gDevTools._tools) {
+      if (toolDefinition.key) {
+        // Prevent multiple entries for the same tool.
+        if (doc.getElementById("key_" + id)) {
+          continue;
+        }
+        let key = doc.createElement("key");
+        key.id = "key_" + id;
+
+        if (toolDefinition.key.startsWith("VK_")) {
+          key.setAttribute("keycode", toolDefinition.key);
+        } else {
+          key.setAttribute("key", toolDefinition.key);
+        }
+
+        key.setAttribute("modifiers", toolDefinition.modifiers);
+        key.setAttribute("oncommand", "void(0);"); // needed. See bug 371900
+        key.addEventListener("command", function(toolId) {
+          this.selectTool(toolId);
+        }.bind(this, id), true);
+        doc.getElementById("toolbox-keyset").appendChild(key);
+      }
+    }
+  },
+
+  /**
    * Build the buttons for changing hosts. Called every time
    * the host changes.
    */
   _buildDockButtons: function TBOX_createDockButtons() {
     let dockBox = this.doc.getElementById("toolbox-dock-buttons");
 
     while (dockBox.firstChild) {
       dockBox.removeChild(dockBox.firstChild);
@@ -376,16 +410,18 @@ Toolbox.prototype = {
     }.bind(this, id));
 
     let vbox = this.doc.createElement("vbox");
     vbox.className = "toolbox-panel";
     vbox.id = "toolbox-panel-" + id;
 
     tabs.appendChild(radio);
     deck.appendChild(vbox);
+
+    this._addKeysToWindow();
   },
 
   /**
    * Switch to the tool with the given id
    *
    * @param {string} id
    *        The id of the tool to switch to
    */
@@ -510,16 +546,17 @@ Toolbox.prototype = {
       this._host.off("window-closed", this.destroy);
       this._host.destroy();
 
       this._host = newHost;
 
       Services.prefs.setCharPref(this._prefs.LAST_HOST, this._host.type);
 
       this._buildDockButtons();
+      this._addKeysToWindow();
 
       this.emit("host-changed");
     }.bind(this));
   },
 
   /**
    * Handler for the tool-registered event.
    * @param  {string} event
@@ -561,16 +598,24 @@ Toolbox.prototype = {
     if (radio) {
       radio.parentNode.removeChild(radio);
     }
 
     if (panel) {
       panel.parentNode.removeChild(panel);
     }
 
+    if (this.hostType == Toolbox.HostType.WINDOW) {
+      let doc = this.doc.defaultView.parent.document;
+      let key = doc.getElementById("key_" + id);
+      if (key) {
+        key.parentNode.removeChild(key);
+      }
+    }
+
     if (this._toolPanels.has(toolId)) {
       let instance = this._toolPanels.get(toolId);
       instance.destroy();
       this._toolPanels.delete(toolId);
     }
   },
 
 
--- a/browser/devtools/framework/test/Makefile.in
+++ b/browser/devtools/framework/test/Makefile.in
@@ -16,11 +16,12 @@ MOCHITEST_BROWSER_FILES = \
 		browser_new_activation_workflow.js \
 		browser_toolbox_dynamic_registration.js \
 		browser_toolbox_hosts.js \
 		browser_toolbox_ready.js \
 		browser_toolbox_select_event.js \
 		browser_target_events.js \
 		browser_toolbox_tool_ready.js \
 		browser_toolbox_sidebar.js \
+		browser_toolbox_window_shortcuts.js \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let temp = {};
+Cu.import("resource:///modules/devtools/Toolbox.jsm", temp);
+let Toolbox = temp.Toolbox;
+temp = null;
+
+let toolbox, toolIDs, idIndex;
+
+function test() {
+  waitForExplicitFinish();
+
+  addTab("about:blank", function() {
+    toolIDs = [];
+    for (let [id, definition] of gDevTools._tools) {
+      if (definition.key) {
+        toolIDs.push(id);
+      }
+    }
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    idIndex = 0;
+    gDevTools.showToolbox(target, toolIDs[0], Toolbox.HostType.WINDOW)
+             .then(testShortcuts);
+  });
+}
+
+function testShortcuts(aToolbox, aIndex) {
+  if (aIndex == toolIDs.length) {
+    tidyUp();
+    return;
+  }
+
+  toolbox = aToolbox;
+  info("Toolbox fired a `ready` event");
+
+  toolbox.once("select", selectCB);
+
+  if (aIndex != null) {
+    // This if block is to allow the call of selectCB without shortcut press for
+    // the first time. That happens because on opening of toolbox, one tool gets
+    // selected atleast.
+
+    let key = gDevTools._tools.get(toolIDs[aIndex]).key;
+    let toolModifiers = gDevTools._tools.get(toolIDs[aIndex]).modifiers;
+    let modifiers = {
+      accelKey: toolModifiers.contains("accel"),
+      altKey: toolModifiers.contains("alt"),
+      shiftKey: toolModifiers.contains("shift"),
+    };
+    idIndex = aIndex;
+    info("Testing shortcut for tool " + aIndex + ":" + toolIDs[aIndex] +
+         " using key " + key);
+    EventUtils.synthesizeKey(key, modifiers, toolbox.doc.defaultView.parent);
+  }
+}
+
+function selectCB(event, id) {
+  info("toolbox-select event from " + id);
+
+  is(toolIDs.indexOf(id), idIndex,
+     "Correct tool is selected on pressing the shortcut for " + id);
+
+  testShortcuts(toolbox, idIndex + 1);
+}
+
+function tidyUp() {
+  toolbox.destroy();
+  gBrowser.removeCurrentTab();
+
+  toolbox = toolIDs = idIndex = Toolbox = null;
+  finish();
+}