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