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 7008dbf052056ffe07953cb56175a55e0d1596d8..3ca2258ac179e219b678e0f47f058959f3deb02d 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js |
| @@ -11,12 +11,17 @@ WebInspector.ThreadsSidebarPane = function() |
| { |
| WebInspector.VBox.call(this); |
| - /** @type {!Map.<!WebInspector.DebuggerModel, !WebInspector.UIList.Item>} */ |
| + /** @type {!Map<!WebInspector.DebuggerModel, !WebInspector.UIList.Item>} */ |
| this._debuggerModelToListItems = new Map(); |
| - /** @type {!Map.<!WebInspector.UIList.Item, !WebInspector.Target>} */ |
| + /** @type {!Map<!WebInspector.UIList.Item, !WebInspector.Target>} */ |
| this._listItemsToTargets = new Map(); |
| /** @type {?WebInspector.UIList.Item} */ |
| this._selectedListItem = null; |
| + /** @type {!Map<!WebInspector.PendingSubTarget, !WebInspector.UIList.Item>} */ |
| + this._subtargetToListItem = new Map(); |
| + /** @type {?WebInspector.PendingSubTarget} */ |
| + this._mainTargetConnection = null; |
| + |
| this.threadList = new WebInspector.UIList(); |
| this.threadList.show(this.element); |
| WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerPaused, this._onDebuggerStateChanged, this); |
| @@ -24,46 +29,107 @@ WebInspector.ThreadsSidebarPane = function() |
| WebInspector.targetManager.addModelListener(WebInspector.RuntimeModel, WebInspector.RuntimeModel.Events.ExecutionContextChanged, this._onExecutionContextChanged, this); |
| 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 subtargets = []; |
| + for (var target of WebInspector.targetManager.targets(WebInspector.Target.Capability.Target)) |
| + subtargets = subtargets.concat(WebInspector.SubTargetsManager.fromTarget(target).subTargets()); |
| + |
| + subtargets |
| + .sort(WebInspector.ThreadsSidebarPane._subTargetsComparator) |
| + .forEach(subtarget => this._addListItem(subtarget)); |
| }; |
| WebInspector.ThreadsSidebarPane.prototype = { |
| /** |
| - * @override |
| - * @param {!WebInspector.Target} target |
| + * @param {!WebInspector.Event} event |
| */ |
| - targetAdded: function(target) |
| + _subTargetAdded: function(event) |
| { |
| + this._addListItem(/** @type {!WebInspector.PendingSubTarget} */ (event.data)); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _subTargetRemoved: function(event) |
| + { |
| + this._removeListItem(/** @type {!WebInspector.PendingSubTarget} */ (event.data)); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Event} event |
| + */ |
| + _targetDetached: function(event) |
| + { |
| + this._targetRemoved(/** @type {!WebInspector.PendingSubTarget} */ (event.data)); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.PendingSubTarget} subTarget |
| + */ |
| + _addListItem: function(subTarget) |
| + { |
| + var target = subTarget.target(); |
| + if (!subTarget.isRemote() && !(target && target.hasJSCapability())) |
| + return; |
| + |
| + var listItem = this._subtargetToListItem.get(subTarget); |
| + if (!listItem) { |
| + listItem = new WebInspector.UIList.Item("", "", false); |
| + this._subtargetToListItem.set(subTarget, listItem); |
| + this.threadList.addItem(listItem); |
| + listItem.element.addEventListener("click", this._onListItemClick.bind(this, listItem), false); |
| + } |
| + if (!target) { |
| + this._setupConnectionItem(listItem, subTarget); |
| + return; |
| + } |
| var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| if (!debuggerModel) |
| return; |
| - |
| - var listItem = new WebInspector.UIList.Item(this._titleForTarget(target), ""); |
| - listItem.element.addEventListener("click", this._onListItemClick.bind(this, listItem), false); |
| var currentTarget = WebInspector.context.flavor(WebInspector.Target); |
| if (currentTarget === target) |
| this._selectListItem(listItem); |
| this._debuggerModelToListItems.set(debuggerModel, listItem); |
| this._listItemsToTargets.set(listItem, target); |
| - this.threadList.addItem(listItem); |
| this._updateDebuggerState(debuggerModel); |
| + this._setupTargetItem(listItem, target, subTarget); |
| }, |
| /** |
| * @override |
| * @param {!WebInspector.Target} target |
| */ |
| - targetRemoved: function(target) |
| + targetAdded: function(target) |
| { |
| - var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| - if (!debuggerModel) |
| + if (target !== WebInspector.targetManager.mainTarget()) |
| return; |
| - var listItem = this._debuggerModelToListItems.remove(debuggerModel); |
| - if (listItem) { |
| - this._listItemsToTargets.remove(listItem); |
| - this.threadList.removeItem(listItem); |
| + if (this._mainTargetConnection) |
| + this._targetRemoved(this._mainTargetConnection); |
| + this._mainTargetConnection = new WebInspector.ThreadsSidebarPane.MainTargetConnection(target); |
| + this._addListItem(this._mainTargetConnection); |
| + }, |
| + |
| + /** |
| + * @override |
| + * @param {!WebInspector.Target} target |
| + */ |
| + targetRemoved: function(target) |
| + { |
| + var subtargetManager = WebInspector.SubTargetsManager.fromTarget(target); |
| + var subtargets = subtargetManager ? subtargetManager.subTargets() : []; |
| + for (var subTarget of subtargets) { |
| + if (subTarget.target()) |
| + this._targetRemoved(subTarget); |
| } |
| + if (target === WebInspector.targetManager.mainTarget() && this._mainTargetConnection) |
| + this._targetRemoved(this._mainTargetConnection); |
| }, |
| /** |
| @@ -161,10 +227,155 @@ WebInspector.ThreadsSidebarPane.prototype = { |
| */ |
| _onListItemClick: function(listItem) |
| { |
| - WebInspector.context.setFlavor(WebInspector.Target, this._listItemsToTargets.get(listItem)); |
| + var target = this._listItemsToTargets.get(listItem); |
| + if (!target) |
| + return; |
| + WebInspector.context.setFlavor(WebInspector.Target, target); |
| listItem.element.scrollIntoViewIfNeeded(); |
| }, |
| + /** |
| + * @param {!WebInspector.UIList.Item} item |
| + * @param {!WebInspector.Target} target |
| + * @param {?WebInspector.PendingSubTarget} subtarget |
| + */ |
| + _setupTargetItem: function(item, target, subtarget) |
| + { |
| + this._listItemsToTargets.set(item, target); |
| + item.setTitle(this._titleForTarget(target)); |
| + item.setSubtitle(""); |
| + item.setDimmed(false); |
| + if (subtarget && subtarget.isRemote()) |
| + item.setAction("Disconnect", () => subtarget.disconnect()); |
| + else |
| + item.setAction(null, null); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.UIList.Item} item |
| + * @param {!WebInspector.PendingSubTarget} subtarget |
| + */ |
| + _setupConnectionItem: function(item, subtarget) |
|
dgozman
2016/11/01 22:07:39
If we'd have pending.isConnected(), we can merge t
eostroukhov
2016/11/02 21:55:53
Done.
|
| + { |
| + item.setTitle(subtarget.name()); |
| + item.setSubtitle(""); |
| + if (subtarget.isRemote()) |
| + item.setAction("Connect", (() => subtarget.connect().then(target => WebInspector.context.setFlavor(WebInspector.Target, target)))); |
| + else |
| + item.setAction(null, null); |
| + item.setDimmed(true); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.PendingSubTarget} subtarget |
| + */ |
| + _targetRemoved: function(subtarget) |
| + { |
| + var item = this._subtargetToListItem.get(subtarget); |
| + var target = this._listItemsToTargets.remove(item); |
| + if (!target) |
| + return; |
| + var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| + console.assert(debuggerModel); |
| + this._debuggerModelToListItems.remove(debuggerModel); |
| + this._listItemsToTargets.remove(item); |
| + if (subtarget.isRemote()) |
| + this._setupConnectionItem(item, subtarget); |
| + else |
| + this._removeListItem(subtarget); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.PendingSubTarget} subtarget |
| + */ |
| + _removeListItem: function(subtarget) |
| + { |
| + var item = this._subtargetToListItem.get(subtarget); |
| + if (!item) |
| + return; |
| + this.threadList.removeItem(item); |
| + this._subtargetToListItem.delete(subtarget); |
| + this._listItemsToTargets.delete(item); |
| + }, |
| __proto__: WebInspector.VBox.prototype |
| }; |
| + |
| +/** |
| + * @return {boolean} |
| + */ |
| +WebInspector.ThreadsSidebarPane.isShown = function() |
| +{ |
| + if (WebInspector.targetManager.targets(WebInspector.Target.Capability.JS).length > 1) |
| + return true; |
| + for (var target of WebInspector.targetManager.targets(WebInspector.Target.Capability.Target)) |
| + { |
| + if (WebInspector.SubTargetsManager.fromTarget(target).subTargets().some(subTarget => subTarget.isRemote())) |
| + return true; |
| + } |
| + return false; |
| +}; |
| + |
| + |
| +/** |
| + * @constructor |
| + * @extends {WebInspector.PendingSubTarget} |
| + */ |
| +WebInspector.ThreadsSidebarPane.MainTargetConnection = function(target) |
| +{ |
| + WebInspector.PendingSubTarget.call(this, "main-target-list-node-" + target.id(), target.title, false, null); |
| + |
| + this._target = target; |
| +}; |
| + |
| +WebInspector.ThreadsSidebarPane.MainTargetConnection.prototype = { |
| + /** |
| + * @override |
| + * @return {!WebInspector.Target} |
| + */ |
| + target: function() |
| + { |
| + return this._target; |
| + }, |
| + |
| + /** |
| + * @override |
| + * @return {string} |
| + */ |
| + name: function() |
| + { |
| + return this._target.name(); |
| + }, |
| + |
| + /** |
| + * @override |
| + * @return {boolean} |
| + */ |
| + isRemote: function() |
|
dgozman
2016/11/01 22:07:39
Already passing false in constructor.
eostroukhov
2016/11/02 21:55:53
Done.
|
| + { |
| + return false; |
| + }, |
| + |
| + __proto__: WebInspector.PendingSubTarget.prototype, |
| +}; |
| + |
| +/** |
| + * Sorts show tha connected targets appear first, followed by pending subtargets. |
| + * |
| + * @param {!WebInspector.PendingSubTarget} c1 |
| + * @param {!WebInspector.PendingSubTarget} c2 |
| + * @return {number} |
| + */ |
| +WebInspector.ThreadsSidebarPane._subTargetsComparator = function(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) { // both are null |
| + return name1.toLowerCase().localeCompare(name2.toLowerCase()); |
| + } else if (t1) { |
| + return -1; |
| + } |
| + return 1; |
| +}; |