 Chromium Code Reviews
 Chromium Code Reviews Issue 2773583002:
  [DevTools] Introduce a sidebar with a drop-down
    
  
    Issue 2773583002:
  [DevTools] Introduce a sidebar with a drop-down 
  | OLD | NEW | 
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 Resources.FrameMenu = class extends Common.Object { | |
| 6 constructor() { | |
| 7 super(); | |
| 8 this._button = createElement('button'); | |
| 9 this._button.className = 'frame-selector'; | |
| 10 this._button.appendChild(UI.Icon.create('largeicon-navigator-frame')); | |
| 11 this._nameLabel = this._button.createChild('span', 'frame-name'); | |
| 12 this._button.appendChild(UI.Icon.create('smallicon-triangle-down')); | |
| 13 | |
| 14 this._button.addEventListener('click', () => this._showPopup()); | |
| 15 | |
| 16 /** @type {?SDK.ResourceTreeFrame} */ | |
| 17 this._selectedFrame = null; | |
| 18 | |
| 19 this.selectFrame(null); | |
| 20 } | |
| 21 | |
| 22 /** | |
| 23 * @param {number} depth | |
| 24 * @param {?string} parentId | |
| 25 * @param {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} framesTree | |
| 26 * @param {!Array<!Resources.FrameMenu._ListItem>} array | |
| 27 * @return {!Array<!Resources.FrameMenu._ListItem>} | |
| 
dgozman
2017/04/05 20:52:56
Let's not return since this function actually popu
 
eostroukhov
2017/05/03 00:33:47
Done.
 | |
| 28 */ | |
| 29 static _flatten(depth, parentId, framesTree, array) { | |
| 30 var frames = framesTree.get(parentId); | |
| 
dgozman
2017/04/05 20:52:56
Looks like you call this with |null| parentId firs
 
eostroukhov
2017/05/03 00:33:46
Not sure I understand. Can you elaborate?
 | |
| 31 if (!frames) | |
| 32 return array; | |
| 33 for (var frame of frames) { | |
| 34 array.push(new Resources.FrameMenu._ListItem(frame, depth)); | |
| 35 Resources.FrameMenu._flatten(depth + 1, frame.id, framesTree, array); | |
| 36 } | |
| 37 return array; | |
| 38 } | |
| 39 | |
| 40 /** | |
| 41 * @param {?SDK.Target} target | |
| 42 * @param {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} framesTree | |
| 
dgozman
2017/04/05 20:52:56
Why frame id is nullable? I don't see where you us
 
eostroukhov
2017/05/03 00:33:47
It is for frames with null parent, e.g. for the ro
 | |
| 43 * @param {!Set<!SDK.Target>} visitedTargets | |
| 44 * @return {?string} main frame ID | |
| 45 */ | |
| 46 static _collectFrames(target, framesTree, visitedTargets) { | |
| 47 if (!target) | |
| 48 return null; | |
| 49 var model = target.model(SDK.ResourceTreeModel); | |
| 50 if (!model || !model.mainFrame) | |
| 51 return null; | |
| 52 if (visitedTargets.has(target)) | |
| 53 return model.mainFrame.id; | |
| 54 visitedTargets.add(target); | |
| 55 var parentId = Resources.FrameMenu._collectFrames(target.parentTarget(), fra mesTree, visitedTargets); | |
| 56 framesTree.get(parentId).push(model.mainFrame); | |
| 57 Resources.FrameMenu._addChildFrames(model.mainFrame, framesTree); | |
| 58 return model.mainFrame.id; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * @param {!SDK.ResourceTreeFrame} frame | |
| 63 * @param {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} framesTree | |
| 64 */ | |
| 65 static _addChildFrames(frame, framesTree) { | |
| 66 framesTree.set(frame.id, frame.childFrames); | |
| 67 for (var childFrame of frame.childFrames) | |
| 68 Resources.FrameMenu._addChildFrames(childFrame, framesTree); | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * @returns {!Element} | |
| 73 */ | |
| 74 get element() { | |
| 
dgozman
2017/04/05 20:52:56
No getters.
 
eostroukhov
2017/05/03 00:33:46
Done.
 | |
| 75 return this._button; | |
| 76 } | |
| 77 | |
| 78 /** | |
| 79 * @return {?SDK.ResourceTreeFrame} frame | |
| 80 */ | |
| 81 selectedFrame() { | |
| 82 return this._selectedFrame; | |
| 83 } | |
| 84 | |
| 85 selectRootFrame() { | |
| 86 var target = SDK.targetManager.mainTarget(); | |
| 87 var model = target && target.model(SDK.ResourceTreeModel); | |
| 88 var frame = model && model.mainFrame; | |
| 89 this.selectFrame(frame); | |
| 90 } | |
| 91 | |
| 92 _showPopup() { | |
| 93 /** @type {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} */ | |
| 94 var framesTree = new Map(); | |
| 95 framesTree.set(null, []); | |
| 96 /** @type {!Set<!SDK.Target>} */ | |
| 97 var visitedTargets = new Set(); | |
| 98 for (var target of SDK.targetManager.targets()) | |
| 99 Resources.FrameMenu._collectFrames(target, framesTree, visitedTargets); | |
| 100 | |
| 101 var items = Resources.FrameMenu._flatten(0, null, framesTree, []); | |
| 102 var provider = new Resources.FrameMenu._ListProvider(this, items); | |
| 103 var list = new QuickOpen.FilteredListWidget(provider); | |
| 104 var selectedItem = null; | |
| 105 if (this._selectedFrame) { | |
| 106 for (var i = 0; i < items.length; i++) { | |
| 107 if (items[i].frame === this._selectedFrame) { | |
| 108 selectedItem = i; | |
| 109 break; | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 if (selectedItem !== null) | |
| 114 list.selectItem(selectedItem); | |
| 115 list.setInputIcon('mediumicon-search'); | |
| 116 var anchorBox = this._button.firstElementChild.boxInWindow(); | |
| 117 list.showAsDialog(anchorBox, UI.GlassPane.AnchorBehavior.PreferBottom); | |
| 118 } | |
| 119 | |
| 120 reset() { | |
| 
dgozman
2017/04/05 20:52:56
Inline this one.
 
eostroukhov
2017/05/03 00:33:46
It was not used anywhere anyways :)
 | |
| 121 this.selectFrame(null); | |
| 122 } | |
| 123 | |
| 124 /** | |
| 125 * @param {?SDK.ResourceTreeFrame} frame | |
| 126 */ | |
| 127 selectFrame(frame) { | |
| 128 this._selectedFrame = frame; | |
| 129 | |
| 130 var displayName = frame ? frame.displayName() : ''; | |
| 131 var frameName = frame ? frame.name : ''; | |
| 132 | |
| 133 this._nameLabel.textContent = frameName || displayName; | |
| 134 this._button.title = displayName; | |
| 135 } | |
| 136 }; | |
| 137 | |
| 138 Resources.FrameMenu._ListItem = class { | |
| 139 /** | |
| 140 * @param {!SDK.ResourceTreeFrame} frame | |
| 141 * @param {number} depth | |
| 142 */ | |
| 143 constructor(frame, depth) { | |
| 144 this.frame = frame; | |
| 145 this.depth = depth; | |
| 146 } | |
| 147 }; | |
| 148 | |
| 149 Resources.FrameMenu._ListProvider = class extends QuickOpen.FilteredListWidget.P rovider { | |
| 
dgozman
2017/04/05 20:52:56
Why not merge with FrameMenu itself?
 
eostroukhov
2017/05/03 00:33:47
I felt like it was more natural as it ties frames
 | |
| 150 /** | |
| 151 * @param {!Resources.FrameMenu} menu | |
| 152 * @param {!Array<!Resources.FrameMenu._ListItem>} items | |
| 153 */ | |
| 154 constructor(menu, items) { | |
| 155 super(); | |
| 156 this._menu = menu; | |
| 157 this._items = items; | |
| 158 } | |
| 159 | |
| 160 /** | |
| 161 * @override | |
| 162 * @return {number} | |
| 163 */ | |
| 164 itemCount() { | |
| 165 return this._items.length; | |
| 166 } | |
| 167 | |
| 168 /** | |
| 169 * @override | |
| 170 * @param {number} itemIndex | |
| 171 * @return {string} | |
| 172 */ | |
| 173 itemKeyAt(itemIndex) { | |
| 174 var frame = this._items[itemIndex].frame; | |
| 175 return frame.displayName() + frame.securityOrigin; | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * @override | |
| 180 * @param {?number} itemIndex | |
| 181 */ | |
| 182 hoverItem(itemIndex) { | |
| 183 SDK.DOMModel.hideDOMNodeHighlight(); | |
| 184 if (itemIndex === null) | |
| 185 return; | |
| 186 var frame = this._items[itemIndex].frame; | |
| 187 var domModel = frame && frame.target().model(SDK.DOMModel); | |
| 
dgozman
2017/04/05 20:52:56
How there could be no frame?
 
eostroukhov
2017/05/03 00:33:46
Done.
 | |
| 188 if (!domModel) | |
| 189 return; | |
| 190 domModel.highlightFrame(frame.id); | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * @override | |
| 195 * @param {number} itemIndex | |
| 196 * @param {string} query | |
| 197 * @param {!Element} titleElement | |
| 198 * @param {!Element} subtitleElement | |
| 199 */ | |
| 200 renderItem(itemIndex, query, titleElement, subtitleElement) { | |
| 201 var frame = this._items[itemIndex].frame; | |
| 202 var indent = query ? 0 : (this._items[itemIndex].depth * 16); | |
| 203 var padding = 24 + indent + 'px'; | |
| 204 titleElement.textContent = frame.displayName(); | |
| 205 subtitleElement.textContent = frame.securityOrigin; | |
| 206 titleElement.style.paddingLeft = padding; | |
| 207 subtitleElement.style.paddingLeft = padding; | |
| 208 QuickOpen.FilteredListWidget.highlightRanges(titleElement, query, true); | |
| 209 QuickOpen.FilteredListWidget.highlightRanges(subtitleElement, query, true); | |
| 210 } | |
| 211 | |
| 212 /** | |
| 213 * @override | |
| 214 * @param {?number} itemIndex | |
| 215 * @param {string} promptValue | |
| 216 */ | |
| 217 selectItem(itemIndex, promptValue) { | |
| 218 if (itemIndex === null) | |
| 219 return; | |
| 220 var frame = this._items[itemIndex].frame; | |
| 221 this._menu.selectFrame(frame); | |
| 222 this._menu.dispatchEventToListeners(Resources.FrameMenu.Events.FrameSelected , frame); | |
| 223 } | |
| 224 | |
| 225 /** | |
| 226 * @override | |
| 227 * @return {boolean} | |
| 228 */ | |
| 229 renderAsTwoRows() { | |
| 230 return true; | |
| 231 } | |
| 232 }; | |
| 233 | |
| 234 /** | |
| 235 * @enum {symbol} | |
| 236 */ | |
| 237 Resources.FrameMenu.Events = { | |
| 238 FrameSelected: Symbol('FrameSelected') | |
| 239 }; | |
| OLD | NEW |