panel.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. const { Cc, Ci, Cu, Cr } = require("chrome");
  7. const promise = require("promise");
  8. const EventEmitter = require("devtools/shared/event-emitter");
  9. const DevToolsUtils = require("devtools/shared/DevToolsUtils");
  10. function DebuggerPanel(iframeWindow, toolbox) {
  11. this.panelWin = iframeWindow;
  12. this._toolbox = toolbox;
  13. this._destroyer = null;
  14. this._view = this.panelWin.DebuggerView;
  15. this._controller = this.panelWin.DebuggerController;
  16. this._view._hostType = this._toolbox.hostType;
  17. this._controller._target = this.target;
  18. this._controller._toolbox = this._toolbox;
  19. this.handleHostChanged = this.handleHostChanged.bind(this);
  20. EventEmitter.decorate(this);
  21. }
  22. exports.DebuggerPanel = DebuggerPanel;
  23. DebuggerPanel.prototype = {
  24. /**
  25. * Open is effectively an asynchronous constructor.
  26. *
  27. * @return object
  28. * A promise that is resolved when the Debugger completes opening.
  29. */
  30. open: function () {
  31. let targetPromise;
  32. // Local debugging needs to make the target remote.
  33. if (!this.target.isRemote) {
  34. targetPromise = this.target.makeRemote();
  35. // Listen for tab switching events to manage focus when the content window
  36. // is paused and events suppressed.
  37. this.target.tab.addEventListener("TabSelect", this);
  38. } else {
  39. targetPromise = promise.resolve(this.target);
  40. }
  41. return targetPromise
  42. .then(() => this._controller.startupDebugger())
  43. .then(() => this._controller.connect())
  44. .then(() => {
  45. this._toolbox.on("host-changed", this.handleHostChanged);
  46. // Add keys from this document's keyset to the toolbox, so they
  47. // can work when the split console is focused.
  48. let keysToClone = ["resumeKey", "stepOverKey", "stepInKey", "stepOutKey"];
  49. for (let key of keysToClone) {
  50. let elm = this.panelWin.document.getElementById(key);
  51. let keycode = elm.getAttribute("keycode");
  52. let modifiers = elm.getAttribute("modifiers");
  53. let command = elm.getAttribute("command");
  54. let handler = this._view.Toolbar.getCommandHandler(command);
  55. let keyShortcut = this.translateToKeyShortcut(keycode, modifiers);
  56. this._toolbox.useKeyWithSplitConsole(keyShortcut, handler, "jsdebugger");
  57. }
  58. this.isReady = true;
  59. this.emit("ready");
  60. return this;
  61. })
  62. .then(null, function onError(aReason) {
  63. DevToolsUtils.reportException("DebuggerPanel.prototype.open", aReason);
  64. });
  65. },
  66. /**
  67. * Translate a VK_ keycode, with modifiers, to a key shortcut that can be used with
  68. * shared/key-shortcut.
  69. *
  70. * @param {String} keycode
  71. * The VK_* keycode to translate
  72. * @param {String} modifiers
  73. * The list (blank-space separated) of modifiers applying to this keycode.
  74. * @return {String} a key shortcut ready to be used with shared/key-shortcut.js
  75. */
  76. translateToKeyShortcut: function (keycode, modifiers) {
  77. // Remove the VK_ prefix.
  78. keycode = keycode.replace("VK_", "");
  79. // Translate modifiers
  80. if (modifiers.includes("shift")) {
  81. keycode = "Shift+" + keycode;
  82. }
  83. if (modifiers.includes("alt")) {
  84. keycode = "Alt+" + keycode;
  85. }
  86. if (modifiers.includes("control")) {
  87. keycode = "Ctrl+" + keycode;
  88. }
  89. if (modifiers.includes("meta")) {
  90. keycode = "Cmd+" + keycode;
  91. }
  92. if (modifiers.includes("accel")) {
  93. keycode = "CmdOrCtrl+" + keycode;
  94. }
  95. return keycode;
  96. },
  97. // DevToolPanel API
  98. get target() {
  99. return this._toolbox.target;
  100. },
  101. destroy: function () {
  102. // Make sure this panel is not already destroyed.
  103. if (this._destroyer) {
  104. return this._destroyer;
  105. }
  106. if (!this.target.isRemote) {
  107. this.target.tab.removeEventListener("TabSelect", this);
  108. }
  109. return this._destroyer = this._controller.shutdownDebugger().then(() => {
  110. this.emit("destroyed");
  111. });
  112. },
  113. // DebuggerPanel API
  114. getFrames() {
  115. let framesController = this.panelWin.DebuggerController.StackFrames;
  116. let thread = framesController.activeThread;
  117. if (thread && thread.paused) {
  118. return {
  119. frames: thread.cachedFrames,
  120. selected: framesController.currentFrameDepth,
  121. };
  122. }
  123. return null;
  124. },
  125. addBreakpoint: function (location) {
  126. const { actions } = this.panelWin;
  127. const { dispatch } = this._controller;
  128. return dispatch(actions.addBreakpoint(location));
  129. },
  130. removeBreakpoint: function (location) {
  131. const { actions } = this.panelWin;
  132. const { dispatch } = this._controller;
  133. return dispatch(actions.removeBreakpoint(location));
  134. },
  135. blackbox: function (source, flag) {
  136. const { actions } = this.panelWin;
  137. const { dispatch } = this._controller;
  138. return dispatch(actions.blackbox(source, flag));
  139. },
  140. handleHostChanged: function () {
  141. this._view.handleHostChanged(this._toolbox.hostType);
  142. },
  143. // nsIDOMEventListener API
  144. handleEvent: function (aEvent) {
  145. if (aEvent.target == this.target.tab &&
  146. this._controller.activeThread.state == "paused") {
  147. // Wait a tick for the content focus event to be delivered.
  148. DevToolsUtils.executeSoon(() => this._toolbox.focusTool("jsdebugger"));
  149. }
  150. }
  151. };