Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/resources/FrameMenu.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/resources/FrameMenu.js b/third_party/WebKit/Source/devtools/front_end/resources/FrameMenu.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7c60fa0fee449728464d7e716d17559ee3f61b33 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/resources/FrameMenu.js |
| @@ -0,0 +1,239 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +Resources.FrameMenu = class extends Common.Object { |
| + constructor() { |
| + super(); |
| + this._button = createElement('button'); |
| + this._button.className = 'frame-selector'; |
| + this._button.appendChild(UI.Icon.create('largeicon-navigator-frame')); |
| + this._nameLabel = this._button.createChild('span', 'frame-name'); |
| + this._button.appendChild(UI.Icon.create('smallicon-triangle-down')); |
| + |
| + this._button.addEventListener('click', () => this._showPopup()); |
| + |
| + /** @type {?SDK.ResourceTreeFrame} */ |
| + this._selectedFrame = null; |
| + |
| + this.selectFrame(null); |
| + } |
| + |
| + /** |
| + * @param {number} depth |
| + * @param {?string} parentId |
| + * @param {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} framesTree |
| + * @param {!Array<!Resources.FrameMenu._ListItem>} array |
| + * @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.
|
| + */ |
| + static _flatten(depth, parentId, framesTree, array) { |
| + 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?
|
| + if (!frames) |
| + return array; |
| + for (var frame of frames) { |
| + array.push(new Resources.FrameMenu._ListItem(frame, depth)); |
| + Resources.FrameMenu._flatten(depth + 1, frame.id, framesTree, array); |
| + } |
| + return array; |
| + } |
| + |
| + /** |
| + * @param {?SDK.Target} target |
| + * @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
|
| + * @param {!Set<!SDK.Target>} visitedTargets |
| + * @return {?string} main frame ID |
| + */ |
| + static _collectFrames(target, framesTree, visitedTargets) { |
| + if (!target) |
| + return null; |
| + var model = target.model(SDK.ResourceTreeModel); |
| + if (!model || !model.mainFrame) |
| + return null; |
| + if (visitedTargets.has(target)) |
| + return model.mainFrame.id; |
| + visitedTargets.add(target); |
| + var parentId = Resources.FrameMenu._collectFrames(target.parentTarget(), framesTree, visitedTargets); |
| + framesTree.get(parentId).push(model.mainFrame); |
| + Resources.FrameMenu._addChildFrames(model.mainFrame, framesTree); |
| + return model.mainFrame.id; |
| + } |
| + |
| + /** |
| + * @param {!SDK.ResourceTreeFrame} frame |
| + * @param {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} framesTree |
| + */ |
| + static _addChildFrames(frame, framesTree) { |
| + framesTree.set(frame.id, frame.childFrames); |
| + for (var childFrame of frame.childFrames) |
| + Resources.FrameMenu._addChildFrames(childFrame, framesTree); |
| + } |
| + |
| + /** |
| + * @returns {!Element} |
| + */ |
| + get element() { |
|
dgozman
2017/04/05 20:52:56
No getters.
eostroukhov
2017/05/03 00:33:46
Done.
|
| + return this._button; |
| + } |
| + |
| + /** |
| + * @return {?SDK.ResourceTreeFrame} frame |
| + */ |
| + selectedFrame() { |
| + return this._selectedFrame; |
| + } |
| + |
| + selectRootFrame() { |
| + var target = SDK.targetManager.mainTarget(); |
| + var model = target && target.model(SDK.ResourceTreeModel); |
| + var frame = model && model.mainFrame; |
| + this.selectFrame(frame); |
| + } |
| + |
| + _showPopup() { |
| + /** @type {!Map<?string, !Array<!SDK.ResourceTreeFrame>>} */ |
| + var framesTree = new Map(); |
| + framesTree.set(null, []); |
| + /** @type {!Set<!SDK.Target>} */ |
| + var visitedTargets = new Set(); |
| + for (var target of SDK.targetManager.targets()) |
| + Resources.FrameMenu._collectFrames(target, framesTree, visitedTargets); |
| + |
| + var items = Resources.FrameMenu._flatten(0, null, framesTree, []); |
| + var provider = new Resources.FrameMenu._ListProvider(this, items); |
| + var list = new QuickOpen.FilteredListWidget(provider); |
| + var selectedItem = null; |
| + if (this._selectedFrame) { |
| + for (var i = 0; i < items.length; i++) { |
| + if (items[i].frame === this._selectedFrame) { |
| + selectedItem = i; |
| + break; |
| + } |
| + } |
| + } |
| + if (selectedItem !== null) |
| + list.selectItem(selectedItem); |
| + list.setInputIcon('mediumicon-search'); |
| + var anchorBox = this._button.firstElementChild.boxInWindow(); |
| + list.showAsDialog(anchorBox, UI.GlassPane.AnchorBehavior.PreferBottom); |
| + } |
| + |
| + reset() { |
|
dgozman
2017/04/05 20:52:56
Inline this one.
eostroukhov
2017/05/03 00:33:46
It was not used anywhere anyways :)
|
| + this.selectFrame(null); |
| + } |
| + |
| + /** |
| + * @param {?SDK.ResourceTreeFrame} frame |
| + */ |
| + selectFrame(frame) { |
| + this._selectedFrame = frame; |
| + |
| + var displayName = frame ? frame.displayName() : ''; |
| + var frameName = frame ? frame.name : ''; |
| + |
| + this._nameLabel.textContent = frameName || displayName; |
| + this._button.title = displayName; |
| + } |
| +}; |
| + |
| +Resources.FrameMenu._ListItem = class { |
| + /** |
| + * @param {!SDK.ResourceTreeFrame} frame |
| + * @param {number} depth |
| + */ |
| + constructor(frame, depth) { |
| + this.frame = frame; |
| + this.depth = depth; |
| + } |
| +}; |
| + |
| +Resources.FrameMenu._ListProvider = class extends QuickOpen.FilteredListWidget.Provider { |
|
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
|
| + /** |
| + * @param {!Resources.FrameMenu} menu |
| + * @param {!Array<!Resources.FrameMenu._ListItem>} items |
| + */ |
| + constructor(menu, items) { |
| + super(); |
| + this._menu = menu; |
| + this._items = items; |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {number} |
| + */ |
| + itemCount() { |
| + return this._items.length; |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {number} itemIndex |
| + * @return {string} |
| + */ |
| + itemKeyAt(itemIndex) { |
| + var frame = this._items[itemIndex].frame; |
| + return frame.displayName() + frame.securityOrigin; |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {?number} itemIndex |
| + */ |
| + hoverItem(itemIndex) { |
| + SDK.DOMModel.hideDOMNodeHighlight(); |
| + if (itemIndex === null) |
| + return; |
| + var frame = this._items[itemIndex].frame; |
| + 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.
|
| + if (!domModel) |
| + return; |
| + domModel.highlightFrame(frame.id); |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {number} itemIndex |
| + * @param {string} query |
| + * @param {!Element} titleElement |
| + * @param {!Element} subtitleElement |
| + */ |
| + renderItem(itemIndex, query, titleElement, subtitleElement) { |
| + var frame = this._items[itemIndex].frame; |
| + var indent = query ? 0 : (this._items[itemIndex].depth * 16); |
| + var padding = 24 + indent + 'px'; |
| + titleElement.textContent = frame.displayName(); |
| + subtitleElement.textContent = frame.securityOrigin; |
| + titleElement.style.paddingLeft = padding; |
| + subtitleElement.style.paddingLeft = padding; |
| + QuickOpen.FilteredListWidget.highlightRanges(titleElement, query, true); |
| + QuickOpen.FilteredListWidget.highlightRanges(subtitleElement, query, true); |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {?number} itemIndex |
| + * @param {string} promptValue |
| + */ |
| + selectItem(itemIndex, promptValue) { |
| + if (itemIndex === null) |
| + return; |
| + var frame = this._items[itemIndex].frame; |
| + this._menu.selectFrame(frame); |
| + this._menu.dispatchEventToListeners(Resources.FrameMenu.Events.FrameSelected, frame); |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {boolean} |
| + */ |
| + renderAsTwoRows() { |
| + return true; |
| + } |
| +}; |
| + |
| +/** |
| + * @enum {symbol} |
| + */ |
| +Resources.FrameMenu.Events = { |
| + FrameSelected: Symbol('FrameSelected') |
| +}; |