Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / devices / DevicesView.js
blob722527cd697402c8768c1461c4b9d0b7d2cafa70
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * @constructor
7  * @extends {WebInspector.VBox}
8  */
9 WebInspector.DevicesView = function()
11     WebInspector.VBox.call(this, true);
12     this.registerRequiredCSS("devices/devicesView.css");
14     this._tabbedPane = new WebInspector.TabbedPane();
15     var titleElement = createElementWithClass("div", "devices-view-title");
16     titleElement.createTextChild(WebInspector.UIString("Devices"));
18     this._tabbedPane.insertBeforeTabStrip(titleElement);
19     this._tabbedPane.setShrinkableTabs(false);
20     this._tabbedPane.setVerticalTabLayout(true);
22     this._discoveryView = new WebInspector.DevicesView.DiscoveryView();
23     this._tabbedPane.appendTab("discovery", WebInspector.UIString("Settings"), this._discoveryView);
25     /** @type {!Map<string, !WebInspector.DevicesView.DeviceView>} */
26     this._viewById = new Map();
27     /** @type {!Array<!Adb.Device>} */
28     this._devices = [];
30     this._tabbedPane.show(this.contentElement);
32     var discoveryFooter = this.contentElement.createChild("div", "devices-footer");
33     this._deviceCountSpan = discoveryFooter.createChild("span");
34     discoveryFooter.createChild("span").textContent = WebInspector.UIString(" Read ");
35     discoveryFooter.appendChild(WebInspector.linkifyURLAsNode("https://developers.google.com/chrome-developer-tools/docs/remote-debugging", WebInspector.UIString("remote debugging documentation"), undefined, true));
36     discoveryFooter.createChild("span").textContent = WebInspector.UIString(" for more information.");
37     this._updateFooter();
39     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DevicesUpdated, this._devicesUpdated, this);
40     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this);
43 WebInspector.DevicesView.prototype = {
44     /**
45      * @param {!WebInspector.Event} event
46      */
47     _devicesUpdated: function(event)
48     {
49         this._devices = /** @type {!Array.<!Adb.Device>} */ (event.data).slice();
51         var ids = new Set();
52         for (var device of this._devices)
53             ids.add(device.id);
55         for (var deviceId of this._viewById.keys()) {
56             if (!ids.has(deviceId)) {
57                 this._tabbedPane.closeTab(deviceId);
58                 this._viewById.remove(deviceId);
59             }
60         }
62         for (var device of this._devices) {
63             var view = this._viewById.get(device.id);
64             if (!view) {
65                 view = new WebInspector.DevicesView.DeviceView();
66                 this._viewById.set(device.id, view);
67                 this._tabbedPane.appendTab(device.id, device.adbModel, view);
68             }
69             this._tabbedPane.changeTabTitle(device.id, device.adbModel);
70             view.update(device);
71         }
73         this._updateFooter();
74     },
76     /**
77      * @param {!WebInspector.Event} event
78      */
79     _devicesDiscoveryConfigChanged: function(event)
80     {
81         var discoverUsbDevices = /** @type {boolean} */ (event.data["discoverUsbDevices"]);
82         var portForwardingEnabled = /** @type {boolean} */ (event.data["portForwardingEnabled"]);
83         var portForwardingConfig = /** @type {!Adb.PortForwardingConfig} */ (event.data["portForwardingConfig"]);
84         this._discoveryView.discoveryConfigChanged(discoverUsbDevices, portForwardingEnabled, portForwardingConfig);
85     },
87     _updateFooter: function()
88     {
89         this._deviceCountSpan.textContent =
90             !this._devices.length ? WebInspector.UIString("No devices detected.") :
91                 this._devices.length === 1 ? WebInspector.UIString("1 device detected.") : WebInspector.UIString("%d devices detected.", this._devices.length);
92     },
94     /**
95      * @override
96      */
97     wasShown: function()
98     {
99         WebInspector.PanelWithSidebar.prototype.wasShown.call(this);
100         InspectorFrontendHost.setDevicesUpdatesEnabled(true);
101     },
103     /**
104      * @override
105      */
106     willHide: function()
107     {
108         WebInspector.PanelWithSidebar.prototype.wasShown.call(this);
109         InspectorFrontendHost.setDevicesUpdatesEnabled(false);
110     },
112     __proto__: WebInspector.VBox.prototype
116  * @return {!WebInspector.DevicesView}
117  */
118 WebInspector.DevicesView._instance = function()
120     if (!WebInspector.DevicesView._instanceObject)
121         WebInspector.DevicesView._instanceObject = new WebInspector.DevicesView();
122     return WebInspector.DevicesView._instanceObject;
127  * @constructor
128  * @extends {WebInspector.VBox}
129  */
130 WebInspector.DevicesView.DiscoveryView = function()
132     WebInspector.VBox.call(this);
133     this.setMinimumSize(100, 100);
134     this.element.classList.add("discovery-view");
136     this.contentElement.createChild("div", "hbox device-text-row").createChild("div", "view-title").textContent = WebInspector.UIString("Settings");
138     var discoverUsbDevicesCheckbox = createCheckboxLabel(WebInspector.UIString("Discover USB devices"));
139     discoverUsbDevicesCheckbox.classList.add("usb-checkbox");
140     this.element.appendChild(discoverUsbDevicesCheckbox);
141     this._discoverUsbDevicesCheckbox = discoverUsbDevicesCheckbox.checkboxElement;
142     this._discoverUsbDevicesCheckbox.addEventListener("click", this._updateDiscoveryConfig.bind(this), false);
144     var portForwardingEnabledCheckbox = createCheckboxLabel(WebInspector.UIString("Port forwarding"));
145     portForwardingEnabledCheckbox.classList.add("port-forwarding-checkbox");
146     this.element.appendChild(portForwardingEnabledCheckbox);
147     this._portForwardingEnabledCheckbox = portForwardingEnabledCheckbox.checkboxElement;
148     this._portForwardingEnabledCheckbox.addEventListener("click", this._updateDiscoveryConfig.bind(this), false);
150     this._portForwardingList = this.element.createChild("div", "port-forwarding-list");
152     var portForwardingFooter = this.element.createChild("div", "port-forwarding-footer");
153     portForwardingFooter.createChild("span").textContent = WebInspector.UIString("Define the listening port on your device that maps to a port accessible from your development machine. ");
154     portForwardingFooter.appendChild(WebInspector.linkifyURLAsNode("https://developer.chrome.com/devtools/docs/remote-debugging#reverse-port-forwarding", WebInspector.UIString("Learn more"), undefined, true));
157 WebInspector.DevicesView.DiscoveryView.prototype = {
158     /**
159      * @param {boolean} discoverUsbDevices
160      * @param {boolean} portForwardingEnabled
161      * @param {!Adb.PortForwardingConfig} portForwardingConfig
162      */
163     discoveryConfigChanged: function(discoverUsbDevices, portForwardingEnabled, portForwardingConfig)
164     {
165         this._discoverUsbDevicesCheckbox.checked = discoverUsbDevices;
166         this._portForwardingEnabledCheckbox.checked = portForwardingEnabled;
167     },
169     _updateDiscoveryConfig: function()
170     {
171         InspectorFrontendHost.setDevicesDiscoveryConfig(this._discoverUsbDevicesCheckbox.checked, this._portForwardingEnabledCheckbox.checked, {"8080": "localhost:8080"});
172     },
174     __proto__: WebInspector.VBox.prototype
179  * @constructor
180  * @extends {WebInspector.VBox}
181  */
182 WebInspector.DevicesView.DeviceView = function()
184     WebInspector.VBox.call(this);
185     this.setMinimumSize(100, 100);
186     this.contentElement.classList.add("device-view");
188     var topRow = this.contentElement.createChild("div", "hbox device-text-row");
189     this._deviceTitle = topRow.createChild("div", "view-title");
190     this._deviceSerial = topRow.createChild("div", "device-serial");
192     this._deviceOffline = this.contentElement.createChild("div");
193     this._deviceOffline.textContent = WebInspector.UIString("Pending authentication: please accept debugging session on the device.");
195     this._noBrowsers = this.contentElement.createChild("div");
196     this._noBrowsers.textContent = WebInspector.UIString("No browsers detected.");
198     this._browsers = this.contentElement.createChild("div", "device-browser-list vbox");
200     /** @type {!Map<string, !WebInspector.DevicesView.BrowserSection>} */
201     this._browserById = new Map();
203     this._device = null;
206 /** @typedef {!{browser: ?Adb.Browser, element: !Element, title: !Element, pages: !Element, pageSections: !Map<string, !WebInspector.DevicesView.PageSection>}} */
207 WebInspector.DevicesView.BrowserSection;
209 /** @typedef {!{page: ?Adb.Page, element: !Element, title: !Element, url: !Element, inspect: !Element}} */
210 WebInspector.DevicesView.PageSection;
212 WebInspector.DevicesView.DeviceView.prototype = {
213     /**
214      * @param {!Adb.Device} device
215      */
216     update: function(device)
217     {
218         if (!this._device || this._device.adbModel !== device.adbModel)
219             this._deviceTitle.textContent = device.adbModel;
221         if (!this._device || this._device.adbSerial !== device.adbSerial)
222             this._deviceSerial.textContent = "#" + device.adbSerial;
224         this._deviceOffline.classList.toggle("hidden", device.adbConnected);
225         this._noBrowsers.classList.toggle("hidden", !device.adbConnected || device.browsers.length);
226         this._browsers.classList.toggle("hidden", !device.adbConnected || !device.browsers.length);
228         var browserIds = new Set();
229         for (var browser of device.browsers)
230             browserIds.add(browser.id);
232         for (var browserId of this._browserById.keys()) {
233             if (!browserIds.has(browserId)) {
234                 this._browserById.get(browserId).element.remove();
235                 this._browserById.remove(browserId);
236             }
237         }
239         for (var browser of device.browsers) {
240             var section = this._browserById.get(browser.id);
241             if (!section) {
242                 section = this._createBrowserSection();
243                 this._browserById.set(browser.id, section);
244                 this._browsers.appendChild(section.element);
245             }
246             this._updateBrowserSection(section, browser);
247         }
249         this._device = device;
250     },
252     /**
253      * @return {!WebInspector.DevicesView.BrowserSection}
254      */
255     _createBrowserSection: function()
256     {
257         var element = createElementWithClass("div", "vbox flex-none");
258         var topRow = element.createChild("div", "");
259         var title = topRow.createChild("div", "device-browser-title");
260         var pages = element.createChild("div", "device-page-list vbox");
261         return {browser: null, element: element, title: title, pages: pages, pageSections: new Map()};
262     },
264     /**
265      * @param {!WebInspector.DevicesView.BrowserSection} section
266      * @param {!Adb.Browser} browser
267      */
268     _updateBrowserSection: function(section, browser)
269     {
270         if (!section.browser || section.browser.adbBrowserName !== browser.adbBrowserName || section.browser.adbBrowserVersion !== browser.adbBrowserVersion) {
271             if (browser.adbBrowserVersion)
272                 section.title.textContent = String.sprintf("%s (%s)", browser.adbBrowserName, browser.adbBrowserVersion);
273             else
274                 section.title.textContent = browser.adbBrowserName;
275         }
277         var pageIds = new Set();
278         for (var page of browser.pages)
279             pageIds.add(page.id);
281         for (var pageId of section.pageSections.keys()) {
282             if (!pageIds.has(pageId)) {
283                 section.pageSections.get(pageId).element.remove();
284                 section.pageSections.remove(pageId);
285             }
286         }
288         for (var page of browser.pages) {
289             var pageSection = section.pageSections.get(page.id);
290             if (!pageSection) {
291                 pageSection = this._createPageSection();
292                 section.pageSections.set(page.id, pageSection);
293                 section.pages.appendChild(pageSection.element);
294             }
295             this._updatePageSection(pageSection, page);
296         }
298         section.browser = browser;
299     },
301     /**
302      * @return {!WebInspector.DevicesView.PageSection}
303      */
304     _createPageSection: function()
305     {
306         var element = createElementWithClass("div", "vbox");
307         var title = element.createChild("div", "device-page-title");
308         var url = element.createChild("div", "device-page-url");
309         var actions = element.createChild("div", "device-page-actions hbox");
310         var section = /** @type {!WebInspector.DevicesView.PageSection} */ ({page: null, element: element, title: title, url: url});
311         section.inspect = this._createAction(actions, WebInspector.UIString("inspect"), "inspect", section);
312         this._createAction(actions, WebInspector.UIString("reload"), "reload", section);
313         this._createAction(actions, WebInspector.UIString("activate"), "activate", section);
314         this._createAction(actions, WebInspector.UIString("close"), "close", section);
315         return section;
316     },
318     /**
319      * @param {!Element} container
320      * @param {string} title
321      * @param {string} action
322      * @param {!WebInspector.DevicesView.PageSection} section
323      * @return {!Element}
324      */
325     _createAction: function(container, title, action, section)
326     {
327         var element = container.createChild("div", "link");
328         element.textContent = title;
329         element.addEventListener("click", onClick, false);
330         return element;
332         function onClick()
333         {
334             if (section.page)
335                 InspectorFrontendHost.performActionOnRemotePage(section.page.id, action);
336         }
337     },
339     /**
340      * @param {!WebInspector.DevicesView.PageSection} section
341      * @param {!Adb.Page} page
342      */
343     _updatePageSection: function(section, page)
344     {
345         if (!section.page || section.page.name !== page.name)
346             section.title.textContent = page.name;
347         if (!section.page || section.page.url !== page.url) {
348             section.url.textContent = "";
349             section.url.appendChild(WebInspector.linkifyURLAsNode(page.url, undefined, undefined, true));
350         }
351         section.inspect.disabled = page.adbAttachedForeign;
353         section.page = page;
354     },
356     __proto__: WebInspector.VBox.prototype