Index: third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c6b4f4e13f7a029df440cd8c965e1eb8ba3d686c |
--- /dev/null |
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js |
@@ -0,0 +1,358 @@ |
+// 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.ResourcesSection = class { |
+ /** |
+ * @param {!Resources.ResourcesPanel} storagePanel |
+ * @param {!UI.TreeElement} treeElement |
+ */ |
+ constructor(storagePanel, treeElement) { |
+ this._panel = storagePanel; |
+ this._treeElement = treeElement; |
+ /** @type {!Map<string, !Resources.FrameTreeElement>} */ |
+ this._treeElementForFrameId = new Map(); |
+ |
+ function addListener(eventType, handler, target) { |
+ SDK.targetManager.addModelListener(SDK.ResourceTreeModel, eventType, event => handler.call(target, event.data)); |
+ } |
+ addListener(SDK.ResourceTreeModel.Events.FrameAdded, this.frameAdded, this); |
caseq
2017/03/03 21:59:54
let's keep listeners private.
eostroukhov
2017/03/04 00:16:36
Done.
|
+ addListener(SDK.ResourceTreeModel.Events.FrameNavigated, this.frameNavigated, this); |
+ addListener(SDK.ResourceTreeModel.Events.FrameDetached, this.frameDetached, this); |
+ addListener(SDK.ResourceTreeModel.Events.ResourceAdded, this.resourceAdded, this); |
+ |
+ var mainTarget = SDK.targetManager.mainTarget(); |
+ var resourceTreeModel = mainTarget && mainTarget.hasDOMCapability() && SDK.ResourceTreeModel.fromTarget(mainTarget); |
+ var mainFrame = resourceTreeModel && resourceTreeModel.mainFrame; |
+ if (mainFrame) |
+ this.populateFrame(mainFrame); |
dgozman
2017/02/25 00:54:42
Why populate with main frame?
eostroukhov
2017/02/25 01:00:22
It is the root node.
|
+ } |
+ |
+ /** |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ * @returns {?SDK.ResourceTreeFrame} |
+ */ |
+ static _getParentFrame(frame) { |
+ var parentFrame = frame.parentFrame; |
+ if (parentFrame) |
+ return parentFrame; |
+ var parentTarget = frame.target().parentTarget(); |
+ while (parentTarget && !parentTarget.hasDOMCapability()) |
caseq
2017/03/03 21:59:54
Does it ever happen?
eostroukhov
2017/03/04 00:16:36
Changed to console.assert, as per offline discussi
|
+ parentTarget = parentTarget.parentTarget(); |
+ if (!parentTarget) |
+ return null; |
+ var model = SDK.ResourceTreeModel.fromTarget(parentTarget); |
+ return model.mainFrame; |
+ } |
+ |
+ /** |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ */ |
+ frameAdded(frame) { |
+ var parentFrame = Resources.ResourcesSection._getParentFrame(frame); |
+ var parentTreeElement = parentFrame ? this._treeElementForFrameId.get(parentFrame.id) : this._treeElement; |
+ if (!parentTreeElement) { |
+ console.warn('No frame to route ' + frame.url + ' to.'); |
caseq
2017/03/03 21:59:54
nit: `No frame to route ${frame.url} to.`
eostroukhov
2017/03/04 00:16:36
Done.
|
+ return; |
+ } |
+ |
+ var frameTreeElement = new Resources.FrameTreeElement(this._panel, frame); |
+ this._treeElementForFrameId.set(frame.id, frameTreeElement); |
+ parentTreeElement.appendChild(frameTreeElement); |
+ } |
+ |
+ /** |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ */ |
+ frameDetached(frame) { |
+ var frameTreeElement = this._treeElementForFrameId.get(frame.id); |
+ if (!frameTreeElement) |
+ return; |
+ |
+ this._treeElementForFrameId.remove(frame.id); |
+ if (frameTreeElement.parent) |
+ frameTreeElement.parent.removeChild(frameTreeElement); |
+ } |
+ |
+ /** |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ */ |
+ frameNavigated(frame) { |
+ if (!Resources.ResourcesSection._getParentFrame(frame)) |
+ return; |
+ var frameTreeElement = this._treeElementForFrameId.get(frame.id); |
+ if (frameTreeElement) |
+ frameTreeElement.frameNavigated(frame); |
+ } |
+ |
+ /** |
+ * @param {!SDK.Resource} resource |
+ */ |
+ resourceAdded(resource) { |
+ var statusCode = resource['statusCode']; |
+ if (statusCode >= 301 && statusCode <= 303) |
+ return; |
+ |
+ var frameTreeElement = this._treeElementForFrameId.get(resource.frameId); |
+ if (!frameTreeElement) { |
+ // This is a frame's main resource, it will be retained |
+ // and re-added by the resource manager; |
+ return; |
+ } |
+ |
+ frameTreeElement.appendResource(resource); |
+ } |
+ |
+ reset() { |
+ this._treeElement.removeChildren(); |
+ this._treeElementForFrameId.clear(); |
+ } |
+ |
+ /** |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ */ |
+ populateFrame(frame) { |
+ this.frameAdded(frame); |
+ for (var child of frame.childFrames) |
+ this.populateFrame(child); |
+ for (var resource of frame.resources()) |
+ this.resourceAdded(resource); |
+ } |
+}; |
+ |
+Resources.FrameTreeElement = class extends Resources.BaseStorageTreeElement { |
dgozman
2017/02/25 00:54:42
Didn't we agree on the frame picker? Why is there
eostroukhov
2017/02/25 01:00:22
This is a refactoring change, functionality remain
caseq
2017/03/03 21:59:55
Mind re-uploading with --similarity=<something-sma
eostroukhov
2017/03/04 00:16:36
I tried that.
|
+ /** |
+ * @param {!Resources.ResourcesPanel} storagePanel |
+ * @param {!SDK.ResourceTreeFrame} frame |
+ */ |
+ constructor(storagePanel, frame) { |
+ super(storagePanel, '', false); |
+ this._panel = storagePanel; |
+ this._frame = frame; |
+ this._frameId = frame.id; |
+ this._categoryElements = {}; |
+ this._treeElementForResource = {}; |
+ this.frameNavigated(frame); |
+ |
+ var icon = UI.Icon.create('largeicon-navigator-frame', 'navigator-tree-item'); |
+ icon.classList.add('navigator-frame-tree-item'); |
+ this.setLeadingIcons([icon]); |
+ } |
+ |
+ frameNavigated(frame) { |
+ this.removeChildren(); |
+ this._frameId = frame.id; |
+ this.title = frame.displayName(); |
+ this._categoryElements = {}; |
+ this._treeElementForResource = {}; |
+ } |
+ |
+ get itemURL() { |
+ return 'frame://' + encodeURI(this.titleAsText()); |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {boolean} |
+ */ |
+ onselect(selectedByUser) { |
+ super.onselect(selectedByUser); |
+ this._panel.showCategoryView(this.titleAsText()); |
+ |
+ this.listItemElement.classList.remove('hovered'); |
+ SDK.DOMModel.hideDOMNodeHighlight(); |
+ return false; |
+ } |
+ |
+ set hovered(hovered) { |
+ if (hovered) { |
+ this.listItemElement.classList.add('hovered'); |
+ var domModel = SDK.DOMModel.fromTarget(this._frame.target()); |
+ if (domModel) |
+ domModel.highlightFrame(this._frameId); |
+ } else { |
+ this.listItemElement.classList.remove('hovered'); |
+ SDK.DOMModel.hideDOMNodeHighlight(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!SDK.Resource} resource |
+ */ |
+ appendResource(resource) { |
+ var resourceType = resource.resourceType(); |
+ var categoryName = resourceType.name(); |
+ var categoryElement = resourceType === Common.resourceTypes.Document ? this : this._categoryElements[categoryName]; |
+ if (!categoryElement) { |
+ categoryElement = |
+ new Resources.StorageCategoryTreeElement(this._panel, resource.resourceType().category().title, categoryName); |
+ this._categoryElements[resourceType.name()] = categoryElement; |
+ this._insertInPresentationOrder(this, categoryElement); |
+ } |
+ var resourceTreeElement = new Resources.FrameResourceTreeElement(this._panel, resource); |
+ this._insertInPresentationOrder(categoryElement, resourceTreeElement); |
+ this._treeElementForResource[resource.url] = resourceTreeElement; |
+ } |
+ |
+ /** |
+ * @param {string} url |
+ * @return {?SDK.Resource} |
+ */ |
+ resourceByURL(url) { |
+ var treeElement = this._treeElementForResource[url]; |
+ return treeElement ? treeElement._resource : null; |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ appendChild(treeElement) { |
+ this._insertInPresentationOrder(this, treeElement); |
+ } |
+ |
+ _insertInPresentationOrder(parentTreeElement, childTreeElement) { |
+ // Insert in the alphabetical order, first frames, then resources. Document resource goes last. |
+ function typeWeight(treeElement) { |
+ if (treeElement instanceof Resources.StorageCategoryTreeElement) |
+ return 2; |
+ if (treeElement instanceof Resources.FrameTreeElement) |
+ return 1; |
+ return 3; |
+ } |
+ |
+ function compare(treeElement1, treeElement2) { |
+ var typeWeight1 = typeWeight(treeElement1); |
+ var typeWeight2 = typeWeight(treeElement2); |
+ |
+ var result; |
+ if (typeWeight1 > typeWeight2) |
+ result = 1; |
+ else if (typeWeight1 < typeWeight2) |
+ result = -1; |
+ else |
+ result = treeElement1.titleAsText().localeCompare(treeElement2.titleAsText()); |
+ return result; |
+ } |
+ |
+ var childCount = parentTreeElement.childCount(); |
+ var i; |
+ for (i = 0; i < childCount; ++i) { |
+ if (compare(childTreeElement, parentTreeElement.childAt(i)) < 0) |
+ break; |
+ } |
+ parentTreeElement.insertChild(childTreeElement, i); |
+ } |
+}; |
+ |
+Resources.FrameResourceTreeElement = class extends Resources.BaseStorageTreeElement { |
+ /** |
+ * @param {!Resources.ResourcesPanel} storagePanel |
+ * @param {!SDK.Resource} resource |
+ */ |
+ constructor(storagePanel, resource) { |
+ super(storagePanel, resource.displayName, false); |
+ this._panel = storagePanel; |
+ /** @type {!SDK.Resource} */ |
+ this._resource = resource; |
+ /** @type {?SourceFrame.ResourceSourceFrame} */ |
+ this._sourceFrame = null; |
+ this.tooltip = resource.url; |
+ this._resource[Resources.FrameResourceTreeElement._symbol] = this; |
+ |
+ var icon = UI.Icon.create('largeicon-navigator-file', 'navigator-tree-item'); |
+ icon.classList.add('navigator-file-tree-item'); |
+ icon.classList.add('navigator-' + resource.resourceType().name() + '-tree-item'); |
+ this.setLeadingIcons([icon]); |
+ } |
+ |
+ /** |
+ * @param {!SDK.Resource} resource |
+ */ |
+ static forResource(resource) { |
+ return resource[Resources.FrameResourceTreeElement._symbol]; |
+ } |
+ |
+ /** |
+ * @param {!SDK.Resource} resource |
+ * @return {?UI.Widget} |
+ */ |
+ static resourceViewForResource(resource) { |
+ if (resource.hasTextContent()) { |
+ var treeElement = Resources.FrameResourceTreeElement.forResource(resource); |
+ if (!treeElement) |
+ return null; |
+ return treeElement._sourceView(); |
+ } |
+ |
+ switch (resource.resourceType()) { |
+ case Common.resourceTypes.Image: |
+ return new SourceFrame.ImageView(resource.mimeType, resource); |
+ case Common.resourceTypes.Font: |
+ return new SourceFrame.FontView(resource.mimeType, resource); |
+ default: |
+ return new UI.EmptyWidget(resource.url); |
+ } |
+ } |
+ |
+ get itemURL() { |
+ return this._resource.url; |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {boolean} |
+ */ |
+ onselect(selectedByUser) { |
+ super.onselect(selectedByUser); |
+ this.showView(Resources.FrameResourceTreeElement.resourceViewForResource(this._resource)); |
+ return false; |
+ } |
+ |
+ /** |
+ * @override |
+ * @return {boolean} |
+ */ |
+ ondblclick(event) { |
+ InspectorFrontendHost.openInNewTab(this._resource.url); |
+ return false; |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ onattach() { |
+ super.onattach(); |
+ this.listItemElement.draggable = true; |
+ this.listItemElement.addEventListener('dragstart', this._ondragstart.bind(this), false); |
+ this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true); |
+ } |
+ |
+ /** |
+ * @param {!MouseEvent} event |
+ * @return {boolean} |
+ */ |
+ _ondragstart(event) { |
+ event.dataTransfer.setData('text/plain', this._resource.content || ''); |
+ event.dataTransfer.effectAllowed = 'copy'; |
+ return true; |
+ } |
+ |
+ _handleContextMenuEvent(event) { |
+ var contextMenu = new UI.ContextMenu(event); |
+ contextMenu.appendApplicableItems(this._resource); |
+ contextMenu.show(); |
+ } |
+ |
+ /** |
+ * @return {!SourceFrame.ResourceSourceFrame} |
+ */ |
+ _sourceView() { |
+ if (!this._sourceFrame) { |
+ this._sourceFrame = new SourceFrame.ResourceSourceFrame(this._resource); |
+ this._sourceFrame.setHighlighterType(this._resource.canonicalMimeType()); |
+ } |
+ return this._sourceFrame; |
+ } |
+}; |
+ |
+Resources.FrameResourceTreeElement._symbol = Symbol('treeElement'); |