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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. 20 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @constructor 31 * @extends {WebInspector.Object} 32 */ 33 WebInspector.ApplicationCacheModel = function() 34 { 35 ApplicationCacheAgent.enable(); 36 InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher(this)); 37 38 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); 39 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); 40 41 this._statuses = {}; 42 this._manifestURLsByFrame = {}; 43 44 this._mainFrameNavigated(); 45 46 this._onLine = true; 47 } 48 49 WebInspector.ApplicationCacheModel.EventTypes = { 50 FrameManifestStatusUpdated: "FrameManifestStatusUpdated", 51 FrameManifestAdded: "FrameManifestAdded", 52 FrameManifestRemoved: "FrameManifestRemoved", 53 NetworkStateChanged: "NetworkStateChanged" 54 } 55 56 WebInspector.ApplicationCacheModel.prototype = { 57 _frameNavigated: function(event) 58 { 59 var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data); 60 if (frame.isMainFrame()) { 61 this._mainFrameNavigated(); 62 return; 63 } 64 65 ApplicationCacheAgent.getManifestForFrame(frame.id, this._manifestForFrameLoaded.bind(this, frame.id)); 66 }, 67 68 /** 69 * @param {!WebInspector.Event} event 70 */ 71 _frameDetached: function(event) 72 { 73 var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data); 74 this._frameManifestRemoved(frame.id); 75 }, 76 77 _mainFrameNavigated: function() 78 { 79 ApplicationCacheAgent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this)); 80 }, 81 82 /** 83 * @param {string} frameId 84 * @param {?Protocol.Error} error 85 * @param {string} manifestURL 86 */ 87 _manifestForFrameLoaded: function(frameId, error, manifestURL) 88 { 89 if (error) { 90 console.error(error); 91 return; 92 } 93 94 if (!manifestURL) 95 this._frameManifestRemoved(frameId); 96 }, 97 98 /** 99 * @param {?Protocol.Error} error 100 * @param {!Array.<!ApplicationCacheAgent.FrameWithManifest>} framesWithManifests 101 */ 102 _framesWithManifestsLoaded: function(error, framesWithManifests) 103 { 104 if (error) { 105 console.error(error); 106 return; 107 } 108 109 for (var i = 0; i < framesWithManifests.length; ++i) 110 this._frameManifestUpdated(framesWithManifests[i].frameId, framesWithManifests[i].manifestURL, framesWithManifests[i].status); 111 }, 112 113 /** 114 * @param {string} frameId 115 * @param {string} manifestURL 116 * @param {number} status 117 */ 118 _frameManifestUpdated: function(frameId, manifestURL, status) 119 { 120 if (status === applicationCache.UNCACHED) { 121 this._frameManifestRemoved(frameId); 122 return; 123 } 124 125 if (!manifestURL) 126 return; 127 128 if (this._manifestURLsByFrame[frameId] && manifestURL !== this._manifestURLsByFrame[frameId]) 129 this._frameManifestRemoved(frameId); 130 131 var statusChanged = this._statuses[frameId] !== status; 132 this._statuses[frameId] = status; 133 134 if (!this._manifestURLsByFrame[frameId]) { 135 this._manifestURLsByFrame[frameId] = manifestURL; 136 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, frameId); 137 } 138 139 if (statusChanged) 140 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, frameId); 141 }, 142 143 /** 144 * @param {string} frameId 145 */ 146 _frameManifestRemoved: function(frameId) 147 { 148 if (!this._manifestURLsByFrame[frameId]) 149 return; 150 151 var manifestURL = this._manifestURLsByFrame[frameId]; 152 delete this._manifestURLsByFrame[frameId]; 153 delete this._statuses[frameId]; 154 155 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, frameId); 156 }, 157 158 /** 159 * @param {string} frameId 160 * @return {string} 161 */ 162 frameManifestURL: function(frameId) 163 { 164 return this._manifestURLsByFrame[frameId] || ""; 165 }, 166 167 /** 168 * @param {string} frameId 169 * @return {number} 170 */ 171 frameManifestStatus: function(frameId) 172 { 173 return this._statuses[frameId] || applicationCache.UNCACHED; 174 }, 175 176 /** 177 * @return {boolean} 178 */ 179 get onLine() 180 { 181 return this._onLine; 182 }, 183 184 /** 185 * @param {string} frameId 186 * @param {string} manifestURL 187 * @param {number} status 188 */ 189 _statusUpdated: function(frameId, manifestURL, status) 190 { 191 this._frameManifestUpdated(frameId, manifestURL, status); 192 }, 193 194 /** 195 * @param {string} frameId 196 * @param {function(?ApplicationCacheAgent.ApplicationCache)} callback 197 */ 198 requestApplicationCache: function(frameId, callback) 199 { 200 /** 201 * @param {?Protocol.Error} error 202 * @param {!ApplicationCacheAgent.ApplicationCache} applicationCache 203 */ 204 function callbackWrapper(error, applicationCache) 205 { 206 if (error) { 207 console.error(error); 208 callback(null); 209 return; 210 } 211 212 callback(applicationCache); 213 } 214 215 ApplicationCacheAgent.getApplicationCacheForFrame(frameId, callbackWrapper.bind(this)); 216 }, 217 218 /** 219 * @param {boolean} isNowOnline 220 */ 221 _networkStateUpdated: function(isNowOnline) 222 { 223 this._onLine = isNowOnline; 224 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, isNowOnline); 225 }, 226 227 __proto__: WebInspector.Object.prototype 228 } 229 230 /** 231 * @constructor 232 * @implements {ApplicationCacheAgent.Dispatcher} 233 */ 234 WebInspector.ApplicationCacheDispatcher = function(applicationCacheModel) 235 { 236 this._applicationCacheModel = applicationCacheModel; 237 } 238 239 WebInspector.ApplicationCacheDispatcher.prototype = { 240 /** 241 * @param {string} frameId 242 * @param {string} manifestURL 243 * @param {number} status 244 */ 245 applicationCacheStatusUpdated: function(frameId, manifestURL, status) 246 { 247 this._applicationCacheModel._statusUpdated(frameId, manifestURL, status); 248 }, 249 250 /** 251 * @param {boolean} isNowOnline 252 */ 253 networkStateUpdated: function(isNowOnline) 254 { 255 this._applicationCacheModel._networkStateUpdated(isNowOnline); 256 } 257 } 258