Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2013 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.ProjectDelegate}
     34  * @extends {WebInspector.Object}
     35  * @param {string} type
     36  */
     37 WebInspector.ContentProviderBasedProjectDelegate = function(type)
     38 {
     39     this._type = type;
     40     /** @type {!Object.<string, !WebInspector.ContentProvider>} */
     41     this._contentProviders = {};
     42     /** @type {!Object.<string, boolean>} */
     43     this._isContentScriptMap = {};
     44 }
     45 
     46 WebInspector.ContentProviderBasedProjectDelegate.prototype = {
     47     /**
     48      * @return {string}
     49      */
     50     id: function()
     51     {
     52         // Overriddden by subclasses
     53         return "";
     54     },
     55 
     56     /**
     57      * @return {string}
     58      */
     59     type: function()
     60     {
     61         return this._type;
     62     },
     63 
     64     /**
     65      * @return {string}
     66      */
     67     displayName: function()
     68     {
     69         // Overriddden by subclasses
     70         return "";
     71     },
     72 
     73     /**
     74      * @param {string} path
     75      * @param {function(?Date, ?number)} callback
     76      */
     77     requestMetadata: function(path, callback)
     78     {
     79         callback(null, null);
     80     },
     81 
     82     /**
     83      * @param {string} path
     84      * @param {function(?string)} callback
     85      */
     86     requestFileContent: function(path, callback)
     87     {
     88         var contentProvider = this._contentProviders[path];
     89         contentProvider.requestContent(callback);
     90 
     91         /**
     92          * @param {?string} content
     93          * @param {boolean} encoded
     94          * @param {string} mimeType
     95          */
     96         function innerCallback(content, encoded, mimeType)
     97         {
     98             callback(content);
     99         }
    100     },
    101 
    102     /**
    103      * @return {boolean}
    104      */
    105     canSetFileContent: function()
    106     {
    107         return false;
    108     },
    109 
    110     /**
    111      * @param {string} path
    112      * @param {string} newContent
    113      * @param {function(?string)} callback
    114      */
    115     setFileContent: function(path, newContent, callback)
    116     {
    117         callback(null);
    118     },
    119 
    120     /**
    121      * @return {boolean}
    122      */
    123     canRename: function()
    124     {
    125         return false;
    126     },
    127 
    128     /**
    129      * @param {string} path
    130      * @param {string} newName
    131      * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
    132      */
    133     rename: function(path, newName, callback)
    134     {
    135         this.performRename(path, newName, innerCallback.bind(this));
    136 
    137         /**
    138          * @param {boolean} success
    139          * @param {string=} newName
    140          * @this {WebInspector.ContentProviderBasedProjectDelegate}
    141          */
    142         function innerCallback(success, newName)
    143         {
    144             if (success)
    145                 this._updateName(path, /** @type {string} */ (newName));
    146             callback(success, newName);
    147         }
    148     },
    149 
    150     /**
    151      * @param {string} path
    152      */
    153     refresh: function(path)
    154     {
    155     },
    156 
    157     /**
    158      * @param {string} path
    159      */
    160     excludeFolder: function(path)
    161     {
    162     },
    163 
    164     /**
    165      * @param {string} path
    166      * @param {?string} name
    167      * @param {string} content
    168      * @param {function(?string)} callback
    169      */
    170     createFile: function(path, name, content, callback)
    171     {
    172     },
    173 
    174     /**
    175      * @param {string} path
    176      */
    177     deleteFile: function(path)
    178     {
    179     },
    180 
    181     remove: function()
    182     {
    183     },
    184 
    185     /**
    186      * @param {string} path
    187      * @param {string} newName
    188      * @param {function(boolean, string=)} callback
    189      */
    190     performRename: function(path, newName, callback)
    191     {
    192         callback(false);
    193     },
    194 
    195     /**
    196      * @param {string} path
    197      * @param {string} newName
    198      */
    199     _updateName: function(path, newName)
    200     {
    201         var oldPath = path;
    202         var copyOfPath = path.split("/");
    203         copyOfPath[copyOfPath.length - 1] = newName;
    204         var newPath = copyOfPath.join("/");
    205         this._contentProviders[newPath] = this._contentProviders[oldPath];
    206         delete this._contentProviders[oldPath];
    207     },
    208 
    209     /**
    210      * @param {string} path
    211      * @param {string} query
    212      * @param {boolean} caseSensitive
    213      * @param {boolean} isRegex
    214      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
    215      */
    216     searchInFileContent: function(path, query, caseSensitive, isRegex, callback)
    217     {
    218         var contentProvider = this._contentProviders[path];
    219         contentProvider.searchInContent(query, caseSensitive, isRegex, callback);
    220     },
    221 
    222     /**
    223      * @param {!Array.<string>} queries
    224      * @param {!Array.<string>} fileQueries
    225      * @param {boolean} caseSensitive
    226      * @param {boolean} isRegex
    227      * @param {!WebInspector.Progress} progress
    228      * @param {function(!Array.<string>)} callback
    229      */
    230     findFilesMatchingSearchRequest: function(queries, fileQueries, caseSensitive, isRegex, progress, callback)
    231     {
    232         var result = [];
    233         var paths = Object.keys(this._contentProviders);
    234         var totalCount = paths.length;
    235         if (totalCount === 0) {
    236             // searchInContent should call back later.
    237             setTimeout(doneCallback, 0);
    238             return;
    239         }
    240 
    241         /**
    242          * @param {string} path
    243          * @this {WebInspector.ContentProviderBasedProjectDelegate}
    244          */
    245         function filterOutContentScripts(path)
    246         {
    247             return !this._isContentScriptMap[path];
    248         }
    249 
    250         if (!WebInspector.settings.searchInContentScripts.get())
    251             paths = paths.filter(filterOutContentScripts.bind(this));
    252 
    253         var fileRegexes = [];
    254         for (var i = 0; i < fileQueries.length; ++i)
    255             fileRegexes.push(new RegExp(fileQueries[i], caseSensitive ? "" : "i"));
    256 
    257         /**
    258          * @param {!string} file
    259          */
    260         function filterOutNonMatchingFiles(file)
    261         {
    262             for (var i = 0; i < fileRegexes.length; ++i) {
    263                 if (!file.match(fileRegexes[i]))
    264                     return false;
    265             }
    266             return true;
    267         }
    268 
    269         paths = paths.filter(filterOutNonMatchingFiles);
    270         var barrier = new CallbackBarrier();
    271         progress.setTotalWork(paths.length);
    272         for (var i = 0; i < paths.length; ++i)
    273             searchInContent.call(this, paths[i], barrier.createCallback(searchInContentCallback.bind(this, paths[i])));
    274         barrier.callWhenDone(doneCallback);
    275 
    276         /**
    277          * @param {string} path
    278          * @param {function(boolean)} callback
    279          * @this {WebInspector.ContentProviderBasedProjectDelegate}
    280          */
    281         function searchInContent(path, callback)
    282         {
    283             var queriesToRun = queries.slice();
    284             searchNextQuery.call(this);
    285 
    286             /**
    287              * @this {WebInspector.ContentProviderBasedProjectDelegate}
    288              */
    289             function searchNextQuery()
    290             {
    291                 if (!queriesToRun.length) {
    292                     callback(true);
    293                     return;
    294                 }
    295                 var query = queriesToRun.shift();
    296                 this._contentProviders[path].searchInContent(query, caseSensitive, isRegex, contentCallback.bind(this));
    297             }
    298 
    299             /**
    300              * @param {!Array.<!WebInspector.ContentProvider.SearchMatch>} searchMatches
    301              * @this {WebInspector.ContentProviderBasedProjectDelegate}
    302              */
    303             function contentCallback(searchMatches)
    304             {
    305                 if (!searchMatches.length) {
    306                     callback(false);
    307                     return;
    308                 }
    309                 searchNextQuery.call(this);
    310             }
    311         }
    312 
    313         /**
    314          * @param {string} path
    315          * @param {boolean} matches
    316          */
    317         function searchInContentCallback(path, matches)
    318         {
    319             if (matches)
    320                 result.push(path);
    321             progress.worked(1);
    322         }
    323 
    324         function doneCallback()
    325         {
    326             callback(result);
    327             progress.done();
    328         }
    329     },
    330 
    331     /**
    332      * @param {!WebInspector.Progress} progress
    333      * @param {function()} callback
    334      */
    335     indexContent: function(progress, callback)
    336     {
    337         setTimeout(innerCallback, 0);
    338 
    339         function innerCallback()
    340         {
    341             progress.done();
    342             callback();
    343         }
    344     },
    345 
    346     /**
    347      * @param {string} parentPath
    348      * @param {string} name
    349      * @param {string} url
    350      * @param {!WebInspector.ContentProvider} contentProvider
    351      * @param {boolean} isEditable
    352      * @param {boolean=} isContentScript
    353      * @return {string}
    354      */
    355     addContentProvider: function(parentPath, name, url, contentProvider, isEditable, isContentScript)
    356     {
    357         var path = parentPath ? parentPath + "/" + name : name;
    358         var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, url, url, contentProvider.contentType(), isEditable, isContentScript);
    359         this._contentProviders[path] = contentProvider;
    360         this._isContentScriptMap[path] = isContentScript || false;
    361         this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor);
    362         return path;
    363     },
    364 
    365     /**
    366      * @param {string} path
    367      */
    368     removeFile: function(path)
    369     {
    370         delete this._contentProviders[path];
    371         delete this._isContentScriptMap[path];
    372         this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
    373     },
    374 
    375     /**
    376      * @return {!Object.<string, !WebInspector.ContentProvider>}
    377      */
    378     contentProviders: function()
    379     {
    380         return this._contentProviders;
    381     },
    382 
    383     reset: function()
    384     {
    385         this._contentProviders = {};
    386         this._isContentScriptMap = {};
    387         this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.Reset, null);
    388     },
    389 
    390     __proto__: WebInspector.Object.prototype
    391 }
    392