Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| index 2cfed689bcb276bd3ed0b734ab604dd455bf2104..53c33741ae1fbd81eda702971bbfafb6aeb6520e 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| @@ -9,12 +9,14 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| constructor() { |
| super(); |
| - /** @type {!Map.<!WebInspector.DebuggerModel, !WebInspector.UIList.Item>} */ |
| - this._debuggerModelToListItems = new Map(); |
| - /** @type {!Map.<!WebInspector.UIList.Item, !WebInspector.Target>} */ |
| - this._listItemsToTargets = new Map(); |
| /** @type {?WebInspector.UIList.Item} */ |
| this._selectedListItem = null; |
| + /** @type {!Map<!WebInspector.PendingTarget, !WebInspector.UIList.Item>} */ |
| + this._pendingToListItem = new Map(); |
| + /** @type {!Map<!WebInspector.Target, !WebInspector.PendingTarget>} */ |
| + this._targetToPending = new Map(); |
| + /** @type {?WebInspector.PendingTarget} */ |
| + this._mainTargetPending = null; |
| this.threadList = new WebInspector.UIList(); |
| this.threadList.show(this.element); |
| WebInspector.targetManager.addModelListener( |
| @@ -29,28 +31,113 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._targetChanged, this); |
| WebInspector.targetManager.addEventListener( |
| WebInspector.TargetManager.Events.NameChanged, this._targetNameChanged, this); |
| + WebInspector.targetManager.addModelListener(WebInspector.SubTargetsManager, WebInspector.SubTargetsManager.Events.SubTargetAdded, this._subTargetAdded, this); |
| + WebInspector.targetManager.addModelListener(WebInspector.SubTargetsManager, WebInspector.SubTargetsManager.Events.SubTargetRemoved, this._subTargetRemoved, this); |
| + WebInspector.targetManager.addModelListener(WebInspector.SubTargetsManager, WebInspector.SubTargetsManager.Events.SubTargetAttached, this._subTargetAdded, this); |
| + WebInspector.targetManager.addModelListener(WebInspector.SubTargetsManager, WebInspector.SubTargetsManager.Events.SubTargetDetached, this._targetDetached, this); |
| WebInspector.targetManager.observeTargets(this); |
| + |
| + var pendingTargets = []; |
| + for (var target of WebInspector.targetManager.targets(WebInspector.Target.Capability.Target)) |
| + pendingTargets = pendingTargets.concat(WebInspector.SubTargetsManager.fromTarget(target).pendingTargets()); |
| + |
| + pendingTargets |
| + .sort(WebInspector.ThreadsSidebarPane._subTargetsComparator) |
| + .forEach(pendingTarget => this._addListItem(pendingTarget)); |
| } |
| /** |
| - * @override |
| - * @param {!WebInspector.Target} target |
| + * @return {boolean} |
| */ |
| - targetAdded(target) { |
| - var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| - if (!debuggerModel) |
| + static shouldBeShown() { |
| + if (WebInspector.targetManager.targets(WebInspector.Target.Capability.JS).length > 1) |
| + return true; |
| + for (var target of WebInspector.targetManager.targets(WebInspector.Target.Capability.Target)) { |
| + var pendingTargets = WebInspector.SubTargetsManager.fromTarget(target).pendingTargets(); |
| + if (pendingTargets.some(pendingTarget => pendingTarget.canConnect())) |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + /** |
| + * Sorts show tha connected targets appear first, followed by pending subtargets. |
| + * |
| + * @param {!WebInspector.PendingTarget} c1 |
| + * @param {!WebInspector.PendingTarget} c2 |
| + * @return {number} |
| + */ |
| + static _subTargetsComparator(c1, c2) |
| + { |
| + var t1 = c1.target(); |
| + var t2 = c2.target(); |
| + var name1 = t1 ? t1.name() : c1.name(); |
| + var name2 = t2 ? t2.name() : c2.name(); |
| + if (!!t1 === !!t2) { // Either both are connected or disconnected |
| + return name1.toLowerCase().localeCompare(name2.toLowerCase()); |
| + } else if (t1) { |
| + return -1; |
| + } |
| + return 1; |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _subTargetAdded(event) { |
| + this._addListItem(/** @type {!WebInspector.PendingTarget} */ (event.data)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _subTargetRemoved(event) { |
| + this._removeListItem(/** @type {!WebInspector.PendingTarget} */ (event.data)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _targetDetached(event) { |
| + this._targetRemoved(/** @type {!WebInspector.PendingTarget} */ (event.data)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| + */ |
| + _addListItem(pendingTarget) { |
| + var target = pendingTarget.target(); |
| + if (!pendingTarget.canConnect() && !(target && target.hasJSCapability())) |
| return; |
| - var listItem = new WebInspector.UIList.Item(this._titleForTarget(target), ''); |
| - listItem.element.addEventListener('click', this._onListItemClick.bind(this, listItem), false); |
| + var listItem = this._pendingToListItem.get(pendingTarget); |
| + if (!listItem) { |
| + listItem = new WebInspector.UIList.Item('', '', false); |
| + listItem[WebInspector.ThreadsSidebarPane._pendingTargetSymbol] = pendingTarget; |
| + listItem[WebInspector.ThreadsSidebarPane._targetSymbol] = target; |
| + this._pendingToListItem.set(pendingTarget, listItem); |
| + this.threadList.addItem(listItem); |
| + listItem.element.addEventListener('click', this._onListItemClick.bind(this, listItem), false); |
| + } |
| + this._updateListItem(listItem, pendingTarget); |
| + this._updateDebuggerState(pendingTarget); |
| var currentTarget = WebInspector.context.flavor(WebInspector.Target); |
| if (currentTarget === target) |
| this._selectListItem(listItem); |
| + if (target) |
| + this._targetToPending.set(target, pendingTarget); |
| + } |
| - this._debuggerModelToListItems.set(debuggerModel, listItem); |
| - this._listItemsToTargets.set(listItem, target); |
| - this.threadList.addItem(listItem); |
| - this._updateDebuggerState(debuggerModel); |
| + /** |
| + * @override |
| + * @param {!WebInspector.Target} target |
| + */ |
| + targetAdded(target) { |
| + if (target !== WebInspector.targetManager.mainTarget()) |
| + return; |
| + console.assert(!this._mainTargetPending); |
| + this._mainTargetPending = new WebInspector.ThreadsSidebarPane.MainTargetConnection(target); |
| + this._addListItem(this._mainTargetPending); |
| } |
| /** |
| @@ -58,14 +145,14 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| * @param {!WebInspector.Target} target |
| */ |
| targetRemoved(target) { |
| - var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| - if (!debuggerModel) |
| - return; |
| - var listItem = this._debuggerModelToListItems.remove(debuggerModel); |
| - if (listItem) { |
| - this._listItemsToTargets.remove(listItem); |
| - this.threadList.removeItem(listItem); |
| + var subtargetManager = WebInspector.SubTargetsManager.fromTarget(target); |
| + var pendingTargets = subtargetManager ? subtargetManager.pendingTargets() : []; |
| + for (var pendingTarget of pendingTargets) { |
| + if (pendingTarget.target()) |
| + this._targetRemoved(pendingTarget); |
| } |
| + if (target === WebInspector.targetManager.mainTarget() && this._mainTargetPending) |
| + this._targetRemoved(this._mainTargetPending); |
|
dgozman
2016/11/03 21:21:30
this._mainTargetPending = null;
eostroukhov
2016/11/03 22:44:50
Thanks! Missed that one.
|
| } |
| /** |
| @@ -75,7 +162,7 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| var target = /** @type {!WebInspector.Target} */ (event.data); |
| var listItem = this._listItemForTarget(target); |
| if (listItem) |
| - listItem.setTitle(this._titleForTarget(target)); |
| + listItem.setTitle(this._titleForSubtarget(this._targetToPending.get(target))); |
| } |
| /** |
| @@ -92,17 +179,18 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| * @return {?WebInspector.UIList.Item} |
| */ |
| _listItemForTarget(target) { |
| - var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| - if (!debuggerModel) |
| - return null; |
| - return this._debuggerModelToListItems.get(debuggerModel) || null; |
| + var pendingTarget = this._targetToPending.get(target); |
| + return this._pendingToListItem.get(pendingTarget) || null; |
| } |
| /** |
| - * @param {!WebInspector.Target} target |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| * @return {string} |
| */ |
| - _titleForTarget(target) { |
| + _titleForSubtarget(pendingTarget) { |
|
dgozman
2016/11/03 21:21:30
_titleForPending
eostroukhov
2016/11/03 22:44:50
Done.
|
| + var target = pendingTarget.target(); |
| + if (!target) |
| + return pendingTarget.name(); |
| var executionContext = target.runtimeModel.defaultExecutionContext(); |
| return executionContext && executionContext.label() ? executionContext.label() : target.name(); |
| } |
| @@ -112,7 +200,8 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| */ |
| _onDebuggerStateChanged(event) { |
| var debuggerModel = /** @type {!WebInspector.DebuggerModel} */ (event.target); |
| - this._updateDebuggerState(debuggerModel); |
| + var pendingTarget = this._targetToPending.get(debuggerModel.target()); |
| + this._updateDebuggerState(pendingTarget); |
| } |
| /** |
| @@ -122,19 +211,21 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| var executionContext = /** @type {!WebInspector.ExecutionContext} */ (event.data); |
| if (!executionContext.isDefault) |
| return; |
| - var debuggerModel = |
| - /** @type {!WebInspector.DebuggerModel} */ (WebInspector.DebuggerModel.fromTarget(executionContext.target())); |
| - var listItem = this._debuggerModelToListItems.get(debuggerModel); |
| + var pendingTarget = this._targetToPending.get(executionContext.target()); |
| + var listItem = this._pendingToListItem.get(pendingTarget); |
| if (listItem && executionContext.label()) |
| listItem.setTitle(executionContext.label()); |
| } |
| /** |
| - * @param {!WebInspector.DebuggerModel} debuggerModel |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| */ |
| - _updateDebuggerState(debuggerModel) { |
| - var listItem = this._debuggerModelToListItems.get(debuggerModel); |
| - listItem.setSubtitle(WebInspector.UIString(debuggerModel.isPaused() ? 'paused' : '')); |
| + _updateDebuggerState(pendingTarget) { |
| + var listItem = this._pendingToListItem.get(pendingTarget); |
| + var target = pendingTarget.target(); |
| + var debuggerModel = target && WebInspector.DebuggerModel.fromTarget(target); |
| + var isPaused = !!debuggerModel && debuggerModel.isPaused(); |
| + listItem.setSubtitle(WebInspector.UIString(isPaused ? 'paused' : '')); |
| } |
| /** |
| @@ -155,7 +246,106 @@ WebInspector.ThreadsSidebarPane = class extends WebInspector.VBox { |
| * @param {!WebInspector.UIList.Item} listItem |
| */ |
| _onListItemClick(listItem) { |
| - WebInspector.context.setFlavor(WebInspector.Target, this._listItemsToTargets.get(listItem)); |
| + var pendingTarget = listItem[WebInspector.ThreadsSidebarPane._pendingTargetSymbol]; |
| + var target = pendingTarget.target(); |
| + if (!target) |
| + return; |
| + WebInspector.context.setFlavor(WebInspector.Target, target); |
| listItem.element.scrollIntoViewIfNeeded(); |
| } |
| + |
| + /** |
| + * @param {!WebInspector.UIList.Item} item |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| + */ |
| + _updateListItem(item, pendingTarget) { |
| + item.setTitle(this._titleForSubtarget(pendingTarget)); |
| + item.setSubtitle(''); |
| + var target = pendingTarget.target(); |
| + var action = null; |
| + var actionLabel = null; |
| + if (pendingTarget.canConnect()) { |
| + actionLabel = target ? 'Disconnect' : 'Connect'; |
| + action = this._toggleConnection.bind(this, pendingTarget); |
| + } |
| + item.setAction(actionLabel, action); |
| + item.setDimmed(!target); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.Target} target |
| + */ |
| + _selectNewlyAddedTarget(target) { |
| + setTimeout(() => WebInspector.context.setFlavor(WebInspector.Target, target)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| + */ |
| + _toggleConnection(pendingTarget) { |
| + var target = pendingTarget.target(); |
| + if (target) |
| + pendingTarget.disconnect(); |
| + else |
| + pendingTarget.connect().then(target => this._selectNewlyAddedTarget(target)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| + */ |
| + _targetRemoved(pendingTarget) { |
| + var item = this._pendingToListItem.get(pendingTarget); |
| + if (!item) // Not all targets are represented in the UI. |
| + return; |
| + var target = item[WebInspector.ThreadsSidebarPane._targetSymbol]; |
| + item[WebInspector.ThreadsSidebarPane._targetSymbol] = null; |
| + this._targetToPending.remove(target); |
| + if (pendingTarget.canConnect()) |
| + this._updateListItem(item, pendingTarget); |
| + else |
| + this._removeListItem(pendingTarget); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.PendingTarget} pendingTarget |
| + */ |
| + _removeListItem(pendingTarget) { |
| + var item = this._pendingToListItem.get(pendingTarget); |
| + if (!item) |
| + return; |
| + this.threadList.removeItem(item); |
| + this._pendingToListItem.delete(pendingTarget); |
| + } |
| +}; |
| + |
| +WebInspector.ThreadsSidebarPane._pendingTargetSymbol = Symbol('_subtargetSymbol'); |
| +WebInspector.ThreadsSidebarPane._targetSymbol = Symbol('_targetSymbol'); |
| + |
| +/** |
| + * @unrestricted |
| + */ |
| +WebInspector.ThreadsSidebarPane.MainTargetConnection = class extends WebInspector.PendingTarget { |
| + /** |
| + * @param {!WebInspector.Target} target |
| + */ |
| + constructor(target) { |
| + super('main-target-list-node-' + target.id(), target.title, false, null); |
| + this._target = target; |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {!WebInspector.Target} |
| + */ |
| + target() { |
| + return this._target; |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {string} |
| + */ |
| + name() { |
| + return this._target.name(); |
| + } |
| }; |