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.TargetAwareObject} 32 * @param {!WebInspector.Target} target 33 */ 34WebInspector.ApplicationCacheModel = function(target) 35{ 36 WebInspector.TargetAwareObject.call(this, target); 37 38 target.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher(this)); 39 this._agent = target.applicationCacheAgent(); 40 this._agent.enable(); 41 42 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); 43 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); 44 45 this._statuses = {}; 46 this._manifestURLsByFrame = {}; 47 48 this._mainFrameNavigated(); 49 50 this._onLine = true; 51} 52 53WebInspector.ApplicationCacheModel.EventTypes = { 54 FrameManifestStatusUpdated: "FrameManifestStatusUpdated", 55 FrameManifestAdded: "FrameManifestAdded", 56 FrameManifestRemoved: "FrameManifestRemoved", 57 NetworkStateChanged: "NetworkStateChanged" 58} 59 60WebInspector.ApplicationCacheModel.prototype = { 61 _frameNavigated: function(event) 62 { 63 var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data); 64 if (frame.isMainFrame()) { 65 this._mainFrameNavigated(); 66 return; 67 } 68 69 this._agent.getManifestForFrame(frame.id, this._manifestForFrameLoaded.bind(this, frame.id)); 70 }, 71 72 /** 73 * @param {!WebInspector.Event} event 74 */ 75 _frameDetached: function(event) 76 { 77 var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data); 78 this._frameManifestRemoved(frame.id); 79 }, 80 81 _mainFrameNavigated: function() 82 { 83 this._agent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this)); 84 }, 85 86 /** 87 * @param {string} frameId 88 * @param {?Protocol.Error} error 89 * @param {string} manifestURL 90 */ 91 _manifestForFrameLoaded: function(frameId, error, manifestURL) 92 { 93 if (error) { 94 console.error(error); 95 return; 96 } 97 98 if (!manifestURL) 99 this._frameManifestRemoved(frameId); 100 }, 101 102 /** 103 * @param {?Protocol.Error} error 104 * @param {!Array.<!ApplicationCacheAgent.FrameWithManifest>} framesWithManifests 105 */ 106 _framesWithManifestsLoaded: function(error, framesWithManifests) 107 { 108 if (error) { 109 console.error(error); 110 return; 111 } 112 113 for (var i = 0; i < framesWithManifests.length; ++i) 114 this._frameManifestUpdated(framesWithManifests[i].frameId, framesWithManifests[i].manifestURL, framesWithManifests[i].status); 115 }, 116 117 /** 118 * @param {string} frameId 119 * @param {string} manifestURL 120 * @param {number} status 121 */ 122 _frameManifestUpdated: function(frameId, manifestURL, status) 123 { 124 if (status === applicationCache.UNCACHED) { 125 this._frameManifestRemoved(frameId); 126 return; 127 } 128 129 if (!manifestURL) 130 return; 131 132 if (this._manifestURLsByFrame[frameId] && manifestURL !== this._manifestURLsByFrame[frameId]) 133 this._frameManifestRemoved(frameId); 134 135 var statusChanged = this._statuses[frameId] !== status; 136 this._statuses[frameId] = status; 137 138 if (!this._manifestURLsByFrame[frameId]) { 139 this._manifestURLsByFrame[frameId] = manifestURL; 140 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, frameId); 141 } 142 143 if (statusChanged) 144 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, frameId); 145 }, 146 147 /** 148 * @param {string} frameId 149 */ 150 _frameManifestRemoved: function(frameId) 151 { 152 if (!this._manifestURLsByFrame[frameId]) 153 return; 154 155 var manifestURL = this._manifestURLsByFrame[frameId]; 156 delete this._manifestURLsByFrame[frameId]; 157 delete this._statuses[frameId]; 158 159 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, frameId); 160 }, 161 162 /** 163 * @param {string} frameId 164 * @return {string} 165 */ 166 frameManifestURL: function(frameId) 167 { 168 return this._manifestURLsByFrame[frameId] || ""; 169 }, 170 171 /** 172 * @param {string} frameId 173 * @return {number} 174 */ 175 frameManifestStatus: function(frameId) 176 { 177 return this._statuses[frameId] || applicationCache.UNCACHED; 178 }, 179 180 /** 181 * @return {boolean} 182 */ 183 get onLine() 184 { 185 return this._onLine; 186 }, 187 188 /** 189 * @param {string} frameId 190 * @param {string} manifestURL 191 * @param {number} status 192 */ 193 _statusUpdated: function(frameId, manifestURL, status) 194 { 195 this._frameManifestUpdated(frameId, manifestURL, status); 196 }, 197 198 /** 199 * @param {string} frameId 200 * @param {function(?ApplicationCacheAgent.ApplicationCache)} callback 201 */ 202 requestApplicationCache: function(frameId, callback) 203 { 204 /** 205 * @param {?Protocol.Error} error 206 * @param {!ApplicationCacheAgent.ApplicationCache} applicationCache 207 */ 208 function callbackWrapper(error, applicationCache) 209 { 210 if (error) { 211 console.error(error); 212 callback(null); 213 return; 214 } 215 216 callback(applicationCache); 217 } 218 219 this._agent.getApplicationCacheForFrame(frameId, callbackWrapper); 220 }, 221 222 /** 223 * @param {boolean} isNowOnline 224 */ 225 _networkStateUpdated: function(isNowOnline) 226 { 227 this._onLine = isNowOnline; 228 this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, isNowOnline); 229 }, 230 231 __proto__: WebInspector.TargetAwareObject.prototype 232} 233 234/** 235 * @constructor 236 * @implements {ApplicationCacheAgent.Dispatcher} 237 */ 238WebInspector.ApplicationCacheDispatcher = function(applicationCacheModel) 239{ 240 this._applicationCacheModel = applicationCacheModel; 241} 242 243WebInspector.ApplicationCacheDispatcher.prototype = { 244 /** 245 * @param {string} frameId 246 * @param {string} manifestURL 247 * @param {number} status 248 */ 249 applicationCacheStatusUpdated: function(frameId, manifestURL, status) 250 { 251 this._applicationCacheModel._statusUpdated(frameId, manifestURL, status); 252 }, 253 254 /** 255 * @param {boolean} isNowOnline 256 */ 257 networkStateUpdated: function(isNowOnline) 258 { 259 this._applicationCacheModel._networkStateUpdated(isNowOnline); 260 } 261} 262