Home | History | Annotate | Download | only in front-end
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 
     32 WebInspector.ResourceTreeModel = function(networkManager)
     33 {
     34     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceStarted, this._onResourceStarted, this);
     35     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceUpdated, this._onResourceUpdated, this);
     36     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceFinished, this._onResourceUpdated, this);
     37     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.FrameDetached, this._onFrameDetachedFromParent, this);
     38     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.FrameCommittedLoad, this._onCommitLoad, this);
     39 
     40     this.frontendReused();
     41 }
     42 
     43 WebInspector.ResourceTreeModel.EventTypes = {
     44     FrameAdded: "FrameAdded",
     45     FrameNavigated: "FrameNavigated",
     46     FrameDetached: "FrameDetached",
     47     ResourceAdded: "ResourceAdded",
     48     CachedResourcesLoaded: "CachedResourcesLoaded"
     49 }
     50 
     51 WebInspector.ResourceTreeModel.prototype = {
     52     frontendReused: function()
     53     {
     54         this._resourcesByURL = {};
     55         this._resourcesByFrameId = {};
     56         this._subframes = {};
     57         NetworkAgent.getCachedResources(this._processCachedResources.bind(this));
     58     },
     59 
     60     _processCachedResources: function(error, mainFramePayload)
     61     {
     62         if (error)
     63             return;
     64 
     65         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, 0);
     66 
     67         WebInspector.mainResource = this._addFramesRecursively(mainFramePayload);
     68         this._cachedResourcesProcessed = true;
     69 
     70         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded);
     71     },
     72 
     73     _addOrUpdateFrame: function(frame)
     74     {
     75         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, frame);
     76 
     77         var subframes = this._subframes[frame.parentId];
     78         if (!subframes) {
     79             subframes = [];
     80             this._subframes[frame.parentId || 0] = subframes;
     81         }
     82         subframes.push(frame);
     83     },
     84 
     85     frames: function(parentFrameId)
     86     {
     87         return this._subframes[parentFrameId] || [];
     88     },
     89 
     90     subframes: function(parentFrameId)
     91     {
     92         return this._subframes[parentFrameId] || [];
     93     },
     94 
     95     resources: function(frameId)
     96     {
     97         var result = [];
     98         var resources = this._resourcesByFrameId[frameId] || {};
     99         for (var url in resources)
    100             result.push(resources[url]);
    101         return result;
    102     },
    103 
    104     _onCommitLoad: function(event)
    105     {
    106         if (!this._cachedResourcesProcessed)
    107             return;
    108 
    109         var frame = event.data.frame;
    110         var loaderId = event.data.loaderId;
    111         var isMainFrame = !frame.parentId;
    112 
    113         // frame.parentId === 0 is when main frame navigation happens.
    114         this._clearChildFramesAndResources(isMainFrame ? 0 : frame.id, loaderId);
    115 
    116         this._addOrUpdateFrame(frame);
    117 
    118         var resourcesForFrame = this._resourcesByFrameId[frame.id];
    119         if (resourcesForFrame) {
    120             for (var url in resourcesForFrame)
    121                 this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resourcesForFrame[url]);
    122         }
    123 
    124         if (isMainFrame && this.resourceForURL(frame.url))
    125             WebInspector.mainResource = this.resourceForURL(frame.url);
    126     },
    127 
    128     _onFrameDetachedFromParent: function(event)
    129     {
    130         if (!this._cachedResourcesProcessed)
    131             return;
    132 
    133         var frameId = event.data;
    134         this._clearChildFramesAndResources(frameId, 0);
    135         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, frameId);
    136     },
    137 
    138     _onResourceStarted: function(event)
    139     {
    140         if (!this._cachedResourcesProcessed)
    141             return;
    142         this._bindResourceURL(event.data);
    143     },
    144 
    145     _onResourceUpdated: function(event)
    146     {
    147         if (!this._cachedResourcesProcessed)
    148             return;
    149         this._addResourceToFrame(event.data);
    150     },
    151 
    152     _addResourceToFrame: function(resource)
    153     {
    154         var frameId = resource.frameId;
    155         var resourcesForFrame = this._resourcesByFrameId[frameId];
    156         if (!resourcesForFrame) {
    157             resourcesForFrame = {};
    158             this._resourcesByFrameId[frameId] = resourcesForFrame;
    159         }
    160         if (resourcesForFrame[resource.url] === resource) {
    161             // Already in the tree, we just got an extra update.
    162             return;
    163         }
    164 
    165         resourcesForFrame[resource.url] = resource;
    166         this._bindResourceURL(resource);
    167         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource);
    168     },
    169 
    170     forAllResources: function(callback)
    171     {
    172         this._callForFrameResources(0, callback);
    173     },
    174 
    175     addConsoleMessage: function(msg)
    176     {
    177         var resource = this.resourceForURL(msg.url);
    178         if (!resource)
    179             return;
    180 
    181         switch (msg.level) {
    182         case WebInspector.ConsoleMessage.MessageLevel.Warning:
    183             resource.warnings += msg.repeatDelta;
    184             break;
    185         case WebInspector.ConsoleMessage.MessageLevel.Error:
    186             resource.errors += msg.repeatDelta;
    187             break;
    188         }
    189 
    190         var view = WebInspector.ResourceView.resourceViewForResource(resource);
    191         if (view.addMessage && msg.isErrorOrWarning() && msg.message)
    192             view.addMessage(msg);
    193     },
    194 
    195     clearConsoleMessages: function()
    196     {
    197         function callback(resource)
    198         {
    199             resource.clearErrorsAndWarnings();
    200         }
    201         this.forAllResources(callback);
    202     },
    203 
    204     resourceForURL: function(url)
    205     {
    206         return this._resourcesByURL[url];
    207     },
    208 
    209     _bindResourceURL: function(resource)
    210     {
    211         this._resourcesByURL[resource.url] = resource;
    212     },
    213 
    214     _clearChildFramesAndResources: function(frameId, loaderToPreserveId)
    215     {
    216         this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, frameId);
    217 
    218         this._clearResources(frameId, loaderToPreserveId);
    219         var subframes = this._subframes[frameId];
    220         for (var i = 0; subframes && i < subframes.length; ++ i) {
    221             this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameRemoved, subframes[i].id);
    222             this._clearChildFramesAndResources(subframes[i].id, loaderToPreserveId);
    223         }
    224         delete this._subframes[frameId];
    225     },
    226 
    227     _clearResources: function(frameId, loaderToPreserveId)
    228     {
    229         var resourcesForFrame = this._resourcesByFrameId[frameId];
    230         if (!resourcesForFrame)
    231             return;
    232 
    233         var preservedResourcesForFrame = [];
    234         for (var url in resourcesForFrame) {
    235             var resource = resourcesForFrame[url];
    236             if (resource.loaderId === loaderToPreserveId) {
    237                 preservedResourcesForFrame[url] = resource;
    238                 continue;
    239             }
    240             this._unbindResourceURL(resource);
    241         }
    242 
    243         delete this._resourcesByFrameId[frameId];
    244         if (preservedResourcesForFrame.length) {
    245             this._resourcesByFrameId[frameId] = preservedResourcesForFrame;
    246         }
    247     },
    248 
    249     _callForFrameResources: function(frameId, callback)
    250     {
    251         var resources = this._resourcesByFrameId[frameId];
    252 
    253         for (var url in resources) {
    254             if (callback(resources[url]))
    255                 return true;
    256         }
    257 
    258         var frames = this._subframes[frameId];
    259         for (var i = 0; frames && i < frames.length; ++i) {
    260             if (this._callForFrameResources(frames[i].id, callback))
    261                 return true;
    262         }
    263         return false;
    264     },
    265 
    266     _unbindResourceURL: function(resource)
    267     {
    268         delete this._resourcesByURL[resource.url];
    269     },
    270 
    271     _addFramesRecursively: function(frameTreePayload)
    272     {
    273         var framePayload = frameTreePayload.frame;
    274 
    275         // Create frame resource.
    276         var frameResource = this._createResource(framePayload, framePayload.url);
    277         frameResource.type = WebInspector.Resource.Type.Document;
    278         frameResource.finished = true;
    279 
    280         this._addOrUpdateFrame(framePayload);
    281         this._addResourceToFrame(frameResource);
    282 
    283         for (var i = 0; frameTreePayload.childFrames && i < frameTreePayload.childFrames.length; ++i)
    284             this._addFramesRecursively(frameTreePayload.childFrames[i]);
    285 
    286         if (!frameTreePayload.resources)
    287             return;
    288 
    289         // Create frame subresources.
    290         for (var i = 0; i < frameTreePayload.resources.length; ++i) {
    291             var subresource = frameTreePayload.resources[i];
    292             var resource = this._createResource(framePayload, subresource.url);
    293             resource.type = WebInspector.Resource.Type[subresource.type];
    294             resource.finished = true;
    295             this._addResourceToFrame(resource);
    296         }
    297         return frameResource;
    298     },
    299 
    300     _createResource: function(frame, url)
    301     {
    302         var resource = new WebInspector.Resource(null, url);
    303         resource.frameId = frame.id;
    304         resource.loaderId = frame.loaderId;
    305         resource.documentURL = frame.url;
    306         return resource;
    307     }
    308 }
    309 
    310 WebInspector.ResourceTreeModel.prototype.__proto__ = WebInspector.Object.prototype;
    311