Bug 1397366 - restore source-editor commands controller for scratchpad & styleeditor menus;r=ochameau draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 03 Jan 2018 20:52:58 +0100
changeset 717800 45f03264527acc9fe70a49931c08a76e97ee778a
parent 717738 6f5fac320fcb6625603fa8a744ffa8523f8b3d71
child 745349 3b1673261a0bba385fab88cb8f8251c06d4d3de4
push id94782
push userjdescottes@mozilla.com
push dateTue, 09 Jan 2018 16:42:54 +0000
reviewersochameau
bugs1397366
milestone59.0a1
Bug 1397366 - restore source-editor commands controller for scratchpad & styleeditor menus;r=ochameau MozReview-Commit-ID: Cfgws8fqgvp
devtools/client/scratchpad/scratchpad.js
devtools/client/sourceeditor/editor-commands-controller.js
devtools/client/sourceeditor/editor.js
devtools/client/sourceeditor/moz.build
devtools/client/styleeditor/StyleSheetEditor.jsm
--- a/devtools/client/scratchpad/scratchpad.js
+++ b/devtools/client/scratchpad/scratchpad.js
@@ -1727,16 +1727,19 @@ var Scratchpad = {
                                                       document.querySelector("#scratchpad-notificationbox"),
                                                       msg, okstring);
       editorElement.addEventListener("paste", this._onPaste, true);
       editorElement.addEventListener("drop", this._onPaste);
       this.editor.on("saveRequested", () => this.saveFile());
       this.editor.focus();
       this.editor.setCursor({ line: lines.length, ch: lines.pop().length });
 
+      // Add the commands controller for the source-editor.
+      this.editor.insertCommandsController();
+
       if (state)
         this.dirty = !state.saved;
 
       this.initialized = true;
       this._triggerObservers("Ready");
       this.populateRecentFilesMenu();
       PreferenceObserver.init();
       CloseObserver.init();
new file mode 100644
--- /dev/null
+++ b/devtools/client/sourceeditor/editor-commands-controller.js
@@ -0,0 +1,97 @@
+/* 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/. */
+
+"use strict";
+
+/**
+ * The source editor exposes XUL commands that can be used when embedded in a XUL
+ * document. This controller drives the availability and behavior of the commands. When
+ * the editor input field is focused, this controller will update the matching menu item
+ * entries found in application menus or context menus.
+ */
+
+/**
+ * Returns a controller object that can be used for editor-specific commands:
+ * - find
+ * - find again
+ * - go to line
+ * - undo
+ * - redo
+ * - delete
+ * - select all
+ */
+function createController(ed) {
+  return {
+    supportsCommand: function (cmd) {
+      switch (cmd) {
+        case "cmd_find":
+        case "cmd_findAgain":
+        case "cmd_gotoLine":
+        case "cmd_undo":
+        case "cmd_redo":
+        case "cmd_delete":
+        case "cmd_selectAll":
+          return true;
+      }
+
+      return false;
+    },
+
+    isCommandEnabled: function (cmd) {
+      let cm = ed.codeMirror;
+
+      switch (cmd) {
+        case "cmd_find":
+        case "cmd_gotoLine":
+        case "cmd_selectAll":
+          return true;
+        case "cmd_findAgain":
+          return cm.state.search != null && cm.state.search.query != null;
+        case "cmd_undo":
+          return ed.canUndo();
+        case "cmd_redo":
+          return ed.canRedo();
+        case "cmd_delete":
+          return ed.somethingSelected();
+      }
+
+      return false;
+    },
+
+    doCommand: function (cmd) {
+      let cm = ed.codeMirror;
+
+      let map = {
+        "cmd_selectAll": "selectAll",
+        "cmd_find": "find",
+        "cmd_undo": "undo",
+        "cmd_redo": "redo",
+        "cmd_delete": "delCharAfter",
+        "cmd_findAgain": "findNext"
+      };
+
+      if (map[cmd]) {
+        cm.execCommand(map[cmd]);
+        return;
+      }
+
+      if (cmd == "cmd_gotoLine") {
+        ed.jumpToLine();
+      }
+    },
+
+    onEvent: function () {}
+  };
+}
+
+/**
+ * Create and insert a commands controller for the provided SourceEditor instance.
+ */
+function insertCommandsController(sourceEditor) {
+  let input = sourceEditor.codeMirror.getInputField();
+  let controller = createController(sourceEditor);
+  input.controllers.insertControllerAt(0, controller);
+}
+
+module.exports = { insertCommandsController };
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -479,16 +479,26 @@ Editor.prototype = {
     // turn it off and back on again so the proper mode can be used.
     if (this.config.autocomplete) {
       this.setOption("autocomplete", false);
       this.setOption("autocomplete", true);
     }
   },
 
   /**
+   * The source editor can expose several commands linked from system and context menus.
+   * Kept for backward compatibility with scratchpad and styleeditor.
+   */
+  insertCommandsController: function () {
+    const { insertCommandsController } =
+      require("devtools/client/sourceeditor/editor-commands-controller");
+    insertCommandsController(this);
+  },
+
+  /**
    * Returns text from the text area. If line argument is provided
    * the method returns only that line.
    */
   getText: function (line) {
     let cm = editors.get(this);
 
     if (line == null) {
       return cm.getValue();
--- a/devtools/client/sourceeditor/moz.build
+++ b/devtools/client/sourceeditor/moz.build
@@ -7,16 +7,17 @@
 DIRS += [
     'tern',
 ]
 
 DevToolsModules(
     'autocomplete.js',
     'css-autocompleter.js',
     'debugger.js',
+    'editor-commands-controller.js',
     'editor.js',
     'wasm.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
-with Files('**'):
-    BUG_COMPONENT = ('Firefox', 'Developer Tools: Source Editor')
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Source Editor')
--- a/devtools/client/styleeditor/StyleSheetEditor.jsm
+++ b/devtools/client/styleeditor/StyleSheetEditor.jsm
@@ -464,16 +464,19 @@ StyleSheetEditor.prototype = {
 
       sourceEditor.setSelection(this._state.selection.start,
                                 this._state.selection.end);
 
       if (this.highlighter && this.walker) {
         sourceEditor.container.addEventListener("mousemove", this._onMouseMove);
       }
 
+      // Add the commands controller for the source-editor.
+      sourceEditor.insertCommandsController();
+
       this.emit("source-editor-load");
     });
   },
 
   /**
    * Get the source editor for this editor.
    *
    * @return {Promise}