/* * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ WebInspector.ResourceTreeModel = function(networkManager) { WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceStarted, this._onResourceStarted, this); WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceUpdated, this._onResourceUpdated, this); WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceFinished, this._onResourceUpdated, this); WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.FrameDetached, this._onFrameDetachedFromParent, this); WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.FrameCommittedLoad, this._onCommitLoad, this); this.frontendReused(); } WebInspector.ResourceTreeModel.EventTypes = { FrameAdded: "FrameAdded", FrameNavigated: "FrameNavigated", FrameDetached: "FrameDetached", ResourceAdded: "ResourceAdded", CachedResourcesLoaded: "CachedResourcesLoaded" } WebInspector.ResourceTreeModel.prototype = { frontendReused: function() { this._resourcesByURL = {}; this._resourcesByFrameId = {}; this._subframes = {}; NetworkAgent.getCachedResources(this._processCachedResources.bind(this)); }, _processCachedResources: function(error, mainFramePayload) { if (error) return; this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, 0); WebInspector.mainResource = this._addFramesRecursively(mainFramePayload); this._cachedResourcesProcessed = true; this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded); }, _addOrUpdateFrame: function(frame) { this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, frame); var subframes = this._subframes[frame.parentId]; if (!subframes) { subframes = []; this._subframes[frame.parentId || 0] = subframes; } subframes.push(frame); }, frames: function(parentFrameId) { return this._subframes[parentFrameId] || []; }, subframes: function(parentFrameId) { return this._subframes[parentFrameId] || []; }, resources: function(frameId) { var result = []; var resources = this._resourcesByFrameId[frameId] || {}; for (var url in resources) result.push(resources[url]); return result; }, _onCommitLoad: function(event) { if (!this._cachedResourcesProcessed) return; var frame = event.data.frame; var loaderId = event.data.loaderId; var isMainFrame = !frame.parentId; // frame.parentId === 0 is when main frame navigation happens. this._clearChildFramesAndResources(isMainFrame ? 0 : frame.id, loaderId); this._addOrUpdateFrame(frame); var resourcesForFrame = this._resourcesByFrameId[frame.id]; if (resourcesForFrame) { for (var url in resourcesForFrame) this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resourcesForFrame[url]); } if (isMainFrame && this.resourceForURL(frame.url)) WebInspector.mainResource = this.resourceForURL(frame.url); }, _onFrameDetachedFromParent: function(event) { if (!this._cachedResourcesProcessed) return; var frameId = event.data; this._clearChildFramesAndResources(frameId, 0); this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, frameId); }, _onResourceStarted: function(event) { if (!this._cachedResourcesProcessed) return; this._bindResourceURL(event.data); }, _onResourceUpdated: function(event) { if (!this._cachedResourcesProcessed) return; this._addResourceToFrame(event.data); }, _addResourceToFrame: function(resource) { var frameId = resource.frameId; var resourcesForFrame = this._resourcesByFrameId[frameId]; if (!resourcesForFrame) { resourcesForFrame = {}; this._resourcesByFrameId[frameId] = resourcesForFrame; } if (resourcesForFrame[resource.url] === resource) { // Already in the tree, we just got an extra update. return; } resourcesForFrame[resource.url] = resource; this._bindResourceURL(resource); this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource); }, forAllResources: function(callback) { this._callForFrameResources(0, callback); }, addConsoleMessage: function(msg) { var resource = this.resourceForURL(msg.url); if (!resource) return; switch (msg.level) { case WebInspector.ConsoleMessage.MessageLevel.Warning: resource.warnings += msg.repeatDelta; break; case WebInspector.ConsoleMessage.MessageLevel.Error: resource.errors += msg.repeatDelta; break; } var view = WebInspector.ResourceView.resourceViewForResource(resource); if (view.addMessage && msg.isErrorOrWarning() && msg.message) view.addMessage(msg); }, clearConsoleMessages: function() { function callback(resource) { resource.clearErrorsAndWarnings(); } this.forAllResources(callback); }, resourceForURL: function(url) { return this._resourcesByURL[url]; }, _bindResourceURL: function(resource) { this._resourcesByURL[resource.url] = resource; }, _clearChildFramesAndResources: function(frameId, loaderToPreserveId) { this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, frameId); this._clearResources(frameId, loaderToPreserveId); var subframes = this._subframes[frameId]; for (var i = 0; subframes && i < subframes.length; ++ i) { this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameRemoved, subframes[i].id); this._clearChildFramesAndResources(subframes[i].id, loaderToPreserveId); } delete this._subframes[frameId]; }, _clearResources: function(frameId, loaderToPreserveId) { var resourcesForFrame = this._resourcesByFrameId[frameId]; if (!resourcesForFrame) return; var preservedResourcesForFrame = []; for (var url in resourcesForFrame) { var resource = resourcesForFrame[url]; if (resource.loaderId === loaderToPreserveId) { preservedResourcesForFrame[url] = resource; continue; } this._unbindResourceURL(resource); } delete this._resourcesByFrameId[frameId]; if (preservedResourcesForFrame.length) { this._resourcesByFrameId[frameId] = preservedResourcesForFrame; } }, _callForFrameResources: function(frameId, callback) { var resources = this._resourcesByFrameId[frameId]; for (var url in resources) { if (callback(resources[url])) return true; } var frames = this._subframes[frameId]; for (var i = 0; frames && i < frames.length; ++i) { if (this._callForFrameResources(frames[i].id, callback)) return true; } return false; }, _unbindResourceURL: function(resource) { delete this._resourcesByURL[resource.url]; }, _addFramesRecursively: function(frameTreePayload) { var framePayload = frameTreePayload.frame; // Create frame resource. var frameResource = this._createResource(framePayload, framePayload.url); frameResource.type = WebInspector.Resource.Type.Document; frameResource.finished = true; this._addOrUpdateFrame(framePayload); this._addResourceToFrame(frameResource); for (var i = 0; frameTreePayload.childFrames && i < frameTreePayload.childFrames.length; ++i) this._addFramesRecursively(frameTreePayload.childFrames[i]); if (!frameTreePayload.resources) return; // Create frame subresources. for (var i = 0; i < frameTreePayload.resources.length; ++i) { var subresource = frameTreePayload.resources[i]; var resource = this._createResource(framePayload, subresource.url); resource.type = WebInspector.Resource.Type[subresource.type]; resource.finished = true; this._addResourceToFrame(resource); } return frameResource; }, _createResource: function(frame, url) { var resource = new WebInspector.Resource(null, url); resource.frameId = frame.id; resource.loaderId = frame.loaderId; resource.documentURL = frame.url; return resource; } } WebInspector.ResourceTreeModel.prototype.__proto__ = WebInspector.Object.prototype;