2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
34 WebInspector
.ProjectSearchConfig = function() {}
36 WebInspector
.ProjectSearchConfig
.prototype = {
40 query: function() { },
45 ignoreCase: function() { },
50 isRegex: function() { },
53 * @return {!Array.<string>}
55 queries: function() { },
58 * @param {string} filePath
61 filePathMatchesFileQuery: function(filePath
) { }
66 * @param {string} parentPath
67 * @param {string} name
68 * @param {string} originURL
70 * @param {!WebInspector.ResourceType} contentType
72 WebInspector
.FileDescriptor = function(parentPath
, name
, originURL
, url
, contentType
)
74 this.parentPath
= parentPath
;
76 this.originURL
= originURL
;
78 this.contentType
= contentType
;
83 * @extends {WebInspector.EventTarget}
85 WebInspector
.ProjectDelegate = function() { }
87 WebInspector
.ProjectDelegate
.Events
= {
88 FileAdded
: "FileAdded",
89 FileRemoved
: "FileRemoved",
92 WebInspector
.ProjectDelegate
.prototype = {
101 displayName: function() { },
109 * @param {string} path
110 * @param {function(?Date, ?number)} callback
112 requestMetadata: function(path
, callback
) { },
115 * @param {string} path
116 * @param {function(?string)} callback
118 requestFileContent: function(path
, callback
) { },
123 canSetFileContent: function() { },
126 * @param {string} path
127 * @param {string} newContent
128 * @param {function(?string)} callback
130 setFileContent: function(path
, newContent
, callback
) { },
135 canRename: function() { },
138 * @param {string} path
139 * @param {string} newName
140 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
142 rename: function(path
, newName
, callback
) { },
145 * @param {string} path
146 * @param {function()=} callback
148 refresh: function(path
, callback
) { },
151 * @param {string} path
153 excludeFolder: function(path
) { },
156 * @param {string} path
157 * @param {?string} name
158 * @param {string} content
159 * @param {function(?string)} callback
161 createFile: function(path
, name
, content
, callback
) { },
164 * @param {string} path
166 deleteFile: function(path
) { },
168 remove: function() { },
171 * @param {string} path
172 * @param {string} query
173 * @param {boolean} caseSensitive
174 * @param {boolean} isRegex
175 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
177 searchInFileContent: function(path
, query
, caseSensitive
, isRegex
, callback
) { },
180 * @param {!WebInspector.ProjectSearchConfig} searchConfig
181 * @param {!Array.<string>} filesMathingFileQuery
182 * @param {!WebInspector.Progress} progress
183 * @param {function(!Array.<string>)} callback
185 findFilesMatchingSearchRequest: function(searchConfig
, filesMathingFileQuery
, progress
, callback
) { },
188 * @param {!WebInspector.Progress} progress
190 indexContent: function(progress
) { }
195 * @extends {WebInspector.Object}
196 * @param {!WebInspector.Workspace} workspace
197 * @param {string} projectId
198 * @param {!WebInspector.ProjectDelegate} projectDelegate
200 WebInspector
.Project = function(workspace
, projectId
, projectDelegate
)
202 /** @type {!Map.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */
203 this._uiSourceCodesMap
= new Map();
204 /** @type {!Array.<!WebInspector.UISourceCode>} */
205 this._uiSourceCodesList
= [];
206 this._workspace
= workspace
;
207 this._projectId
= projectId
;
208 this._projectDelegate
= projectDelegate
;
209 this._url
= this._projectDelegate
.url();
210 this._displayName
= this._projectDelegate
.displayName();
211 projectDelegate
.addEventListener(WebInspector
.ProjectDelegate
.Events
.FileAdded
, this._fileAdded
, this);
212 projectDelegate
.addEventListener(WebInspector
.ProjectDelegate
.Events
.FileRemoved
, this._fileRemoved
, this);
218 WebInspector
.Project
.Events
= {
219 DisplayNameUpdated
: "DisplayNameUpdated"
222 WebInspector
.Project
.prototype = {
228 return this._projectId
;
236 return this._projectDelegate
.type();
242 displayName: function()
244 return this._displayName
;
248 * @param {string} displayName
250 setDisplayName: function(displayName
)
252 if (this._displayName
=== displayName
)
254 this._displayName
= displayName
;
255 this.dispatchEventToListeners(WebInspector
.Project
.Events
.DisplayNameUpdated
);
269 isServiceProject: function()
271 return this._projectDelegate
.type() === WebInspector
.projectTypes
.Debugger
|| this._projectDelegate
.type() === WebInspector
.projectTypes
.Formatter
|| this._projectDelegate
.type() === WebInspector
.projectTypes
.Service
;
276 * @param {!WebInspector.Event} event
278 _fileAdded: function(event
)
280 var fileDescriptor
= /** @type {!WebInspector.FileDescriptor} */ (event
.data
);
281 var path
= fileDescriptor
.parentPath
? fileDescriptor
.parentPath
+ "/" + fileDescriptor
.name
: fileDescriptor
.name
;
282 var uiSourceCode
= this.uiSourceCode(path
);
286 uiSourceCode
= new WebInspector
.UISourceCode(this, fileDescriptor
.parentPath
, fileDescriptor
.name
, fileDescriptor
.originURL
, fileDescriptor
.url
, fileDescriptor
.contentType
);
288 this._uiSourceCodesMap
.set(path
, {uiSourceCode
: uiSourceCode
, index
: this._uiSourceCodesList
.length
});
289 this._uiSourceCodesList
.push(uiSourceCode
);
290 this._workspace
.dispatchEventToListeners(WebInspector
.Workspace
.Events
.UISourceCodeAdded
, uiSourceCode
);
294 * @param {!WebInspector.Event} event
296 _fileRemoved: function(event
)
298 var path
= /** @type {string} */ (event
.data
);
299 this._removeFile(path
);
303 * @param {string} path
305 _removeFile: function(path
)
307 var uiSourceCode
= this.uiSourceCode(path
);
311 var entry
= this._uiSourceCodesMap
.get(path
);
312 var movedUISourceCode
= this._uiSourceCodesList
[this._uiSourceCodesList
.length
- 1];
313 this._uiSourceCodesList
[entry
.index
] = movedUISourceCode
;
314 var movedEntry
= this._uiSourceCodesMap
.get(movedUISourceCode
.path());
315 movedEntry
.index
= entry
.index
;
316 this._uiSourceCodesList
.splice(this._uiSourceCodesList
.length
- 1, 1);
317 this._uiSourceCodesMap
.delete(path
);
318 this._workspace
.dispatchEventToListeners(WebInspector
.Workspace
.Events
.UISourceCodeRemoved
, entry
.uiSourceCode
);
323 this._projectDelegate
.removeEventListener(WebInspector
.ProjectDelegate
.Events
.FileAdded
, this._fileAdded
, this);
324 this._projectDelegate
.removeEventListener(WebInspector
.ProjectDelegate
.Events
.FileRemoved
, this._fileRemoved
, this);
325 this._workspace
.dispatchEventToListeners(WebInspector
.Workspace
.Events
.ProjectRemoved
, this);
326 this._uiSourceCodesMap
= new Map();
327 this._uiSourceCodesList
= [];
331 * @return {!WebInspector.Workspace}
333 workspace: function()
335 return this._workspace
;
339 * @param {string} path
340 * @return {?WebInspector.UISourceCode}
342 uiSourceCode: function(path
)
344 var entry
= this._uiSourceCodesMap
.get(path
);
345 return entry
? entry
.uiSourceCode
: null;
349 * @param {string} originURL
350 * @return {?WebInspector.UISourceCode}
352 uiSourceCodeForOriginURL: function(originURL
)
354 for (var i
= 0; i
< this._uiSourceCodesList
.length
; ++i
) {
355 var uiSourceCode
= this._uiSourceCodesList
[i
];
356 if (uiSourceCode
.originURL() === originURL
)
363 * @return {!Array.<!WebInspector.UISourceCode>}
365 uiSourceCodes: function()
367 return this._uiSourceCodesList
;
371 * @param {!WebInspector.UISourceCode} uiSourceCode
372 * @param {function(?Date, ?number)} callback
374 requestMetadata: function(uiSourceCode
, callback
)
376 this._projectDelegate
.requestMetadata(uiSourceCode
.path(), callback
);
380 * @param {!WebInspector.UISourceCode} uiSourceCode
381 * @param {function(?string)} callback
383 requestFileContent: function(uiSourceCode
, callback
)
385 this._projectDelegate
.requestFileContent(uiSourceCode
.path(), callback
);
391 canSetFileContent: function()
393 return this._projectDelegate
.canSetFileContent();
397 * @param {!WebInspector.UISourceCode} uiSourceCode
398 * @param {string} newContent
399 * @param {function(?string)} callback
401 setFileContent: function(uiSourceCode
, newContent
, callback
)
403 this._projectDelegate
.setFileContent(uiSourceCode
.path(), newContent
, onSetContent
.bind(this));
406 * @param {?string} content
407 * @this {WebInspector.Project}
409 function onSetContent(content
)
411 this._workspace
.dispatchEventToListeners(WebInspector
.Workspace
.Events
.UISourceCodeContentCommitted
, { uiSourceCode
: uiSourceCode
, content
: newContent
});
419 canRename: function()
421 return this._projectDelegate
.canRename();
425 * @param {!WebInspector.UISourceCode} uiSourceCode
426 * @param {string} newName
427 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
429 rename: function(uiSourceCode
, newName
, callback
)
431 if (newName
=== uiSourceCode
.name()) {
432 callback(true, uiSourceCode
.name(), uiSourceCode
.networkURL(), uiSourceCode
.originURL(), uiSourceCode
.contentType());
436 this._projectDelegate
.rename(uiSourceCode
.path(), newName
, innerCallback
.bind(this));
439 * @param {boolean} success
440 * @param {string=} newName
441 * @param {string=} newURL
442 * @param {string=} newOriginURL
443 * @param {!WebInspector.ResourceType=} newContentType
444 * @this {WebInspector.Project}
446 function innerCallback(success
, newName
, newURL
, newOriginURL
, newContentType
)
448 if (!success
|| !newName
) {
452 var oldPath
= uiSourceCode
.path();
453 var newPath
= uiSourceCode
.parentPath() ? uiSourceCode
.parentPath() + "/" + newName
: newName
;
454 var value
= /** @type {!{uiSourceCode: !WebInspector.UISourceCode, index: number}} */ (this._uiSourceCodesMap
.get(oldPath
));
455 this._uiSourceCodesMap
.set(newPath
, value
);
456 this._uiSourceCodesMap
.delete(oldPath
);
457 callback(true, newName
, newURL
, newOriginURL
, newContentType
);
462 * @param {string} path
463 * @param {function()=} callback
465 refresh: function(path
, callback
)
467 this._projectDelegate
.refresh(path
, callback
);
471 * @param {string} path
473 excludeFolder: function(path
)
475 this._projectDelegate
.excludeFolder(path
);
476 var uiSourceCodes
= this._uiSourceCodesList
.slice();
477 for (var i
= 0; i
< uiSourceCodes
.length
; ++i
) {
478 var uiSourceCode
= uiSourceCodes
[i
];
479 if (uiSourceCode
.path().startsWith(path
.substr(1)))
480 this._removeFile(uiSourceCode
.path());
485 * @param {string} path
486 * @param {?string} name
487 * @param {string} content
488 * @param {function(?string)} callback
490 createFile: function(path
, name
, content
, callback
)
492 this._projectDelegate
.createFile(path
, name
, content
, innerCallback
);
494 function innerCallback(filePath
)
501 * @param {string} path
503 deleteFile: function(path
)
505 this._projectDelegate
.deleteFile(path
);
510 this._projectDelegate
.remove();
514 * @param {!WebInspector.UISourceCode} uiSourceCode
515 * @param {string} query
516 * @param {boolean} caseSensitive
517 * @param {boolean} isRegex
518 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
520 searchInFileContent: function(uiSourceCode
, query
, caseSensitive
, isRegex
, callback
)
522 this._projectDelegate
.searchInFileContent(uiSourceCode
.path(), query
, caseSensitive
, isRegex
, callback
);
526 * @param {!WebInspector.ProjectSearchConfig} searchConfig
527 * @param {!Array.<string>} filesMathingFileQuery
528 * @param {!WebInspector.Progress} progress
529 * @param {function(!Array.<string>)} callback
531 findFilesMatchingSearchRequest: function(searchConfig
, filesMathingFileQuery
, progress
, callback
)
533 this._projectDelegate
.findFilesMatchingSearchRequest(searchConfig
, filesMathingFileQuery
, progress
, callback
);
537 * @param {!WebInspector.Progress} progress
539 indexContent: function(progress
)
541 this._projectDelegate
.indexContent(progress
);
544 __proto__
: WebInspector
.Object
.prototype
550 WebInspector
.projectTypes
= {
551 Debugger
: "debugger",
552 Formatter
: "formatter",
554 Snippets
: "snippets",
555 FileSystem
: "filesystem",
556 ContentScripts
: "contentscripts",
562 * @extends {WebInspector.Object}
563 * @param {!WebInspector.FileSystemMapping} fileSystemMapping
565 WebInspector
.Workspace = function(fileSystemMapping
)
567 this._fileSystemMapping
= fileSystemMapping
;
568 /** @type {!Object.<string, !WebInspector.Project>} */
570 this._hasResourceContentTrackingExtensions
= false;
573 WebInspector
.Workspace
.Events
= {
574 UISourceCodeAdded
: "UISourceCodeAdded",
575 UISourceCodeRemoved
: "UISourceCodeRemoved",
576 UISourceCodeContentCommitted
: "UISourceCodeContentCommitted",
577 UISourceCodeWorkingCopyChanged
: "UISourceCodeWorkingCopyChanged",
578 ProjectAdded
: "ProjectAdded",
579 ProjectRemoved
: "ProjectRemoved"
582 WebInspector
.Workspace
.prototype = {
584 * @return {!Array.<!WebInspector.UISourceCode>}
586 unsavedSourceCodes: function()
589 * @param {!WebInspector.UISourceCode} sourceCode
592 function filterUnsaved(sourceCode
)
594 return sourceCode
.isDirty();
597 var unsavedSourceCodes
= [];
598 var projects
= this.projectsForType(WebInspector
.projectTypes
.FileSystem
);
599 for (var i
= 0; i
< projects
.length
; ++i
)
600 unsavedSourceCodes
= unsavedSourceCodes
.concat(projects
[i
].uiSourceCodes().filter(filterUnsaved
));
602 return unsavedSourceCodes
;
606 * @param {string} projectId
607 * @param {string} path
608 * @return {?WebInspector.UISourceCode}
610 uiSourceCode: function(projectId
, path
)
612 var project
= this._projects
[projectId
];
613 return project
? project
.uiSourceCode(path
) : null;
617 * @param {string} originURL
618 * @return {?WebInspector.UISourceCode}
620 uiSourceCodeForOriginURL: function(originURL
)
622 var projects
= this.projectsForType(WebInspector
.projectTypes
.Network
);
623 projects
= projects
.concat(this.projectsForType(WebInspector
.projectTypes
.ContentScripts
));
624 for (var i
= 0; i
< projects
.length
; ++i
) {
625 var project
= projects
[i
];
626 var uiSourceCode
= project
.uiSourceCodeForOriginURL(originURL
);
634 * @param {string} originURL
635 * @return {?WebInspector.UISourceCode}
637 filesystemUISourceCode: function(originURL
)
639 var projects
= this.projectsForType(WebInspector
.projectTypes
.FileSystem
);
640 for (var i
= 0; i
< projects
.length
; ++i
) {
641 var project
= projects
[i
];
642 var uiSourceCode
= project
.uiSourceCodeForOriginURL(originURL
);
650 * @param {string} type
651 * @return {!Array.<!WebInspector.UISourceCode>}
653 uiSourceCodesForProjectType: function(type
)
656 for (var projectName
in this._projects
) {
657 var project
= this._projects
[projectName
];
658 if (project
.type() === type
)
659 result
= result
.concat(project
.uiSourceCodes());
665 * @param {string} projectId
666 * @param {!WebInspector.ProjectDelegate} projectDelegate
667 * @return {!WebInspector.Project}
669 addProject: function(projectId
, projectDelegate
)
671 var project
= new WebInspector
.Project(this, projectId
, projectDelegate
);
672 this._projects
[projectId
] = project
;
673 this.dispatchEventToListeners(WebInspector
.Workspace
.Events
.ProjectAdded
, project
);
678 * @param {string} projectId
680 removeProject: function(projectId
)
682 var project
= this._projects
[projectId
];
685 delete this._projects
[projectId
];
690 * @param {string} projectId
691 * @return {!WebInspector.Project}
693 project: function(projectId
)
695 return this._projects
[projectId
];
699 * @return {!Array.<!WebInspector.Project>}
703 return Object
.values(this._projects
);
707 * @param {string} type
708 * @return {!Array.<!WebInspector.Project>}
710 projectsForType: function(type
)
712 function filterByType(project
)
714 return project
.type() === type
;
716 return this.projects().filter(filterByType
);
720 * @return {!Array.<!WebInspector.UISourceCode>}
722 uiSourceCodes: function()
725 for (var projectId
in this._projects
) {
726 var project
= this._projects
[projectId
];
727 result
= result
.concat(project
.uiSourceCodes());
733 * @param {boolean} hasExtensions
735 setHasResourceContentTrackingExtensions: function(hasExtensions
)
737 this._hasResourceContentTrackingExtensions
= hasExtensions
;
743 hasResourceContentTrackingExtensions: function()
745 return this._hasResourceContentTrackingExtensions
;
748 __proto__
: WebInspector
.Object
.prototype
752 * @type {!WebInspector.Workspace}
754 WebInspector
.workspace
;