Bug 1271988 - Convert computed view to use key-shortcuts module. r=bgrins
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 03 Jun 2016 02:24:31 -0700
changeset 339333 10371d73bb08fa730e311885433bd147bf2a3576
parent 339332 e5edc0ec18b9fdea1b830853441b9ccda4ea2014
child 339334 28b383d15b1ade1b36f56beaeadc0eecf26b15de
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgrins
bugs1271988
milestone49.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 1271988 - Convert computed view to use key-shortcuts module. r=bgrins
devtools/client/inspector/computed/computed.js
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -19,16 +19,18 @@ const {OutputParser} = require("devtools
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
 const {createChild} = require("devtools/client/inspector/shared/utils");
 const {gDevTools} = require("devtools/client/framework/devtools");
 
 loader.lazyRequireGetter(this, "overlays",
   "devtools/client/inspector/shared/style-inspector-overlays");
 loader.lazyRequireGetter(this, "StyleInspectorMenu",
   "devtools/client/inspector/shared/style-inspector-menu");
+loader.lazyRequireGetter(this, "KeyShortcuts",
+  "devtools/client/shared/key-shortcuts", true);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyGetter(CssComputedView, "_strings", function () {
   return Services.strings.createBundle(
@@ -150,42 +152,42 @@ function CssComputedView(inspector, docu
   this._outputParser = new OutputParser(document);
 
   let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
     .getService(Ci.nsIXULChromeRegistry);
   this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr";
 
   // Create bound methods.
   this.focusWindow = this.focusWindow.bind(this);
-  this._onKeypress = this._onKeypress.bind(this);
   this._onContextMenu = this._onContextMenu.bind(this);
   this._onClick = this._onClick.bind(this);
   this._onCopy = this._onCopy.bind(this);
   this._onFilterStyles = this._onFilterStyles.bind(this);
-  this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
   this._onClearSearch = this._onClearSearch.bind(this);
   this._onIncludeBrowserStyles = this._onIncludeBrowserStyles.bind(this);
   this._onFilterTextboxContextMenu =
     this._onFilterTextboxContextMenu.bind(this);
 
   let doc = this.styleDocument;
   this.root = doc.getElementById("root");
   this.element = doc.getElementById("propertyContainer");
   this.searchField = doc.getElementById("computedview-searchbox");
   this.searchClearButton = doc.getElementById("computedview-searchinput-clear");
   this.includeBrowserStylesCheckbox =
     doc.getElementById("browser-style-checkbox");
 
-  this.styleDocument.addEventListener("keypress", this._onKeypress);
+  this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
+  this._onShortcut = this._onShortcut.bind(this);
+  this.shortcuts.on("CmdOrCtrl+F", this._onShortcut);
+  this.shortcuts.on("Escape", this._onShortcut);
   this.styleDocument.addEventListener("mousedown", this.focusWindow);
   this.element.addEventListener("click", this._onClick);
   this.element.addEventListener("copy", this._onCopy);
   this.element.addEventListener("contextmenu", this._onContextMenu);
   this.searchField.addEventListener("input", this._onFilterStyles);
-  this.searchField.addEventListener("keypress", this._onFilterKeyPress);
   this.searchField.addEventListener("contextmenu",
                                     this._onFilterTextboxContextMenu);
   this.searchClearButton.addEventListener("click", this._onClearSearch);
   this.includeBrowserStylesCheckbox.addEventListener("command",
     this._onIncludeBrowserStyles);
 
   this.searchClearButton.hidden = true;
 
@@ -497,27 +499,29 @@ CssComputedView.prototype = {
         }
       );
       this._refreshProcess.schedule();
       return deferred.promise;
     }).then(null, (err) => console.error(err));
   },
 
   /**
-   * Handle the keypress event in the computed view.
+   * Handle the shortcut events in the computed view.
    */
-  _onKeypress: function (event) {
+  _onShortcut: function (name, event) {
     if (!event.target.closest("#sidebar-panel-computedview")) {
       return;
     }
-    let isOSX = Services.appinfo.OS === "Darwin";
-
-    if (((isOSX && event.metaKey && !event.ctrlKey && !event.altKey) ||
-        (!isOSX && event.ctrlKey && !event.metaKey && !event.altKey)) &&
-        event.key === "f") {
+    // Handle the search box's keypress event. If the escape key is pressed,
+    // clear the search box field.
+    if (name === "Escape" && event.target === this.searchField &&
+        this._onClearSearch()) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else if (name === "CmdOrCtrl+F") {
       this.searchField.focus();
       event.preventDefault();
     }
   },
 
   /**
    * Set the filter style search value.
    * @param {String} value
@@ -549,28 +553,16 @@ CssComputedView.prototype = {
       }
 
       this.refreshPanel();
       this._filterChangeTimeout = null;
     }, filterTimeout);
   },
 
   /**
-   * Handle the search box's keypress event. If the escape key is pressed,
-   * clear the search box field.
-   */
-  _onFilterKeyPress: function (event) {
-    if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE &&
-        this._onClearSearch()) {
-      event.preventDefault();
-      event.stopPropagation();
-    }
-  },
-
-  /**
    * Context menu handler for filter style search box.
    */
   _onFilterTextboxContextMenu: function (event) {
     try {
       this.styleDocument.defaultView.focus();
       let contextmenu = this.inspector.toolbox.textboxContextMenuPopup;
       contextmenu.openPopupAtScreen(event.screenX, event.screenY, true);
     } catch (e) {
@@ -771,17 +763,16 @@ CssComputedView.prototype = {
     this.highlighters.destroy();
 
     // Remove bound listeners
     this.styleDocument.removeEventListener("mousedown", this.focusWindow);
     this.element.removeEventListener("click", this._onClick);
     this.element.removeEventListener("copy", this._onCopy);
     this.element.removeEventListener("contextmenu", this._onContextMenu);
     this.searchField.removeEventListener("input", this._onFilterStyles);
-    this.searchField.removeEventListener("keypress", this._onFilterKeyPress);
     this.searchField.removeEventListener("contextmenu",
                                          this._onFilterTextboxContextMenu);
     this.searchClearButton.removeEventListener("click", this._onClearSearch);
     this.includeBrowserStylesCheckbox.removeEventListener("command",
       this.includeBrowserStylesChanged);
 
     // Nodes used in templating
     this.root = null;
@@ -952,28 +943,25 @@ PropertyView.prototype = {
     // Build the container element
     this.onMatchedToggle = this.onMatchedToggle.bind(this);
     this.element = doc.createElementNS(HTML_NS, "div");
     this.element.setAttribute("class", this.propertyHeaderClassName);
     this.element.addEventListener("dblclick", this.onMatchedToggle, false);
 
     // Make it keyboard navigable
     this.element.setAttribute("tabindex", "0");
-    this.onKeyDown = (event) => {
-      let keyEvent = Ci.nsIDOMKeyEvent;
-      if (event.keyCode === keyEvent.DOM_VK_F1) {
-        this.mdnLinkClick();
-        event.preventDefault();
-      }
-      if (event.keyCode === keyEvent.DOM_VK_RETURN ||
-        event.keyCode === keyEvent.DOM_VK_SPACE) {
-        this.onMatchedToggle(event);
-      }
-    };
-    this.element.addEventListener("keydown", this.onKeyDown, false);
+    this.shortcuts = new KeyShortcuts({
+      window: this.tree.styleWindow,
+      target: this.element
+    });
+    this.shortcuts.on("F1", (name, event) => {
+      this.mdnLinkClick(event);
+    });
+    this.shortcuts.on("Return", (name, event) => this.onMatchedToggle(event));
+    this.shortcuts.on("Space", (name, event) => this.onMatchedToggle(event));
 
     let nameContainer = doc.createElementNS(HTML_NS, "div");
     nameContainer.className = "property-name-container";
     this.element.appendChild(nameContainer);
 
     // Build the twisty expand/collapse
     this.matchedExpander = doc.createElementNS(HTML_NS, "div");
     this.matchedExpander.className = "expander theme-twisty";
@@ -1111,17 +1099,21 @@ PropertyView.prototype = {
         target: "_blank",
         class: "link theme-link",
         title: selector.href,
         sourcelocation: selector.source,
         tabindex: "0",
         textContent: selector.source
       });
       link.addEventListener("click", selector.openStyleEditor, false);
-      link.addEventListener("keydown", selector.maybeOpenStyleEditor, false);
+      let shortcuts = new KeyShortcuts({
+        window: this.tree.styleWindow,
+        target: link
+      });
+      shortcuts.on("Return", () => selector.openStyleEditor());
 
       let status = createChild(p, "span", {
         dir: "ltr",
         class: "rule-text theme-fg-color3 " + selector.statusClass,
         title: selector.statusText,
         textContent: selector.sourceText
       });
       let valueSpan = createChild(status, "span", {
@@ -1186,24 +1178,25 @@ PropertyView.prototype = {
   mdnLinkClick: function (event) {
     let inspector = this.tree.inspector;
 
     if (inspector.target.tab) {
       let browserWin = inspector.target.tab.ownerDocument.defaultView;
       browserWin.openUILinkIn(this.link, "tab");
     }
     event.preventDefault();
+    event.stopPropagation();
   },
 
   /**
    * Destroy this property view, removing event listeners
    */
   destroy: function () {
     this.element.removeEventListener("dblclick", this.onMatchedToggle, false);
-    this.element.removeEventListener("keydown", this.onKeyDown, false);
+    this.shortcuts.destroy();
     this.element = null;
 
     this.matchedExpander.removeEventListener("click", this.onMatchedToggle,
                                              false);
     this.matchedExpander = null;
 
     this.nameNode.removeEventListener("click", this.onFocus, false);
     this.nameNode = null;
@@ -1221,17 +1214,16 @@ PropertyView.prototype = {
  * @param selectorInfo
  */
 function SelectorView(tree, selectorInfo) {
   this.tree = tree;
   this.selectorInfo = selectorInfo;
   this._cacheStatusNames();
 
   this.openStyleEditor = this.openStyleEditor.bind(this);
-  this.maybeOpenStyleEditor = this.maybeOpenStyleEditor.bind(this);
 
   this.ready = this.updateSourceLink();
 }
 
 /**
  * Decode for cssInfo.rule.status
  * @see SelectorView.prototype._cacheStatusNames
  * @see CssLogic.STATUS
@@ -1364,26 +1356,16 @@ SelectorView.prototype = {
     }
 
     let oldSource = this.source;
     this.source = CssLogic.shortSource(this.sheet) + ":" + rule.line;
     return promise.resolve(oldSource);
   },
 
   /**
-   * Open the style editor if the RETURN key was pressed.
-   */
-  maybeOpenStyleEditor: function (event) {
-    let keyEvent = Ci.nsIDOMKeyEvent;
-    if (event.keyCode === keyEvent.DOM_VK_RETURN) {
-      this.openStyleEditor();
-    }
-  },
-
-  /**
    * When a css link is clicked this method is called in order to either:
    *   1. Open the link in view source (for chrome stylesheets).
    *   2. Open the link in the style editor.
    *
    *   We can only view stylesheets contained in document.styleSheets inside the
    *   style editor.
    */
   openStyleEditor: function () {