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._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          * @this {WebInspector.ConcatenatedScriptsContentProvider}
    139          */
    140         function searchCallback(script, searchMatches)
    141         {
    142             results[script.scriptId] = [];
    143             for (var i = 0; i < searchMatches.length; ++i) {
    144                 var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber + script.lineOffset, searchMatches[i].lineContent);
    145                 results[script.scriptId].push(searchMatch);
    146             }
    147             scriptsLeft--;
    148             maybeCallback.call(this);
    149         }
    150 
    151         maybeCallback();
    152         for (var i = 0; i < scripts.length; ++i)
    153             scripts[i].searchInContent(query, caseSensitive, isRegex, searchCallback.bind(this, scripts[i]));
    154     },
    155 
    156     /**
    157      * @return {string}
    158      */
    159     _concatenateScriptsContent: function(scripts, sources)
    160     {
    161         var content = "";
    162         var lineNumber = 0;
    163         var columnNumber = 0;
    164 
    165         var scriptOpenTag = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag;
    166         var scriptCloseTag = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag;
    167         for (var i = 0; i < scripts.length; ++i) {
    168             // Fill the gap with whitespace characters.
    169             for (var newLinesCount = scripts[i].lineOffset - lineNumber; newLinesCount > 0; --newLinesCount) {
    170                 columnNumber = 0;
    171                 content += "\n";
    172             }
    173             for (var spacesCount = scripts[i].columnOffset - columnNumber - scriptOpenTag.length; spacesCount > 0; --spacesCount)
    174                 content += " ";
    175 
    176             // Add script tag.
    177             content += scriptOpenTag;
    178             content += sources[i];
    179             content += scriptCloseTag;
    180             lineNumber = scripts[i].endLine;
    181             columnNumber = scripts[i].endColumn + scriptCloseTag.length;
    182         }
    183 
    184         return content;
    185     },
    186 
    187     __proto__: WebInspector.ContentProvider.prototype
    188 }
    189 
    190 /**
    191  * @constructor
    192  * @param {string} sourceURL
    193  * @param {!WebInspector.ResourceType} contentType
    194  * @implements {WebInspector.ContentProvider}
    195  */
    196 WebInspector.CompilerSourceMappingContentProvider = function(sourceURL, contentType)
    197 {
    198     this._sourceURL = sourceURL;
    199     this._contentType = contentType;
    200 }
    201 
    202 WebInspector.CompilerSourceMappingContentProvider.prototype = {
    203     /**
    204      * @return {string}
    205      */
    206     contentURL: function()
    207     {
    208         return this._sourceURL;
    209     },
    210 
    211     /**
    212      * @return {!WebInspector.ResourceType}
    213      */
    214     contentType: function()
    215     {
    216         return this._contentType;
    217     },
    218 
    219     /**
    220      * @param {function(?string)} callback
    221      */
    222     requestContent: function(callback)
    223     {
    224         NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, this._sourceURL, undefined, contentLoaded.bind(this));
    225 
    226         /**
    227          * @param {?Protocol.Error} error
    228          * @param {number} statusCode
    229          * @param {!NetworkAgent.Headers} headers
    230          * @param {string} content
    231          * @this {WebInspector.CompilerSourceMappingContentProvider}
    232          */
    233         function contentLoaded(error, statusCode, headers, content)
    234         {
    235             if (error || statusCode >= 400) {
    236                 console.error("Could not load content for " + this._sourceURL + " : " + (error || ("HTTP status code: " + statusCode)));
    237                 callback(null);
    238                 return;
    239             }
    240 
    241             callback(content);
    242         }
    243     },
    244 
    245     /**
    246      * @param {string} query
    247      * @param {boolean} caseSensitive
    248      * @param {boolean} isRegex
    249      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
    250      */
    251     searchInContent: function(query, caseSensitive, isRegex, callback)
    252     {
    253         this.requestContent(contentLoaded);
    254 
    255         /**
    256          * @param {?string} content
    257          */
    258         function contentLoaded(content)
    259         {
    260             if (typeof content !== "string") {
    261                 callback([]);
    262                 return;
    263             }
    264 
    265             callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex));
    266         }
    267     },
    268 
    269     __proto__: WebInspector.ContentProvider.prototype
    270 }
    271 
    272 /**
    273  * @constructor
    274  * @implements {WebInspector.ContentProvider}
    275  * @param {!WebInspector.ResourceType} contentType
    276  * @param {string} content
    277  */
    278 WebInspector.StaticContentProvider = function(contentType, content)
    279 {
    280     this._content = content;
    281     this._contentType = contentType;
    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)} callback
    303      */
    304     requestContent: function(callback)
    305     {
    306         callback(this._content);
    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         /**
    318          * @this {WebInspector.StaticContentProvider}
    319          */
    320         function performSearch()
    321         {
    322             callback(WebInspector.ContentProvider.performSearchInContent(this._content, query, caseSensitive, isRegex));
    323         }
    324 
    325         // searchInContent should call back later.
    326         window.setTimeout(performSearch.bind(this), 0);
    327     },
    328 
    329     __proto__: WebInspector.ContentProvider.prototype
    330 }
    331