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