Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / workspace / Workspace.js
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 {!Map.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */
232     this._uiSourceCodesMap = new Map();
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             this._projectDelegate.type() === WebInspector.projectTypes.Service;
300     },
301
302     /**
303      * @param {!WebInspector.FileDescriptor} fileDescriptor
304      */
305     _addFile: function(fileDescriptor)
306     {
307         var path = fileDescriptor.parentPath ? fileDescriptor.parentPath + "/" + fileDescriptor.name : fileDescriptor.name;
308         var uiSourceCode = this.uiSourceCode(path);
309         if (uiSourceCode)
310             return;
311
312         uiSourceCode = new WebInspector.UISourceCode(this, fileDescriptor.parentPath, fileDescriptor.name, fileDescriptor.originURL, fileDescriptor.url, fileDescriptor.contentType);
313
314         this._uiSourceCodesMap.set(path, {uiSourceCode: uiSourceCode, index: this._uiSourceCodesList.length});
315         this._uiSourceCodesList.push(uiSourceCode);
316         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeAdded, uiSourceCode);
317     },
318
319     /**
320      * @param {string} path
321      */
322     _removeFile: function(path)
323     {
324         var uiSourceCode = this.uiSourceCode(path);
325         if (!uiSourceCode)
326             return;
327
328         var entry = this._uiSourceCodesMap.get(path);
329         var movedUISourceCode = this._uiSourceCodesList[this._uiSourceCodesList.length - 1];
330         this._uiSourceCodesList[entry.index] = movedUISourceCode;
331         var movedEntry = this._uiSourceCodesMap.get(movedUISourceCode.path());
332         movedEntry.index = entry.index;
333         this._uiSourceCodesList.splice(this._uiSourceCodesList.length - 1, 1);
334         this._uiSourceCodesMap.delete(path);
335         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeRemoved, entry.uiSourceCode);
336     },
337
338     _remove: function()
339     {
340         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectRemoved, this);
341         this._uiSourceCodesMap = new Map();
342         this._uiSourceCodesList = [];
343     },
344
345     /**
346      * @return {!WebInspector.Workspace}
347      */
348     workspace: function()
349     {
350         return this._workspace;
351     },
352
353     /**
354      * @param {string} path
355      * @return {?WebInspector.UISourceCode}
356      */
357     uiSourceCode: function(path)
358     {
359         var entry = this._uiSourceCodesMap.get(path);
360         return entry ? entry.uiSourceCode : null;
361     },
362
363     /**
364      * @param {string} originURL
365      * @return {?WebInspector.UISourceCode}
366      */
367     uiSourceCodeForOriginURL: function(originURL)
368     {
369         for (var i = 0; i < this._uiSourceCodesList.length; ++i) {
370             var uiSourceCode = this._uiSourceCodesList[i];
371             if (uiSourceCode.originURL() === originURL)
372                 return uiSourceCode;
373         }
374         return null;
375     },
376
377     /**
378      * @return {!Array.<!WebInspector.UISourceCode>}
379      */
380     uiSourceCodes: function()
381     {
382         return this._uiSourceCodesList;
383     },
384
385     /**
386      * @param {!WebInspector.UISourceCode} uiSourceCode
387      * @param {function(?Date, ?number)} callback
388      */
389     requestMetadata: function(uiSourceCode, callback)
390     {
391         this._projectDelegate.requestMetadata(uiSourceCode.path(), callback);
392     },
393
394     /**
395      * @param {!WebInspector.UISourceCode} uiSourceCode
396      * @param {function(?string)} callback
397      */
398     requestFileContent: function(uiSourceCode, callback)
399     {
400         this._projectDelegate.requestFileContent(uiSourceCode.path(), callback);
401     },
402
403     /**
404      * @return {boolean}
405      */
406     canSetFileContent: function()
407     {
408         return this._projectDelegate.canSetFileContent();
409     },
410
411     /**
412      * @param {!WebInspector.UISourceCode} uiSourceCode
413      * @param {string} newContent
414      * @param {function(?string)} callback
415      */
416     setFileContent: function(uiSourceCode, newContent, callback)
417     {
418         this._projectDelegate.setFileContent(uiSourceCode.path(), newContent, onSetContent.bind(this));
419
420         /**
421          * @param {?string} content
422          * @this {WebInspector.Project}
423          */
424         function onSetContent(content)
425         {
426             this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeContentCommitted, { uiSourceCode: uiSourceCode, content: newContent });
427             callback(content);
428         }
429     },
430
431     /**
432      * @return {boolean}
433      */
434     canRename: function()
435     {
436         return this._projectDelegate.canRename();
437     },
438
439     /**
440      * @param {!WebInspector.UISourceCode} uiSourceCode
441      * @param {string} newName
442      * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
443      */
444     rename: function(uiSourceCode, newName, callback)
445     {
446         if (newName === uiSourceCode.name()) {
447             callback(true, uiSourceCode.name(), uiSourceCode.url, uiSourceCode.originURL(), uiSourceCode.contentType());
448             return;
449         }
450
451         this._projectDelegate.rename(uiSourceCode.path(), newName, innerCallback.bind(this));
452
453         /**
454          * @param {boolean} success
455          * @param {string=} newName
456          * @param {string=} newURL
457          * @param {string=} newOriginURL
458          * @param {!WebInspector.ResourceType=} newContentType
459          * @this {WebInspector.Project}
460          */
461         function innerCallback(success, newName, newURL, newOriginURL, newContentType)
462         {
463             if (!success || !newName) {
464                 callback(false);
465                 return;
466             }
467             var oldPath = uiSourceCode.path();
468             var newPath = uiSourceCode.parentPath() ? uiSourceCode.parentPath() + "/" + newName : newName;
469             this._uiSourceCodesMap.set(newPath, this._uiSourceCodesMap.get(oldPath));
470             this._uiSourceCodesMap.delete(oldPath);
471             callback(true, newName, newURL, newOriginURL, newContentType);
472         }
473     },
474
475     /**
476      * @param {string} path
477      * @param {function()=} callback
478      */
479     refresh: function(path, callback)
480     {
481         this._projectDelegate.refresh(path, callback);
482     },
483
484     /**
485      * @param {string} path
486      */
487     excludeFolder: function(path)
488     {
489         this._projectDelegate.excludeFolder(path);
490         var uiSourceCodes = this._uiSourceCodesList.slice();
491         for (var i = 0; i < uiSourceCodes.length; ++i) {
492             var uiSourceCode = uiSourceCodes[i];
493             if (uiSourceCode.path().startsWith(path.substr(1)))
494                 this._removeFile(uiSourceCode.path());
495         }
496     },
497
498     /**
499      * @param {string} path
500      * @param {?string} name
501      * @param {string} content
502      * @param {function(?string)} callback
503      */
504     createFile: function(path, name, content, callback)
505     {
506         this._projectDelegate.createFile(path, name, content, innerCallback);
507
508         function innerCallback(filePath)
509         {
510             callback(filePath);
511         }
512     },
513
514     /**
515      * @param {string} path
516      */
517     deleteFile: function(path)
518     {
519         this._projectDelegate.deleteFile(path);
520     },
521
522     remove: function()
523     {
524         this._projectDelegate.remove();
525     },
526
527     /**
528      * @param {!WebInspector.UISourceCode} uiSourceCode
529      * @param {string} query
530      * @param {boolean} caseSensitive
531      * @param {boolean} isRegex
532      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
533      */
534     searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback)
535     {
536         this._projectDelegate.searchInFileContent(uiSourceCode.path(), query, caseSensitive, isRegex, callback);
537     },
538
539     /**
540      * @param {!WebInspector.ProjectSearchConfig} searchConfig
541      * @param {!Array.<string>} filesMathingFileQuery
542      * @param {!WebInspector.Progress} progress
543      * @param {function(!Array.<string>)} callback
544      */
545     findFilesMatchingSearchRequest: function(searchConfig, filesMathingFileQuery, progress, callback)
546     {
547         this._projectDelegate.findFilesMatchingSearchRequest(searchConfig, filesMathingFileQuery, progress, callback);
548     },
549
550     /**
551      * @param {!WebInspector.Progress} progress
552      */
553     indexContent: function(progress)
554     {
555         this._projectDelegate.indexContent(progress);
556     },
557
558     __proto__: WebInspector.Object.prototype
559 }
560
561 /**
562  * @enum {string}
563  */
564 WebInspector.projectTypes = {
565     Debugger: "debugger",
566     Formatter: "formatter",
567     LiveEdit: "liveedit",
568     Network: "network",
569     Snippets: "snippets",
570     FileSystem: "filesystem",
571     ContentScripts: "contentscripts",
572     Service: "service"
573 }
574
575 /**
576  * @constructor
577  * @extends {WebInspector.Object}
578  * @param {!WebInspector.FileSystemMapping} fileSystemMapping
579  */
580 WebInspector.Workspace = function(fileSystemMapping)
581 {
582     this._fileSystemMapping = fileSystemMapping;
583     /** @type {!Object.<string, !WebInspector.Project>} */
584     this._projects = {};
585     this._hasResourceContentTrackingExtensions = false;
586     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
587 }
588
589 WebInspector.Workspace.Events = {
590     UISourceCodeAdded: "UISourceCodeAdded",
591     UISourceCodeRemoved: "UISourceCodeRemoved",
592     UISourceCodeContentCommitted: "UISourceCodeContentCommitted",
593     ProjectAdded: "ProjectAdded",
594     ProjectRemoved: "ProjectRemoved"
595 }
596
597 WebInspector.Workspace.prototype = {
598     /**
599      * @return {!Array.<!WebInspector.UISourceCode>}
600      */
601     unsavedSourceCodes: function()
602     {
603         /**
604          * @param {!WebInspector.UISourceCode} sourceCode
605          * @return {boolean}
606          */
607         function filterUnsaved(sourceCode)
608         {
609             return sourceCode.isDirty();
610         }
611
612         var unsavedSourceCodes = [];
613         var projects = this.projectsForType(WebInspector.projectTypes.FileSystem);
614         for (var i = 0; i < projects.length; ++i)
615             unsavedSourceCodes = unsavedSourceCodes.concat(projects[i].uiSourceCodes().filter(filterUnsaved));
616
617         return unsavedSourceCodes;
618     },
619
620     /**
621      * @param {string} projectId
622      * @param {string} path
623      * @return {?WebInspector.UISourceCode}
624      */
625     uiSourceCode: function(projectId, path)
626     {
627         var project = this._projects[projectId];
628         return project ? project.uiSourceCode(path) : null;
629     },
630
631     /**
632      * @param {string} originURL
633      * @return {?WebInspector.UISourceCode}
634      */
635     uiSourceCodeForOriginURL: function(originURL)
636     {
637         var projects = this.projectsForType(WebInspector.projectTypes.Network);
638         projects = projects.concat(this.projectsForType(WebInspector.projectTypes.ContentScripts));
639         for (var i = 0; i < projects.length; ++i) {
640             var project = projects[i];
641             var uiSourceCode = project.uiSourceCodeForOriginURL(originURL);
642             if (uiSourceCode)
643                 return uiSourceCode;
644         }
645         return null;
646     },
647
648     /**
649      * @param {string} type
650      * @return {!Array.<!WebInspector.UISourceCode>}
651      */
652     uiSourceCodesForProjectType: function(type)
653     {
654         var result = [];
655         for (var projectName in this._projects) {
656             var project = this._projects[projectName];
657             if (project.type() === type)
658                 result = result.concat(project.uiSourceCodes());
659         }
660         return result;
661     },
662
663     /**
664      * @param {string} projectId
665      * @param {!WebInspector.ProjectDelegate} projectDelegate
666      * @return {!WebInspector.ProjectStore}
667      */
668     addProject: function(projectId, projectDelegate)
669     {
670         var project = new WebInspector.Project(this, projectId, projectDelegate);
671         this._projects[projectId] = project;
672         var projectStore = new WebInspector.ProjectStore(project);
673         this.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectAdded, project);
674         return projectStore;
675     },
676
677     /**
678      * @param {string} projectId
679      */
680     removeProject: function(projectId)
681     {
682         var project = this._projects[projectId];
683         if (!project)
684             return;
685         delete this._projects[projectId];
686         project._remove();
687     },
688
689     /**
690      * @param {string} projectId
691      * @return {!WebInspector.Project}
692      */
693     project: function(projectId)
694     {
695         return this._projects[projectId];
696     },
697
698     /**
699      * @return {!Array.<!WebInspector.Project>}
700      */
701     projects: function()
702     {
703         return Object.values(this._projects);
704     },
705
706     /**
707      * @param {string} type
708      * @return {!Array.<!WebInspector.Project>}
709      */
710     projectsForType: function(type)
711     {
712         function filterByType(project)
713         {
714             return project.type() === type;
715         }
716         return this.projects().filter(filterByType);
717     },
718
719     /**
720      * @return {!Array.<!WebInspector.UISourceCode>}
721      */
722     uiSourceCodes: function()
723     {
724         var result = [];
725         for (var projectId in this._projects) {
726             var project = this._projects[projectId];
727             result = result.concat(project.uiSourceCodes());
728         }
729         return result;
730     },
731
732     /**
733      * @param {string} url
734      * @return {boolean}
735      */
736     hasMappingForURL: function(url)
737     {
738         return this._fileSystemMapping.hasMappingForURL(url);
739     },
740
741     /**
742      * @param {string} url
743      * @return {?WebInspector.UISourceCode}
744      */
745     _networkUISourceCodeForURL: function(url)
746     {
747         var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url);
748         var projectId = 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     _contentScriptUISourceCodeForURL: function(url)
758     {
759         var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url);
760         var projectId = "contentscripts:" + splitURL[0];
761         var project = this.project(projectId);
762         return project ? project.uiSourceCode(splitURL.slice(1).join("/")) : null;
763     },
764
765     /**
766      * @param {string} url
767      * @return {?WebInspector.UISourceCode}
768      */
769     uiSourceCodeForURL: function(url)
770     {
771         var file = this._fileSystemMapping.fileForURL(url);
772         if (!file)
773             return this._networkUISourceCodeForURL(url) || this._contentScriptUISourceCodeForURL(url);
774
775         var projectId = WebInspector.FileSystemWorkspaceBinding.projectId(file.fileSystemPath);
776         var project = this.project(projectId);
777         return project ? project.uiSourceCode(file.filePath) : null;
778     },
779
780     /**
781      * @param {string} fileSystemPath
782      * @param {string} filePath
783      * @return {string}
784      */
785     urlForPath: function(fileSystemPath, filePath)
786     {
787         return this._fileSystemMapping.urlForPath(fileSystemPath, filePath);
788     },
789
790     /**
791      * @param {!WebInspector.UISourceCode} networkUISourceCode
792      * @param {!WebInspector.UISourceCode} uiSourceCode
793      * @param {!WebInspector.FileSystemWorkspaceBinding} fileSystemWorkspaceBinding
794      */
795     addMapping: function(networkUISourceCode, uiSourceCode, fileSystemWorkspaceBinding)
796     {
797         var url = networkUISourceCode.url;
798         var path = uiSourceCode.path();
799         var fileSystemPath = fileSystemWorkspaceBinding.fileSystemPath(uiSourceCode.project().id());
800         this._fileSystemMapping.addMappingForResource(url, fileSystemPath, path);
801     },
802
803     /**
804      * @param {!WebInspector.UISourceCode} uiSourceCode
805      */
806     removeMapping: function(uiSourceCode)
807     {
808         this._fileSystemMapping.removeMappingForURL(uiSourceCode.url);
809     },
810
811     /**
812      * @param {boolean} hasExtensions
813      */
814     setHasResourceContentTrackingExtensions: function(hasExtensions)
815     {
816         this._hasResourceContentTrackingExtensions = hasExtensions;
817     },
818
819     /**
820      * @return {boolean}
821      */
822     hasResourceContentTrackingExtensions: function()
823     {
824         return this._hasResourceContentTrackingExtensions;
825     },
826
827     /**
828      * @param {!WebInspector.Event} event
829      */
830     _revealSourceLine: function(event)
831     {
832         var url = /** @type {string} */ (event.data["url"]);
833         var lineNumber = /** @type {number} */ (event.data["lineNumber"]);
834         var columnNumber = /** @type {number} */ (event.data["columnNumber"]);
835
836         var uiSourceCode = this.uiSourceCodeForURL(url);
837         if (uiSourceCode) {
838             WebInspector.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
839             return;
840         }
841
842         /**
843          * @param {!WebInspector.Event} event
844          * @this {WebInspector.Workspace}
845          */
846         function listener(event)
847         {
848             var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
849             if (uiSourceCode.url === url) {
850                 WebInspector.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
851                 this.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, listener, this);
852             }
853         }
854
855         this.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, listener, this);
856     },
857
858     __proto__: WebInspector.Object.prototype
859 }
860
861 /**
862  * @type {!WebInspector.Workspace}
863  */
864 WebInspector.workspace;