| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 /** | 4 /** |
| 5 * @implements {SDK.TargetManager.Observer} | 5 * @implements {SDK.TargetManager.Observer} |
| 6 * @unrestricted | 6 * @unrestricted |
| 7 */ | 7 */ |
| 8 Sources.ThreadsSidebarPane = class extends UI.VBox { | 8 Sources.ThreadsSidebarPane = class extends UI.VBox { |
| 9 constructor() { | 9 constructor() { |
| 10 super(); | 10 super(); |
| 11 | 11 |
| 12 /** @type {?Sources.UIList.Item} */ | 12 /** @type {?Sources.UIList.Item} */ |
| 13 this._selectedListItem = null; | 13 this._selectedListItem = null; |
| 14 /** @type {!Map<!SDK.PendingTarget, !Sources.UIList.Item>} */ | 14 /** @type {!Map<!SDK.Target, !Sources.UIList.Item>} */ |
| 15 this._pendingToListItem = new Map(); | 15 this._targetToListItem = new Map(); |
| 16 /** @type {!Map<!SDK.Target, !SDK.PendingTarget>} */ | 16 |
| 17 this._targetToPending = new Map(); | |
| 18 /** @type {?SDK.PendingTarget} */ | |
| 19 this._mainTargetPending = null; | |
| 20 this.threadList = new Sources.UIList(); | 17 this.threadList = new Sources.UIList(); |
| 21 this.threadList.show(this.element); | 18 this.threadList.show(this.element); |
| 19 |
| 20 this._availableNodeTargetsElement = this.element.createChild('div', 'hidden
available-node-targets'); |
| 21 |
| 22 SDK.targetManager.addModelListener( | 22 SDK.targetManager.addModelListener( |
| 23 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._onDebu
ggerStateChanged, this); | 23 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._onDebu
ggerStateChanged, this); |
| 24 SDK.targetManager.addModelListener( | 24 SDK.targetManager.addModelListener( |
| 25 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerResumed, this._onDeb
uggerStateChanged, this); | 25 SDK.DebuggerModel, SDK.DebuggerModel.Events.DebuggerResumed, this._onDeb
uggerStateChanged, this); |
| 26 SDK.targetManager.addModelListener( | 26 SDK.targetManager.addModelListener( |
| 27 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this.
_onExecutionContextChanged, this); | 27 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this.
_onExecutionContextChanged, this); |
| 28 UI.context.addFlavorChangeListener(SDK.Target, this._targetChanged, this); | 28 UI.context.addFlavorChangeListener(SDK.Target, this._targetChanged, this); |
| 29 SDK.targetManager.addEventListener(SDK.TargetManager.Events.NameChanged, thi
s._targetNameChanged, this); | 29 SDK.targetManager.addEventListener(SDK.TargetManager.Events.NameChanged, thi
s._targetNameChanged, this); |
| 30 SDK.targetManager.addModelListener( | 30 SDK.targetManager.addModelListener( |
| 31 SDK.SubTargetsManager, SDK.SubTargetsManager.Events.PendingTargetAdded,
this._addTargetItem, this); | 31 SDK.SubTargetsManager, SDK.SubTargetsManager.Events.AvailableNodeTargets
Changed, |
| 32 SDK.targetManager.addModelListener( | 32 this._availableNodeTargetsChanged, this); |
| 33 SDK.SubTargetsManager, SDK.SubTargetsManager.Events.PendingTargetRemoved
, this._pendingTargetRemoved, this); | 33 SDK.targetManager.observeTargets(this, SDK.Target.Capability.JS); |
| 34 SDK.targetManager.addModelListener( | 34 this._availableNodeTargetsChanged(); |
| 35 SDK.SubTargetsManager, SDK.SubTargetsManager.Events.PendingTargetAttache
d, this._addTargetItem, this); | |
| 36 SDK.targetManager.addModelListener( | |
| 37 SDK.SubTargetsManager, SDK.SubTargetsManager.Events.PendingTargetDetache
d, this._targetDetached, this); | |
| 38 SDK.targetManager.observeTargets(this); | |
| 39 | |
| 40 var pendingTargets = []; | |
| 41 for (var target of SDK.targetManager.targets(SDK.Target.Capability.Target)) | |
| 42 pendingTargets = pendingTargets.concat(SDK.SubTargetsManager.fromTarget(ta
rget).pendingTargets()); | |
| 43 | |
| 44 pendingTargets.sort(Sources.ThreadsSidebarPane._pendingTargetsComparator) | |
| 45 .forEach(pendingTarget => this._addListItem(pendingTarget)); | |
| 46 } | 35 } |
| 47 | 36 |
| 48 /** | 37 /** |
| 49 * @return {boolean} | 38 * @return {boolean} |
| 50 */ | 39 */ |
| 51 static shouldBeShown() { | 40 static shouldBeShown() { |
| 52 if (SDK.targetManager.targets(SDK.Target.Capability.JS).length > 1) | 41 var minJSTargets = Runtime.queryParam('nodeFrontend') ? 1 : 2; |
| 42 if (SDK.targetManager.targets(SDK.Target.Capability.JS).length >= minJSTarge
ts) |
| 53 return true; | 43 return true; |
| 54 for (var target of SDK.targetManager.targets(SDK.Target.Capability.Target))
{ | 44 if (Sources.ThreadsSidebarPane.availableNodeTargetsCount()) |
| 55 var pendingTargets = SDK.SubTargetsManager.fromTarget(target).pendingTarge
ts(); | 45 return true; |
| 56 if (pendingTargets.some(pendingTarget => pendingTarget.canConnect())) | |
| 57 return true; | |
| 58 } | |
| 59 return false; | 46 return false; |
| 60 } | 47 } |
| 61 | 48 |
| 62 /** | 49 /** |
| 63 * Sorts show tha connected targets appear first, followed by pending subtarge
ts. | |
| 64 * | |
| 65 * @param {!SDK.PendingTarget} c1 | |
| 66 * @param {!SDK.PendingTarget} c2 | |
| 67 * @return {number} | 50 * @return {number} |
| 68 */ | 51 */ |
| 69 static _pendingTargetsComparator(c1, c2) { | 52 static availableNodeTargetsCount() { |
| 70 var t1 = c1.target(); | 53 var count = 0; |
| 71 var t2 = c2.target(); | 54 for (var target of SDK.targetManager.targets(SDK.Target.Capability.Target)) |
| 72 var name1 = t1 ? t1.name() : c1.name(); | 55 count += SDK.SubTargetsManager.fromTarget(target).availableNodeTargetsCoun
t(); |
| 73 var name2 = t2 ? t2.name() : c2.name(); | 56 |
| 74 if (!!t1 === !!t2) { // Either both are connected or disconnected | 57 return count; |
| 75 return name1.toLowerCase().localeCompare(name2.toLowerCase()); | 58 } |
| 76 } else if (t1) { | 59 |
| 77 return -1; | 60 _availableNodeTargetsChanged() { |
| 61 var count = Sources.ThreadsSidebarPane.availableNodeTargetsCount(); |
| 62 if (!count) { |
| 63 this._availableNodeTargetsElement.classList.add('hidden'); |
| 64 return; |
| 78 } | 65 } |
| 79 return 1; | 66 this._availableNodeTargetsElement.removeChildren(); |
| 67 this._availableNodeTargetsElement.createTextChild( |
| 68 count === 1 ? Common.UIString('Node instance available.') : |
| 69 Common.UIString('%d Node instances available.', count)); |
| 70 var link = this._availableNodeTargetsElement.createChild('span', 'link'); |
| 71 link.textContent = Common.UIString('Connect'); |
| 72 link.addEventListener('click', () => { |
| 73 InspectorFrontendHost.openNodeFrontend(); |
| 74 }, false); |
| 75 this._availableNodeTargetsElement.classList.remove('hidden'); |
| 80 } | 76 } |
| 81 | 77 |
| 82 /** | 78 /** |
| 83 * @param {!Common.Event} event | |
| 84 */ | |
| 85 _addTargetItem(event) { | |
| 86 this._addListItem(/** @type {!SDK.PendingTarget} */ (event.data)); | |
| 87 } | |
| 88 | |
| 89 /** | |
| 90 * @param {!Common.Event} event | |
| 91 */ | |
| 92 _pendingTargetRemoved(event) { | |
| 93 this._removeListItem(/** @type {!SDK.PendingTarget} */ (event.data)); | |
| 94 } | |
| 95 | |
| 96 /** | |
| 97 * @param {!Common.Event} event | |
| 98 */ | |
| 99 _targetDetached(event) { | |
| 100 this._targetRemoved(/** @type {!SDK.PendingTarget} */ (event.data)); | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * @param {!SDK.PendingTarget} pendingTarget | |
| 105 */ | |
| 106 _addListItem(pendingTarget) { | |
| 107 var target = pendingTarget.target(); | |
| 108 if (!pendingTarget.canConnect() && !(target && target.hasJSCapability())) | |
| 109 return; | |
| 110 | |
| 111 var listItem = this._pendingToListItem.get(pendingTarget); | |
| 112 if (!listItem) { | |
| 113 listItem = new Sources.UIList.Item('', '', false); | |
| 114 listItem[Sources.ThreadsSidebarPane._pendingTargetSymbol] = pendingTarget; | |
| 115 listItem[Sources.ThreadsSidebarPane._targetSymbol] = target; | |
| 116 this._pendingToListItem.set(pendingTarget, listItem); | |
| 117 this.threadList.addItem(listItem); | |
| 118 listItem.element.addEventListener('click', this._onListItemClick.bind(this
, listItem), false); | |
| 119 } | |
| 120 this._updateListItem(listItem, pendingTarget); | |
| 121 this._updateDebuggerState(pendingTarget); | |
| 122 var currentTarget = UI.context.flavor(SDK.Target); | |
| 123 if (currentTarget === target) | |
| 124 this._selectListItem(listItem); | |
| 125 if (target) | |
| 126 this._targetToPending.set(target, pendingTarget); | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * @override | 79 * @override |
| 131 * @param {!SDK.Target} target | 80 * @param {!SDK.Target} target |
| 132 */ | 81 */ |
| 133 targetAdded(target) { | 82 targetAdded(target) { |
| 134 if (target !== SDK.targetManager.mainTarget()) | 83 var listItem = new Sources.UIList.Item('', '', false); |
| 135 return; | 84 listItem.element.addEventListener('click', this._onListItemClick.bind(this,
listItem, target), false); |
| 136 console.assert(!this._mainTargetPending); | 85 this._targetToListItem.set(target, listItem); |
| 137 this._mainTargetPending = new Sources.ThreadsSidebarPane.MainTargetConnectio
n(target); | 86 this.threadList.addItem(listItem); |
| 138 this._addListItem(this._mainTargetPending); | 87 listItem.setTitle(this._titleForTarget(target)); |
| 88 this._updateDebuggerState(target); |
| 89 |
| 90 var currentTarget = UI.context.flavor(SDK.Target); |
| 91 if (currentTarget === target) |
| 92 this._selectListItem(listItem); |
| 139 } | 93 } |
| 140 | 94 |
| 141 /** | 95 /** |
| 142 * @override | 96 * @override |
| 143 * @param {!SDK.Target} target | 97 * @param {!SDK.Target} target |
| 144 */ | 98 */ |
| 145 targetRemoved(target) { | 99 targetRemoved(target) { |
| 146 var subtargetManager = SDK.SubTargetsManager.fromTarget(target); | 100 var item = this._targetToListItem.get(target); |
| 147 var pendingTargets = subtargetManager ? subtargetManager.pendingTargets() :
[]; | 101 if (!item) |
| 148 for (var pendingTarget of pendingTargets) { | 102 return; |
| 149 if (pendingTarget.target()) | 103 this.threadList.removeItem(item); |
| 150 this._targetRemoved(pendingTarget); | 104 this._targetToListItem.delete(target); |
| 151 } | |
| 152 if (target === SDK.targetManager.mainTarget() && this._mainTargetPending) { | |
| 153 this._targetRemoved(this._mainTargetPending); | |
| 154 this._mainTargetPending = null; | |
| 155 } | |
| 156 } | 105 } |
| 157 | 106 |
| 158 /** | 107 /** |
| 159 * @param {!Common.Event} event | 108 * @param {!Common.Event} event |
| 160 */ | 109 */ |
| 161 _targetNameChanged(event) { | 110 _targetNameChanged(event) { |
| 162 var target = /** @type {!SDK.Target} */ (event.data); | 111 var target = /** @type {!SDK.Target} */ (event.data); |
| 163 var listItem = this._listItemForTarget(target); | 112 var listItem = this._targetToListItem.get(target); |
| 164 if (listItem) | 113 if (listItem) |
| 165 listItem.setTitle(this._titleForPending(this._targetToPending.get(target))
); | 114 listItem.setTitle(this._titleForTarget(target)); |
| 166 } | 115 } |
| 167 | 116 |
| 168 /** | 117 /** |
| 169 * @param {!Common.Event} event | 118 * @param {!Common.Event} event |
| 170 */ | 119 */ |
| 171 _targetChanged(event) { | 120 _targetChanged(event) { |
| 172 var listItem = this._listItemForTarget(/** @type {!SDK.Target} */ (event.dat
a)); | 121 var listItem = this._targetToListItem.get(/** @type {!SDK.Target} */ (event.
data)); |
| 173 if (listItem) | 122 if (listItem) |
| 174 this._selectListItem(listItem); | 123 this._selectListItem(listItem); |
| 175 } | 124 } |
| 176 | 125 |
| 177 /** | 126 /** |
| 178 * @param {!SDK.Target} target | 127 * @param {!SDK.Target} target |
| 179 * @return {?Sources.UIList.Item} | |
| 180 */ | |
| 181 _listItemForTarget(target) { | |
| 182 var pendingTarget = this._targetToPending.get(target); | |
| 183 return this._pendingToListItem.get(pendingTarget) || null; | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * @param {!SDK.PendingTarget} pendingTarget | |
| 188 * @return {string} | 128 * @return {string} |
| 189 */ | 129 */ |
| 190 _titleForPending(pendingTarget) { | 130 _titleForTarget(target) { |
| 191 var target = pendingTarget.target(); | |
| 192 if (!target) | |
| 193 return pendingTarget.name(); | |
| 194 var executionContext = target.runtimeModel.defaultExecutionContext(); | 131 var executionContext = target.runtimeModel.defaultExecutionContext(); |
| 195 return executionContext && executionContext.label() ? executionContext.label
() : target.name(); | 132 return executionContext && executionContext.label() ? executionContext.label
() : target.name(); |
| 196 } | 133 } |
| 197 | 134 |
| 198 /** | 135 /** |
| 199 * @param {!Common.Event} event | 136 * @param {!Common.Event} event |
| 200 */ | 137 */ |
| 201 _onDebuggerStateChanged(event) { | 138 _onDebuggerStateChanged(event) { |
| 202 var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data); | 139 var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data); |
| 203 var pendingTarget = this._targetToPending.get(debuggerModel.target()); | 140 this._updateDebuggerState(debuggerModel.target()); |
| 204 this._updateDebuggerState(pendingTarget); | |
| 205 } | 141 } |
| 206 | 142 |
| 207 /** | 143 /** |
| 208 * @param {!Common.Event} event | 144 * @param {!Common.Event} event |
| 209 */ | 145 */ |
| 210 _onExecutionContextChanged(event) { | 146 _onExecutionContextChanged(event) { |
| 211 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); | 147 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); |
| 212 if (!executionContext.isDefault) | 148 var target = executionContext.target(); |
| 213 return; | 149 var listItem = this._targetToListItem.get(target); |
| 214 var pendingTarget = this._targetToPending.get(executionContext.target()); | 150 if (listItem) |
| 215 var listItem = this._pendingToListItem.get(pendingTarget); | 151 listItem.setTitle(this._titleForTarget(target)); |
| 216 if (listItem && executionContext.label()) | |
| 217 listItem.setTitle(executionContext.label()); | |
| 218 } | 152 } |
| 219 | 153 |
| 220 /** | 154 /** |
| 221 * @param {!SDK.PendingTarget} pendingTarget | 155 * @param {!SDK.Target} target |
| 222 */ | 156 */ |
| 223 _updateDebuggerState(pendingTarget) { | 157 _updateDebuggerState(target) { |
| 224 var listItem = this._pendingToListItem.get(pendingTarget); | 158 var listItem = this._targetToListItem.get(target); |
| 225 var target = pendingTarget.target(); | 159 var debuggerModel = SDK.DebuggerModel.fromTarget(target); |
| 226 var debuggerModel = target && SDK.DebuggerModel.fromTarget(target); | 160 console.assert(debuggerModel); |
| 227 var isPaused = !!debuggerModel && debuggerModel.isPaused(); | 161 listItem.setSubtitle(Common.UIString(debuggerModel.isPaused() ? 'paused' : '
')); |
| 228 listItem.setSubtitle(Common.UIString(isPaused ? 'paused' : '')); | |
| 229 } | 162 } |
| 230 | 163 |
| 231 /** | 164 /** |
| 232 * @param {!Sources.UIList.Item} listItem | 165 * @param {!Sources.UIList.Item} listItem |
| 233 */ | 166 */ |
| 234 _selectListItem(listItem) { | 167 _selectListItem(listItem) { |
| 235 if (listItem === this._selectedListItem) | 168 if (listItem === this._selectedListItem) |
| 236 return; | 169 return; |
| 237 | 170 |
| 238 if (this._selectedListItem) | 171 if (this._selectedListItem) |
| 239 this._selectedListItem.setSelected(false); | 172 this._selectedListItem.setSelected(false); |
| 240 | 173 |
| 241 this._selectedListItem = listItem; | 174 this._selectedListItem = listItem; |
| 242 listItem.setSelected(true); | 175 listItem.setSelected(true); |
| 243 } | 176 } |
| 244 | 177 |
| 245 /** | 178 /** |
| 246 * @param {!Sources.UIList.Item} listItem | 179 * @param {!Sources.UIList.Item} listItem |
| 180 * @param {!SDK.Target} target |
| 247 */ | 181 */ |
| 248 _onListItemClick(listItem) { | 182 _onListItemClick(listItem, target) { |
| 249 var pendingTarget = listItem[Sources.ThreadsSidebarPane._pendingTargetSymbol
]; | |
| 250 var target = pendingTarget.target(); | |
| 251 if (!target) | |
| 252 return; | |
| 253 UI.context.setFlavor(SDK.Target, target); | 183 UI.context.setFlavor(SDK.Target, target); |
| 254 listItem.element.scrollIntoViewIfNeeded(); | 184 listItem.element.scrollIntoViewIfNeeded(); |
| 255 } | 185 } |
| 256 | |
| 257 /** | |
| 258 * @param {!Sources.UIList.Item} item | |
| 259 * @param {!SDK.PendingTarget} pendingTarget | |
| 260 */ | |
| 261 _updateListItem(item, pendingTarget) { | |
| 262 item.setTitle(this._titleForPending(pendingTarget)); | |
| 263 item.setSubtitle(''); | |
| 264 var target = pendingTarget.target(); | |
| 265 var action = null; | |
| 266 var actionLabel = null; | |
| 267 if (pendingTarget.canConnect()) { | |
| 268 actionLabel = target ? 'Disconnect' : 'Connect'; | |
| 269 action = this._toggleConnection.bind(this, pendingTarget); | |
| 270 } | |
| 271 item.setAction(actionLabel, action); | |
| 272 item.setDimmed(!target); | |
| 273 } | |
| 274 | |
| 275 /** | |
| 276 * @param {!SDK.Target} target | |
| 277 */ | |
| 278 _selectNewlyAddedTarget(target) { | |
| 279 setTimeout(() => UI.context.setFlavor(SDK.Target, target)); | |
| 280 } | |
| 281 | |
| 282 /** | |
| 283 * @param {!SDK.PendingTarget} pendingTarget | |
| 284 * @return {!Promise} | |
| 285 */ | |
| 286 _toggleConnection(pendingTarget) { | |
| 287 var target = pendingTarget.target(); | |
| 288 if (target) | |
| 289 return pendingTarget.detach(); | |
| 290 else | |
| 291 return pendingTarget.attach().then(target => this._selectNewlyAddedTarget(
target)); | |
| 292 } | |
| 293 | |
| 294 /** | |
| 295 * @param {!SDK.PendingTarget} pendingTarget | |
| 296 */ | |
| 297 _targetRemoved(pendingTarget) { | |
| 298 var item = this._pendingToListItem.get(pendingTarget); | |
| 299 if (!item) // Not all targets are represented in the UI. | |
| 300 return; | |
| 301 var target = item[Sources.ThreadsSidebarPane._targetSymbol]; | |
| 302 item[Sources.ThreadsSidebarPane._targetSymbol] = null; | |
| 303 this._targetToPending.remove(target); | |
| 304 if (pendingTarget.canConnect()) | |
| 305 this._updateListItem(item, pendingTarget); | |
| 306 else | |
| 307 this._removeListItem(pendingTarget); | |
| 308 } | |
| 309 | |
| 310 /** | |
| 311 * @param {!SDK.PendingTarget} pendingTarget | |
| 312 */ | |
| 313 _removeListItem(pendingTarget) { | |
| 314 var item = this._pendingToListItem.get(pendingTarget); | |
| 315 if (!item) | |
| 316 return; | |
| 317 this.threadList.removeItem(item); | |
| 318 this._pendingToListItem.delete(pendingTarget); | |
| 319 } | |
| 320 }; | 186 }; |
| 321 | 187 |
| 322 Sources.ThreadsSidebarPane._pendingTargetSymbol = Symbol('_subtargetSymbol'); | |
| 323 Sources.ThreadsSidebarPane._targetSymbol = Symbol('_targetSymbol'); | 188 Sources.ThreadsSidebarPane._targetSymbol = Symbol('_targetSymbol'); |
| 324 | |
| 325 /** | |
| 326 * @unrestricted | |
| 327 */ | |
| 328 Sources.ThreadsSidebarPane.MainTargetConnection = class extends SDK.PendingTarge
t { | |
| 329 /** | |
| 330 * @param {!SDK.Target} target | |
| 331 */ | |
| 332 constructor(target) { | |
| 333 super('main-target-list-node-' + target.id(), target.title, false, null); | |
| 334 this._target = target; | |
| 335 } | |
| 336 | |
| 337 /** | |
| 338 * @override | |
| 339 * @return {!SDK.Target} | |
| 340 */ | |
| 341 target() { | |
| 342 return this._target; | |
| 343 } | |
| 344 | |
| 345 /** | |
| 346 * @override | |
| 347 * @return {string} | |
| 348 */ | |
| 349 name() { | |
| 350 return this._target.name(); | |
| 351 } | |
| 352 }; | |
| OLD | NEW |