Home | History | Annotate | Download | only in sdk
      1 /*
      2  * Copyright (C) 2012 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  * @param {string} parentPath
     34  * @param {string} name
     35  * @param {string} originURL
     36  * @param {string} url
     37  * @param {!WebInspector.ResourceType} contentType
     38  */
     39 WebInspector.FileDescriptor = function(parentPath, name, originURL, url, contentType)
     40 {
     41     this.parentPath = parentPath;
     42     this.name = name;
     43     this.originURL = originURL;
     44     this.url = url;
     45     this.contentType = contentType;
     46 }
     47 
     48 /**
     49  * @interface
     50  */
     51 WebInspector.ProjectDelegate = function() { }
     52 
     53 WebInspector.ProjectDelegate.prototype = {
     54     /**
     55      * @return {string}
     56      */
     57     type: function() { },
     58 
     59     /**
     60      * @return {string}
     61      */
     62     displayName: function() { },
     63 
     64     /**
     65      * @param {string} path
     66      * @param {function(?Date, ?number)} callback
     67      */
     68     requestMetadata: function(path, callback) { },
     69 
     70     /**
     71      * @param {string} path
     72      * @param {function(?string)} callback
     73      */
     74     requestFileContent: function(path, callback) { },
     75 
     76     /**
     77      * @return {boolean}
     78      */
     79     canSetFileContent: function() { },
     80 
     81     /**
     82      * @param {string} path
     83      * @param {string} newContent
     84      * @param {function(?string)} callback
     85      */
     86     setFileContent: function(path, newContent, callback) { },
     87 
     88     /**
     89      * @return {boolean}
     90      */
     91     canRename: function() { },
     92 
     93     /**
     94      * @param {string} path
     95      * @param {string} newName
     96      * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
     97      */
     98     rename: function(path, newName, callback) { },
     99 
    100     /**
    101      * @param {string} path
    102      */
    103     refresh: function(path) { },
    104 
    105     /**
    106      * @param {string} path
    107      */
    108     excludeFolder: function(path) { },
    109 
    110     /**
    111      * @param {string} path
    112      * @param {?string} name
    113      * @param {string} content
    114      * @param {function(?string)} callback
    115      */
    116     createFile: function(path, name, content, callback) { },
    117 
    118     /**
    119      * @param {string} path
    120      */
    121     deleteFile: function(path) { },
    122 
    123     remove: function() { },
    124 
    125     /**
    126      * @param {string} path
    127      * @param {string} query
    128      * @param {boolean} caseSensitive
    129      * @param {boolean} isRegex
    130      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
    131      */
    132     searchInFileContent: function(path, query, caseSensitive, isRegex, callback) { },
    133 
    134     /**
    135      * @param {!WebInspector.ProjectSearchConfig} searchConfig
    136      * @param {!WebInspector.Progress} progress
    137      * @param {function(!Array.<string>)} callback
    138      */
    139     findFilesMatchingSearchRequest: function(searchConfig, progress, callback) { },
    140 
    141     /**
    142      * @param {!WebInspector.Progress} progress
    143      */
    144     indexContent: function(progress) { }
    145 }
    146 
    147 /**
    148  * @interface
    149  */
    150 WebInspector.ProjectSearchConfig = function() {}
    151 
    152 WebInspector.ProjectSearchConfig.prototype = {
    153     /**
    154      * @return {string}
    155      */
    156     query: function() { },
    157 
    158     /**
    159      * @return {boolean}
    160      */
    161     ignoreCase: function() { },
    162 
    163     /**
    164      * @return {boolean}
    165      */
    166     isRegex: function() { },
    167 
    168     /**
    169      * @return {!Array.<string>}
    170      */
    171     queries: function() { },
    172 
    173     /**
    174      * @param {string} filePath
    175      * @return {boolean}
    176      */
    177     filePathMatchesFileQuery: function(filePath) { }
    178 }
    179 
    180 /**
    181  * @constructor
    182  * @param {!WebInspector.Project} project
    183  */
    184 WebInspector.ProjectStore = function(project)
    185 {
    186     this._project = project;
    187 }
    188 
    189 WebInspector.ProjectStore.prototype = {
    190     /**
    191      * @param {!WebInspector.FileDescriptor} fileDescriptor
    192      */
    193     addFile: function(fileDescriptor)
    194     {
    195         this._project._addFile(fileDescriptor);
    196     },
    197 
    198     /**
    199      * @param {string} path
    200      */
    201     removeFile: function(path)
    202     {
    203         this._project._removeFile(path);
    204     },
    205 
    206     /**
    207      * @return {!WebInspector.Project}
    208      */
    209     project: function()
    210     {
    211         return this._project;
    212     }
    213 }
    214 
    215 /**
    216  * @param {!WebInspector.Workspace} workspace
    217  * @param {string} projectId
    218  * @param {!WebInspector.ProjectDelegate} projectDelegate
    219  * @constructor
    220  */
    221 WebInspector.Project = function(workspace, projectId, projectDelegate)
    222 {
    223     /** @type {!Object.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */
    224     this._uiSourceCodesMap = {};
    225     /** @type {!Array.<!WebInspector.UISourceCode>} */
    226     this._uiSourceCodesList = [];
    227     this._workspace = workspace;
    228     this._projectId = projectId;
    229     this._projectDelegate = projectDelegate;
    230     this._displayName = this._projectDelegate.displayName();
    231 }
    232 
    233 WebInspector.Project.prototype = {
    234     /**
    235      * @return {string}
    236      */
    237     id: function()
    238     {
    239         return this._projectId;
    240     },
    241 
    242     /**
    243      * @return {string}
    244      */
    245     type: function()
    246     {
    247         return this._projectDelegate.type();
    248     },
    249 
    250     /**
    251      * @return {string}
    252      */
    253     displayName: function()
    254     {
    255         return this._displayName;
    256     },
    257 
    258     /**
    259      * @return {boolean}
    260      */
    261     isServiceProject: function()
    262     {
    263         return this._projectDelegate.type() === WebInspector.projectTypes.Debugger || this._projectDelegate.type() === WebInspector.projectTypes.Formatter || this._projectDelegate.type() === WebInspector.projectTypes.LiveEdit;
    264     },
    265 
    266     /**
    267      * @param {!WebInspector.FileDescriptor} fileDescriptor
    268      */
    269     _addFile: function(fileDescriptor)
    270     {
    271         var path = fileDescriptor.parentPath ? fileDescriptor.parentPath + "/" + fileDescriptor.name : fileDescriptor.name;
    272         var uiSourceCode = this.uiSourceCode(path);
    273         if (uiSourceCode)
    274             return;
    275 
    276         uiSourceCode = new WebInspector.UISourceCode(this, fileDescriptor.parentPath, fileDescriptor.name, fileDescriptor.originURL, fileDescriptor.url, fileDescriptor.contentType);
    277 
    278         this._uiSourceCodesMap[path] = {uiSourceCode: uiSourceCode, index: this._uiSourceCodesList.length};
    279         this._uiSourceCodesList.push(uiSourceCode);
    280         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeAdded, uiSourceCode);
    281     },
    282 
    283     /**
    284      * @param {string} path
    285      */
    286     _removeFile: function(path)
    287     {
    288         var uiSourceCode = this.uiSourceCode(path);
    289         if (!uiSourceCode)
    290             return;
    291 
    292         var entry = this._uiSourceCodesMap[path];
    293         var movedUISourceCode = this._uiSourceCodesList[this._uiSourceCodesList.length - 1];
    294         this._uiSourceCodesList[entry.index] = movedUISourceCode;
    295         var movedEntry = this._uiSourceCodesMap[movedUISourceCode.path()];
    296         movedEntry.index = entry.index;
    297         this._uiSourceCodesList.splice(this._uiSourceCodesList.length - 1, 1);
    298         delete this._uiSourceCodesMap[path];
    299         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeRemoved, entry.uiSourceCode);
    300     },
    301 
    302     _remove: function()
    303     {
    304         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectRemoved, this);
    305         this._uiSourceCodesMap = {};
    306         this._uiSourceCodesList = [];
    307     },
    308 
    309     /**
    310      * @return {!WebInspector.Workspace}
    311      */
    312     workspace: function()
    313     {
    314         return this._workspace;
    315     },
    316 
    317     /**
    318      * @param {string} path
    319      * @return {?WebInspector.UISourceCode}
    320      */
    321     uiSourceCode: function(path)
    322     {
    323         var entry = this._uiSourceCodesMap[path];
    324         return entry ? entry.uiSourceCode : null;
    325     },
    326 
    327     /**
    328      * @param {string} originURL
    329      * @return {?WebInspector.UISourceCode}
    330      */
    331     uiSourceCodeForOriginURL: function(originURL)
    332     {
    333         for (var i = 0; i < this._uiSourceCodesList.length; ++i) {
    334             var uiSourceCode = this._uiSourceCodesList[i];
    335             if (uiSourceCode.originURL() === originURL)
    336                 return uiSourceCode;
    337         }
    338         return null;
    339     },
    340 
    341     /**
    342      * @return {!Array.<!WebInspector.UISourceCode>}
    343      */
    344     uiSourceCodes: function()
    345     {
    346         return this._uiSourceCodesList;
    347     },
    348 
    349     /**
    350      * @param {!WebInspector.UISourceCode} uiSourceCode
    351      * @param {function(?Date, ?number)} callback
    352      */
    353     requestMetadata: function(uiSourceCode, callback)
    354     {
    355         this._projectDelegate.requestMetadata(uiSourceCode.path(), callback);
    356     },
    357 
    358     /**
    359      * @param {!WebInspector.UISourceCode} uiSourceCode
    360      * @param {function(?string)} callback
    361      */
    362     requestFileContent: function(uiSourceCode, callback)
    363     {
    364         this._projectDelegate.requestFileContent(uiSourceCode.path(), callback);
    365     },
    366 
    367     /**
    368      * @return {boolean}
    369      */
    370     canSetFileContent: function()
    371     {
    372         return this._projectDelegate.canSetFileContent();
    373     },
    374 
    375     /**
    376      * @param {!WebInspector.UISourceCode} uiSourceCode
    377      * @param {string} newContent
    378      * @param {function(?string)} callback
    379      */
    380     setFileContent: function(uiSourceCode, newContent, callback)
    381     {
    382         this._projectDelegate.setFileContent(uiSourceCode.path(), newContent, onSetContent.bind(this));
    383 
    384         /**
    385          * @param {?string} content
    386          * @this {WebInspector.Project}
    387          */
    388         function onSetContent(content)
    389         {
    390             this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeContentCommitted, { uiSourceCode: uiSourceCode, content: newContent });
    391             callback(content);
    392         }
    393     },
    394 
    395     /**
    396      * @return {boolean}
    397      */
    398     canRename: function()
    399     {
    400         return this._projectDelegate.canRename();
    401     },
    402 
    403     /**
    404      * @param {!WebInspector.UISourceCode} uiSourceCode
    405      * @param {string} newName
    406      * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
    407      */
    408     rename: function(uiSourceCode, newName, callback)
    409     {
    410         if (newName === uiSourceCode.name()) {
    411             callback(true, uiSourceCode.name(), uiSourceCode.url, uiSourceCode.originURL(), uiSourceCode.contentType());
    412             return;
    413         }
    414 
    415         this._projectDelegate.rename(uiSourceCode.path(), newName, innerCallback.bind(this));
    416 
    417         /**
    418          * @param {boolean} success
    419          * @param {string=} newName
    420          * @param {string=} newURL
    421          * @param {string=} newOriginURL
    422          * @param {!WebInspector.ResourceType=} newContentType
    423          * @this {WebInspector.Project}
    424          */
    425         function innerCallback(success, newName, newURL, newOriginURL, newContentType)
    426         {
    427             if (!success || !newName) {
    428                 callback(false);
    429                 return;
    430             }
    431             var oldPath = uiSourceCode.path();
    432             var newPath = uiSourceCode.parentPath() ? uiSourceCode.parentPath() + "/" + newName : newName;
    433             this._uiSourceCodesMap[newPath] = this._uiSourceCodesMap[oldPath];
    434             delete this._uiSourceCodesMap[oldPath];
    435             callback(true, newName, newURL, newOriginURL, newContentType);
    436         }
    437     },
    438 
    439     /**
    440      * @param {string} path
    441      */
    442     refresh: function(path)
    443     {
    444         this._projectDelegate.refresh(path);
    445     },
    446 
    447     /**
    448      * @param {string} path
    449      */
    450     excludeFolder: function(path)
    451     {
    452         this._projectDelegate.excludeFolder(path);
    453         var uiSourceCodes = this._uiSourceCodesList.slice();
    454         for (var i = 0; i < uiSourceCodes.length; ++i) {
    455             var uiSourceCode = uiSourceCodes[i];
    456             if (uiSourceCode.path().startsWith(path.substr(1)))
    457                 this._removeFile(uiSourceCode.path());
    458         }
    459     },
    460 
    461     /**
    462      * @param {string} path
    463      * @param {?string} name
    464      * @param {string} content
    465      * @param {function(?string)} callback
    466      */
    467     createFile: function(path, name, content, callback)
    468     {
    469         this._projectDelegate.createFile(path, name, content, innerCallback);
    470 
    471         function innerCallback(filePath)
    472         {
    473             callback(filePath);
    474         }
    475     },
    476 
    477     /**
    478      * @param {string} path
    479      */
    480     deleteFile: function(path)
    481     {
    482         this._projectDelegate.deleteFile(path);
    483     },
    484 
    485     remove: function()
    486     {
    487         this._projectDelegate.remove();
    488     },
    489 
    490     /**
    491      * @param {!WebInspector.UISourceCode} uiSourceCode
    492      * @param {string} query
    493      * @param {boolean} caseSensitive
    494      * @param {boolean} isRegex
    495      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
    496      */
    497     searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback)
    498     {
    499         this._projectDelegate.searchInFileContent(uiSourceCode.path(), query, caseSensitive, isRegex, callback);
    500     },
    501 
    502     /**
    503      * @param {!WebInspector.ProjectSearchConfig} searchConfig
    504      * @param {!WebInspector.Progress} progress
    505      * @param {function(!Array.<string>)} callback
    506      */
    507     findFilesMatchingSearchRequest: function(searchConfig, progress, callback)
    508     {
    509         this._projectDelegate.findFilesMatchingSearchRequest(searchConfig, progress, callback);
    510     },
    511 
    512     /**
    513      * @param {!WebInspector.Progress} progress
    514      */
    515     indexContent: function(progress)
    516     {
    517         this._projectDelegate.indexContent(progress);
    518     }
    519 }
    520 
    521 /**
    522  * @enum {string}
    523  */
    524 WebInspector.projectTypes = {
    525     Debugger: "debugger",
    526     Formatter: "formatter",
    527     LiveEdit: "liveedit",
    528     Network: "network",
    529     Snippets: "snippets",
    530     FileSystem: "filesystem",
    531     ContentScripts: "contentscripts"
    532 }
    533 
    534 /**
    535  * @constructor
    536  * @extends {WebInspector.Object}
    537  * @param {!WebInspector.FileSystemMapping} fileSystemMapping
    538  */
    539 WebInspector.Workspace = function(fileSystemMapping)
    540 {
    541     this._fileSystemMapping = fileSystemMapping;
    542     /** @type {!Object.<string, !WebInspector.Project>} */
    543     this._projects = {};
    544     this._hasResourceContentTrackingExtensions = false;
    545 }
    546 
    547 WebInspector.Workspace.Events = {
    548     UISourceCodeAdded: "UISourceCodeAdded",
    549     UISourceCodeRemoved: "UISourceCodeRemoved",
    550     UISourceCodeContentCommitted: "UISourceCodeContentCommitted",
    551     ProjectRemoved: "ProjectRemoved"
    552 }
    553 
    554 WebInspector.Workspace.prototype = {
    555     /**
    556      * @return {!Array.<!WebInspector.UISourceCode>}
    557      */
    558     unsavedSourceCodes: function()
    559     {
    560         function filterUnsaved(sourceCode)
    561         {
    562             return sourceCode.isDirty();
    563         }
    564         return this.uiSourceCodes().filter(filterUnsaved);
    565     },
    566 
    567     /**
    568      * @param {string} projectId
    569      * @param {string} path
    570      * @return {?WebInspector.UISourceCode}
    571      */
    572     uiSourceCode: function(projectId, path)
    573     {
    574         var project = this._projects[projectId];
    575         return project ? project.uiSourceCode(path) : null;
    576     },
    577 
    578     /**
    579      * @param {string} originURL
    580      * @return {?WebInspector.UISourceCode}
    581      */
    582     uiSourceCodeForOriginURL: function(originURL)
    583     {
    584         var projects = this.projectsForType(WebInspector.projectTypes.Network);
    585         projects = projects.concat(this.projectsForType(WebInspector.projectTypes.ContentScripts));
    586         for (var i = 0; i < projects.length; ++i) {
    587             var project = projects[i];
    588             var uiSourceCode = project.uiSourceCodeForOriginURL(originURL);
    589             if (uiSourceCode)
    590                 return uiSourceCode;
    591         }
    592         return null;
    593     },
    594 
    595     /**
    596      * @param {string} type
    597      * @return {!Array.<!WebInspector.UISourceCode>}
    598      */
    599     uiSourceCodesForProjectType: function(type)
    600     {
    601         var result = [];
    602         for (var projectName in this._projects) {
    603             var project = this._projects[projectName];
    604             if (project.type() === type)
    605                 result = result.concat(project.uiSourceCodes());
    606         }
    607         return result;
    608     },
    609 
    610     /**
    611      * @param {string} projectId
    612      * @param {!WebInspector.ProjectDelegate} projectDelegate
    613      * @return {!WebInspector.ProjectStore}
    614      */
    615     addProject: function(projectId, projectDelegate)
    616     {
    617         var project = new WebInspector.Project(this, projectId, projectDelegate);
    618         this._projects[projectId] = project;
    619         var projectStore = new WebInspector.ProjectStore(project);
    620         return projectStore;
    621     },
    622 
    623     /**
    624      * @param {string} projectId
    625      */
    626     removeProject: function(projectId)
    627     {
    628         var project = this._projects[projectId];
    629         if (!project)
    630             return;
    631         delete this._projects[projectId];
    632         project._remove();
    633     },
    634 
    635     /**
    636      * @param {string} projectId
    637      * @return {!WebInspector.Project}
    638      */
    639     project: function(projectId)
    640     {
    641         return this._projects[projectId];
    642     },
    643 
    644     /**
    645      * @return {!Array.<!WebInspector.Project>}
    646      */
    647     projects: function()
    648     {
    649         return Object.values(this._projects);
    650     },
    651 
    652     /**
    653      * @param {string} type
    654      * @return {!Array.<!WebInspector.Project>}
    655      */
    656     projectsForType: function(type)
    657     {
    658         function filterByType(project)
    659         {
    660             return project.type() === type;
    661         }
    662         return this.projects().filter(filterByType);
    663     },
    664 
    665     /**
    666      * @return {!Array.<!WebInspector.UISourceCode>}
    667      */
    668     uiSourceCodes: function()
    669     {
    670         var result = [];
    671         for (var projectId in this._projects) {
    672             var project = this._projects[projectId];
    673             result = result.concat(project.uiSourceCodes());
    674         }
    675         return result;
    676     },
    677 
    678     /**
    679      * @param {string} url
    680      * @return {boolean}
    681      */
    682     hasMappingForURL: function(url)
    683     {
    684         return this._fileSystemMapping.hasMappingForURL(url);
    685     },
    686 
    687     /**
    688      * @param {string} url
    689      * @return {?WebInspector.UISourceCode}
    690      */
    691     _networkUISourceCodeForURL: function(url)
    692     {
    693         var splitURL = WebInspector.ParsedURL.splitURL(url);
    694         var projectId = splitURL[0];
    695         var project = this.project(projectId);
    696         return project ? project.uiSourceCode(splitURL.slice(1).join("/")) : null;
    697     },
    698 
    699     /**
    700      * @param {string} url
    701      * @return {?WebInspector.UISourceCode}
    702      */
    703     _contentScriptUISourceCodeForURL: function(url)
    704     {
    705         var splitURL = WebInspector.ParsedURL.splitURL(url);
    706         var projectId = "contentscripts:" + splitURL[0];
    707         var project = this.project(projectId);
    708         return project ? project.uiSourceCode(splitURL.slice(1).join("/")) : null;
    709     },
    710 
    711     /**
    712      * @param {string} url
    713      * @return {?WebInspector.UISourceCode}
    714      */
    715     uiSourceCodeForURL: function(url)
    716     {
    717         var file = this._fileSystemMapping.fileForURL(url);
    718         if (!file)
    719             return this._networkUISourceCodeForURL(url) || this._contentScriptUISourceCodeForURL(url);
    720 
    721         var projectId = WebInspector.FileSystemWorkspaceBinding.projectId(file.fileSystemPath);
    722         var project = this.project(projectId);
    723         return project ? project.uiSourceCode(file.filePath) : null;
    724     },
    725 
    726     /**
    727      * @param {string} fileSystemPath
    728      * @param {string} filePath
    729      * @return {string}
    730      */
    731     urlForPath: function(fileSystemPath, filePath)
    732     {
    733         return this._fileSystemMapping.urlForPath(fileSystemPath, filePath);
    734     },
    735 
    736     /**
    737      * @param {!WebInspector.UISourceCode} networkUISourceCode
    738      * @param {!WebInspector.UISourceCode} uiSourceCode
    739      * @param {!WebInspector.FileSystemWorkspaceBinding} fileSystemWorkspaceBinding
    740      */
    741     addMapping: function(networkUISourceCode, uiSourceCode, fileSystemWorkspaceBinding)
    742     {
    743         var url = networkUISourceCode.url;
    744         var path = uiSourceCode.path();
    745         var fileSystemPath = fileSystemWorkspaceBinding.fileSystemPath(uiSourceCode.project().id());
    746         this._fileSystemMapping.addMappingForResource(url, fileSystemPath, path);
    747     },
    748 
    749     /**
    750      * @param {!WebInspector.UISourceCode} uiSourceCode
    751      */
    752     removeMapping: function(uiSourceCode)
    753     {
    754         this._fileSystemMapping.removeMappingForURL(uiSourceCode.url);
    755     },
    756 
    757     /**
    758      * @param {boolean} hasExtensions
    759      */
    760     setHasResourceContentTrackingExtensions: function(hasExtensions)
    761     {
    762         this._hasResourceContentTrackingExtensions = hasExtensions;
    763     },
    764 
    765     /**
    766      * @return {boolean}
    767      */
    768     hasResourceContentTrackingExtensions: function()
    769     {
    770         return this._hasResourceContentTrackingExtensions;
    771     },
    772 
    773     __proto__: WebInspector.Object.prototype
    774 }
    775 
    776 /**
    777  * @type {!WebInspector.Workspace}
    778  */
    779 WebInspector.workspace;
    780