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 * @constructor 33 * @implements {WebInspector.ContentProvider} 34 * @param {Array.<WebInspector.Script>} scripts 35 */ 36 WebInspector.ConcatenatedScriptsContentProvider = function(scripts) 37 { 38 this._mimeType = "text/html"; 39 this._scripts = scripts; 40 } 41 42 WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag = "<script>"; 43 WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag = "</script>"; 44 45 WebInspector.ConcatenatedScriptsContentProvider.prototype = { 46 /** 47 * @return {Array.<WebInspector.Script>} 48 */ 49 _sortedScripts: function() 50 { 51 if (this._sortedScriptsArray) 52 return this._sortedScriptsArray; 53 54 this._sortedScriptsArray = []; 55 56 var scripts = this._scripts.slice(); 57 scripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; }); 58 59 var scriptOpenTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag.length; 60 var scriptCloseTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag.length; 61 62 this._sortedScriptsArray.push(scripts[0]); 63 for (var i = 1; i < scripts.length; ++i) { 64 var previousScript = this._sortedScriptsArray[this._sortedScriptsArray.length - 1]; 65 66 var lineNumber = previousScript.endLine; 67 var columnNumber = previousScript.endColumn + scriptCloseTagLength + scriptOpenTagLength; 68 69 if (lineNumber < scripts[i].lineOffset || (lineNumber === scripts[i].lineOffset && columnNumber <= scripts[i].columnOffset)) 70 this._sortedScriptsArray.push(scripts[i]); 71 } 72 return this._sortedScriptsArray; 73 }, 74 75 /** 76 * @return {string} 77 */ 78 contentURL: function() 79 { 80 return ""; 81 }, 82 83 /** 84 * @return {WebInspector.ResourceType} 85 */ 86 contentType: function() 87 { 88 return WebInspector.resourceTypes.Document; 89 }, 90 91 /** 92 * @param {function(?string,boolean,string)} callback 93 */ 94 requestContent: function(callback) 95 { 96 var scripts = this._sortedScripts(); 97 var sources = []; 98 function didRequestSource(content, contentEncoded, mimeType) 99 { 100 sources.push(content); 101 if (sources.length == scripts.length) 102 callback(this._concatenateScriptsContent(scripts, sources), false, this._mimeType); 103 } 104 for (var i = 0; i < scripts.length; ++i) 105 scripts[i].requestContent(didRequestSource.bind(this)); 106 }, 107 108 /** 109 * @param {string} query 110 * @param {boolean} caseSensitive 111 * @param {boolean} isRegex 112 * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback 113 */ 114 searchInContent: function(query, caseSensitive, isRegex, callback) 115 { 116 var results = {}; 117 var scripts = this._sortedScripts(); 118 var scriptsLeft = scripts.length; 119 120 function maybeCallback() 121 { 122 if (scriptsLeft) 123 return; 124 125 var result = []; 126 for (var i = 0; i < scripts.length; ++i) 127 result = result.concat(results[scripts[i].scriptId]); 128 callback(result); 129 } 130 131 /** 132 * @param {WebInspector.Script} script 133 * @param {Array.<PageAgent.SearchMatch>} searchMatches 134 */ 135 function searchCallback(script, searchMatches) 136 { 137 results[script.scriptId] = []; 138 for (var i = 0; i < searchMatches.length; ++i) { 139 var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber + script.lineOffset, searchMatches[i].lineContent); 140 results[script.scriptId].push(searchMatch); 141 } 142 scriptsLeft--; 143 maybeCallback.call(this); 144 } 145 146 maybeCallback(); 147 for (var i = 0; i < scripts.length; ++i) 148 scripts[i].searchInContent(query, caseSensitive, isRegex, searchCallback.bind(this, scripts[i])); 149 }, 150 151 /** 152 * @return {string} 153 */ 154 _concatenateScriptsContent: function(scripts, sources) 155 { 156 var content = ""; 157 var lineNumber = 0; 158 var columnNumber = 0; 159 160 var scriptOpenTag = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag; 161 var scriptCloseTag = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag; 162 for (var i = 0; i < scripts.length; ++i) { 163 // Fill the gap with whitespace characters. 164 for (var newLinesCount = scripts[i].lineOffset - lineNumber; newLinesCount > 0; --newLinesCount) { 165 columnNumber = 0; 166 content += "\n"; 167 } 168 for (var spacesCount = scripts[i].columnOffset - columnNumber - scriptOpenTag.length; spacesCount > 0; --spacesCount) 169 content += " "; 170 171 // Add script tag. 172 content += scriptOpenTag; 173 content += sources[i]; 174 content += scriptCloseTag; 175 lineNumber = scripts[i].endLine; 176 columnNumber = scripts[i].endColumn + scriptCloseTag.length; 177 } 178 179 return content; 180 }, 181 182 __proto__: WebInspector.ContentProvider.prototype 183 } 184 185 /** 186 * @constructor 187 * @param {string} sourceURL 188 * @param {WebInspector.ResourceType} contentType 189 * @param {string} mimeType 190 * @implements {WebInspector.ContentProvider} 191 */ 192 WebInspector.CompilerSourceMappingContentProvider = function(sourceURL, contentType, mimeType) 193 { 194 this._sourceURL = sourceURL; 195 this._contentType = contentType; 196 this._mimeType = mimeType; 197 } 198 199 WebInspector.CompilerSourceMappingContentProvider.prototype = { 200 /** 201 * @return {string} 202 */ 203 contentURL: function() 204 { 205 return this._sourceURL; 206 }, 207 208 /** 209 * @return {WebInspector.ResourceType} 210 */ 211 contentType: function() 212 { 213 return this._contentType; 214 }, 215 216 /** 217 * @param {function(?string,boolean,string)} callback 218 */ 219 requestContent: function(callback) 220 { 221 NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, this._sourceURL, undefined, contentLoaded.bind(this)); 222 223 /** 224 * @param {?Protocol.Error} error 225 * @param {number} statusCode 226 * @param {NetworkAgent.Headers} headers 227 * @param {string} content 228 */ 229 function contentLoaded(error, statusCode, headers, content) 230 { 231 if (error || statusCode >= 400) { 232 console.error("Could not load content for " + this._sourceURL + " : " + (error || ("HTTP status code: " + statusCode))); 233 callback(null, false, this._mimeType); 234 return; 235 } 236 237 callback(content, false, this._mimeType); 238 } 239 }, 240 241 /** 242 * @param {string} query 243 * @param {boolean} caseSensitive 244 * @param {boolean} isRegex 245 * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback 246 */ 247 searchInContent: function(query, caseSensitive, isRegex, callback) 248 { 249 this.requestContent(contentLoaded); 250 251 /** 252 * @param {?string} content 253 * @param {boolean} base64Encoded 254 * @param {string} mimeType 255 */ 256 function contentLoaded(content, base64Encoded, mimeType) 257 { 258 if (typeof content !== "string") { 259 callback([]); 260 return; 261 } 262 263 callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex)); 264 } 265 }, 266 267 __proto__: WebInspector.ContentProvider.prototype 268 } 269 270 /** 271 * @constructor 272 * @implements {WebInspector.ContentProvider} 273 * @param {WebInspector.ResourceType} contentType 274 * @param {string} content 275 * @param {string=} mimeType 276 */ 277 WebInspector.StaticContentProvider = function(contentType, content, mimeType) 278 { 279 this._content = content; 280 this._contentType = contentType; 281 this._mimeType = mimeType; 282 } 283 284 WebInspector.StaticContentProvider.prototype = { 285 /** 286 * @return {string} 287 */ 288 contentURL: function() 289 { 290 return ""; 291 }, 292 293 /** 294 * @return {WebInspector.ResourceType} 295 */ 296 contentType: function() 297 { 298 return this._contentType; 299 }, 300 301 /** 302 * @param {function(?string,boolean,string)} callback 303 */ 304 requestContent: function(callback) 305 { 306 callback(this._content, false, this._mimeType || this._contentType.canonicalMimeType()); 307 }, 308 309 /** 310 * @param {string} query 311 * @param {boolean} caseSensitive 312 * @param {boolean} isRegex 313 * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback 314 */ 315 searchInContent: function(query, caseSensitive, isRegex, callback) 316 { 317 function performSearch() 318 { 319 callback(WebInspector.ContentProvider.performSearchInContent(this._content, query, caseSensitive, isRegex)); 320 } 321 322 // searchInContent should call back later. 323 window.setTimeout(performSearch.bind(this), 0); 324 }, 325 326 __proto__: WebInspector.ContentProvider.prototype 327 } 328 329 /** 330 * @constructor 331 * @implements {WebInspector.ContentProvider} 332 * @param {WebInspector.ContentProvider} contentProvider 333 * @param {string} mimeType 334 */ 335 WebInspector.ContentProviderOverridingMimeType = function(contentProvider, mimeType) 336 { 337 this._contentProvider = contentProvider; 338 this._mimeType = mimeType; 339 } 340 341 WebInspector.ContentProviderOverridingMimeType.prototype = { 342 /** 343 * @return {string} 344 */ 345 contentURL: function() 346 { 347 return this._contentProvider.contentURL(); 348 }, 349 350 /** 351 * @return {WebInspector.ResourceType} 352 */ 353 contentType: function() 354 { 355 return this._contentProvider.contentType(); 356 }, 357 358 /** 359 * @param {function(?string,boolean,string)} callback 360 */ 361 requestContent: function(callback) 362 { 363 this._contentProvider.requestContent(innerCallback.bind(this)); 364 365 function innerCallback(content, contentEncoded, mimeType) 366 { 367 callback(content, contentEncoded, this._mimeType); 368 } 369 }, 370 371 /** 372 * @param {string} query 373 * @param {boolean} caseSensitive 374 * @param {boolean} isRegex 375 * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback 376 */ 377 searchInContent: function(query, caseSensitive, isRegex, callback) 378 { 379 this._contentProvider.searchInContent(query, caseSensitive, isRegex, callback); 380 }, 381 382 __proto__: WebInspector.ContentProvider.prototype 383 } 384