connect.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. var Cu = Components.utils;
  7. var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
  8. var Services = require("Services");
  9. var {gDevTools} = require("devtools/client/framework/devtools");
  10. var {TargetFactory} = require("devtools/client/framework/target");
  11. var {Toolbox} = require("devtools/client/framework/toolbox");
  12. var {DebuggerClient} = require("devtools/shared/client/main");
  13. var {Task} = require("devtools/shared/task");
  14. var {LocalizationHelper} = require("devtools/shared/l10n");
  15. var L10N = new LocalizationHelper("devtools/client/locales/connection-screen.properties");
  16. var gClient;
  17. var gConnectionTimeout;
  18. /**
  19. * Once DOM is ready, we prefil the host/port inputs with
  20. * pref-stored values.
  21. */
  22. window.addEventListener("DOMContentLoaded", function onDOMReady() {
  23. window.removeEventListener("DOMContentLoaded", onDOMReady, true);
  24. let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
  25. let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
  26. if (host) {
  27. document.getElementById("host").value = host;
  28. }
  29. if (port) {
  30. document.getElementById("port").value = port;
  31. }
  32. let form = document.querySelector("#connection-form form");
  33. form.addEventListener("submit", function () {
  34. window.submit().catch(e => {
  35. console.error(e);
  36. // Bug 921850: catch rare exception from DebuggerClient.socketConnect
  37. showError("unexpected");
  38. });
  39. });
  40. }, true);
  41. /**
  42. * Called when the "connect" button is clicked.
  43. */
  44. var submit = Task.async(function* () {
  45. // Show the "connecting" screen
  46. document.body.classList.add("connecting");
  47. let host = document.getElementById("host").value;
  48. let port = document.getElementById("port").value;
  49. // Save the host/port values
  50. try {
  51. Services.prefs.setCharPref("devtools.debugger.remote-host", host);
  52. Services.prefs.setIntPref("devtools.debugger.remote-port", port);
  53. } catch (e) {
  54. // Fails in e10s mode, but not a critical feature.
  55. }
  56. // Initiate the connection
  57. let transport = yield DebuggerClient.socketConnect({ host, port });
  58. gClient = new DebuggerClient(transport);
  59. let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
  60. gConnectionTimeout = setTimeout(handleConnectionTimeout, delay);
  61. let response = yield gClient.connect();
  62. yield onConnectionReady(...response);
  63. });
  64. /**
  65. * Connection is ready. List actors and build buttons.
  66. */
  67. var onConnectionReady = Task.async(function* ([aType, aTraits]) {
  68. clearTimeout(gConnectionTimeout);
  69. let response = yield gClient.listAddons();
  70. let parent = document.getElementById("addonActors");
  71. if (!response.error && response.addons.length > 0) {
  72. // Add one entry for each add-on.
  73. for (let addon of response.addons) {
  74. if (!addon.debuggable) {
  75. continue;
  76. }
  77. buildAddonLink(addon, parent);
  78. }
  79. }
  80. else {
  81. // Hide the section when there are no add-ons
  82. parent.previousElementSibling.remove();
  83. parent.remove();
  84. }
  85. response = yield gClient.listTabs();
  86. parent = document.getElementById("tabActors");
  87. // Add Global Process debugging...
  88. let globals = Cu.cloneInto(response, {});
  89. delete globals.tabs;
  90. delete globals.selected;
  91. // ...only if there are appropriate actors (a 'from' property will always
  92. // be there).
  93. // Add one entry for each open tab.
  94. for (let i = 0; i < response.tabs.length; i++) {
  95. buildTabLink(response.tabs[i], parent, i == response.selected);
  96. }
  97. let gParent = document.getElementById("globalActors");
  98. // Build the Remote Process button
  99. // If Fx<39, tab actors were used to be exposed on RootActor
  100. // but in Fx>=39, chrome is debuggable via getProcess() and ChromeActor
  101. if (globals.consoleActor || gClient.mainRoot.traits.allowChromeProcess) {
  102. let a = document.createElement("a");
  103. a.onclick = function () {
  104. if (gClient.mainRoot.traits.allowChromeProcess) {
  105. gClient.getProcess()
  106. .then(aResponse => {
  107. openToolbox(aResponse.form, true);
  108. });
  109. } else if (globals.consoleActor) {
  110. openToolbox(globals, true, "webconsole", false);
  111. }
  112. };
  113. a.title = a.textContent = L10N.getStr("mainProcess");
  114. a.className = "remote-process";
  115. a.href = "#";
  116. gParent.appendChild(a);
  117. }
  118. // Move the selected tab on top
  119. let selectedLink = parent.querySelector("a.selected");
  120. if (selectedLink) {
  121. parent.insertBefore(selectedLink, parent.firstChild);
  122. }
  123. document.body.classList.remove("connecting");
  124. document.body.classList.add("actors-mode");
  125. // Ensure the first link is focused
  126. let firstLink = parent.querySelector("a:first-of-type");
  127. if (firstLink) {
  128. firstLink.focus();
  129. }
  130. });
  131. /**
  132. * Build one button for an add-on actor.
  133. */
  134. function buildAddonLink(addon, parent) {
  135. let a = document.createElement("a");
  136. a.onclick = function () {
  137. openToolbox(addon, true, "jsdebugger", false);
  138. };
  139. a.textContent = addon.name;
  140. a.title = addon.id;
  141. a.href = "#";
  142. parent.appendChild(a);
  143. }
  144. /**
  145. * Build one button for a tab actor.
  146. */
  147. function buildTabLink(tab, parent, selected) {
  148. let a = document.createElement("a");
  149. a.onclick = function () {
  150. openToolbox(tab);
  151. };
  152. a.textContent = tab.title;
  153. a.title = tab.url;
  154. if (!a.textContent) {
  155. a.textContent = tab.url;
  156. }
  157. a.href = "#";
  158. if (selected) {
  159. a.classList.add("selected");
  160. }
  161. parent.appendChild(a);
  162. }
  163. /**
  164. * An error occured. Let's show it and return to the first screen.
  165. */
  166. function showError(type) {
  167. document.body.className = "error";
  168. let activeError = document.querySelector(".error-message.active");
  169. if (activeError) {
  170. activeError.classList.remove("active");
  171. }
  172. activeError = document.querySelector(".error-" + type);
  173. if (activeError) {
  174. activeError.classList.add("active");
  175. }
  176. }
  177. /**
  178. * Connection timeout.
  179. */
  180. function handleConnectionTimeout() {
  181. showError("timeout");
  182. }
  183. /**
  184. * The user clicked on one of the buttons.
  185. * Opens the toolbox.
  186. */
  187. function openToolbox(form, chrome = false, tool = "webconsole", isTabActor) {
  188. let options = {
  189. form: form,
  190. client: gClient,
  191. chrome: chrome,
  192. isTabActor: isTabActor
  193. };
  194. TargetFactory.forRemoteTab(options).then((target) => {
  195. let hostType = Toolbox.HostType.WINDOW;
  196. gDevTools.showToolbox(target, tool, hostType).then((toolbox) => {
  197. toolbox.once("destroyed", function () {
  198. gClient.close();
  199. });
  200. }, console.error.bind(console));
  201. window.close();
  202. }, console.error.bind(console));
  203. }