Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Cu = Components.utils;
6 const Ci = Components.interfaces;
7 Cu.import("resource://gre/modules/Services.jsm");
8 Cu.import("resource:///modules/devtools/gDevTools.jsm");
10 const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm")
11 const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
12 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
13 const {require} = devtools;
15 const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
16 const {getDeviceFront} = require("devtools/server/actors/device");
17 const ConnectionStore = require("devtools/app-manager/connection-store");
18 const DeviceStore = require("devtools/app-manager/device-store");
19 const simulatorsStore = require("devtools/app-manager/simulators-store");
20 const adbStore = require("devtools/app-manager/builtin-adb-store");
22 window.addEventListener("unload", function onUnload() {
23 window.removeEventListener("unload", onUnload);
24 UI.destroy();
25 });
27 let UI = {
28 init: function() {
29 this.useFloatingScrollbarsIfNeeded();
30 let connections = ConnectionManager.connections;
31 if (connections.length > 0) {
32 let hash = window.location.hash;
33 if (hash) {
34 let res = (/cid=([^&]+)/).exec(hash)
35 if (res) {
36 let [,cid] = res;
37 this.connection = connections.filter((({uid}) => uid == cid))[0];
38 }
39 }
40 if (!this.connection) {
41 // We take the first connection available.
42 this.connection = connections[0];
43 }
44 } else {
45 let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
46 let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
47 this.connection = ConnectionManager.createConnection(host, port);
48 }
50 window.location.hash = "cid=" + this.connection.uid;
51 window.parent.postMessage(JSON.stringify({name:"connection",cid:this.connection.uid}), "*");
53 this.store = Utils.mergeStores({
54 "device": new DeviceStore(this.connection),
55 "connection": new ConnectionStore(this.connection),
56 "simulators": simulatorsStore,
57 "adb": adbStore
58 });
60 let pre = document.querySelector("#logs > pre");
61 pre.textContent = this.connection.logs;
62 pre.scrollTop = pre.scrollTopMax;
63 this.connection.on(Connection.Events.NEW_LOG, this._onNewLog);
65 this.template = new Template(document.body, this.store, Utils.l10n);
66 this.template.start();
68 this._onSimulatorConnected = this._onSimulatorConnected.bind(this);
69 this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this);
70 },
72 destroy: function() {
73 this.store.destroy();
74 this.connection.off(Connection.Events.NEW_LOG, this._onNewLog);
75 this.template.destroy();
76 },
78 _onNewLog: function(event, str) {
79 let pre = document.querySelector("#logs > pre");
80 pre.textContent += "\n" + str;
81 pre.scrollTop = pre.scrollTopMax;
82 },
84 useFloatingScrollbarsIfNeeded: function() {
85 if (Services.appinfo.OS == "Darwin") {
86 return;
87 }
88 let scrollbarsUrl = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars-light.css", null, null);
89 let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
90 winUtils.loadSheet(scrollbarsUrl, winUtils.AGENT_SHEET);
91 let computedStyle = window.getComputedStyle(document.documentElement);
92 if (computedStyle) { // Force a reflow to take the new css into account
93 let display = computedStyle.display; // Save display value
94 document.documentElement.style.display = "none";
95 window.getComputedStyle(document.documentElement).display; // Flush
96 document.documentElement.style.display = display; // Restore
97 }
98 },
100 disconnect: function() {
101 this.connection.disconnect();
102 },
104 connect: function() {
105 this.connection.connect();
106 },
108 editConnectionParameters: function() {
109 document.body.classList.add("edit-connection");
110 document.querySelector("input.host").focus();
111 },
113 saveConnectionInfo: function() {
114 document.body.classList.remove("edit-connection");
115 document.querySelector("#connect-button").focus();
116 let host = document.querySelector("input.host").value;
117 let port = document.querySelector("input.port").value;
118 this.connection.port = port;
119 this.connection.host = host;
120 Services.prefs.setCharPref("devtools.debugger.remote-host", host);
121 Services.prefs.setIntPref("devtools.debugger.remote-port", port);
122 },
124 showSimulatorList: function() {
125 document.body.classList.add("show-simulators");
126 },
128 cancelShowSimulatorList: function() {
129 document.body.classList.remove("show-simulators");
130 },
132 installSimulator: function() {
133 let url = "https://developer.mozilla.org/docs/Mozilla/Firefox_OS/Using_the_App_Manager#Simulator";
134 window.open(url);
135 },
137 startSimulator: function(version) {
138 this._portBeforeSimulatorStarted = this.connection.port;
139 let port = ConnectionManager.getFreeTCPPort();
140 let simulator = Simulator.getByVersion(version);
141 if (!simulator) {
142 this.connection.log("Error: can't find simulator: " + version);
143 return;
144 }
145 if (!simulator.launch) {
146 this.connection.log("Error: invalid simulator: " + version);
147 return;
148 }
149 this.connection.log("Found simulator: " + version);
150 this.connection.log("Starting simulator...");
152 this.simulator = simulator;
153 this.simulator.launch({ port: port })
154 .then(() => {
155 this.connection.log("Simulator ready. Connecting.");
156 this.connection.port = port;
157 this.connection.host = "localhost";
158 this.connection.once("connected",
159 this._onSimulatorConnected);
160 this.connection.once("disconnected",
161 this._onSimulatorDisconnected);
162 this.connection.keepConnecting = true;
163 this.connection.connect();
164 });
165 document.body.classList.remove("show-simulators");
166 },
168 _onSimulatorConnected: function() {
169 this.connection.log("Connected to simulator.");
170 this.connection.keepConnecting = false;
172 // This doesn't change the current (successful) connection,
173 // but makes sure that when the simulator is disconnected, the
174 // connection doesn't end up with a random port number (from
175 // getFreeTCPPort).
176 this.connection.port = this._portBeforeSimulatorStarted;
177 },
179 _onSimulatorDisconnected: function() {
180 this.connection.off("connected", this._onSimulatorConnected);
181 },
183 connectToAdbDevice: function(name) {
184 let device = Devices.getByName(name);
185 device.connect().then((port) => {
186 this.connection.host = "localhost";
187 this.connection.port = port;
188 this.connect();
189 });
190 },
192 screenshot: function() {
193 this.connection.client.listTabs(
194 response => {
195 let front = getDeviceFront(this.connection.client, response);
196 front.screenshotToBlob().then(blob => {
197 let topWindow = Services.wm.getMostRecentWindow("navigator:browser");
198 let gBrowser = topWindow.gBrowser;
199 let url = topWindow.URL.createObjectURL(blob);
200 let tab = gBrowser.selectedTab = gBrowser.addTab(url);
201 tab.addEventListener("TabClose", function onTabClose() {
202 tab.removeEventListener("TabClose", onTabClose, false);
203 topWindow.URL.revokeObjectURL(url);
204 }, false);
205 }).then(null, console.error);
206 }
207 );
208 },
209 }