Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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.SDKModelObserver<!SDK.RuntimeModel>} | 5 * @implements {SDK.SDKModelObserver<!SDK.RuntimeModel>} |
| 6 * @implements {UI.ListDelegate<!SDK.ExecutionContext>} | |
| 6 * @unrestricted | 7 * @unrestricted |
| 7 */ | 8 */ |
| 8 Console.ConsoleContextSelector = class { | 9 Console.ConsoleContextSelector = class extends UI.ToolbarItem { |
|
dgozman
2017/05/08 23:16:47
Should not extend from UI controls.
einbinder
2017/05/09 22:00:43
Done.
| |
| 9 /** | 10 constructor() { |
| 10 * @param {!Element} selectElement | 11 super(createElementWithClass('button', 'console-context')); |
| 11 */ | 12 this._titleElement = this.element.createChild('span'); |
| 12 constructor(selectElement) { | 13 this._titleElement.textContent = ''; |
| 13 this._selectElement = selectElement; | 14 this._titleElement.style.paddingRight = '5px'; |
| 14 /** | 15 this._titleElement.style.width = '120px'; |
|
dgozman
2017/05/08 23:16:41
Remove?
einbinder
2017/05/09 22:00:45
Done.
| |
| 15 * @type {!Map.<!SDK.ExecutionContext, !Element>} | 16 this._titleElement.style.overflow = 'hidden'; |
| 16 */ | 17 this._titleElement.style.textOverflow = 'ellipsis '; |
| 17 this._optionByExecutionContext = new Map(); | 18 this._productRegistry = null; |
| 19 | |
| 20 ProductRegistry.instance().then(registry => { | |
| 21 this._productRegistry = registry; | |
| 22 this._list.refreshAllItems(); | |
| 23 }); | |
| 24 this.element.classList.add('toolbar-has-dropdown'); | |
| 25 this.element.tabIndex = 0; | |
| 26 this._glassPane = new UI.GlassPane(); | |
| 27 this._glassPane.setMaxContentSize(new UI.Size(315, 310)); | |
| 28 this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin); | |
| 29 this._glassPane.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHe ight); | |
| 30 this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferBottom); | |
| 31 this._glassPane.setOutsideClickCallback(this._hide.bind(this)); | |
| 32 /** @type {!Array<!SDK.ExecutionContext>} */ | |
| 33 this._executionContexts = []; | |
|
dgozman
2017/05/08 23:16:42
You don't need this: list.itemAtIndex()
einbinder
2017/05/09 22:00:45
Done.
| |
| 34 this._list = new UI.ListControl(this, UI.ListMode.NonViewport); | |
|
dgozman
2017/05/08 23:16:47
Viewport it.
einbinder
2017/05/09 22:00:44
Viewporting it ended up being a lot slower.
dgozman
2017/05/09 23:11:12
Can you elaborate on this?
einbinder
2017/05/11 00:07:03
Fixed.
| |
| 35 this._list.element.classList.add('context-list'); | |
| 36 this._list.element.tabIndex = -1; | |
| 37 var shadowRoot = | |
| 38 UI.createShadowRootWithCoreStyles(this._glassPane.contentElement, 'conso le/consoleContextSelector.css'); | |
| 39 shadowRoot.appendChild(this._list.element); | |
| 40 | |
| 41 this._canSelect = false; | |
|
dgozman
2017/05/08 23:16:44
shouldHideOnMouseUp
einbinder
2017/05/09 22:00:44
Done.
| |
| 42 this.element.addEventListener('mousedown', event => { | |
| 43 if (this._canSelect) | |
| 44 this._hide(event); | |
| 45 else | |
| 46 this._show(event); | |
| 47 }, false); | |
| 48 this.element.addEventListener('click', event => { | |
| 49 if (!this._canSelect) | |
| 50 this._show(event); | |
| 51 }, false); | |
| 52 this.element.addEventListener('keydown', this._onKeyDown.bind(this), false); | |
| 53 this.element.addEventListener('blur', this._hide.bind(this), false); | |
| 54 this._list.element.addEventListener('mousedown', event => { | |
| 55 this._hide(event); | |
| 56 this._updateSelectedContext(); | |
| 57 }, false); | |
| 58 this._list.element.addEventListener('mouseup', event => { | |
| 59 if (!this._canSelect) | |
| 60 return; | |
| 61 this._hide(event); | |
| 62 this._updateSelectedContext(); | |
| 63 }, false); | |
| 64 | |
| 65 var dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down', 'toolbar-d ropdown-arrow'); | |
| 66 this.element.appendChild(dropdownArrowIcon); | |
| 18 | 67 |
| 19 SDK.targetManager.addModelListener( | 68 SDK.targetManager.addModelListener( |
| 20 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextCreated, this. _onExecutionContextCreated, this); | 69 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextCreated, this. _onExecutionContextCreated, this); |
| 21 SDK.targetManager.addModelListener( | 70 SDK.targetManager.addModelListener( |
| 22 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this. _onExecutionContextChanged, this); | 71 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this. _onExecutionContextChanged, this); |
| 23 SDK.targetManager.addModelListener( | 72 SDK.targetManager.addModelListener( |
| 24 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, thi s._onExecutionContextDestroyed, this); | 73 SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, thi s._onExecutionContextDestroyed, this); |
| 74 SDK.targetManager.addModelListener( | |
| 75 SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this ._frameNavigated, this); | |
| 25 | 76 |
| 26 this._selectElement.addEventListener('change', this._executionContextChanged .bind(this), false); | |
| 27 UI.context.addFlavorChangeListener(SDK.ExecutionContext, this._executionCont extChangedExternally, this); | 77 UI.context.addFlavorChangeListener(SDK.ExecutionContext, this._executionCont extChangedExternally, this); |
| 28 UI.context.addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this._callFr ameSelectedInUI, this); | 78 UI.context.addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this._callFr ameSelectedInUI, this); |
| 29 SDK.targetManager.observeModels(SDK.RuntimeModel, this); | 79 SDK.targetManager.observeModels(SDK.RuntimeModel, this); |
| 30 SDK.targetManager.addModelListener( | 80 SDK.targetManager.addModelListener( |
| 31 SDK.DebuggerModel, SDK.DebuggerModel.Events.CallFrameSelected, this._cal lFrameSelectedInModel, this); | 81 SDK.DebuggerModel, SDK.DebuggerModel.Events.CallFrameSelected, this._cal lFrameSelectedInModel, this); |
| 32 } | 82 } |
| 33 | 83 |
| 34 /** | 84 /** |
| 85 * @param {!Event} event | |
| 86 */ | |
| 87 _show(event) { | |
| 88 if (this._glassPane.isShowing()) | |
| 89 return; | |
| 90 this._glassPane.setContentAnchorBox(this.element.boxInWindow()); | |
| 91 if (this.element.ownerDocument) | |
| 92 this._glassPane.show(this.element.ownerDocument); | |
|
dgozman
2017/05/08 23:16:42
nit: just cast it
einbinder
2017/05/09 22:00:43
Done.
| |
| 93 this._list.viewportResized(); | |
| 94 var selectedItem = this._list.selectedItem(); | |
| 95 if (selectedItem) | |
| 96 this._list.scrollItemIntoView(selectedItem, true); | |
| 97 this.element.focus(); | |
| 98 event.consume(true); | |
| 99 setTimeout(() => this._canSelect = true, 200); | |
|
dgozman
2017/05/08 23:16:45
Is it possible to put this in closure?
dgozman
2017/05/09 23:11:12
What about this?
einbinder
2017/05/11 00:07:03
It needs to be set to false if hidden by keyboard,
| |
| 100 } | |
| 101 | |
| 102 /** | |
| 103 * @param {!Event} event | |
| 104 */ | |
| 105 _hide(event) { | |
| 106 setTimeout(() => this._canSelect = false, 200); | |
|
dgozman
2017/05/08 23:16:47
this._canSelect = false ?
einbinder
2017/05/09 22:00:45
If you click the button after the list is open, th
| |
| 107 this._glassPane.hide(); | |
| 108 SDK.OverlayModel.hideDOMNodeHighlight(); | |
| 109 event.consume(true); | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * @param {!Event} event | |
| 114 */ | |
| 115 _onKeyDown(event) { | |
| 116 var handled = false; | |
| 117 switch (event.key) { | |
| 118 case 'ArrowUp': | |
| 119 handled = this._list.selectPreviousItem(false, false); | |
| 120 break; | |
| 121 case 'ArrowDown': | |
| 122 handled = this._list.selectNextItem(false, false); | |
| 123 break; | |
| 124 case 'ArrowRight': | |
| 125 var currentExecutionContext = this._list.selectedItem(); | |
| 126 if (!currentExecutionContext) | |
| 127 break; | |
| 128 var nextExecutionContext = | |
| 129 this._executionContexts[this._executionContexts.indexOf(currentExecu tionContext) + 1]; | |
|
dgozman
2017/05/08 23:16:40
Let's expose selectedIndex()
einbinder
2017/05/09 22:00:44
Done.
| |
| 130 if (nextExecutionContext && this._depthFor(currentExecutionContext) < th is._depthFor(nextExecutionContext)) | |
| 131 handled = this._list.selectNextItem(false, false); | |
| 132 break; | |
| 133 case 'ArrowLeft': | |
| 134 var currentExecutionContext = this._list.selectedItem(); | |
| 135 if (!currentExecutionContext) | |
| 136 break; | |
| 137 var depth = this._depthFor(currentExecutionContext); | |
| 138 for (var i = this._executionContexts.indexOf(currentExecutionContext) - 1; i >= 0; i--) { | |
| 139 if (this._depthFor(this._executionContexts[i]) < depth) { | |
| 140 handled = true; | |
| 141 this._list.selectItem(this._executionContexts[i], false); | |
| 142 break; | |
| 143 } | |
| 144 } | |
| 145 break; | |
| 146 case 'PageUp': | |
| 147 handled = this._list.selectItemPreviousPage(false); | |
| 148 break; | |
| 149 case 'PageDown': | |
| 150 handled = this._list.selectItemNextPage(false); | |
| 151 break; | |
| 152 case 'Escape': | |
| 153 if (this._glassPane.isShowing()) | |
| 154 event.consume(true); | |
| 155 this._glassPane.hide(); | |
| 156 return; | |
| 157 case 'Enter': | |
| 158 handled = this._glassPane.isShowing(); | |
| 159 this._glassPane.hide(); | |
| 160 break; | |
| 161 default: | |
| 162 if (event.key.length === 1) { | |
| 163 var selectedItem = this._list.selectedItem(); | |
| 164 var selectedIndex = selectedItem ? this._executionContexts.indexOf(sel ectedItem) : -1; | |
| 165 var context = | |
| 166 this._executionContexts.slice(selectedIndex + 1) | |
| 167 .find(context => this._titleFor(context).toUpperCase().startsW ith(event.key.toUpperCase())) || | |
| 168 this._executionContexts.slice(0, selectedIndex) | |
| 169 .find(context => this._titleFor(context).toUpperCase().startsW ith(event.key.toUpperCase())); | |
| 170 if (context) | |
| 171 this._list.selectItem(context); | |
| 172 handled = true; | |
| 173 } | |
| 174 break; | |
| 175 } | |
| 176 | |
| 177 if (handled) { | |
| 178 event.consume(true); | |
| 179 this._updateSelectedContext(); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 /** | |
| 35 * @param {!SDK.ExecutionContext} executionContext | 184 * @param {!SDK.ExecutionContext} executionContext |
| 36 * @return {string} | 185 * @return {string} |
| 37 */ | 186 */ |
| 38 _titleFor(executionContext) { | 187 _titleFor(executionContext) { |
| 39 var target = executionContext.target(); | 188 var target = executionContext.target(); |
| 189 var label = executionContext.label() ? target.decorateLabel(executionContext .label()) : ''; | |
| 190 if (executionContext.frameId) { | |
| 191 var resourceTreeModel = target.model(SDK.ResourceTreeModel); | |
| 192 var frame = resourceTreeModel && resourceTreeModel.frameForId(executionCon text.frameId); | |
| 193 if (frame) | |
| 194 label = label || frame.displayName(); | |
| 195 } | |
| 196 label = label || executionContext.origin; | |
| 197 | |
| 198 return label; | |
| 199 } | |
| 200 | |
| 201 /** | |
| 202 * @param {!SDK.ExecutionContext} executionContext | |
| 203 * @return {number} | |
| 204 */ | |
| 205 _depthFor(executionContext) { | |
| 206 var target = executionContext.target(); | |
| 40 var depth = 0; | 207 var depth = 0; |
| 41 var label = executionContext.label() ? target.decorateLabel(executionContext .label()) : ''; | |
| 42 if (!executionContext.isDefault) | 208 if (!executionContext.isDefault) |
| 43 depth++; | 209 depth++; |
| 44 if (executionContext.frameId) { | 210 if (executionContext.frameId) { |
| 45 var resourceTreeModel = target.model(SDK.ResourceTreeModel); | 211 var resourceTreeModel = target.model(SDK.ResourceTreeModel); |
| 46 var frame = resourceTreeModel && resourceTreeModel.frameForId(executionCon text.frameId); | 212 var frame = resourceTreeModel && resourceTreeModel.frameForId(executionCon text.frameId); |
| 47 if (frame) { | 213 while (frame && frame.parentFrame) { |
| 48 label = label || frame.displayName(); | 214 depth++; |
| 49 while (frame.parentFrame) { | 215 frame = frame.parentFrame; |
| 50 depth++; | |
| 51 frame = frame.parentFrame; | |
| 52 } | |
| 53 } | 216 } |
| 54 } | 217 } |
| 55 label = label || executionContext.origin; | |
| 56 var targetDepth = 0; | 218 var targetDepth = 0; |
| 57 while (target.parentTarget()) { | 219 while (target.parentTarget()) { |
| 58 if (target.parentTarget().hasJSCapability()) { | 220 if (target.parentTarget().hasJSCapability()) { |
| 59 targetDepth++; | 221 targetDepth++; |
| 60 } else { | 222 } else { |
| 61 // Special casing service workers to be top-level. | 223 // Special casing service workers to be top-level. |
| 62 targetDepth = 0; | 224 targetDepth = 0; |
| 63 break; | 225 break; |
| 64 } | 226 } |
| 65 target = target.parentTarget(); | 227 target = target.parentTarget(); |
| 66 } | 228 } |
| 67 | |
| 68 depth += targetDepth; | 229 depth += targetDepth; |
| 69 var prefix = new Array(4 * depth + 1).join('\u00a0'); | 230 return depth; |
| 70 var maxLength = 50; | |
| 71 return (prefix + label).trimMiddle(maxLength); | |
| 72 } | 231 } |
| 73 | 232 |
| 74 /** | 233 /** |
| 75 * @param {!SDK.ExecutionContext} executionContext | 234 * @param {!SDK.ExecutionContext} executionContext |
| 76 */ | 235 */ |
| 77 _executionContextCreated(executionContext) { | 236 _executionContextCreated(executionContext) { |
| 78 // FIXME(413886): We never want to show execution context for the main threa d of shadow page in service/shared worker frontend. | 237 // FIXME(413886): We never want to show execution context for the main threa d of shadow page in service/shared worker frontend. |
| 79 // This check could be removed once we do not send this context to frontend. | 238 // This check could be removed once we do not send this context to frontend. |
| 80 if (!executionContext.target().hasJSCapability()) | 239 if (!executionContext.target().hasJSCapability()) |
| 81 return; | 240 return; |
| 82 | 241 |
| 83 var newOption = createElement('option'); | 242 var index = this._executionContexts.lowerBound( |
| 84 newOption.__executionContext = executionContext; | 243 executionContext, executionContext.runtimeModel.executionContextComparat or()); |
| 85 newOption.text = this._titleFor(executionContext); | 244 this._executionContexts.splice(index, 0, executionContext); |
| 86 this._optionByExecutionContext.set(executionContext, newOption); | 245 this._list.insertItemAtIndex(index, executionContext); |
|
dgozman
2017/05/08 23:16:42
Let's pass optional comparator to this method.
einbinder
2017/05/09 22:00:43
Done.
| |
| 87 var options = this._selectElement.options; | |
| 88 var contexts = Array.prototype.map.call(options, mapping); | |
| 89 var index = contexts.lowerBound(executionContext, executionContext.runtimeMo del.executionContextComparator()); | |
| 90 this._selectElement.insertBefore(newOption, options[index]); | |
| 91 | 246 |
| 92 if (executionContext === UI.context.flavor(SDK.ExecutionContext)) | 247 if (executionContext === UI.context.flavor(SDK.ExecutionContext)) { |
| 93 this._select(newOption); | 248 this._list.selectItem(executionContext); |
| 94 this._updateOptionDisabledState(newOption); | 249 this._updateSelectedContext(); |
| 95 | |
| 96 /** | |
| 97 * @param {!Element} option | |
| 98 * @return {!SDK.ExecutionContext} | |
| 99 */ | |
| 100 function mapping(option) { | |
| 101 return option.__executionContext; | |
| 102 } | 250 } |
| 103 } | 251 } |
| 104 | 252 |
| 105 /** | 253 /** |
| 106 * @param {!Common.Event} event | 254 * @param {!Common.Event} event |
| 107 */ | 255 */ |
| 108 _onExecutionContextCreated(event) { | 256 _onExecutionContextCreated(event) { |
| 109 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); | 257 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); |
| 110 this._executionContextCreated(executionContext); | 258 this._executionContextCreated(executionContext); |
| 111 this._updateSelectionWarning(); | 259 this._updateSelectionWarning(); |
| 112 } | 260 } |
| 113 | 261 |
| 114 /** | 262 /** |
| 115 * @param {!Common.Event} event | 263 * @param {!Common.Event} event |
| 116 */ | 264 */ |
| 117 _onExecutionContextChanged(event) { | 265 _onExecutionContextChanged(event) { |
| 118 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); | 266 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); |
| 119 var option = this._optionByExecutionContext.get(executionContext); | 267 if (this._executionContexts.indexOf(executionContext) === -1) |
|
dgozman
2017/05/08 23:16:44
Let's fix this if it ever happens.
einbinder
2017/05/09 22:00:45
This is a hard fix. There are multiple listeners t
| |
| 120 if (option) | 268 return; |
| 121 option.text = this._titleFor(executionContext); | 269 this._executionContextDestroyed(executionContext); |
| 270 this._executionContextCreated(executionContext); | |
| 122 this._updateSelectionWarning(); | 271 this._updateSelectionWarning(); |
| 123 } | 272 } |
| 124 | 273 |
| 125 /** | 274 /** |
| 126 * @param {!SDK.ExecutionContext} executionContext | 275 * @param {!SDK.ExecutionContext} executionContext |
| 127 */ | 276 */ |
| 128 _executionContextDestroyed(executionContext) { | 277 _executionContextDestroyed(executionContext) { |
| 129 var option = this._optionByExecutionContext.remove(executionContext); | 278 if (this._executionContexts.remove(executionContext, true)) |
| 130 option.remove(); | 279 this._list.removeItem(executionContext); |
| 131 } | 280 } |
| 132 | 281 |
| 133 /** | 282 /** |
| 134 * @param {!Common.Event} event | 283 * @param {!Common.Event} event |
| 135 */ | 284 */ |
| 136 _onExecutionContextDestroyed(event) { | 285 _onExecutionContextDestroyed(event) { |
| 137 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); | 286 var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data); |
| 138 this._executionContextDestroyed(executionContext); | 287 this._executionContextDestroyed(executionContext); |
| 139 this._updateSelectionWarning(); | 288 this._updateSelectionWarning(); |
| 140 } | 289 } |
| 141 | 290 |
| 142 /** | 291 /** |
| 143 * @param {!Common.Event} event | 292 * @param {!Common.Event} event |
| 144 */ | 293 */ |
| 145 _executionContextChangedExternally(event) { | 294 _executionContextChangedExternally(event) { |
| 146 var executionContext = /** @type {?SDK.ExecutionContext} */ (event.data); | 295 var executionContext = /** @type {?SDK.ExecutionContext} */ (event.data); |
| 147 if (!executionContext) | 296 if (!executionContext || this._executionContexts.indexOf(executionContext) = == -1) |
|
dgozman
2017/05/08 23:16:42
ditto
| |
| 148 return; | 297 return; |
| 149 | 298 this._list.selectItem(executionContext); |
| 150 var options = this._selectElement.options; | 299 this._updateSelectedContext(); |
| 151 for (var i = 0; i < options.length; ++i) { | |
| 152 if (options[i].__executionContext === executionContext) | |
| 153 this._select(options[i]); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 _executionContextChanged() { | |
| 158 var option = this._selectedOption(); | |
| 159 var newContext = option ? option.__executionContext : null; | |
| 160 UI.context.setFlavor(SDK.ExecutionContext, newContext); | |
| 161 this._updateSelectionWarning(); | |
| 162 } | 300 } |
| 163 | 301 |
| 164 _updateSelectionWarning() { | 302 _updateSelectionWarning() { |
| 165 var executionContext = UI.context.flavor(SDK.ExecutionContext); | 303 var executionContext = UI.context.flavor(SDK.ExecutionContext); |
| 166 this._selectElement.parentElement.classList.toggle( | 304 this.element.classList.toggle('warning', !this._isTopContext(executionContex t) && this._hasTopContext()); |
| 167 'warning', !this._isTopContext(executionContext) && this._hasTopContext( )); | |
| 168 } | 305 } |
| 169 | 306 |
| 170 /** | 307 /** |
| 171 * @param {?SDK.ExecutionContext} executionContext | 308 * @param {?SDK.ExecutionContext} executionContext |
| 172 * @return {boolean} | 309 * @return {boolean} |
| 173 */ | 310 */ |
| 174 _isTopContext(executionContext) { | 311 _isTopContext(executionContext) { |
| 175 if (!executionContext || !executionContext.isDefault) | 312 if (!executionContext || !executionContext.isDefault) |
| 176 return false; | 313 return false; |
| 177 var resourceTreeModel = executionContext.target().model(SDK.ResourceTreeMode l); | 314 var resourceTreeModel = executionContext.target().model(SDK.ResourceTreeMode l); |
| 178 var frame = executionContext.frameId && resourceTreeModel && resourceTreeMod el.frameForId(executionContext.frameId); | 315 var frame = executionContext.frameId && resourceTreeModel && resourceTreeMod el.frameForId(executionContext.frameId); |
| 179 if (!frame) | 316 if (!frame) |
| 180 return false; | 317 return false; |
| 181 return frame.isMainFrame(); | 318 return frame.isMainFrame(); |
| 182 } | 319 } |
| 183 | 320 |
| 184 /** | 321 /** |
| 185 * @return {boolean} | 322 * @return {boolean} |
| 186 */ | 323 */ |
| 187 _hasTopContext() { | 324 _hasTopContext() { |
| 188 var options = this._selectElement.options; | 325 return !!this._executionContexts.find(executionContext => this._isTopContext (executionContext)); |
| 189 for (var i = 0; i < options.length; i++) { | |
| 190 if (this._isTopContext(options[i].__executionContext)) | |
| 191 return true; | |
| 192 } | |
| 193 return false; | |
| 194 } | 326 } |
| 195 | 327 |
| 196 /** | 328 /** |
| 197 * @override | 329 * @override |
| 198 * @param {!SDK.RuntimeModel} runtimeModel | 330 * @param {!SDK.RuntimeModel} runtimeModel |
| 199 */ | 331 */ |
| 200 modelAdded(runtimeModel) { | 332 modelAdded(runtimeModel) { |
| 201 runtimeModel.executionContexts().forEach(this._executionContextCreated, this ); | 333 runtimeModel.executionContexts().forEach(this._executionContextCreated, this ); |
| 202 } | 334 } |
| 203 | 335 |
| 204 /** | 336 /** |
| 205 * @override | 337 * @override |
| 206 * @param {!SDK.RuntimeModel} runtimeModel | 338 * @param {!SDK.RuntimeModel} runtimeModel |
| 207 */ | 339 */ |
| 208 modelRemoved(runtimeModel) { | 340 modelRemoved(runtimeModel) { |
| 209 var executionContexts = this._optionByExecutionContext.keysArray(); | 341 for (var i = 0; i < this._executionContexts.length; ++i) { |
| 210 for (var i = 0; i < executionContexts.length; ++i) { | 342 if (this._executionContexts[i].runtimeModel === runtimeModel) |
| 211 if (executionContexts[i].runtimeModel === runtimeModel) | 343 this._executionContextDestroyed(this._executionContexts[i]); |
| 212 this._executionContextDestroyed(executionContexts[i]); | |
| 213 } | 344 } |
| 214 } | 345 } |
| 215 | 346 |
| 216 /** | 347 /** |
| 217 * @param {!Element} option | 348 * @param {!SDK.ExecutionContext} executionContext |
| 218 */ | 349 */ |
| 219 _select(option) { | 350 _onSelect(executionContext) { |
|
dgozman
2017/05/08 23:16:44
remove
einbinder
2017/05/09 22:00:44
Done.
| |
| 220 this._selectElement.selectedIndex = Array.prototype.indexOf.call(/** @type { ?} */ (this._selectElement), option); | 351 } |
| 352 | |
| 353 /** | |
| 354 * @override | |
| 355 * @param {!SDK.ExecutionContext} item | |
| 356 * @return {!Element} | |
| 357 */ | |
| 358 createElementForItem(item) { | |
| 359 var element = createElementWithClass('div', 'context'); | |
| 360 element.style.paddingLeft = (8 + this._depthFor(item) * 15) + 'px'; | |
| 361 element.createChild('div', 'title').textContent = this._titleFor(item); | |
| 362 element.createChild('div', 'subtitle').textContent = this._subtitleFor(item) ; | |
| 363 element.addEventListener('mousemove', e => { | |
| 364 if (e.movementX || e.movementY) | |
| 365 this._list.selectItem(item, false, /* Don't scroll */ true); | |
| 366 }); | |
| 367 element.classList.toggle('disabled', !this.isItemSelectable(item)); | |
| 368 return element; | |
| 369 } | |
| 370 | |
| 371 /** | |
| 372 * @param {!SDK.ExecutionContext} executionContext | |
| 373 * @return {string} | |
| 374 */ | |
| 375 _subtitleFor(executionContext) { | |
|
dgozman
2017/05/08 23:16:44
Should we move this into some component maybe? Let
einbinder
2017/05/09 22:00:43
Moving it anywhere else is tricky because of depen
| |
| 376 var target = executionContext.target(); | |
| 377 if (executionContext.frameId) { | |
| 378 var resourceTreeModel = target.model(SDK.ResourceTreeModel); | |
| 379 var frame = resourceTreeModel && resourceTreeModel.frameForId(executionCon text.frameId); | |
| 380 } | |
| 381 if (executionContext.origin.startsWith('chrome-extension://')) | |
| 382 return Common.UIString('Extension'); | |
| 383 if (!frame || !frame.parentFrame || frame.parentFrame.securityOrigin !== exe cutionContext.origin) { | |
| 384 var url = executionContext.origin.asParsedURL(); | |
| 385 if (url) { | |
| 386 if (this._productRegistry) { | |
| 387 var product = this._productRegistry.nameForUrl(url); | |
| 388 if (product) | |
| 389 return product; | |
| 390 } | |
| 391 return url.domain(); | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 if (frame) { | |
| 396 var stackTrace = frame.creationStackTrace(); | |
| 397 while (stackTrace) { | |
| 398 for (var stack of stackTrace.callFrames) { | |
| 399 if (stack.url) { | |
| 400 var url = new Common.ParsedURL(stack.url); | |
| 401 if (this._productRegistry) { | |
| 402 var product = this._productRegistry.nameForUrl(url); | |
| 403 if (product) | |
| 404 return product; | |
| 405 } | |
| 406 return url.domain(); | |
| 407 } | |
| 408 } | |
| 409 stackTrace = frame.parent; | |
| 410 } | |
| 411 } | |
| 412 return ''; | |
| 413 } | |
| 414 | |
| 415 /** | |
| 416 * @override | |
| 417 * @param {!SDK.ExecutionContext} item | |
| 418 * @return {number} | |
| 419 */ | |
| 420 heightForItem(item) { | |
| 421 return 20; | |
|
dgozman
2017/05/08 23:16:41
Let the list measure.
einbinder
2017/05/09 22:00:44
Done.
| |
| 422 } | |
| 423 | |
| 424 /** | |
| 425 * @override | |
| 426 * @param {!SDK.ExecutionContext} item | |
| 427 * @return {boolean} | |
| 428 */ | |
| 429 isItemSelectable(item) { | |
| 430 var callFrame = item.debuggerModel.selectedCallFrame(); | |
| 431 var callFrameContext = callFrame && callFrame.script.executionContext(); | |
| 432 return !callFrameContext || item === callFrameContext; | |
| 433 } | |
| 434 | |
| 435 /** | |
| 436 * @override | |
| 437 * @param {?SDK.ExecutionContext} from | |
| 438 * @param {?SDK.ExecutionContext} to | |
| 439 * @param {?Element} fromElement | |
| 440 * @param {?Element} toElement | |
| 441 */ | |
| 442 selectedItemChanged(from, to, fromElement, toElement) { | |
| 443 if (fromElement) | |
| 444 fromElement.classList.remove('selected'); | |
| 445 if (toElement) | |
| 446 toElement.classList.add('selected'); | |
| 447 SDK.OverlayModel.hideDOMNodeHighlight(); | |
| 448 if (to && to.frameId) { | |
| 449 var resourceTreeModel = to.target().model(SDK.ResourceTreeModel); | |
| 450 if (resourceTreeModel) | |
| 451 resourceTreeModel.domModel().overlayModel().highlightFrame(to.frameId); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 _updateSelectedContext() { | |
| 456 var context = this._list.selectedItem(); | |
| 457 if (context) | |
| 458 this._titleElement.textContent = this._titleFor(context); | |
| 459 else | |
| 460 this._titleElement.textContent = ''; | |
| 461 UI.context.setFlavor(SDK.ExecutionContext, context); | |
| 221 this._updateSelectionWarning(); | 462 this._updateSelectionWarning(); |
| 222 } | 463 } |
| 223 | 464 |
| 224 /** | |
| 225 * @return {?Element} | |
| 226 */ | |
| 227 _selectedOption() { | |
| 228 if (this._selectElement.selectedIndex >= 0) | |
| 229 return this._selectElement[this._selectElement.selectedIndex]; | |
| 230 return null; | |
| 231 } | |
| 232 | |
| 233 /** | |
| 234 * @param {!Common.Event} event | |
| 235 */ | |
| 236 _callFrameSelectedInModel(event) { | |
| 237 var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data); | |
| 238 var options = this._selectElement.options; | |
| 239 for (var i = 0; i < options.length; i++) { | |
| 240 if (options[i].__executionContext.debuggerModel === debuggerModel) | |
| 241 this._updateOptionDisabledState(options[i]); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 /** | |
| 246 * @param {!Element} option | |
| 247 */ | |
| 248 _updateOptionDisabledState(option) { | |
| 249 var executionContext = option.__executionContext; | |
| 250 var callFrame = executionContext.debuggerModel.selectedCallFrame(); | |
| 251 var callFrameContext = callFrame && callFrame.script.executionContext(); | |
| 252 option.disabled = callFrameContext && executionContext !== callFrameContext; | |
| 253 } | |
| 254 | |
| 255 _callFrameSelectedInUI() { | 465 _callFrameSelectedInUI() { |
| 256 var callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame); | 466 var callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame); |
| 257 var callFrameContext = callFrame && callFrame.script.executionContext(); | 467 var callFrameContext = callFrame && callFrame.script.executionContext(); |
| 258 if (callFrameContext) | 468 if (callFrameContext) |
| 259 UI.context.setFlavor(SDK.ExecutionContext, callFrameContext); | 469 UI.context.setFlavor(SDK.ExecutionContext, callFrameContext); |
| 260 } | 470 } |
| 471 | |
| 472 /** | |
| 473 * @param {!Common.Event} event | |
| 474 */ | |
| 475 _callFrameSelectedInModel(event) { | |
| 476 var debuggerModel = /** @type {!SDK.DebuggerModel} */ (event.data); | |
| 477 for (var i = 0; i < this._executionContexts.length; i++) { | |
| 478 if (this._executionContexts[i].debuggerModel === debuggerModel) | |
| 479 this._list.refreshItemsInRange(i, i + 1); | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 /** | |
| 484 * @param {!Common.Event} event | |
| 485 */ | |
| 486 _frameNavigated(event) { | |
| 487 var frameId = event.data.id; | |
| 488 for (var i = 0; i < this._executionContexts.length; i++) { | |
| 489 if (frameId === this._executionContexts[i].frameId) | |
| 490 this._list.refreshItemsInRange(i, i + 1); | |
| 491 } | |
| 492 } | |
| 261 }; | 493 }; |
| OLD | NEW |