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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * @extends {WebInspector.VBox}
33 WebInspector
.NavigatorView = function()
35 WebInspector
.VBox
.call(this);
36 this.registerRequiredCSS("sources/navigatorView.css");
38 this.element
.classList
.add("navigator-container");
39 var scriptsOutlineElement
= this.element
.createChild("div", "navigator");
40 this._scriptsTree
= new TreeOutline();
41 this._scriptsTree
.setComparator(WebInspector
.NavigatorView
._treeElementsCompare
);
42 this._scriptsTree
.element
.classList
.add("outline-disclosure");
43 scriptsOutlineElement
.appendChild(this._scriptsTree
.element
);
45 this.setDefaultFocusedElement(this._scriptsTree
.element
);
47 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.NavigatorUISourceCodeTreeNode>} */
48 this._uiSourceCodeNodes
= new Map();
49 /** @type {!Map.<!WebInspector.NavigatorTreeNode, !Map.<string, !WebInspector.NavigatorFolderTreeNode>>} */
50 this._subfolderNodes
= new Map();
52 this._rootNode
= new WebInspector
.NavigatorRootTreeNode(this);
53 this._rootNode
.populate();
55 this.element
.addEventListener("contextmenu", this.handleContextMenu
.bind(this), false);
58 WebInspector
.NavigatorView
.Events
= {
59 ItemSelected
: "ItemSelected",
60 ItemRenamed
: "ItemRenamed",
63 WebInspector
.NavigatorView
.Types
= {
67 UISourceCode
: "UISourceCode",
68 FileSystem
: "FileSystem"
72 * @param {string} type
75 WebInspector
.NavigatorView
.iconClassForType = function(type
)
77 if (type
=== WebInspector
.NavigatorView
.Types
.Domain
)
78 return "navigator-domain-tree-item";
79 if (type
=== WebInspector
.NavigatorView
.Types
.FileSystem
)
80 return "navigator-folder-tree-item";
81 return "navigator-folder-tree-item";
85 * @param {!WebInspector.ContextMenu} contextMenu
87 WebInspector
.NavigatorView
.appendAddFolderItem = function(contextMenu
)
91 WebInspector
.isolatedFileSystemManager
.addFileSystem();
94 var addFolderLabel
= WebInspector
.UIString
.capitalize("Add ^folder to ^workspace");
95 contextMenu
.appendItem(addFolderLabel
, addFolder
);
98 WebInspector
.NavigatorView
.prototype = {
99 setWorkspace: function(workspace
)
101 this._workspace
= workspace
;
102 this._workspace
.addEventListener(WebInspector
.Workspace
.Events
.UISourceCodeAdded
, this._uiSourceCodeAdded
, this);
103 this._workspace
.addEventListener(WebInspector
.Workspace
.Events
.UISourceCodeRemoved
, this._uiSourceCodeRemoved
, this);
104 this._workspace
.addEventListener(WebInspector
.Workspace
.Events
.ProjectRemoved
, this._projectRemoved
.bind(this), this);
112 this._workspace
.uiSourceCodes().forEach(this._addUISourceCode
.bind(this));
116 * @param {!WebInspector.UISourceCode} uiSourceCode
119 accept: function(uiSourceCode
)
121 return !uiSourceCode
.project().isServiceProject();
125 * @param {!WebInspector.UISourceCode} uiSourceCode
127 _addUISourceCode: function(uiSourceCode
)
129 if (!this.accept(uiSourceCode
))
131 var projectNode
= this._projectNode(uiSourceCode
.project());
132 var folderNode
= this._folderNode(projectNode
, uiSourceCode
.parentPath());
133 var uiSourceCodeNode
= new WebInspector
.NavigatorUISourceCodeTreeNode(this, uiSourceCode
);
134 this._uiSourceCodeNodes
.set(uiSourceCode
, uiSourceCodeNode
);
135 folderNode
.appendChild(uiSourceCodeNode
);
139 * @param {!WebInspector.Event} event
141 _uiSourceCodeAdded: function(event
)
143 var uiSourceCode
= /** @type {!WebInspector.UISourceCode} */ (event
.data
);
144 this._addUISourceCode(uiSourceCode
);
148 * @param {!WebInspector.Event} event
150 _uiSourceCodeRemoved: function(event
)
152 var uiSourceCode
= /** @type {!WebInspector.UISourceCode} */ (event
.data
);
153 this._removeUISourceCode(uiSourceCode
);
157 * @param {!WebInspector.Event} event
159 _projectRemoved: function(event
)
161 var project
= /** @type {!WebInspector.Project} */ (event
.data
);
162 project
.removeEventListener(WebInspector
.Project
.Events
.DisplayNameUpdated
, this._updateProjectNodeTitle
, this);
163 var uiSourceCodes
= project
.uiSourceCodes();
164 for (var i
= 0; i
< uiSourceCodes
.length
; ++i
)
165 this._removeUISourceCode(uiSourceCodes
[i
]);
169 * @param {!WebInspector.Project} project
170 * @return {!WebInspector.NavigatorTreeNode}
172 _projectNode: function(project
)
174 if (!project
.displayName())
175 return this._rootNode
;
177 var projectNode
= this._rootNode
.child(project
.id());
179 projectNode
= this._createProjectNode(project
);
180 this._rootNode
.appendChild(projectNode
);
186 * @param {!WebInspector.Project} project
187 * @return {!WebInspector.NavigatorTreeNode}
189 _createProjectNode: function(project
)
191 var type
= project
.type() === WebInspector
.projectTypes
.FileSystem
? WebInspector
.NavigatorView
.Types
.FileSystem
: WebInspector
.NavigatorView
.Types
.Domain
;
192 var projectNode
= new WebInspector
.NavigatorFolderTreeNode(this, project
, project
.id(), type
, "", project
.displayName());
193 project
.addEventListener(WebInspector
.Project
.Events
.DisplayNameUpdated
, this._updateProjectNodeTitle
, this);
198 * @param {!WebInspector.Event} event
200 _updateProjectNodeTitle: function(event
)
202 var project
= /** @type {!WebInspector.Project} */(event
.target
);
203 var projectNode
= this._rootNode
.child(project
.id());
206 projectNode
.treeNode().titleText
= project
.displayName();
210 * @param {!WebInspector.NavigatorTreeNode} projectNode
211 * @param {string} folderPath
212 * @return {!WebInspector.NavigatorTreeNode}
214 _folderNode: function(projectNode
, folderPath
)
219 var subfolderNodes
= this._subfolderNodes
.get(projectNode
);
220 if (!subfolderNodes
) {
221 subfolderNodes
= /** @type {!Map.<string, !WebInspector.NavigatorFolderTreeNode>} */ (new Map());
222 this._subfolderNodes
.set(projectNode
, subfolderNodes
);
225 var folderNode
= subfolderNodes
.get(folderPath
);
229 var parentNode
= projectNode
;
230 var index
= folderPath
.lastIndexOf("/");
232 parentNode
= this._folderNode(projectNode
, folderPath
.substring(0, index
));
234 var name
= folderPath
.substring(index
+ 1);
235 folderNode
= new WebInspector
.NavigatorFolderTreeNode(this, null, name
, WebInspector
.NavigatorView
.Types
.Folder
, folderPath
, name
);
236 subfolderNodes
.set(folderPath
, folderNode
);
237 parentNode
.appendChild(folderNode
);
242 * @param {!WebInspector.UISourceCode} uiSourceCode
243 * @param {boolean=} select
245 revealUISourceCode: function(uiSourceCode
, select
)
247 var node
= this._uiSourceCodeNodes
.get(uiSourceCode
);
250 if (this._scriptsTree
.selectedTreeElement
)
251 this._scriptsTree
.selectedTreeElement
.deselect();
252 this._lastSelectedUISourceCode
= uiSourceCode
;
257 * @param {!WebInspector.UISourceCode} uiSourceCode
258 * @param {boolean} focusSource
260 _sourceSelected: function(uiSourceCode
, focusSource
)
262 this._lastSelectedUISourceCode
= uiSourceCode
;
263 var data
= { uiSourceCode
: uiSourceCode
, focusSource
: focusSource
};
264 this.dispatchEventToListeners(WebInspector
.NavigatorView
.Events
.ItemSelected
, data
);
268 * @param {!WebInspector.UISourceCode} uiSourceCode
270 sourceDeleted: function(uiSourceCode
)
275 * @param {!WebInspector.UISourceCode} uiSourceCode
277 _removeUISourceCode: function(uiSourceCode
)
279 var node
= this._uiSourceCodeNodes
.get(uiSourceCode
);
283 var projectNode
= this._projectNode(uiSourceCode
.project());
284 var subfolderNodes
= this._subfolderNodes
.get(projectNode
);
285 var parentNode
= node
.parent
;
286 this._uiSourceCodeNodes
.remove(uiSourceCode
);
287 parentNode
.removeChild(node
);
291 parentNode
= node
.parent
;
292 if (!parentNode
|| !node
.isEmpty())
295 subfolderNodes
.remove(node
._folderPath
);
296 parentNode
.removeChild(node
);
302 * @param {!WebInspector.UISourceCode} uiSourceCode
304 _updateIcon: function(uiSourceCode
)
306 var node
= this._uiSourceCodeNodes
.get(uiSourceCode
);
312 var nodes
= this._uiSourceCodeNodes
.valuesArray();
313 for (var i
= 0; i
< nodes
.length
; ++i
)
316 this._scriptsTree
.removeChildren();
317 this._uiSourceCodeNodes
.clear();
318 this._subfolderNodes
.clear();
319 this._rootNode
.reset();
323 * @param {!Event} event
325 handleContextMenu: function(event
)
327 var contextMenu
= new WebInspector
.ContextMenu(event
);
328 WebInspector
.NavigatorView
.appendAddFolderItem(contextMenu
);
333 * @param {!WebInspector.Project} project
334 * @param {string} path
336 _handleContextMenuRefresh: function(project
, path
)
338 project
.refresh(path
);
342 * @param {!WebInspector.Project} project
343 * @param {string} path
344 * @param {!WebInspector.UISourceCode=} uiSourceCode
346 _handleContextMenuCreate: function(project
, path
, uiSourceCode
)
348 this.create(project
, path
, uiSourceCode
);
352 * @param {!WebInspector.UISourceCode} uiSourceCode
354 _handleContextMenuRename: function(uiSourceCode
)
356 this.rename(uiSourceCode
, false);
360 * @param {!WebInspector.Project} project
361 * @param {string} path
363 _handleContextMenuExclude: function(project
, path
)
365 var shouldExclude
= window
.confirm(WebInspector
.UIString("Are you sure you want to exclude this folder?"));
367 WebInspector
.startBatchUpdate();
368 project
.excludeFolder(path
);
369 WebInspector
.endBatchUpdate();
374 * @param {!WebInspector.UISourceCode} uiSourceCode
376 _handleContextMenuDelete: function(uiSourceCode
)
378 var shouldDelete
= window
.confirm(WebInspector
.UIString("Are you sure you want to delete this file?"));
380 uiSourceCode
.project().deleteFile(uiSourceCode
.path());
384 * @param {!Event} event
385 * @param {!WebInspector.UISourceCode} uiSourceCode
387 handleFileContextMenu: function(event
, uiSourceCode
)
389 var contextMenu
= new WebInspector
.ContextMenu(event
);
390 contextMenu
.appendApplicableItems(uiSourceCode
);
391 contextMenu
.appendSeparator();
393 var project
= uiSourceCode
.project();
394 if (project
.type() === WebInspector
.projectTypes
.FileSystem
) {
395 var path
= uiSourceCode
.parentPath();
396 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("Rename\u2026"), this._handleContextMenuRename
.bind(this, uiSourceCode
));
397 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("Make a ^copy\u2026"), this._handleContextMenuCreate
.bind(this, project
, path
, uiSourceCode
));
398 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("Delete"), this._handleContextMenuDelete
.bind(this, uiSourceCode
));
399 contextMenu
.appendSeparator();
406 * @param {!Event} event
407 * @param {!WebInspector.NavigatorFolderTreeNode} node
409 handleFolderContextMenu: function(event
, node
)
411 var contextMenu
= new WebInspector
.ContextMenu(event
);
413 var projectNode
= node
;
414 while (projectNode
.parent
!== this._rootNode
) {
415 path
= "/" + projectNode
.id
+ path
;
416 projectNode
= projectNode
.parent
;
419 var project
= projectNode
._project
;
421 if (project
.type() === WebInspector
.projectTypes
.FileSystem
) {
422 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("Refresh"), this._handleContextMenuRefresh
.bind(this, project
, path
));
423 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("New ^file"), this._handleContextMenuCreate
.bind(this, project
, path
));
424 contextMenu
.appendItem(WebInspector
.UIString
.capitalize("Exclude ^folder"), this._handleContextMenuExclude
.bind(this, project
, path
));
426 contextMenu
.appendSeparator();
427 WebInspector
.NavigatorView
.appendAddFolderItem(contextMenu
);
429 function removeFolder()
431 var shouldRemove
= window
.confirm(WebInspector
.UIString("Are you sure you want to remove this folder?"));
436 if (project
.type() === WebInspector
.projectTypes
.FileSystem
&& node
=== projectNode
) {
437 var removeFolderLabel
= WebInspector
.UIString
.capitalize("Remove ^folder from ^workspace");
438 contextMenu
.appendItem(removeFolderLabel
, removeFolder
);
445 * @param {!WebInspector.UISourceCode} uiSourceCode
446 * @param {boolean} deleteIfCanceled
448 rename: function(uiSourceCode
, deleteIfCanceled
)
450 var node
= this._uiSourceCodeNodes
.get(uiSourceCode
);
451 console
.assert(node
);
452 node
.rename(callback
.bind(this));
455 * @this {WebInspector.NavigatorView}
456 * @param {boolean} committed
458 function callback(committed
)
461 if (deleteIfCanceled
)
462 uiSourceCode
.remove();
466 this.dispatchEventToListeners(WebInspector
.NavigatorView
.Events
.ItemRenamed
, uiSourceCode
);
467 this._updateIcon(uiSourceCode
);
468 this._sourceSelected(uiSourceCode
, true);
473 * @param {!WebInspector.Project} project
474 * @param {string} path
475 * @param {!WebInspector.UISourceCode=} uiSourceCodeToCopy
477 create: function(project
, path
, uiSourceCodeToCopy
)
483 * @this {WebInspector.NavigatorView}
484 * @param {?string} content
486 function contentLoaded(content
)
488 createFile
.call(this, content
|| "");
491 if (uiSourceCodeToCopy
)
492 uiSourceCodeToCopy
.requestContent(contentLoaded
.bind(this));
494 createFile
.call(this);
497 * @this {WebInspector.NavigatorView}
498 * @param {string=} content
500 function createFile(content
)
502 project
.createFile(path
, null, content
|| "", fileCreated
.bind(this));
506 * @this {WebInspector.NavigatorView}
507 * @param {?string} path
509 function fileCreated(path
)
514 uiSourceCode
= project
.uiSourceCode(filePath
);
516 console
.assert(uiSourceCode
);
519 this._sourceSelected(uiSourceCode
, false);
520 this.revealUISourceCode(uiSourceCode
, true);
521 this.rename(uiSourceCode
, true);
525 __proto__
: WebInspector
.VBox
.prototype
530 * @extends {WebInspector.NavigatorView}
532 WebInspector
.SourcesNavigatorView = function()
534 WebInspector
.NavigatorView
.call(this);
535 WebInspector
.targetManager
.addEventListener(WebInspector
.TargetManager
.Events
.InspectedURLChanged
, this._inspectedURLChanged
, this);
538 WebInspector
.SourcesNavigatorView
.prototype = {
541 * @param {!WebInspector.UISourceCode} uiSourceCode
544 accept: function(uiSourceCode
)
546 if (!WebInspector
.NavigatorView
.prototype.accept(uiSourceCode
))
548 return uiSourceCode
.project().type() !== WebInspector
.projectTypes
.ContentScripts
&& uiSourceCode
.project().type() !== WebInspector
.projectTypes
.Snippets
;
553 * @param {!WebInspector.Event} event
555 _inspectedURLChanged: function(event
)
557 var nodes
= this._uiSourceCodeNodes
.valuesArray();
558 for (var i
= 0; i
< nodes
.length
; ++i
) {
559 var uiSourceCode
= nodes
[i
].uiSourceCode();
560 var inspectedPageURL
= WebInspector
.targetManager
.inspectedPageURL();
561 if (inspectedPageURL
&& WebInspector
.networkMapping
.networkURL(uiSourceCode
) === inspectedPageURL
)
562 this.revealUISourceCode(uiSourceCode
, true);
568 * @param {!WebInspector.UISourceCode} uiSourceCode
570 _addUISourceCode: function(uiSourceCode
)
572 WebInspector
.NavigatorView
.prototype._addUISourceCode
.call(this, uiSourceCode
);
573 var inspectedPageURL
= WebInspector
.targetManager
.inspectedPageURL();
574 if (inspectedPageURL
&& WebInspector
.networkMapping
.networkURL(uiSourceCode
) === inspectedPageURL
)
575 this.revealUISourceCode(uiSourceCode
, true);
578 __proto__
: WebInspector
.NavigatorView
.prototype
583 * @extends {WebInspector.NavigatorView}
585 WebInspector
.ContentScriptsNavigatorView = function()
587 WebInspector
.NavigatorView
.call(this);
590 WebInspector
.ContentScriptsNavigatorView
.prototype = {
593 * @param {!WebInspector.UISourceCode} uiSourceCode
596 accept: function(uiSourceCode
)
598 if (!WebInspector
.NavigatorView
.prototype.accept(uiSourceCode
))
600 return uiSourceCode
.project().type() === WebInspector
.projectTypes
.ContentScripts
;
603 __proto__
: WebInspector
.NavigatorView
.prototype
607 * @param {!TreeElement} treeElement1
608 * @param {!TreeElement} treeElement2
611 WebInspector
.NavigatorView
._treeElementsCompare
= function compare(treeElement1
, treeElement2
)
613 // Insert in the alphabetical order, first domains, then folders, then scripts.
614 function typeWeight(treeElement
)
616 var type
= treeElement
.type();
617 if (type
=== WebInspector
.NavigatorView
.Types
.Domain
) {
618 if (treeElement
.titleText
=== WebInspector
.targetManager
.inspectedPageDomain())
622 if (type
=== WebInspector
.NavigatorView
.Types
.FileSystem
)
624 if (type
=== WebInspector
.NavigatorView
.Types
.Folder
)
629 var typeWeight1
= typeWeight(treeElement1
);
630 var typeWeight2
= typeWeight(treeElement2
);
633 if (typeWeight1
> typeWeight2
)
635 else if (typeWeight1
< typeWeight2
)
638 var title1
= treeElement1
.titleText
;
639 var title2
= treeElement2
.titleText
;
640 result
= title1
.compareTo(title2
);
647 * @extends {TreeElement}
648 * @param {string} type
649 * @param {string} title
650 * @param {!Array.<string>} iconClasses
651 * @param {boolean} expandable
652 * @param {boolean=} noIcon
654 WebInspector
.BaseNavigatorTreeElement = function(type
, title
, iconClasses
, expandable
, noIcon
)
657 TreeElement
.call(this, "", expandable
);
658 this._titleText
= title
;
659 this._iconClasses
= iconClasses
;
660 this._noIcon
= noIcon
;
663 WebInspector
.BaseNavigatorTreeElement
.prototype = {
666 this.listItemElement
.removeChildren();
667 if (this._iconClasses
) {
668 for (var i
= 0; i
< this._iconClasses
.length
; ++i
)
669 this.listItemElement
.classList
.add(this._iconClasses
[i
]);
672 this.listItemElement
.createChild("div", "selection");
675 this.imageElement
= this.listItemElement
.createChild("img", "icon");
677 this.titleElement
= this.listItemElement
.createChild("div", "base-navigator-tree-element-title");
678 this.titleElement
.textContent
= this._titleText
;
682 * @param {!Array.<string>} iconClasses
684 updateIconClasses: function(iconClasses
)
686 for (var i
= 0; i
< this._iconClasses
.length
; ++i
)
687 this.listItemElement
.classList
.remove(this._iconClasses
[i
]);
688 this._iconClasses
= iconClasses
;
689 for (var i
= 0; i
< this._iconClasses
.length
; ++i
)
690 this.listItemElement
.classList
.add(this._iconClasses
[i
]);
695 if (this.listItemElement
)
696 this.listItemElement
.scrollIntoViewIfNeeded(true);
704 return this._titleText
;
707 set titleText(titleText
)
709 if (this._titleText
=== titleText
)
711 this._titleText
= titleText
|| "";
712 if (this.titleElement
) {
713 this.titleElement
.textContent
= this._titleText
;
714 this.titleElement
.title
= this._titleText
;
726 __proto__
: TreeElement
.prototype
731 * @extends {WebInspector.BaseNavigatorTreeElement}
732 * @param {!WebInspector.NavigatorView} navigatorView
733 * @param {string} type
734 * @param {string} title
736 WebInspector
.NavigatorFolderTreeElement = function(navigatorView
, type
, title
)
738 var iconClass
= WebInspector
.NavigatorView
.iconClassForType(type
);
739 WebInspector
.BaseNavigatorTreeElement
.call(this, type
, title
, [iconClass
], true);
740 this._navigatorView
= navigatorView
;
743 WebInspector
.NavigatorFolderTreeElement
.prototype = {
744 onpopulate: function()
746 this._node
.populate();
751 WebInspector
.BaseNavigatorTreeElement
.prototype.onattach
.call(this);
753 this.listItemElement
.addEventListener("contextmenu", this._handleContextMenuEvent
.bind(this), false);
757 * @param {!WebInspector.NavigatorFolderTreeNode} node
759 setNode: function(node
)
763 while (node
&& !node
.isRoot()) {
764 paths
.push(node
._title
);
768 this.tooltip
= paths
.join("/");
772 * @param {!Event} event
774 _handleContextMenuEvent: function(event
)
779 this._navigatorView
.handleFolderContextMenu(event
, this._node
);
782 __proto__
: WebInspector
.BaseNavigatorTreeElement
.prototype
787 * @extends {WebInspector.BaseNavigatorTreeElement}
788 * @param {!WebInspector.NavigatorView} navigatorView
789 * @param {!WebInspector.UISourceCode} uiSourceCode
790 * @param {string} title
792 WebInspector
.NavigatorSourceTreeElement = function(navigatorView
, uiSourceCode
, title
)
794 this._navigatorView
= navigatorView
;
795 this._uiSourceCode
= uiSourceCode
;
796 WebInspector
.BaseNavigatorTreeElement
.call(this, WebInspector
.NavigatorView
.Types
.UISourceCode
, title
, this._calculateIconClasses(), false);
797 this.tooltip
= uiSourceCode
.originURL();
800 WebInspector
.NavigatorSourceTreeElement
.prototype = {
802 * @return {!WebInspector.UISourceCode}
806 return this._uiSourceCode
;
810 * @return {!Array.<string>}
812 _calculateIconClasses: function()
814 return ["navigator-" + this._uiSourceCode
.contentType().name() + "-tree-item"];
817 updateIcon: function()
819 this.updateIconClasses(this._calculateIconClasses());
824 WebInspector
.BaseNavigatorTreeElement
.prototype.onattach
.call(this);
825 this.listItemElement
.draggable
= true;
826 this.listItemElement
.addEventListener("click", this._onclick
.bind(this), false);
827 this.listItemElement
.addEventListener("contextmenu", this._handleContextMenuEvent
.bind(this), false);
828 this.listItemElement
.addEventListener("mousedown", this._onmousedown
.bind(this), false);
829 this.listItemElement
.addEventListener("dragstart", this._ondragstart
.bind(this), false);
832 _onmousedown: function(event
)
834 if (event
.which
=== 1) // Warm-up data for drag'n'drop
835 this._uiSourceCode
.requestContent(callback
.bind(this));
837 * @param {?string} content
838 * @this {WebInspector.NavigatorSourceTreeElement}
840 function callback(content
)
842 this._warmedUpContent
= content
;
846 _shouldRenameOnMouseDown: function()
848 if (!this._uiSourceCode
.canRename())
850 var isSelected
= this === this.treeOutline
.selectedTreeElement
;
851 var document
= this.treeOutline
.element
.ownerDocument
;
852 var isFocused
= this.treeOutline
.element
.isSelfOrAncestor(document
.activeElement
);
853 return isSelected
&& isFocused
&& !WebInspector
.isBeingEdited(this.treeOutline
.element
);
856 selectOnMouseDown: function(event
)
858 if (event
.which
!== 1 || !this._shouldRenameOnMouseDown()) {
859 TreeElement
.prototype.selectOnMouseDown
.call(this, event
);
862 setTimeout(rename
.bind(this), 300);
865 * @this {WebInspector.NavigatorSourceTreeElement}
869 if (this._shouldRenameOnMouseDown())
870 this._navigatorView
.rename(this.uiSourceCode
, false);
874 _ondragstart: function(event
)
876 event
.dataTransfer
.setData("text/plain", this._warmedUpContent
);
877 event
.dataTransfer
.effectAllowed
= "copy";
887 this._navigatorView
._sourceSelected(this.uiSourceCode
, true);
892 * @param {!Event} event
894 _onclick: function(event
)
896 this._navigatorView
._sourceSelected(this.uiSourceCode
, false);
903 ondblclick: function(event
)
905 var middleClick
= event
.button
=== 1;
906 this._navigatorView
._sourceSelected(this.uiSourceCode
, !middleClick
);
916 this._navigatorView
._sourceSelected(this.uiSourceCode
, true);
926 this._navigatorView
.sourceDeleted(this.uiSourceCode
);
931 * @param {!Event} event
933 _handleContextMenuEvent: function(event
)
936 this._navigatorView
.handleFileContextMenu(event
, this._uiSourceCode
);
939 __proto__
: WebInspector
.BaseNavigatorTreeElement
.prototype
946 WebInspector
.NavigatorTreeNode = function(id
)
949 /** @type {!Map.<string, !WebInspector.NavigatorTreeNode>} */
950 this._children
= new Map();
953 WebInspector
.NavigatorTreeNode
.prototype = {
955 * @return {!TreeElement}
957 treeNode: function() { throw "Not implemented"; },
959 dispose: function() { },
972 hasChildren: function()
979 if (this.isPopulated())
982 this.parent
.populate();
983 this._populated
= true;
987 wasPopulated: function()
989 var children
= this.children();
990 for (var i
= 0; i
< children
.length
; ++i
)
991 this.treeNode().appendChild(/** @type {!TreeElement} */ (children
[i
].treeNode()));
995 * @param {!WebInspector.NavigatorTreeNode} node
997 didAddChild: function(node
)
999 if (this.isPopulated())
1000 this.treeNode().appendChild(/** @type {!TreeElement} */ (node
.treeNode()));
1004 * @param {!WebInspector.NavigatorTreeNode} node
1006 willRemoveChild: function(node
)
1008 if (this.isPopulated())
1009 this.treeNode().removeChild(/** @type {!TreeElement} */ (node
.treeNode()));
1015 isPopulated: function()
1017 return this._populated
;
1025 return !this._children
.size
;
1029 * @param {string} id
1030 * @return {?WebInspector.NavigatorTreeNode}
1034 return this._children
.get(id
) || null;
1038 * @return {!Array.<!WebInspector.NavigatorTreeNode>}
1040 children: function()
1042 return this._children
.valuesArray();
1046 * @param {!WebInspector.NavigatorTreeNode} node
1048 appendChild: function(node
)
1050 this._children
.set(node
.id
, node
);
1052 this.didAddChild(node
);
1056 * @param {!WebInspector.NavigatorTreeNode} node
1058 removeChild: function(node
)
1060 this.willRemoveChild(node
);
1061 this._children
.remove(node
.id
);
1068 this._children
.clear();
1074 * @extends {WebInspector.NavigatorTreeNode}
1075 * @param {!WebInspector.NavigatorView} navigatorView
1077 WebInspector
.NavigatorRootTreeNode = function(navigatorView
)
1079 WebInspector
.NavigatorTreeNode
.call(this, "");
1080 this._navigatorView
= navigatorView
;
1083 WebInspector
.NavigatorRootTreeNode
.prototype = {
1095 * @return {!TreeElement}
1097 treeNode: function()
1099 return this._navigatorView
._scriptsTree
.rootElement();
1102 __proto__
: WebInspector
.NavigatorTreeNode
.prototype
1107 * @extends {WebInspector.NavigatorTreeNode}
1108 * @param {!WebInspector.NavigatorView} navigatorView
1109 * @param {!WebInspector.UISourceCode} uiSourceCode
1111 WebInspector
.NavigatorUISourceCodeTreeNode = function(navigatorView
, uiSourceCode
)
1113 WebInspector
.NavigatorTreeNode
.call(this, uiSourceCode
.name());
1114 this._navigatorView
= navigatorView
;
1115 this._uiSourceCode
= uiSourceCode
;
1116 this._treeElement
= null;
1119 WebInspector
.NavigatorUISourceCodeTreeNode
.prototype = {
1121 * @return {!WebInspector.UISourceCode}
1123 uiSourceCode: function()
1125 return this._uiSourceCode
;
1128 updateIcon: function()
1130 if (this._treeElement
)
1131 this._treeElement
.updateIcon();
1136 * @return {!TreeElement}
1138 treeNode: function()
1140 if (this._treeElement
)
1141 return this._treeElement
;
1143 this._treeElement
= new WebInspector
.NavigatorSourceTreeElement(this._navigatorView
, this._uiSourceCode
, "");
1146 this._uiSourceCode
.addEventListener(WebInspector
.UISourceCode
.Events
.TitleChanged
, this._titleChanged
, this);
1147 this._uiSourceCode
.addEventListener(WebInspector
.UISourceCode
.Events
.WorkingCopyChanged
, this._workingCopyChanged
, this);
1148 this._uiSourceCode
.addEventListener(WebInspector
.UISourceCode
.Events
.WorkingCopyCommitted
, this._workingCopyCommitted
, this);
1150 return this._treeElement
;
1154 * @param {boolean=} ignoreIsDirty
1156 updateTitle: function(ignoreIsDirty
)
1158 if (!this._treeElement
)
1161 var titleText
= this._uiSourceCode
.displayName();
1162 if (!ignoreIsDirty
&& (this._uiSourceCode
.isDirty() || this._uiSourceCode
.hasUnsavedCommittedChanges()))
1163 titleText
= "*" + titleText
;
1164 this._treeElement
.titleText
= titleText
;
1171 hasChildren: function()
1178 if (!this._treeElement
)
1180 this._uiSourceCode
.removeEventListener(WebInspector
.UISourceCode
.Events
.TitleChanged
, this._titleChanged
, this);
1181 this._uiSourceCode
.removeEventListener(WebInspector
.UISourceCode
.Events
.WorkingCopyChanged
, this._workingCopyChanged
, this);
1182 this._uiSourceCode
.removeEventListener(WebInspector
.UISourceCode
.Events
.WorkingCopyCommitted
, this._workingCopyCommitted
, this);
1185 _titleChanged: function(event
)
1190 _workingCopyChanged: function(event
)
1195 _workingCopyCommitted: function(event
)
1201 * @param {boolean=} select
1203 reveal: function(select
)
1205 this.parent
.populate();
1206 this.parent
.treeNode().expand();
1207 this._treeElement
.reveal();
1209 this._treeElement
.select(true);
1213 * @param {function(boolean)=} callback
1215 rename: function(callback
)
1217 if (!this._treeElement
)
1220 // Tree outline should be marked as edited as well as the tree element to prevent search from starting.
1221 var treeOutlineElement
= this._treeElement
.treeOutline
.element
;
1222 WebInspector
.markBeingEdited(treeOutlineElement
, true);
1225 * @param {!Element} element
1226 * @param {string} newTitle
1227 * @param {string} oldTitle
1228 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1230 function commitHandler(element
, newTitle
, oldTitle
)
1232 if (newTitle
!== oldTitle
) {
1233 this._treeElement
.titleText
= newTitle
;
1234 this._uiSourceCode
.rename(newTitle
, renameCallback
.bind(this));
1237 afterEditing
.call(this, true);
1241 * @param {boolean} success
1242 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1244 function renameCallback(success
)
1247 WebInspector
.markBeingEdited(treeOutlineElement
, false);
1249 this.rename(callback
);
1252 afterEditing
.call(this, true);
1256 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1258 function cancelHandler()
1260 afterEditing
.call(this, false);
1264 * @param {boolean} committed
1265 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1267 function afterEditing(committed
)
1269 WebInspector
.markBeingEdited(treeOutlineElement
, false);
1271 this._treeElement
.treeOutline
.focus();
1273 callback(committed
);
1276 var editingConfig
= new WebInspector
.InplaceEditor
.Config(commitHandler
.bind(this), cancelHandler
.bind(this));
1277 this.updateTitle(true);
1278 WebInspector
.InplaceEditor
.startEditing(this._treeElement
.titleElement
, editingConfig
);
1279 treeOutlineElement
.getComponentSelection().setBaseAndExtent(this._treeElement
.titleElement
, 0, this._treeElement
.titleElement
, 1);
1282 __proto__
: WebInspector
.NavigatorTreeNode
.prototype
1287 * @extends {WebInspector.NavigatorTreeNode}
1288 * @param {!WebInspector.NavigatorView} navigatorView
1289 * @param {?WebInspector.Project} project
1290 * @param {string} id
1291 * @param {string} type
1292 * @param {string} folderPath
1293 * @param {string} title
1295 WebInspector
.NavigatorFolderTreeNode = function(navigatorView
, project
, id
, type
, folderPath
, title
)
1297 WebInspector
.NavigatorTreeNode
.call(this, id
);
1298 this._navigatorView
= navigatorView
;
1299 this._project
= project
;
1301 this._folderPath
= folderPath
;
1302 this._title
= title
;
1305 WebInspector
.NavigatorFolderTreeNode
.prototype = {
1308 * @return {!TreeElement}
1310 treeNode: function()
1312 if (this._treeElement
)
1313 return this._treeElement
;
1314 this._treeElement
= this._createTreeElement(this._title
, this);
1315 return this._treeElement
;
1319 * @return {!TreeElement}
1321 _createTreeElement: function(title
, node
)
1323 var treeElement
= new WebInspector
.NavigatorFolderTreeElement(this._navigatorView
, this._type
, title
);
1324 treeElement
.setNode(node
);
1328 wasPopulated: function()
1330 if (!this._treeElement
|| this._treeElement
._node
!== this)
1332 this._addChildrenRecursive();
1335 _addChildrenRecursive: function()
1337 var children
= this.children();
1338 for (var i
= 0; i
< children
.length
; ++i
) {
1339 var child
= children
[i
];
1340 this.didAddChild(child
);
1341 if (child
instanceof WebInspector
.NavigatorFolderTreeNode
)
1342 child
._addChildrenRecursive();
1346 _shouldMerge: function(node
)
1348 return this._type
!== WebInspector
.NavigatorView
.Types
.Domain
&& node
instanceof WebInspector
.NavigatorFolderTreeNode
;
1351 didAddChild: function(node
)
1353 function titleForNode(node
)
1358 if (!this._treeElement
)
1361 var children
= this.children();
1363 if (children
.length
=== 1 && this._shouldMerge(node
)) {
1364 node
._isMerged
= true;
1365 this._treeElement
.titleText
= this._treeElement
.titleText
+ "/" + node
._title
;
1366 node
._treeElement
= this._treeElement
;
1367 this._treeElement
.setNode(node
);
1372 if (children
.length
=== 2)
1373 oldNode
= children
[0] !== node
? children
[0] : children
[1];
1374 if (oldNode
&& oldNode
._isMerged
) {
1375 delete oldNode
._isMerged
;
1376 var mergedToNodes
= [];
1377 mergedToNodes
.push(this);
1378 var treeNode
= this;
1379 while (treeNode
._isMerged
) {
1380 treeNode
= treeNode
.parent
;
1381 mergedToNodes
.push(treeNode
);
1383 mergedToNodes
.reverse();
1384 var titleText
= mergedToNodes
.map(titleForNode
).join("/");
1389 nodes
.push(treeNode
);
1390 children
= treeNode
.children();
1391 treeNode
= children
.length
=== 1 ? children
[0] : null;
1392 } while (treeNode
&& treeNode
._isMerged
);
1394 if (!this.isPopulated()) {
1395 this._treeElement
.titleText
= titleText
;
1396 this._treeElement
.setNode(this);
1397 for (var i
= 0; i
< nodes
.length
; ++i
) {
1398 delete nodes
[i
]._treeElement
;
1399 delete nodes
[i
]._isMerged
;
1403 var oldTreeElement
= this._treeElement
;
1404 var treeElement
= this._createTreeElement(titleText
, this);
1405 for (var i
= 0; i
< mergedToNodes
.length
; ++i
)
1406 mergedToNodes
[i
]._treeElement
= treeElement
;
1407 oldTreeElement
.parent
.appendChild(treeElement
);
1409 oldTreeElement
.setNode(nodes
[nodes
.length
- 1]);
1410 oldTreeElement
.titleText
= nodes
.map(titleForNode
).join("/");
1411 oldTreeElement
.parent
.removeChild(oldTreeElement
);
1412 this._treeElement
.appendChild(oldTreeElement
);
1413 if (oldTreeElement
.expanded
)
1414 treeElement
.expand();
1416 if (this.isPopulated())
1417 this._treeElement
.appendChild(node
.treeNode());
1420 willRemoveChild: function(node
)
1422 if (node
._isMerged
|| !this.isPopulated())
1424 this._treeElement
.removeChild(node
._treeElement
);
1427 __proto__
: WebInspector
.NavigatorTreeNode
.prototype