mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-10 21:54:47 +08:00
Move and rename files. NOAUTOREVERT=true NOPRESUBMIT=true NOTREECHECKS=true Bug: 768828 TBR=darin@chromium.org NOTRY=true Change-Id: I66d3b155808bc5bdbf237b80208e1e552bcf7f28 Reviewed-on: https://chromium-review.googlesource.com/1001153 Reviewed-by: Blink Reformat <blink-reformat@chromium.org> Commit-Queue: Blink Reformat <blink-reformat@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#549061} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 0aee4434a4dba42a42abaea9bfbc0cd196a63bc1
711 lines
25 KiB
JavaScript
711 lines
25 KiB
JavaScript
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
Devices.DevicesView = class extends UI.VBox {
|
|
constructor() {
|
|
super(true);
|
|
this.registerRequiredCSS('devices/devicesView.css');
|
|
this.contentElement.classList.add('devices-view');
|
|
|
|
const hbox = this.contentElement.createChild('div', 'hbox devices-container');
|
|
const sidebar = hbox.createChild('div', 'devices-sidebar');
|
|
sidebar.createChild('div', 'devices-view-title').createTextChild(Common.UIString('Devices'));
|
|
this._sidebarList = sidebar.createChild('div', 'devices-sidebar-list');
|
|
|
|
this._discoveryView = new Devices.DevicesView.DiscoveryView();
|
|
this._sidebarListSpacer = this._sidebarList.createChild('div', 'devices-sidebar-spacer');
|
|
this._discoveryListItem = this._sidebarList.createChild('div', 'devices-sidebar-item');
|
|
this._discoveryListItem.textContent = Common.UIString('Settings');
|
|
this._discoveryListItem.addEventListener(
|
|
'click', this._selectSidebarListItem.bind(this, this._discoveryListItem, this._discoveryView));
|
|
|
|
/** @type {!Map<string, !Devices.DevicesView.DeviceView>} */
|
|
this._viewById = new Map();
|
|
/** @type {!Array<!Adb.Device>} */
|
|
this._devices = [];
|
|
/** @type {!Map<string, !Element>} */
|
|
this._listItemById = new Map();
|
|
/** @type {?Element} */
|
|
this._selectedListItem = null;
|
|
/** @type {?UI.Widget} */
|
|
this._visibleView = null;
|
|
|
|
this._viewContainer = hbox.createChild('div', 'flex-auto vbox');
|
|
|
|
const discoveryFooter = this.contentElement.createChild('div', 'devices-footer');
|
|
this._deviceCountSpan = discoveryFooter.createChild('span');
|
|
discoveryFooter.createChild('span').textContent = Common.UIString(' Read ');
|
|
discoveryFooter.appendChild(UI.XLink.create(
|
|
'https://developers.google.com/chrome-developer-tools/docs/remote-debugging',
|
|
Common.UIString('remote debugging documentation')));
|
|
discoveryFooter.createChild('span').textContent = Common.UIString(' for more information.');
|
|
this._updateFooter();
|
|
this._selectSidebarListItem(this._discoveryListItem, this._discoveryView);
|
|
|
|
InspectorFrontendHost.events.addEventListener(
|
|
InspectorFrontendHostAPI.Events.DevicesUpdated, this._devicesUpdated, this);
|
|
InspectorFrontendHost.events.addEventListener(
|
|
InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this);
|
|
InspectorFrontendHost.events.addEventListener(
|
|
InspectorFrontendHostAPI.Events.DevicesPortForwardingStatusChanged, this._devicesPortForwardingStatusChanged,
|
|
this);
|
|
|
|
this.contentElement.tabIndex = 0;
|
|
this.setDefaultFocusedElement(this.contentElement);
|
|
}
|
|
|
|
/**
|
|
* @return {!Devices.DevicesView}
|
|
*/
|
|
static _instance() {
|
|
if (!Devices.DevicesView._instanceObject)
|
|
Devices.DevicesView._instanceObject = new Devices.DevicesView();
|
|
return Devices.DevicesView._instanceObject;
|
|
}
|
|
|
|
/**
|
|
* @param {!Element} listItem
|
|
* @param {!UI.Widget} view
|
|
*/
|
|
_selectSidebarListItem(listItem, view) {
|
|
if (this._selectedListItem === listItem)
|
|
return;
|
|
|
|
if (this._selectedListItem) {
|
|
this._selectedListItem.classList.remove('selected');
|
|
this._visibleView.detach();
|
|
}
|
|
|
|
this._visibleView = view;
|
|
this._selectedListItem = listItem;
|
|
this._visibleView.show(this._viewContainer);
|
|
this._selectedListItem.classList.add('selected');
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_devicesUpdated(event) {
|
|
this._devices =
|
|
/** @type {!Array.<!Adb.Device>} */ (event.data)
|
|
.slice()
|
|
.filter(d => d.adbSerial.toUpperCase() !== 'WEBRTC' && d.adbSerial.toUpperCase() !== 'LOCALHOST');
|
|
for (const device of this._devices) {
|
|
if (!device.adbConnected)
|
|
device.adbModel = Common.UIString('Unknown');
|
|
}
|
|
|
|
const ids = new Set();
|
|
for (const device of this._devices)
|
|
ids.add(device.id);
|
|
|
|
let selectedRemoved = false;
|
|
for (const deviceId of this._viewById.keys()) {
|
|
if (!ids.has(deviceId)) {
|
|
const listItem = /** @type {!Element} */ (this._listItemById.get(deviceId));
|
|
this._listItemById.remove(deviceId);
|
|
this._viewById.remove(deviceId);
|
|
listItem.remove();
|
|
if (listItem === this._selectedListItem)
|
|
selectedRemoved = true;
|
|
}
|
|
}
|
|
|
|
for (const device of this._devices) {
|
|
let view = this._viewById.get(device.id);
|
|
let listItem = this._listItemById.get(device.id);
|
|
|
|
if (!view) {
|
|
view = new Devices.DevicesView.DeviceView();
|
|
this._viewById.set(device.id, view);
|
|
listItem = this._createSidebarListItem(view);
|
|
this._listItemById.set(device.id, listItem);
|
|
this._sidebarList.insertBefore(listItem, this._sidebarListSpacer);
|
|
}
|
|
|
|
listItem._title.textContent = device.adbModel;
|
|
listItem._status.textContent =
|
|
device.adbConnected ? Common.UIString('Connected') : Common.UIString('Pending Authorization');
|
|
listItem.classList.toggle('device-connected', device.adbConnected);
|
|
view.update(device);
|
|
}
|
|
|
|
if (selectedRemoved)
|
|
this._selectSidebarListItem(this._discoveryListItem, this._discoveryView);
|
|
|
|
this._updateFooter();
|
|
}
|
|
|
|
/**
|
|
* @param {!UI.Widget} view
|
|
* @return {!Element}
|
|
*/
|
|
_createSidebarListItem(view) {
|
|
const listItem = createElementWithClass('div', 'devices-sidebar-item');
|
|
listItem.addEventListener('click', this._selectSidebarListItem.bind(this, listItem, view));
|
|
listItem._title = listItem.createChild('div', 'devices-sidebar-item-title');
|
|
listItem._status = listItem.createChild('div', 'devices-sidebar-item-status');
|
|
return listItem;
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_devicesDiscoveryConfigChanged(event) {
|
|
const config = /** @type {!Adb.Config} */ (event.data);
|
|
this._discoveryView.discoveryConfigChanged(config);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_devicesPortForwardingStatusChanged(event) {
|
|
const status = /** @type {!Adb.PortForwardingStatus} */ (event.data);
|
|
for (const deviceId in status) {
|
|
const view = this._viewById.get(deviceId);
|
|
if (view)
|
|
view.portForwardingStatusChanged(status[deviceId]);
|
|
}
|
|
for (const deviceId of this._viewById.keys()) {
|
|
const view = this._viewById.get(deviceId);
|
|
if (view && !(deviceId in status))
|
|
view.portForwardingStatusChanged({ports: {}, browserId: ''});
|
|
}
|
|
}
|
|
|
|
_updateFooter() {
|
|
this._deviceCountSpan.textContent = !this._devices.length ?
|
|
Common.UIString('No devices detected.') :
|
|
this._devices.length === 1 ? Common.UIString('1 device detected.') :
|
|
Common.UIString('%d devices detected.', this._devices.length);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
wasShown() {
|
|
super.wasShown();
|
|
InspectorFrontendHost.setDevicesUpdatesEnabled(true);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
willHide() {
|
|
super.willHide();
|
|
InspectorFrontendHost.setDevicesUpdatesEnabled(false);
|
|
}
|
|
};
|
|
|
|
Devices.DevicesView.DiscoveryView = class extends UI.VBox {
|
|
constructor() {
|
|
super();
|
|
this.setMinimumSize(100, 100);
|
|
this.element.classList.add('discovery-view');
|
|
|
|
this.contentElement.createChild('div', 'hbox device-text-row').createChild('div', 'view-title').textContent =
|
|
Common.UIString('Settings');
|
|
|
|
const discoverUsbDevicesCheckbox = UI.CheckboxLabel.create(Common.UIString('Discover USB devices'));
|
|
discoverUsbDevicesCheckbox.classList.add('usb-checkbox');
|
|
this.element.appendChild(discoverUsbDevicesCheckbox);
|
|
this._discoverUsbDevicesCheckbox = discoverUsbDevicesCheckbox.checkboxElement;
|
|
this._discoverUsbDevicesCheckbox.addEventListener('click', () => {
|
|
this._config.discoverUsbDevices = this._discoverUsbDevicesCheckbox.checked;
|
|
InspectorFrontendHost.setDevicesDiscoveryConfig(this._config);
|
|
}, false);
|
|
|
|
const help = this.element.createChild('div', 'discovery-help');
|
|
help.createChild('span').textContent = Common.UIString('Need help? Read Chrome ');
|
|
help.appendChild(UI.XLink.create(
|
|
'https://developers.google.com/chrome-developer-tools/docs/remote-debugging',
|
|
Common.UIString('remote debugging documentation.')));
|
|
|
|
/** @type {!Adb.Config} */
|
|
this._config;
|
|
|
|
this._portForwardingView = new Devices.DevicesView.PortForwardingView((enabled, config) => {
|
|
this._config.portForwardingEnabled = enabled;
|
|
this._config.portForwardingConfig = {};
|
|
for (const rule of config)
|
|
this._config.portForwardingConfig[rule.port] = rule.address;
|
|
InspectorFrontendHost.setDevicesDiscoveryConfig(this._config);
|
|
});
|
|
this._portForwardingView.show(this.element);
|
|
}
|
|
|
|
/**
|
|
* @param {!Adb.Config} config
|
|
*/
|
|
discoveryConfigChanged(config) {
|
|
this._config = config;
|
|
this._discoverUsbDevicesCheckbox.checked = config.discoverUsbDevices;
|
|
this._portForwardingView.discoveryConfigChanged(config.portForwardingEnabled, config.portForwardingConfig);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @implements {UI.ListWidget.Delegate<Adb.PortForwardingRule>}
|
|
*/
|
|
Devices.DevicesView.PortForwardingView = class extends UI.VBox {
|
|
/**
|
|
* @param {function(boolean, !Array<!Adb.PortForwardingRule>)} callback
|
|
*/
|
|
constructor(callback) {
|
|
super();
|
|
this._callback = callback;
|
|
this.element.classList.add('port-forwarding-view');
|
|
|
|
const portForwardingHeader = this.element.createChild('div', 'port-forwarding-header');
|
|
const portForwardingEnabledCheckbox = UI.CheckboxLabel.create(Common.UIString('Port forwarding'));
|
|
portForwardingEnabledCheckbox.classList.add('port-forwarding-checkbox');
|
|
portForwardingHeader.appendChild(portForwardingEnabledCheckbox);
|
|
this._portForwardingEnabledCheckbox = portForwardingEnabledCheckbox.checkboxElement;
|
|
this._portForwardingEnabledCheckbox.addEventListener('click', this._update.bind(this), false);
|
|
|
|
const portForwardingFooter = this.element.createChild('div', 'port-forwarding-footer');
|
|
portForwardingFooter.createChild('span').textContent = Common.UIString(
|
|
'Define the listening port on your device that maps to a port accessible from your development machine. ');
|
|
portForwardingFooter.appendChild(UI.XLink.create(
|
|
'https://developer.chrome.com/devtools/docs/remote-debugging#port-forwarding', Common.UIString('Learn more')));
|
|
|
|
/** @type {!UI.ListWidget<!Adb.PortForwardingRule>} */
|
|
this._list = new UI.ListWidget(this);
|
|
this._list.registerRequiredCSS('devices/devicesView.css');
|
|
this._list.element.classList.add('port-forwarding-list');
|
|
const placeholder = createElementWithClass('div', 'port-forwarding-list-empty');
|
|
placeholder.textContent = Common.UIString('No rules');
|
|
this._list.setEmptyPlaceholder(placeholder);
|
|
this._list.show(this.element);
|
|
/** @type {?UI.ListWidget.Editor<!Adb.PortForwardingRule>} */
|
|
this._editor = null;
|
|
|
|
this.element.appendChild(
|
|
UI.createTextButton(Common.UIString('Add rule'), this._addRuleButtonClicked.bind(this), 'add-rule-button'));
|
|
|
|
/** @type {!Array<!Adb.PortForwardingRule>} */
|
|
this._portForwardingConfig = [];
|
|
}
|
|
|
|
_update() {
|
|
this._callback.call(null, this._portForwardingEnabledCheckbox.checked, this._portForwardingConfig);
|
|
}
|
|
|
|
_addRuleButtonClicked() {
|
|
this._list.addNewItem(this._portForwardingConfig.length, {port: '', address: ''});
|
|
}
|
|
|
|
/**
|
|
* @param {boolean} portForwardingEnabled
|
|
* @param {!Adb.PortForwardingConfig} portForwardingConfig
|
|
*/
|
|
discoveryConfigChanged(portForwardingEnabled, portForwardingConfig) {
|
|
this._portForwardingEnabledCheckbox.checked = portForwardingEnabled;
|
|
this._portForwardingConfig = [];
|
|
this._list.clear();
|
|
for (const key of Object.keys(portForwardingConfig)) {
|
|
const rule = /** @type {!Adb.PortForwardingRule} */ ({port: key, address: portForwardingConfig[key]});
|
|
this._portForwardingConfig.push(rule);
|
|
this._list.appendItem(rule, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @param {boolean} editable
|
|
* @return {!Element}
|
|
*/
|
|
renderItem(rule, editable) {
|
|
const element = createElementWithClass('div', 'port-forwarding-list-item');
|
|
const port = element.createChild('div', 'port-forwarding-value port-forwarding-port');
|
|
port.createChild('span', 'port-localhost').textContent = Common.UIString('localhost:');
|
|
port.createTextChild(rule.port);
|
|
element.createChild('div', 'port-forwarding-separator');
|
|
element.createChild('div', 'port-forwarding-value').textContent = rule.address;
|
|
return element;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @param {number} index
|
|
*/
|
|
removeItemRequested(rule, index) {
|
|
this._portForwardingConfig.splice(index, 1);
|
|
this._list.removeItem(index);
|
|
this._update();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @param {!UI.ListWidget.Editor} editor
|
|
* @param {boolean} isNew
|
|
*/
|
|
commitEdit(rule, editor, isNew) {
|
|
rule.port = editor.control('port').value.trim();
|
|
rule.address = editor.control('address').value.trim();
|
|
if (isNew)
|
|
this._portForwardingConfig.push(rule);
|
|
this._update();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @return {!UI.ListWidget.Editor}
|
|
*/
|
|
beginEdit(rule) {
|
|
const editor = this._createEditor();
|
|
editor.control('port').value = rule.port;
|
|
editor.control('address').value = rule.address;
|
|
return editor;
|
|
}
|
|
|
|
/**
|
|
* @return {!UI.ListWidget.Editor<!Adb.PortForwardingRule>}
|
|
*/
|
|
_createEditor() {
|
|
if (this._editor)
|
|
return this._editor;
|
|
|
|
const editor = new UI.ListWidget.Editor();
|
|
this._editor = editor;
|
|
const content = editor.contentElement();
|
|
const fields = content.createChild('div', 'port-forwarding-edit-row');
|
|
fields.createChild('div', 'port-forwarding-value port-forwarding-port')
|
|
.appendChild(editor.createInput('port', 'text', 'Device port (3333)', portValidator.bind(this)));
|
|
fields.createChild('div', 'port-forwarding-separator port-forwarding-separator-invisible');
|
|
fields.createChild('div', 'port-forwarding-value')
|
|
.appendChild(editor.createInput('address', 'text', 'Local address (dev.example.corp:3333)', addressValidator));
|
|
return editor;
|
|
|
|
/**
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @param {number} index
|
|
* @param {!HTMLInputElement|!HTMLSelectElement} input
|
|
* @this {Devices.DevicesView.PortForwardingView}
|
|
* @return {boolean}
|
|
*/
|
|
function portValidator(rule, index, input) {
|
|
const value = input.value.trim();
|
|
const match = value.match(/^(\d+)$/);
|
|
if (!match)
|
|
return false;
|
|
const port = parseInt(match[1], 10);
|
|
if (port < 1024 || port > 65535)
|
|
return false;
|
|
for (let i = 0; i < this._portForwardingConfig.length; ++i) {
|
|
if (i !== index && this._portForwardingConfig[i].port === value)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param {!Adb.PortForwardingRule} rule
|
|
* @param {number} index
|
|
* @param {!HTMLInputElement|!HTMLSelectElement} input
|
|
* @return {boolean}
|
|
*/
|
|
function addressValidator(rule, index, input) {
|
|
const match = input.value.trim().match(/^([a-zA-Z0-9\.\-_]+):(\d+)$/);
|
|
if (!match)
|
|
return false;
|
|
const port = parseInt(match[2], 10);
|
|
return port <= 65535;
|
|
}
|
|
}
|
|
};
|
|
|
|
Devices.DevicesView.DeviceView = class extends UI.VBox {
|
|
constructor() {
|
|
super();
|
|
this.setMinimumSize(100, 100);
|
|
this.contentElement.classList.add('device-view');
|
|
|
|
const topRow = this.contentElement.createChild('div', 'hbox device-text-row');
|
|
this._deviceTitle = topRow.createChild('div', 'view-title');
|
|
this._deviceSerial = topRow.createChild('div', 'device-serial');
|
|
this._portStatus = this.contentElement.createChild('div', 'device-port-status hidden');
|
|
|
|
this._deviceOffline = this.contentElement.createChild('div');
|
|
this._deviceOffline.textContent =
|
|
Common.UIString('Pending authentication: please accept debugging session on the device.');
|
|
|
|
this._noBrowsers = this.contentElement.createChild('div');
|
|
this._noBrowsers.textContent = Common.UIString('No browsers detected.');
|
|
|
|
this._browsers = this.contentElement.createChild('div', 'device-browser-list vbox');
|
|
|
|
/** @type {!Map<string, !Devices.DevicesView.BrowserSection>} */
|
|
this._browserById = new Map();
|
|
|
|
/** @type {?string} */
|
|
this._cachedPortStatus = null;
|
|
/** @type {?Adb.Device} */
|
|
this._device = null;
|
|
}
|
|
|
|
/**
|
|
* @param {!Adb.Device} device
|
|
*/
|
|
update(device) {
|
|
if (!this._device || this._device.adbModel !== device.adbModel)
|
|
this._deviceTitle.textContent = device.adbModel;
|
|
|
|
if (!this._device || this._device.adbSerial !== device.adbSerial)
|
|
this._deviceSerial.textContent = '#' + device.adbSerial;
|
|
|
|
this._deviceOffline.classList.toggle('hidden', device.adbConnected);
|
|
this._noBrowsers.classList.toggle('hidden', !device.adbConnected || !!device.browsers.length);
|
|
this._browsers.classList.toggle('hidden', !device.adbConnected || !device.browsers.length);
|
|
|
|
const browserIds = new Set();
|
|
for (const browser of device.browsers)
|
|
browserIds.add(browser.id);
|
|
|
|
for (const browserId of this._browserById.keys()) {
|
|
if (!browserIds.has(browserId)) {
|
|
this._browserById.get(browserId).element.remove();
|
|
this._browserById.remove(browserId);
|
|
}
|
|
}
|
|
|
|
for (const browser of device.browsers) {
|
|
let section = this._browserById.get(browser.id);
|
|
if (!section) {
|
|
section = this._createBrowserSection();
|
|
this._browserById.set(browser.id, section);
|
|
this._browsers.appendChild(section.element);
|
|
}
|
|
this._updateBrowserSection(section, browser);
|
|
}
|
|
|
|
this._device = device;
|
|
}
|
|
|
|
/**
|
|
* @return {!Devices.DevicesView.BrowserSection}
|
|
*/
|
|
_createBrowserSection() {
|
|
const element = createElementWithClass('div', 'vbox flex-none');
|
|
const topRow = element.createChild('div', '');
|
|
const title = topRow.createChild('div', 'device-browser-title');
|
|
|
|
const newTabRow = element.createChild('div', 'device-browser-new-tab');
|
|
newTabRow.createChild('div', '').textContent = Common.UIString('New tab:');
|
|
const newTabInput = UI.createInput('', 'text');
|
|
newTabRow.appendChild(newTabInput);
|
|
newTabInput.placeholder = Common.UIString('Enter URL');
|
|
newTabInput.addEventListener('keydown', newTabKeyDown, false);
|
|
const newTabButton = UI.createTextButton(Common.UIString('Open'), openNewTab);
|
|
newTabRow.appendChild(newTabButton);
|
|
|
|
const pages = element.createChild('div', 'device-page-list vbox');
|
|
|
|
const viewMore = element.createChild('div', 'device-view-more');
|
|
viewMore.addEventListener('click', viewMoreClick, false);
|
|
updateViewMoreTitle();
|
|
|
|
const section = {
|
|
browser: null,
|
|
element: element,
|
|
title: title,
|
|
pages: pages,
|
|
viewMore: viewMore,
|
|
newTab: newTabRow,
|
|
pageSections: new Map()
|
|
};
|
|
return section;
|
|
|
|
function viewMoreClick() {
|
|
pages.classList.toggle('device-view-more-toggled');
|
|
updateViewMoreTitle();
|
|
}
|
|
|
|
function updateViewMoreTitle() {
|
|
viewMore.textContent = pages.classList.contains('device-view-more-toggled') ?
|
|
Common.UIString('View less tabs\u2026') :
|
|
Common.UIString('View more tabs\u2026');
|
|
}
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
*/
|
|
function newTabKeyDown(event) {
|
|
if (event.key === 'Enter') {
|
|
event.consume(true);
|
|
openNewTab();
|
|
}
|
|
}
|
|
|
|
function openNewTab() {
|
|
if (section.browser) {
|
|
InspectorFrontendHost.openRemotePage(section.browser.id, newTabInput.value.trim() || 'about:blank');
|
|
newTabInput.value = '';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Devices.DevicesView.BrowserSection} section
|
|
* @param {!Adb.Browser} browser
|
|
*/
|
|
_updateBrowserSection(section, browser) {
|
|
if (!section.browser || section.browser.adbBrowserName !== browser.adbBrowserName ||
|
|
section.browser.adbBrowserVersion !== browser.adbBrowserVersion) {
|
|
if (browser.adbBrowserVersion)
|
|
section.title.textContent = String.sprintf('%s (%s)', browser.adbBrowserName, browser.adbBrowserVersion);
|
|
else
|
|
section.title.textContent = browser.adbBrowserName;
|
|
}
|
|
|
|
const pageIds = new Set();
|
|
for (const page of browser.pages)
|
|
pageIds.add(page.id);
|
|
|
|
for (const pageId of section.pageSections.keys()) {
|
|
if (!pageIds.has(pageId)) {
|
|
section.pageSections.get(pageId).element.remove();
|
|
section.pageSections.remove(pageId);
|
|
}
|
|
}
|
|
|
|
for (let index = 0; index < browser.pages.length; ++index) {
|
|
const page = browser.pages[index];
|
|
let pageSection = section.pageSections.get(page.id);
|
|
if (!pageSection) {
|
|
pageSection = this._createPageSection();
|
|
section.pageSections.set(page.id, pageSection);
|
|
section.pages.appendChild(pageSection.element);
|
|
}
|
|
this._updatePageSection(pageSection, page);
|
|
if (!index && section.pages.firstChild !== pageSection.element)
|
|
section.pages.insertBefore(pageSection.element, section.pages.firstChild);
|
|
}
|
|
|
|
const kViewMoreCount = 3;
|
|
for (let index = 0, element = section.pages.firstChild; element; element = element.nextSibling, ++index)
|
|
element.classList.toggle('device-view-more-page', index >= kViewMoreCount);
|
|
section.viewMore.classList.toggle('device-needs-view-more', browser.pages.length > kViewMoreCount);
|
|
section.newTab.classList.toggle('hidden', !browser.adbBrowserChromeVersion);
|
|
section.browser = browser;
|
|
}
|
|
|
|
/**
|
|
* @return {!Devices.DevicesView.PageSection}
|
|
*/
|
|
_createPageSection() {
|
|
const element = createElementWithClass('div', 'vbox');
|
|
|
|
const titleRow = element.createChild('div', 'device-page-title-row');
|
|
const title = titleRow.createChild('div', 'device-page-title');
|
|
const inspect = UI.createTextButton(Common.UIString('Inspect'), doAction.bind(null, 'inspect'));
|
|
titleRow.appendChild(inspect);
|
|
|
|
const toolbar = new UI.Toolbar('');
|
|
toolbar.appendToolbarItem(new UI.ToolbarMenuButton(appendActions));
|
|
titleRow.appendChild(toolbar.element);
|
|
|
|
const url = element.createChild('div', 'device-page-url');
|
|
const section = {page: null, element: element, title: title, url: url, inspect: inspect};
|
|
return section;
|
|
|
|
/**
|
|
* @param {!UI.ContextMenu} contextMenu
|
|
*/
|
|
function appendActions(contextMenu) {
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Reload'), doAction.bind(null, 'reload'));
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Focus'), doAction.bind(null, 'activate'));
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Close'), doAction.bind(null, 'close'));
|
|
}
|
|
|
|
/**
|
|
* @param {string} action
|
|
*/
|
|
function doAction(action) {
|
|
if (section.page)
|
|
InspectorFrontendHost.performActionOnRemotePage(section.page.id, action);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Devices.DevicesView.PageSection} section
|
|
* @param {!Adb.Page} page
|
|
*/
|
|
_updatePageSection(section, page) {
|
|
if (!section.page || section.page.name !== page.name) {
|
|
section.title.textContent = page.name;
|
|
section.title.title = page.name;
|
|
}
|
|
if (!section.page || section.page.url !== page.url) {
|
|
section.url.textContent = '';
|
|
section.url.appendChild(UI.XLink.create(page.url));
|
|
}
|
|
section.inspect.disabled = page.attached;
|
|
|
|
section.page = page;
|
|
}
|
|
|
|
/**
|
|
* @param {!Adb.DevicePortForwardingStatus} status
|
|
*/
|
|
portForwardingStatusChanged(status) {
|
|
const json = JSON.stringify(status);
|
|
if (json === this._cachedPortStatus)
|
|
return;
|
|
this._cachedPortStatus = json;
|
|
|
|
this._portStatus.removeChildren();
|
|
this._portStatus.createChild('div', 'device-port-status-text').textContent = Common.UIString('Port Forwarding:');
|
|
const connected = [];
|
|
const transient = [];
|
|
const error = [];
|
|
let empty = true;
|
|
for (const port in status.ports) {
|
|
if (!status.ports.hasOwnProperty(port))
|
|
continue;
|
|
|
|
empty = false;
|
|
const portStatus = status.ports[port];
|
|
const portNumber = createElementWithClass('div', 'device-view-port-number monospace');
|
|
portNumber.textContent = ':' + port;
|
|
if (portStatus >= 0)
|
|
this._portStatus.appendChild(portNumber);
|
|
else
|
|
this._portStatus.insertBefore(portNumber, this._portStatus.firstChild);
|
|
|
|
const portIcon = createElementWithClass('div', 'device-view-port-icon');
|
|
if (portStatus >= 0) {
|
|
connected.push(port);
|
|
} else if (portStatus === -1 || portStatus === -2) {
|
|
portIcon.classList.add('device-view-port-icon-transient');
|
|
transient.push(port);
|
|
} else if (portStatus < 0) {
|
|
portIcon.classList.add('device-view-port-icon-error');
|
|
error.push(port);
|
|
}
|
|
this._portStatus.insertBefore(portIcon, portNumber);
|
|
}
|
|
|
|
const title = [];
|
|
if (connected.length)
|
|
title.push(Common.UIString('Connected: %s', connected.join(', ')));
|
|
if (transient.length)
|
|
title.push(Common.UIString('Transient: %s', transient.join(', ')));
|
|
if (error.length)
|
|
title.push(Common.UIString('Error: %s', error.join(', ')));
|
|
this._portStatus.title = title.join('; ');
|
|
this._portStatus.classList.toggle('hidden', empty);
|
|
}
|
|
};
|
|
|
|
/** @typedef {!{browser: ?Adb.Browser, element: !Element, title: !Element, pages: !Element, viewMore: !Element, newTab: !Element, pageSections: !Map<string, !Devices.DevicesView.PageSection>}} */
|
|
Devices.DevicesView.BrowserSection;
|
|
|
|
/** @typedef {!{page: ?Adb.Page, element: !Element, title: !Element, url: !Element, inspect: !Element}} */
|
|
Devices.DevicesView.PageSection;
|