Mypal/devtools/client/framework/connect/connect.js
2021-02-04 16:48:36 +02:00

236 lines
6.6 KiB
JavaScript

/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
var Cu = Components.utils;
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
var Services = require("Services");
var {gDevTools} = require("devtools/client/framework/devtools");
var {TargetFactory} = require("devtools/client/framework/target");
var {Toolbox} = require("devtools/client/framework/toolbox");
var {DebuggerClient} = require("devtools/shared/client/main");
var {Task} = require("devtools/shared/task");
var {LocalizationHelper} = require("devtools/shared/l10n");
var L10N = new LocalizationHelper("devtools/client/locales/connection-screen.properties");
var gClient;
var gConnectionTimeout;
/**
* Once DOM is ready, we prefil the host/port inputs with
* pref-stored values.
*/
window.addEventListener("DOMContentLoaded", function onDOMReady() {
window.removeEventListener("DOMContentLoaded", onDOMReady, true);
let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
if (host) {
document.getElementById("host").value = host;
}
if (port) {
document.getElementById("port").value = port;
}
let form = document.querySelector("#connection-form form");
form.addEventListener("submit", function () {
window.submit().catch(e => {
console.error(e);
// Bug 921850: catch rare exception from DebuggerClient.socketConnect
showError("unexpected");
});
});
}, true);
/**
* Called when the "connect" button is clicked.
*/
var submit = Task.async(function* () {
// Show the "connecting" screen
document.body.classList.add("connecting");
let host = document.getElementById("host").value;
let port = document.getElementById("port").value;
// Save the host/port values
try {
Services.prefs.setCharPref("devtools.debugger.remote-host", host);
Services.prefs.setIntPref("devtools.debugger.remote-port", port);
} catch (e) {
// Fails in e10s mode, but not a critical feature.
}
// Initiate the connection
let transport = yield DebuggerClient.socketConnect({ host, port });
gClient = new DebuggerClient(transport);
let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
gConnectionTimeout = setTimeout(handleConnectionTimeout, delay);
let response = yield gClient.connect();
yield onConnectionReady(...response);
});
/**
* Connection is ready. List actors and build buttons.
*/
var onConnectionReady = Task.async(function* ([aType, aTraits]) {
clearTimeout(gConnectionTimeout);
let response = yield gClient.listAddons();
let parent = document.getElementById("addonActors");
if (!response.error && response.addons.length > 0) {
// Add one entry for each add-on.
for (let addon of response.addons) {
if (!addon.debuggable) {
continue;
}
buildAddonLink(addon, parent);
}
}
else {
// Hide the section when there are no add-ons
parent.previousElementSibling.remove();
parent.remove();
}
response = yield gClient.listTabs();
parent = document.getElementById("tabActors");
// Add Global Process debugging...
let globals = Cu.cloneInto(response, {});
delete globals.tabs;
delete globals.selected;
// ...only if there are appropriate actors (a 'from' property will always
// be there).
// Add one entry for each open tab.
for (let i = 0; i < response.tabs.length; i++) {
buildTabLink(response.tabs[i], parent, i == response.selected);
}
let gParent = document.getElementById("globalActors");
// Build the Remote Process button
// If Fx<39, tab actors were used to be exposed on RootActor
// but in Fx>=39, chrome is debuggable via getProcess() and ChromeActor
if (globals.consoleActor || gClient.mainRoot.traits.allowChromeProcess) {
let a = document.createElement("a");
a.onclick = function () {
if (gClient.mainRoot.traits.allowChromeProcess) {
gClient.getProcess()
.then(aResponse => {
openToolbox(aResponse.form, true);
});
} else if (globals.consoleActor) {
openToolbox(globals, true, "webconsole", false);
}
};
a.title = a.textContent = L10N.getStr("mainProcess");
a.className = "remote-process";
a.href = "#";
gParent.appendChild(a);
}
// Move the selected tab on top
let selectedLink = parent.querySelector("a.selected");
if (selectedLink) {
parent.insertBefore(selectedLink, parent.firstChild);
}
document.body.classList.remove("connecting");
document.body.classList.add("actors-mode");
// Ensure the first link is focused
let firstLink = parent.querySelector("a:first-of-type");
if (firstLink) {
firstLink.focus();
}
});
/**
* Build one button for an add-on actor.
*/
function buildAddonLink(addon, parent) {
let a = document.createElement("a");
a.onclick = function () {
openToolbox(addon, true, "jsdebugger", false);
};
a.textContent = addon.name;
a.title = addon.id;
a.href = "#";
parent.appendChild(a);
}
/**
* Build one button for a tab actor.
*/
function buildTabLink(tab, parent, selected) {
let a = document.createElement("a");
a.onclick = function () {
openToolbox(tab);
};
a.textContent = tab.title;
a.title = tab.url;
if (!a.textContent) {
a.textContent = tab.url;
}
a.href = "#";
if (selected) {
a.classList.add("selected");
}
parent.appendChild(a);
}
/**
* An error occured. Let's show it and return to the first screen.
*/
function showError(type) {
document.body.className = "error";
let activeError = document.querySelector(".error-message.active");
if (activeError) {
activeError.classList.remove("active");
}
activeError = document.querySelector(".error-" + type);
if (activeError) {
activeError.classList.add("active");
}
}
/**
* Connection timeout.
*/
function handleConnectionTimeout() {
showError("timeout");
}
/**
* The user clicked on one of the buttons.
* Opens the toolbox.
*/
function openToolbox(form, chrome = false, tool = "webconsole", isTabActor) {
let options = {
form: form,
client: gClient,
chrome: chrome,
isTabActor: isTabActor
};
TargetFactory.forRemoteTab(options).then((target) => {
let hostType = Toolbox.HostType.WINDOW;
gDevTools.showToolbox(target, tool, hostType).then((toolbox) => {
toolbox.once("destroyed", function () {
gClient.close();
});
}, console.error.bind(console));
window.close();
}, console.error.bind(console));
}