Bug 927605 - refactor keyboard shortcut code in devtools into a JSM, r=Unfocused,vporof
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Sun, 20 Oct 2013 22:50:37 +0200
changeset 166324 73bebd77c3ed9d5bd4f4f033a23a8d5c386159b3
parent 166323 83562506fa87d73ead8c8064c5a301872764140f
child 166325 5945380e8d1d858898e0803e9022b2f5d35a52c6
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersUnfocused, vporof
bugs927605
milestone27.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 927605 - refactor keyboard shortcut code in devtools into a JSM, r=Unfocused,vporof
browser/devtools/debugger/debugger-controller.js
browser/devtools/debugger/debugger-toolbar.js
browser/devtools/debugger/test/browser_dbg_pause-resume.js
browser/devtools/scratchpad/scratchpad.js
browser/devtools/shared/helpers.js
toolkit/modules/ShortcutUtils.jsm
toolkit/modules/moz.build
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -91,23 +91,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource:///modules/devtools/Parser.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
   "resource://gre/modules/devtools/DevToolsUtils.jsm");
 
-Object.defineProperty(this, "DevtoolsHelpers", {
-  get: function() {
-    return devtools.require("devtools/shared/helpers");
-  },
-  configurable: true,
-  enumerable: true
-});
+XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
+  "resource://gre/modules/ShortcutUtils.jsm");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
     return devtools.require("devtools/toolkit/webconsole/network-helper");
   },
   configurable: true,
   enumerable: true
 });
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -33,20 +33,20 @@ ToolbarView.prototype = {
     this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
     this._resumeOrderPanel = document.getElementById("resumption-order-panel");
     this._resumeButton = document.getElementById("resume");
     this._stepOverButton = document.getElementById("step-over");
     this._stepInButton = document.getElementById("step-in");
     this._stepOutButton = document.getElementById("step-out");
     this._chromeGlobals = document.getElementById("chrome-globals");
 
-    let resumeKey = DevtoolsHelpers.prettyKey(document.getElementById("resumeKey"), true);
-    let stepOverKey = DevtoolsHelpers.prettyKey(document.getElementById("stepOverKey"), true);
-    let stepInKey = DevtoolsHelpers.prettyKey(document.getElementById("stepInKey"), true);
-    let stepOutKey = DevtoolsHelpers.prettyKey(document.getElementById("stepOutKey"), true);
+    let resumeKey = ShortcutUtils.prettifyShortcut(document.getElementById("resumeKey"), true);
+    let stepOverKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOverKey"), true);
+    let stepInKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepInKey"), true);
+    let stepOutKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOutKey"), true);
     this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", resumeKey);
     this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", resumeKey);
     this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", stepOverKey);
     this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey);
     this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey);
 
     this._instrumentsPaneToggleButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
     this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
