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  * @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