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._scripts = scripts; 39 } 40 41 WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag = "<script>"; 42 WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag = "</script>"; 43 44 WebInspector.ConcatenatedScriptsContentProvider.prototype = { 45 /** 46 * @return {!Array.<!WebInspector.Script>} 47 */ 48 _sortedScripts: function() 49 { 50 if (this._sortedScriptsArray) 51 return this._sortedScriptsArray; 52 53 this._sortedScriptsArray = []; 54 55 var scripts = this._scripts.slice(); 56 scripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; }); 57 58 var scriptOpenTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag.length; 59 var scriptCloseTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag.length; 60 61 this._sortedScriptsArray.push(scripts[0]); 62 for (var i = 1; i < scripts.length; ++i) { 63 var previousScript = this._sortedScriptsArray[this._sortedScriptsArray.length - 1]; 64 65 var lineNumber = previousScript.endLine; 66 var columnNumber = previousScript.endColumn + scriptCloseTagLength + scriptOpenTagLength; 67 68 if (lineNumber < scripts[i].lineOffset || (lineNumber === scripts[i].lineOffset && columnNumber <= scripts[i].columnOffset)) 69 this._sortedScriptsArray.push(scripts[i]); 70 } 71 return this._sortedScriptsArray; 72 }, 73 74 /** 75 * @return {string} 76 */ 77 contentURL: function() 78 { 79 return ""; 80 }, 81 82 /** 83 * @return {!WebInspector.ResourceType} 84 */ 85 contentType: function() 86 { 87 return WebInspector.resourceTypes.Document; 88 }, 89 90 /** 91 * @param {function(?string)} callback 92 */ 93 requestContent: function(callback) 94 { 95 var scripts = this._sortedScripts(); 96 var sources = []; 97 98 /** 99 * @param {?string} content 100 * @this {WebInspector.ConcatenatedScriptsContentProvider} 101 */ 102 function didRequestSource(content) 103 { 104 sources.push(content); 105 if (sources.length == scripts.length) 106 callback(this._concatenateScriptsContent(scripts, sources)); 107 } 108 for (var i = 0; i < scripts.length; ++i) 109 scripts[i].requestContent(didRequestSource.bind(this)); 110 }, 111 112 /** 113 * @param {string} query 114 * @param {boolean} caseSensitive 115 * @param {boolean} isRegex 116 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 117 */ 118 searchInContent: function(query, caseSensitive, isRegex, callback) 119 { 120 var results = {}; 121 var scripts = this._sortedScripts(); 122 var scriptsLeft = scripts.length; 123 124 function maybeCallback() 125 { 126 if (scriptsLeft) 127 return; 128 129 var result = []; 130 for (var i = 0; i < scripts.length; ++i) 131 result = result.concat(results[scripts[i].scriptId]); 132 callback(result); 133 } 134 135 /** 136 * @param {!WebInspector.Script} script 137 * @param {!Array.<!PageAgent.SearchMatch>} searchMatches 138 */ 139 function searchCallback(script, searchMatches) 140 { 141 results[script.scriptId] = []; 142 for (var i = 0; i < searchMatches.length; ++i) { 143 var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber + script.lineOffset, searchMatches[i].lineContent); 144 results[script.scriptId].push(searchMatch); 145 } 146 scriptsLeft--; 147 maybeCallback(); 148 } 149 150 maybeCallback(); 151 for (var i = 0; i < scripts.length; ++i) 152 scripts[i].searchInContent(query, caseSensitive, isRegex, searchCallback.bind(null, scripts[i])); 153 }, 154 155 /** 156 * @return {string} 157 */ 158 _concatenateScriptsContent: function(scripts, sources) 159 { 160 var content = ""; 161 var lineNumber = 0; 162 var columnNumber = 0; 163 164 var scriptOpenTag = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag; 165 var scriptCloseTag = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag; 166 for (var i = 0; i < scripts.length; ++i) { 167 // Fill the gap with whitespace characters. 168 for (var newLinesCount = scripts[i].lineOffset - lineNumber; newLinesCount > 0; --newLinesCount) { 169 columnNumber = 0; 170 content += "\n"; 171 } 172 for (var spacesCount = scripts[i].columnOffset - columnNumber - scriptOpenTag.length; spacesCount > 0; --spacesCount) 173 content += " "; 174 175 // Add script tag. 176 content += scriptOpenTag; 177 content += sources[i]; 178 content += scriptCloseTag; 179 lineNumber = scripts[i].endLine; 180 columnNumber = scripts[i].endColumn + scriptCloseTag.length; 181 } 182 183 return content; 184 } 185 } 186 187 /** 188 * @constructor 189 * @implements {WebInspector.ContentProvider} 190 * @param {string} sourceURL 191 * @param {!WebInspector.ResourceType} contentType 192 */ 193 WebInspector.CompilerSourceMappingContentProvider = function(sourceURL, contentType) 194 { 195 this._sourceURL = sourceURL; 196 this._contentType = contentType; 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)} 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 * @this {WebInspector.CompilerSourceMappingContentProvider} 229 */ 230 function contentLoaded(error, statusCode, headers, content) 231 { 232 if (error || statusCode >= 400) { 233 console.error("Could not load content for " + this._sourceURL + " : " + (error || ("HTTP status code: " + statusCode))); 234 callback(null); 235 return; 236 } 237 238 callback(content); 239 } 240 }, 241 242 /** 243 * @param {string} query 244 * @param {boolean} caseSensitive 245 * @param {boolean} isRegex 246 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 247 */ 248 searchInContent: function(query, caseSensitive, isRegex, callback) 249 { 250 this.requestContent(contentLoaded); 251 252 /** 253 * @param {?string} content 254 */ 255 function contentLoaded(content) 256 { 257 if (typeof content !== "string") { 258 callback([]); 259 return; 260 } 261 262 callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex)); 263 } 264 } 265 } 266 267 /** 268 * @constructor 269 * @implements {WebInspector.ContentProvider} 270 * @param {!WebInspector.ResourceType} contentType 271 * @param {string} content 272 */ 273 WebInspector.StaticContentProvider = function(contentType, content) 274 { 275 this._content = content; 276 this._contentType = contentType; 277 } 278 279 WebInspector.StaticContentProvider.prototype = { 280 /** 281 * @return {string} 282 */ 283 contentURL: function() 284 { 285 return ""; 286 }, 287 288 /** 289 * @return {!WebInspector.ResourceType} 290 */ 291 contentType: function() 292 { 293 return this._contentType; 294 }, 295 296 /** 297 * @param {function(?string)} callback 298 */ 299 requestContent: function(callback) 300 { 301 callback(this._content); 302 }, 303 304 /** 305 * @param {string} query 306 * @param {boolean} caseSensitive 307 * @param {boolean} isRegex 308 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 309 */ 310 searchInContent: function(query, caseSensitive, isRegex, callback) 311 { 312 /** 313 * @this {WebInspector.StaticContentProvider} 314 */ 315 function performSearch() 316 { 317 callback(WebInspector.ContentProvider.performSearchInContent(this._content, query, caseSensitive, isRegex)); 318 } 319 320 // searchInContent should call back later. 321 window.setTimeout(performSearch.bind(this), 0); 322 } 323 } 324