@@ -691,22 +691,22 @@ FilterView.prototype = {
     this._functionOperatorLabel = document.getElementById("function-operator-label");
     this._tokenOperatorButton = document.getElementById("token-operator-button");
     this._tokenOperatorLabel = document.getElementById("token-operator-label");
     this._lineOperatorButton = document.getElementById("line-operator-button");
     this._lineOperatorLabel = document.getElementById("line-operator-label");
     this._variableOperatorButton = document.getElementById("variable-operator-button");
     this._variableOperatorLabel = document.getElementById("variable-operator-label");
 
-    this._fileSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("fileSearchKey"), true);
-    this._globalSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("globalSearchKey"), true);
-    this._filteredFunctionsKey = DevtoolsHelpers.prettyKey(document.getElementById("functionSearchKey"), true);
-    this._tokenSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("tokenSearchKey"), true);
-    this._lineSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("lineSearchKey"), true);
-    this._variableSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("variableSearchKey"), true);
+    this._fileSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("fileSearchKey"), true);
+    this._globalSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("globalSearchKey"), true);
+    this._filteredFunctionsKey = ShortcutUtils.prettifyShortcut(document.getElementById("functionSearchKey"), true);
+    this._tokenSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("tokenSearchKey"), true);
+    this._lineSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("lineSearchKey"), true);
+    this._variableSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("variableSearchKey"), true);
 
     this._searchbox.addEventListener("click", this._onClick, false);
     this._searchbox.addEventListener("select", this._onInput, false);
     this._searchbox.addEventListener("input", this._onInput, false);
     this._searchbox.addEventListener("keypress", this._onKeyPress, false);
     this._searchbox.addEventListener("blur", this._onBlur, false);
 
     this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -25,26 +25,26 @@ function test() {
 }
 
 function testPause() {
   is(gDebugger.gThreadClient.paused, false,
     "Should be running after starting the test.");
 
   is(gResumeButton.getAttribute("tooltiptext"),
      gDebugger.L10N.getFormatStr("pauseButtonTooltip",
-      gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+      gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
     "Button tooltip should be 'pause' when running.");
 
   gDebugger.gThreadClient.addOneTimeListener("paused", () => {
     is(gDebugger.gThreadClient.paused, true,
       "Should be paused after an interrupt request.");
 
     is(gResumeButton.getAttribute("tooltiptext"),
        gDebugger.L10N.getFormatStr("resumeButtonTooltip",
-        gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+        gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
       "Button tooltip should be 'resume' when paused.");
 
     is(gFrames.itemCount, 0,
       "Should have no frames when paused in the main loop.");
 
     testResume();
   });
 
@@ -53,17 +53,17 @@ function testPause() {
 
 function testResume() {
   gDebugger.gThreadClient.addOneTimeListener("resumed", () => {
     is(gDebugger.gThreadClient.paused, false,
       "Should be paused after an interrupt request.");
 
     is(gResumeButton.getAttribute("tooltiptext"),
        gDebugger.L10N.getFormatStr("pauseButtonTooltip",
-        gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+        gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
       "Button tooltip should be pause when running.");
 
     closeDebuggerAndFinish(gPanel);
   });
 
   EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
 }
 
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -32,17 +32,16 @@ const PREF_RECENT_FILES_MAX = "devtools.
 const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
 
 const require   = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise   = require("sdk/core/promise");
 const Telemetry = require("devtools/shared/telemetry");
 const escodegen = require("escodegen/escodegen");
 const Editor    = require("devtools/sourceeditor/editor");
 const TargetFactory = require("devtools/framework/target").TargetFactory;
-const DevtoolsHelpers = require("devtools/shared/helpers");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
@@ -69,16 +68,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/devtools/dbg-server.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "REMOTE_TIMEOUT", () =>
   Services.prefs.getIntPref("devtools.debugger.remote-timeout"));
 
+XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
+  "resource://gre/modules/ShortcutUtils.jsm");
+
 // Because we have no constructor / destructor where we can log metrics we need
 // to do so here.
 let telemetry = new Telemetry();
 telemetry.toolOpened("scratchpad");
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
@@ -1243,19 +1245,19 @@ var Scratchpad = {
       let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
       environmentMenu.removeAttribute("hidden");
       chromeContextCommand.removeAttribute("disabled");
       errorConsoleCommand.removeAttribute("disabled");
     }
 
     let initialText = this.strings.formatStringFromName(
       "scratchpadIntro1",
-      [DevtoolsHelpers.prettyKey(document.getElementById("sp-key-run")),
-       DevtoolsHelpers.prettyKey(document.getElementById("sp-key-inspect")),
-       DevtoolsHelpers.prettyKey(document.getElementById("sp-key-display"))],
+      [ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-run")),
+       ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-inspect")),
+       ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-display"))],
       3);
 
     let args = window.arguments;
     let state = null;
 
     if (args && args[0] instanceof Ci.nsIDialogParamBlock) {
       args = args[0];
       this._instanceId = args.GetString(0);
rename from browser/devtools/shared/helpers.js
rename to toolkit/modules/ShortcutUtils.jsm
--- a/browser/devtools/shared/helpers.js
+++ b/toolkit/modules/ShortcutUtils.jsm
@@ -1,72 +1,100 @@
 /* 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/. */
 
-const {Cu} = require("chrome");
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ShortcutUtils"];
+
+const Cu = Components.utils;
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-let { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 XPCOMUtils.defineLazyGetter(this, "PlatformKeys", function() {
   return Services.strings.createBundle(
     "chrome://global-platform/locale/platformKeys.properties");
 });
 
-/**
-  * Prettifies the modifier keys for an element.
-  *
-  * @param Node aElemKey
-  *        The key element to get the modifiers from.
-  * @param boolean aAllowCloverleaf
-  *        Pass true to use the cloverleaf symbol instead of a descriptive string.
-  * @return string
-  *         A prettified and properly separated modifier keys string.
-  */
-exports.prettyKey = function Helpers_prettyKey(aElemKey, aAllowCloverleaf) {
-  let elemString = "";
-  let elemMod = aElemKey.getAttribute("modifiers");
+XPCOMUtils.defineLazyGetter(this, "Keys", function() {
+  return Services.strings.createBundle(
+    "chrome://global/locale/keys.properties");
+});
 
-  if (elemMod.match("accel")) {
-    if (Services.appinfo.OS == "Darwin") {
-      // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
-      // Orion adds variable height lines.
-      if (!aAllowCloverleaf) {
-        elemString += "Cmd-";
+let ShortcutUtils = {
+  /**
+    * Prettifies the modifier keys for an element.
+    *
+    * @param Node aElemKey
+    *        The key element to get the modifiers from.
+    * @param boolean aAllowCloverleaf
+    *        Pass true to use the cloverleaf symbol instead of a descriptive string. (OS X only)
+    * @return string
+    *         A prettified and properly separated modifier keys string.
+    */
+  prettifyShortcut: function(aElemKey, aAllowCloverleaf) {
+    let elemString = "";
+    let elemMod = aElemKey.getAttribute("modifiers");
+
+    if (elemMod.match("accel")) {
+      if (Services.appinfo.OS == "Darwin") {
+        // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
+        // Orion adds variable height lines.
+        if (!aAllowCloverleaf) {
+          elemString += "Cmd-";
+        } else {
+          elemString += PlatformKeys.GetStringFromName("VK_META") +
+            PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+        }
       } else {
-        elemString += PlatformKeys.GetStringFromName("VK_META") +
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
           PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
       }
-    } else {
+    }
+    if (elemMod.match("access")) {
+      if (Services.appinfo.OS == "Darwin") {
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
+          PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      } else {
+        elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+          PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      }
+    }
+    if (elemMod.match("os")) {
+      elemString += PlatformKeys.GetStringFromName("VK_WIN") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("shift")) {
+      elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("alt")) {
+      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("ctrl") || elemMod.match("control")) {
       elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
-  }
-  if (elemMod.match("access")) {
-    if (Services.appinfo.OS == "Darwin") {
-      elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-    } else {
-      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+    if (elemMod.match("meta")) {
+      elemString += PlatformKeys.GetStringFromName("VK_META") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
-  }
-  if (elemMod.match("shift")) {
-    elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("alt")) {
-    elemString += PlatformKeys.GetStringFromName("VK_ALT") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+
+    let key;
+    let keyCode = aElemKey.getAttribute("keycode");
+    if (keyCode) {
+      try {
+        // Some keys might not exist in the locale file, which will throw:
+        key = Keys.GetStringFromName(keyCode.toUpperCase());
+      } catch (ex) {
+        Cu.reportError("Error finding " + keyCode + ": " + ex);
+        key = keyCode.replace(/^VK_/, '');
+      }
+    } else {
+      key = aElemKey.getAttribute("key");
+    }
+    return elemString + key;
   }
-  if (elemMod.match("ctrl") || elemMod.match("control")) {
-    elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("meta")) {
-    elemString += PlatformKeys.GetStringFromName("VK_META") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
+};
 
-  return elemString +
-    (aElemKey.getAttribute("keycode").replace(/^.*VK_/, "") ||
-     aElemKey.getAttribute("key")).toUpperCase();
-}
+Object.freeze(ShortcutUtils);
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -30,16 +30,17 @@ EXTRA_JS_MODULES += [
     'RemoteAddonsParent.jsm',
     'RemoteController.jsm',
     'RemoteFinder.jsm',
     'RemoteSecurityUI.jsm',
     'RemoteWebNavigation.jsm',
     'RemoteWebProgress.jsm',
     'SelectContentHelper.jsm',
     'SelectParentHelper.jsm',
+    'ShortcutUtils.jsm',
     'Sntp.jsm',
     'SpatialNavigation.jsm',
     'Sqlite.jsm',
     'Task.jsm',
     'TelemetryTimestamps.jsm',
     'Timer.jsm',
     'debug.js',
 ]