Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(599)

Unified Diff: third_party/WebKit/Source/devtools/front_end/resources/ResourcesSection.js

Issue 2712043002: [DevTools] Separate frames and resources handling (Closed)
Patch Set: Added missing null check Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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');

Powered by Google App Engine
This is Rietveld 408576698