browser/devtools/framework/connect/connect.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/framework/connect/connect.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,231 @@
     1.4 +/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +"use strict";
    1.11 +
    1.12 +const Cu = Components.utils;
    1.13 +Cu.import('resource://gre/modules/XPCOMUtils.jsm');
    1.14 +Cu.import("resource://gre/modules/Services.jsm");
    1.15 +Cu.import("resource://gre/modules/Task.jsm");
    1.16 +Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
    1.17 +let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
    1.18 +let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
    1.19 +let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
    1.20 +
    1.21 +let gClient;
    1.22 +let gConnectionTimeout;
    1.23 +
    1.24 +XPCOMUtils.defineLazyGetter(window, 'l10n', function () {
    1.25 +  return Services.strings.createBundle('chrome://browser/locale/devtools/connection-screen.properties');
    1.26 +});
    1.27 +
    1.28 +/**
    1.29 + * Once DOM is ready, we prefil the host/port inputs with
    1.30 + * pref-stored values.
    1.31 + */
    1.32 +window.addEventListener("DOMContentLoaded", function onDOMReady() {
    1.33 +  window.removeEventListener("DOMContentLoaded", onDOMReady, true);
    1.34 +  let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
    1.35 +  let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
    1.36 +
    1.37 +  if (host) {
    1.38 +    document.getElementById("host").value = host;
    1.39 +  }
    1.40 +
    1.41 +  if (port) {
    1.42 +    document.getElementById("port").value = port;
    1.43 +  }
    1.44 +
    1.45 +  let form = document.querySelector("#connection-form form");
    1.46 +  form.addEventListener("submit", function() {
    1.47 +    window.submit();
    1.48 +  });
    1.49 +}, true);
    1.50 +
    1.51 +/**
    1.52 + * Called when the "connect" button is clicked.
    1.53 + */
    1.54 +function submit() {
    1.55 +  // Show the "connecting" screen
    1.56 +  document.body.classList.add("connecting");
    1.57 +
    1.58 +  // Save the host/port values
    1.59 +  let host = document.getElementById("host").value;
    1.60 +  Services.prefs.setCharPref("devtools.debugger.remote-host", host);
    1.61 +
    1.62 +  let port = document.getElementById("port").value;
    1.63 +  Services.prefs.setIntPref("devtools.debugger.remote-port", port);
    1.64 +
    1.65 +  // Initiate the connection
    1.66 +  let transport;
    1.67 +  try {
    1.68 +    transport = debuggerSocketConnect(host, port);
    1.69 +  } catch(e) {
    1.70 +    // Bug 921850: catch rare exception from debuggerSocketConnect
    1.71 +    showError("unexpected");
    1.72 +    return;
    1.73 +  }
    1.74 +  gClient = new DebuggerClient(transport);
    1.75 +  let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
    1.76 +  gConnectionTimeout = setTimeout(handleConnectionTimeout, delay);
    1.77 +  gClient.connect(onConnectionReady);
    1.78 +}
    1.79 +
    1.80 +/**
    1.81 + * Connection is ready. List actors and build buttons.
    1.82 + */
    1.83 +let onConnectionReady = Task.async(function*(aType, aTraits) {
    1.84 +  clearTimeout(gConnectionTimeout);
    1.85 +
    1.86 +  let deferred = promise.defer();
    1.87 +  gClient.listAddons(deferred.resolve);
    1.88 +  let response = yield deferred.promise;
    1.89 +
    1.90 +  let parent = document.getElementById("addonActors")
    1.91 +  if (!response.error && response.addons.length > 0) {
    1.92 +    // Add one entry for each add-on.
    1.93 +    for (let addon of response.addons) {
    1.94 +      if (!addon.debuggable) {
    1.95 +        continue;
    1.96 +      }
    1.97 +      buildAddonLink(addon, parent);
    1.98 +    }
    1.99 +  }
   1.100 +  else {
   1.101 +    // Hide the section when there are no add-ons
   1.102 +    parent.previousElementSibling.remove();
   1.103 +    parent.remove();
   1.104 +  }
   1.105 +
   1.106 +  deferred = promise.defer();
   1.107 +  gClient.listTabs(deferred.resolve);
   1.108 +  response = yield deferred.promise;
   1.109 +
   1.110 +  parent = document.getElementById("tabActors");
   1.111 +
   1.112 +  // Add Global Process debugging...
   1.113 +  let globals = JSON.parse(JSON.stringify(response));
   1.114 +  delete globals.tabs;
   1.115 +  delete globals.selected;
   1.116 +  // ...only if there are appropriate actors (a 'from' property will always
   1.117 +  // be there).
   1.118 +
   1.119 +  // Add one entry for each open tab.
   1.120 +  for (let i = 0; i < response.tabs.length; i++) {
   1.121 +    buildTabLink(response.tabs[i], parent, i == response.selected);
   1.122 +  }
   1.123 +
   1.124 +  let gParent = document.getElementById("globalActors");
   1.125 +
   1.126 +  // Build the Remote Process button
   1.127 +  if (Object.keys(globals).length > 1) {
   1.128 +    let a = document.createElement("a");
   1.129 +    a.onclick = function() {
   1.130 +      openToolbox(globals, true);
   1.131 +
   1.132 +    }
   1.133 +    a.title = a.textContent = window.l10n.GetStringFromName("mainProcess");
   1.134 +    a.className = "remote-process";
   1.135 +    a.href = "#";
   1.136 +    gParent.appendChild(a);
   1.137 +  }
   1.138 +  // Move the selected tab on top
   1.139 +  let selectedLink = parent.querySelector("a.selected");
   1.140 +  if (selectedLink) {
   1.141 +    parent.insertBefore(selectedLink, parent.firstChild);
   1.142 +  }
   1.143 +
   1.144 +  document.body.classList.remove("connecting");
   1.145 +  document.body.classList.add("actors-mode");
   1.146 +
   1.147 +  // Ensure the first link is focused
   1.148 +  let firstLink = parent.querySelector("a:first-of-type");
   1.149 +  if (firstLink) {
   1.150 +    firstLink.focus();
   1.151 +  }
   1.152 +});
   1.153 +
   1.154 +/**
   1.155 + * Build one button for an add-on actor.
   1.156 + */
   1.157 +function buildAddonLink(addon, parent) {
   1.158 +  let a = document.createElement("a");
   1.159 +  a.onclick = function() {
   1.160 +    openToolbox({ addonActor: addon.actor, title: addon.name }, true, "jsdebugger");
   1.161 +  }
   1.162 +
   1.163 +  a.textContent = addon.name;
   1.164 +  a.title = addon.id;
   1.165 +  a.href = "#";
   1.166 +
   1.167 +  parent.appendChild(a);
   1.168 +}
   1.169 +
   1.170 +/**
   1.171 + * Build one button for a tab actor.
   1.172 + */
   1.173 +function buildTabLink(tab, parent, selected) {
   1.174 +  let a = document.createElement("a");
   1.175 +  a.onclick = function() {
   1.176 +    openToolbox(tab);
   1.177 +  }
   1.178 +
   1.179 +  a.textContent = tab.title;
   1.180 +  a.title = tab.url;
   1.181 +  if (!a.textContent) {
   1.182 +    a.textContent = tab.url;
   1.183 +  }
   1.184 +  a.href = "#";
   1.185 +
   1.186 +  if (selected) {
   1.187 +    a.classList.add("selected");
   1.188 +  }
   1.189 +
   1.190 +  parent.appendChild(a);
   1.191 +}
   1.192 +
   1.193 +/**
   1.194 + * An error occured. Let's show it and return to the first screen.
   1.195 + */
   1.196 +function showError(type) {
   1.197 +  document.body.className = "error";
   1.198 +  let activeError = document.querySelector(".error-message.active");
   1.199 +  if (activeError) {
   1.200 +    activeError.classList.remove("active");
   1.201 +  }
   1.202 +  activeError = document.querySelector(".error-" + type);
   1.203 +  if (activeError) {
   1.204 +    activeError.classList.add("active");
   1.205 +  }
   1.206 +}
   1.207 +
   1.208 +/**
   1.209 + * Connection timeout.
   1.210 + */
   1.211 +function handleConnectionTimeout() {
   1.212 +  showError("timeout");
   1.213 +}
   1.214 +
   1.215 +/**
   1.216 + * The user clicked on one of the buttons.
   1.217 + * Opens the toolbox.
   1.218 + */
   1.219 +function openToolbox(form, chrome=false, tool="webconsole") {
   1.220 +  let options = {
   1.221 +    form: form,
   1.222 +    client: gClient,
   1.223 +    chrome: chrome
   1.224 +  };
   1.225 +  devtools.TargetFactory.forRemoteTab(options).then((target) => {
   1.226 +    let hostType = devtools.Toolbox.HostType.WINDOW;
   1.227 +    gDevTools.showToolbox(target, tool, hostType).then((toolbox) => {
   1.228 +      toolbox.once("destroyed", function() {
   1.229 +        gClient.close();
   1.230 +      });
   1.231 +    });
   1.232 +    window.close();
   1.233 +  });
   1.234 +}

mercurial