236 lines
6.6 KiB
JavaScript
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));
|
|
}
|