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.
30 * @extends {WebInspector.View}
33 WebInspector.NavigatorView = function()
35 WebInspector.View.call(this);
36 this.registerRequiredCSS("navigatorView.css");
38 var scriptsTreeElement = document.createElement("ol");
39 this._scriptsTree = new WebInspector.NavigatorTreeOutline(scriptsTreeElement);
40 this._scriptsTree.childrenListElement.addEventListener("keypress", this._treeKeyPress.bind(this), true);
42 var scriptsOutlineElement = document.createElement("div");
43 scriptsOutlineElement.classList.add("outline-disclosure");
44 scriptsOutlineElement.classList.add("navigator");
45 scriptsOutlineElement.appendChild(scriptsTreeElement);
47 this.element.classList.add("navigator-container");
48 this.element.appendChild(scriptsOutlineElement);
49 this.setDefaultFocusedElement(this._scriptsTree.element);
51 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.NavigatorUISourceCodeTreeNode>} */
52 this._uiSourceCodeNodes = new Map();
53 /** @type {!Map.<!WebInspector.NavigatorTreeNode, !StringMap.<!WebInspector.NavigatorFolderTreeNode>>} */
54 this._subfolderNodes = new Map();
56 this._rootNode = new WebInspector.NavigatorRootTreeNode(this);
57 this._rootNode.populate();
59 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this);
60 this.element.addEventListener("contextmenu", this.handleContextMenu.bind(this), false);
63 WebInspector.NavigatorView.Events = {
64 ItemSelected: "ItemSelected",
65 ItemSearchStarted: "ItemSearchStarted",
66 ItemRenamingRequested: "ItemRenamingRequested",
67 ItemCreationRequested: "ItemCreationRequested"
70 WebInspector.NavigatorView.iconClassForType = function(type)
72 if (type === WebInspector.NavigatorTreeOutline.Types.Domain)
73 return "navigator-domain-tree-item";
74 if (type === WebInspector.NavigatorTreeOutline.Types.FileSystem)
75 return "navigator-folder-tree-item";
76 return "navigator-folder-tree-item";
79 WebInspector.NavigatorView.prototype = {
81 * @param {!WebInspector.UISourceCode} uiSourceCode
83 addUISourceCode: function(uiSourceCode)
85 var projectNode = this._projectNode(uiSourceCode.project());
86 var folderNode = this._folderNode(projectNode, uiSourceCode.parentPath());
87 var uiSourceCodeNode = new WebInspector.NavigatorUISourceCodeTreeNode(this, uiSourceCode);
88 this._uiSourceCodeNodes.put(uiSourceCode, uiSourceCodeNode);
89 folderNode.appendChild(uiSourceCodeNode);
90 if (uiSourceCode.url === WebInspector.inspectedPageURL)
91 this.revealUISourceCode(uiSourceCode);
95 * @param {!WebInspector.Event} event
97 _inspectedURLChanged: function(event)
99 var nodes = this._uiSourceCodeNodes.values();
100 for (var i = 0; i < nodes.length; ++i) {
101 var uiSourceCode = nodes[i].uiSourceCode();
102 if (uiSourceCode.url === WebInspector.inspectedPageURL)
103 this.revealUISourceCode(uiSourceCode);
108 * @param {!WebInspector.Project} project
109 * @return {!WebInspector.NavigatorTreeNode}
111 _projectNode: function(project)
113 if (!project.displayName())
114 return this._rootNode;
116 var projectNode = this._rootNode.child(project.id());
118 var type = project.type() === WebInspector.projectTypes.FileSystem ? WebInspector.NavigatorTreeOutline.Types.FileSystem : WebInspector.NavigatorTreeOutline.Types.Domain;
119 projectNode = new WebInspector.NavigatorFolderTreeNode(this, project, project.id(), type, "", project.displayName());
120 this._rootNode.appendChild(projectNode);
126 * @param {!WebInspector.NavigatorTreeNode} projectNode
127 * @param {string} folderPath
128 * @return {!WebInspector.NavigatorTreeNode}
130 _folderNode: function(projectNode, folderPath)
135 var subfolderNodes = this._subfolderNodes.get(projectNode);
136 if (!subfolderNodes) {
137 subfolderNodes = /** @type {!StringMap.<!WebInspector.NavigatorFolderTreeNode>} */ (new StringMap());
138 this._subfolderNodes.put(projectNode, subfolderNodes);
141 var folderNode = subfolderNodes.get(folderPath);
145 var parentNode = projectNode;
146 var index = folderPath.lastIndexOf("/");
148 parentNode = this._folderNode(projectNode, folderPath.substring(0, index));
150 var name = folderPath.substring(index + 1);
151 folderNode = new WebInspector.NavigatorFolderTreeNode(this, null, name, WebInspector.NavigatorTreeOutline.Types.Folder, folderPath, name);
152 subfolderNodes.put(folderPath, folderNode);
153 parentNode.appendChild(folderNode);
158 * @param {!WebInspector.UISourceCode} uiSourceCode
159 * @param {boolean=} select
161 revealUISourceCode: function(uiSourceCode, select)
163 var node = this._uiSourceCodeNodes.get(uiSourceCode);
166 if (this._scriptsTree.selectedTreeElement)
167 this._scriptsTree.selectedTreeElement.deselect();
168 this._lastSelectedUISourceCode = uiSourceCode;
173 * @param {!WebInspector.UISourceCode} uiSourceCode
174 * @param {boolean} focusSource
176 _sourceSelected: function(uiSourceCode, focusSource)
178 this._lastSelectedUISourceCode = uiSourceCode;
179 var data = { uiSourceCode: uiSourceCode, focusSource: focusSource};
180 this.dispatchEventToListeners(WebInspector.NavigatorView.Events.ItemSelected, data);
184 * @param {!WebInspector.UISourceCode} uiSourceCode
186 sourceDeleted: function(uiSourceCode)
191 * @param {!WebInspector.UISourceCode} uiSourceCode
193 removeUISourceCode: function(uiSourceCode)
195 var node = this._uiSourceCodeNodes.get(uiSourceCode);
199 var projectNode = this._projectNode(uiSourceCode.project());
200 var subfolderNodes = this._subfolderNodes.get(projectNode);
201 var parentNode = node.parent;
202 this._uiSourceCodeNodes.remove(uiSourceCode);
203 parentNode.removeChild(node);
207 parentNode = node.parent;
208 if (!parentNode || !node.isEmpty())
211 subfolderNodes.remove(node._folderPath);
212 parentNode.removeChild(node);
218 * @param {!WebInspector.UISourceCode} uiSourceCode
220 updateIcon: function(uiSourceCode)
222 var node = this._uiSourceCodeNodes.get(uiSourceCode);
227 * @param {!WebInspector.UISourceCode} uiSourceCode
229 requestRename: function(uiSourceCode)
231 this.dispatchEventToListeners(WebInspector.SourcesNavigator.Events.ItemRenamingRequested, uiSourceCode);
235 * @param {!WebInspector.UISourceCode} uiSourceCode
236 * @param {function(boolean)=} callback
238 rename: function(uiSourceCode, callback)
240 var node = this._uiSourceCodeNodes.get(uiSourceCode);
243 node.rename(callback);
248 var nodes = this._uiSourceCodeNodes.values();
249 for (var i = 0; i < nodes.length; ++i)
252 this._scriptsTree.removeChildren();
253 this._uiSourceCodeNodes.clear();
254 this._subfolderNodes.clear();
255 this._rootNode.reset();
259 * @param {?Event} event
261 handleContextMenu: function(event)
263 var contextMenu = new WebInspector.ContextMenu(event);
264 this._appendAddFolderItem(contextMenu);
269 * @param {!WebInspector.ContextMenu} contextMenu
271 _appendAddFolderItem: function(contextMenu)
275 WebInspector.isolatedFileSystemManager.addFileSystem();
278 var addFolderLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add folder to workspace" : "Add Folder to Workspace");
279 contextMenu.appendItem(addFolderLabel, addFolder);
283 * @param {!WebInspector.Project} project
284 * @param {string} path
286 _handleContextMenuRefresh: function(project, path)
288 project.refresh(path);
292 * @param {!WebInspector.Project} project
293 * @param {string} path
294 * @param {!WebInspector.UISourceCode=} uiSourceCode
296 _handleContextMenuCreate: function(project, path, uiSourceCode)
299 data.project = project;
301 data.uiSourceCode = uiSourceCode;
302 this.dispatchEventToListeners(WebInspector.NavigatorView.Events.ItemCreationRequested, data);
306 * @param {!WebInspector.Project} project
307 * @param {string} path
309 _handleContextMenuExclude: function(project, path)
311 var shouldExclude = window.confirm(WebInspector.UIString("Are you sure you want to exclude this folder?"));
313 WebInspector.startBatchUpdate();
314 project.excludeFolder(path);
315 WebInspector.endBatchUpdate();
320 * @param {!WebInspector.UISourceCode} uiSourceCode
322 _handleContextMenuDelete: function(uiSourceCode)
324 var shouldDelete = window.confirm(WebInspector.UIString("Are you sure you want to delete this file?"));
326 uiSourceCode.project().deleteFile(uiSourceCode.path());
330 * @param {!Event} event
331 * @param {!WebInspector.UISourceCode} uiSourceCode
333 handleFileContextMenu: function(event, uiSourceCode)
335 var contextMenu = new WebInspector.ContextMenu(event);
336 contextMenu.appendApplicableItems(uiSourceCode);
337 contextMenu.appendSeparator();
339 var project = uiSourceCode.project();
340 var path = uiSourceCode.parentPath();
341 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Refresh parent" : "Refresh Parent"), this._handleContextMenuRefresh.bind(this, project, path));
342 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Duplicate file" : "Duplicate File"), this._handleContextMenuCreate.bind(this, project, path, uiSourceCode));
343 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Exclude parent folder" : "Exclude Parent Folder"), this._handleContextMenuExclude.bind(this, project, path));
344 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete file" : "Delete File"), this._handleContextMenuDelete.bind(this, uiSourceCode));
345 contextMenu.appendSeparator();
346 this._appendAddFolderItem(contextMenu);
351 * @param {!Event} event
352 * @param {!WebInspector.NavigatorFolderTreeNode} node
354 handleFolderContextMenu: function(event, node)
356 var contextMenu = new WebInspector.ContextMenu(event);
358 var projectNode = node;
359 while (projectNode.parent !== this._rootNode) {
360 path = "/" + projectNode.id + path;
361 projectNode = projectNode.parent;
364 var project = projectNode._project;
366 if (project.type() === WebInspector.projectTypes.FileSystem) {
367 contextMenu.appendItem(WebInspector.UIString("Refresh"), this._handleContextMenuRefresh.bind(this, project, path));
368 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "New file" : "New File"), this._handleContextMenuCreate.bind(this, project, path));
369 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Exclude folder" : "Exclude Folder"), this._handleContextMenuExclude.bind(this, project, path));
371 contextMenu.appendSeparator();
372 this._appendAddFolderItem(contextMenu);
374 function removeFolder()
376 var shouldRemove = window.confirm(WebInspector.UIString("Are you sure you want to remove this folder?"));
381 if (project.type() === WebInspector.projectTypes.FileSystem && node === projectNode) {
382 var removeFolderLabel = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove folder from workspace" : "Remove Folder from Workspace");
383 contextMenu.appendItem(removeFolderLabel, removeFolder);
390 * @param {?Event} event
392 _treeKeyPress: function(event)
394 if (WebInspector.isBeingEdited(this._scriptsTree.childrenListElement))
397 var searchText = String.fromCharCode(event.charCode);
398 if (searchText.trim() !== searchText)
400 this.dispatchEventToListeners(WebInspector.NavigatorView.Events.ItemSearchStarted, searchText);
404 __proto__: WebInspector.View.prototype
409 * @extends {TreeOutline}
410 * @param {!Element} element
412 WebInspector.NavigatorTreeOutline = function(element)
414 TreeOutline.call(this, element);
415 this.element = element;
417 this.comparator = WebInspector.NavigatorTreeOutline._treeElementsCompare;
420 WebInspector.NavigatorTreeOutline.Types = {
424 UISourceCode: "UISourceCode",
425 FileSystem: "FileSystem"
429 * @param {!TreeElement} treeElement1
430 * @param {!TreeElement} treeElement2
433 WebInspector.NavigatorTreeOutline._treeElementsCompare = function compare(treeElement1, treeElement2)
435 // Insert in the alphabetical order, first domains, then folders, then scripts.
436 function typeWeight(treeElement)
438 var type = treeElement.type();
439 if (type === WebInspector.NavigatorTreeOutline.Types.Domain) {
440 if (treeElement.titleText === WebInspector.inspectedPageDomain)
444 if (type === WebInspector.NavigatorTreeOutline.Types.FileSystem)
446 if (type === WebInspector.NavigatorTreeOutline.Types.Folder)
451 var typeWeight1 = typeWeight(treeElement1);
452 var typeWeight2 = typeWeight(treeElement2);
455 if (typeWeight1 > typeWeight2)
457 else if (typeWeight1 < typeWeight2)
460 var title1 = treeElement1.titleText;
461 var title2 = treeElement2.titleText;
462 result = title1.compareTo(title2);
467 WebInspector.NavigatorTreeOutline.prototype = {
469 * @return {!Array.<!WebInspector.UISourceCode>}
471 scriptTreeElements: function()
474 if (this.children.length) {
475 for (var treeElement = this.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this, true)) {
476 if (treeElement instanceof WebInspector.NavigatorSourceTreeElement)
477 result.push(treeElement.uiSourceCode);
483 __proto__: TreeOutline.prototype
488 * @extends {TreeElement}
489 * @param {string} type
490 * @param {string} title
491 * @param {!Array.<string>} iconClasses
492 * @param {boolean} hasChildren
493 * @param {boolean=} noIcon
495 WebInspector.BaseNavigatorTreeElement = function(type, title, iconClasses, hasChildren, noIcon)
498 TreeElement.call(this, "", null, hasChildren);
499 this._titleText = title;
500 this._iconClasses = iconClasses;
501 this._noIcon = noIcon;
504 WebInspector.BaseNavigatorTreeElement.prototype = {
507 this.listItemElement.removeChildren();
508 if (this._iconClasses) {
509 for (var i = 0; i < this._iconClasses.length; ++i)
510 this.listItemElement.classList.add(this._iconClasses[i]);
513 var selectionElement = document.createElement("div");
514 selectionElement.className = "selection";
515 this.listItemElement.appendChild(selectionElement);
518 this.imageElement = document.createElement("img");
519 this.imageElement.className = "icon";
520 this.listItemElement.appendChild(this.imageElement);
523 this.titleElement = document.createElement("div");
524 this.titleElement.className = "base-navigator-tree-element-title";
525 this._titleTextNode = document.createTextNode("");
526 this._titleTextNode.textContent = this._titleText;
527 this.titleElement.appendChild(this._titleTextNode);
528 this.listItemElement.appendChild(this.titleElement);
531 updateIconClasses: function(iconClasses)
533 for (var i = 0; i < this._iconClasses.length; ++i)
534 this.listItemElement.classList.remove(this._iconClasses[i]);
535 this._iconClasses = iconClasses;
536 for (var i = 0; i < this._iconClasses.length; ++i)
537 this.listItemElement.classList.add(this._iconClasses[i]);
542 if (this.listItemElement)
543 this.listItemElement.scrollIntoViewIfNeeded(true);
551 return this._titleText;
554 set titleText(titleText)
556 if (this._titleText === titleText)
558 this._titleText = titleText || "";
559 if (this.titleElement)
560 this.titleElement.textContent = this._titleText;
571 __proto__: TreeElement.prototype
576 * @extends {WebInspector.BaseNavigatorTreeElement}
577 * @param {!WebInspector.NavigatorView} navigatorView
578 * @param {string} type
579 * @param {string} title
581 WebInspector.NavigatorFolderTreeElement = function(navigatorView, type, title)
583 var iconClass = WebInspector.NavigatorView.iconClassForType(type);
584 WebInspector.BaseNavigatorTreeElement.call(this, type, title, [iconClass], true);
585 this._navigatorView = navigatorView;
588 WebInspector.NavigatorFolderTreeElement.prototype = {
589 onpopulate: function()
591 this._node.populate();
596 WebInspector.BaseNavigatorTreeElement.prototype.onattach.call(this);
598 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
602 * @param {!WebInspector.NavigatorFolderTreeNode} node
604 setNode: function(node)
608 while (node && !node.isRoot()) {
609 paths.push(node._title);
613 this.tooltip = paths.join("/");
617 * @param {?Event} event
619 _handleContextMenuEvent: function(event)
624 this._navigatorView.handleFolderContextMenu(/** @type {!Event} */ (event), this._node);
627 __proto__: WebInspector.BaseNavigatorTreeElement.prototype
632 * @extends {WebInspector.BaseNavigatorTreeElement}
633 * @param {!WebInspector.NavigatorView} navigatorView
634 * @param {!WebInspector.UISourceCode} uiSourceCode
635 * @param {string} title
637 WebInspector.NavigatorSourceTreeElement = function(navigatorView, uiSourceCode, title)
639 this._navigatorView = navigatorView;
640 this._uiSourceCode = uiSourceCode;
641 WebInspector.BaseNavigatorTreeElement.call(this, WebInspector.NavigatorTreeOutline.Types.UISourceCode, title, this._calculateIconClasses(), false);
642 this.tooltip = uiSourceCode.originURL();
645 WebInspector.NavigatorSourceTreeElement.prototype = {
647 * @return {!WebInspector.UISourceCode}
651 return this._uiSourceCode;
655 * @return {!Array.<string>}
657 _calculateIconClasses: function()
659 return ["navigator-" + this._uiSourceCode.contentType().name() + "-tree-item"];
662 updateIcon: function()
664 this.updateIconClasses(this._calculateIconClasses());
669 WebInspector.BaseNavigatorTreeElement.prototype.onattach.call(this);
670 this.listItemElement.draggable = true;
671 this.listItemElement.addEventListener("click", this._onclick.bind(this), false);
672 this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
673 this.listItemElement.addEventListener("mousedown", this._onmousedown.bind(this), false);
674 this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
677 _onmousedown: function(event)
679 if (event.which === 1) // Warm-up data for drag'n'drop
680 this._uiSourceCode.requestContent(callback.bind(this));
682 * @param {?string} content
683 * @this {WebInspector.NavigatorSourceTreeElement}
685 function callback(content)
687 this._warmedUpContent = content;
691 _shouldRenameOnMouseDown: function()
693 if (!this._uiSourceCode.canRename())
695 var isSelected = this === this.treeOutline.selectedTreeElement;
696 var isFocused = this.treeOutline.childrenListElement.isSelfOrAncestor(document.activeElement);
697 return isSelected && isFocused && !WebInspector.isBeingEdited(this.treeOutline.element);
700 selectOnMouseDown: function(event)
702 if (event.which !== 1 || !this._shouldRenameOnMouseDown()) {
703 TreeElement.prototype.selectOnMouseDown.call(this, event);
706 setTimeout(rename.bind(this), 300);
709 * @this {WebInspector.NavigatorSourceTreeElement}
713 if (this._shouldRenameOnMouseDown())
714 this._navigatorView.requestRename(this._uiSourceCode);
718 _ondragstart: function(event)
720 event.dataTransfer.setData("text/plain", this._warmedUpContent);
721 event.dataTransfer.effectAllowed = "copy";
730 this._navigatorView._sourceSelected(this.uiSourceCode, true);
735 * @param {!Event} event
737 _onclick: function(event)
739 this._navigatorView._sourceSelected(this.uiSourceCode, false);
746 ondblclick: function(event)
748 var middleClick = event.button === 1;
749 this._navigatorView._sourceSelected(this.uiSourceCode, !middleClick);
759 this._navigatorView._sourceSelected(this.uiSourceCode, true);
769 this._navigatorView.sourceDeleted(this.uiSourceCode);
774 * @param {!Event} event
776 _handleContextMenuEvent: function(event)
779 this._navigatorView.handleFileContextMenu(event, this._uiSourceCode);
782 __proto__: WebInspector.BaseNavigatorTreeElement.prototype
789 WebInspector.NavigatorTreeNode = function(id)
792 /** @type {!StringMap.<!WebInspector.NavigatorTreeNode>} */
793 this._children = new StringMap();
796 WebInspector.NavigatorTreeNode.prototype = {
798 * @return {!TreeElement}
800 treeElement: function() { throw "Not implemented"; },
802 dispose: function() { },
815 hasChildren: function()
822 if (this.isPopulated())
825 this.parent.populate();
826 this._populated = true;
830 wasPopulated: function()
832 var children = this.children();
833 for (var i = 0; i < children.length; ++i)
834 this.treeElement().appendChild(children[i].treeElement());
838 * @param {!WebInspector.NavigatorTreeNode} node
840 didAddChild: function(node)
842 if (this.isPopulated())
843 this.treeElement().appendChild(node.treeElement());
847 * @param {!WebInspector.NavigatorTreeNode} node
849 willRemoveChild: function(node)
851 if (this.isPopulated())
852 this.treeElement().removeChild(node.treeElement());
858 isPopulated: function()
860 return this._populated;
868 return !this._children.size();
873 * @return {?WebInspector.NavigatorTreeNode}
877 return this._children.get(id) || null;
881 * @return {!Array.<!WebInspector.NavigatorTreeNode>}
885 return this._children.values();
889 * @param {!WebInspector.NavigatorTreeNode} node
891 appendChild: function(node)
893 this._children.put(node.id, node);
895 this.didAddChild(node);
899 * @param {!WebInspector.NavigatorTreeNode} node
901 removeChild: function(node)
903 this.willRemoveChild(node);
904 this._children.remove(node.id);
911 this._children.clear();
917 * @extends {WebInspector.NavigatorTreeNode}
918 * @param {!WebInspector.NavigatorView} navigatorView
920 WebInspector.NavigatorRootTreeNode = function(navigatorView)
922 WebInspector.NavigatorTreeNode.call(this, "");
923 this._navigatorView = navigatorView;
926 WebInspector.NavigatorRootTreeNode.prototype = {
936 * @return {!TreeOutline}
938 treeElement: function()
940 return this._navigatorView._scriptsTree;
943 __proto__: WebInspector.NavigatorTreeNode.prototype
948 * @extends {WebInspector.NavigatorTreeNode}
949 * @param {!WebInspector.NavigatorView} navigatorView
950 * @param {!WebInspector.UISourceCode} uiSourceCode
952 WebInspector.NavigatorUISourceCodeTreeNode = function(navigatorView, uiSourceCode)
954 WebInspector.NavigatorTreeNode.call(this, uiSourceCode.name());
955 this._navigatorView = navigatorView;
956 this._uiSourceCode = uiSourceCode;
957 this._treeElement = null;
960 WebInspector.NavigatorUISourceCodeTreeNode.prototype = {
962 * @return {!WebInspector.UISourceCode}
964 uiSourceCode: function()
966 return this._uiSourceCode;
969 updateIcon: function()
971 if (this._treeElement)
972 this._treeElement.updateIcon();
976 * @return {!TreeElement}
978 treeElement: function()
980 if (this._treeElement)
981 return this._treeElement;
983 this._treeElement = new WebInspector.NavigatorSourceTreeElement(this._navigatorView, this._uiSourceCode, "");
986 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._titleChanged, this);
987 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
988 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
989 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._formattedChanged, this);
991 return this._treeElement;
995 * @param {boolean=} ignoreIsDirty
997 updateTitle: function(ignoreIsDirty)
999 if (!this._treeElement)
1002 var titleText = this._uiSourceCode.displayName();
1003 if (!ignoreIsDirty && (this._uiSourceCode.isDirty() || this._uiSourceCode.hasUnsavedCommittedChanges()))
1004 titleText = "*" + titleText;
1005 this._treeElement.titleText = titleText;
1011 hasChildren: function()
1018 if (!this._treeElement)
1020 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._titleChanged, this);
1021 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
1022 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopyCommitted, this);
1023 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._formattedChanged, this);
1026 _titleChanged: function(event)
1031 _workingCopyChanged: function(event)
1036 _workingCopyCommitted: function(event)
1041 _formattedChanged: function(event)
1047 * @param {boolean=} select
1049 reveal: function(select)
1051 this.parent.populate();
1052 this.parent.treeElement().expand();
1053 this._treeElement.reveal();
1055 this._treeElement.select();
1059 * @param {function(boolean)=} callback
1061 rename: function(callback)
1063 if (!this._treeElement)
1066 // Tree outline should be marked as edited as well as the tree element to prevent search from starting.
1067 var treeOutlineElement = this._treeElement.treeOutline.element;
1068 WebInspector.markBeingEdited(treeOutlineElement, true);
1071 * @param {!Element} element
1072 * @param {string} newTitle
1073 * @param {string} oldTitle
1074 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1076 function commitHandler(element, newTitle, oldTitle)
1078 if (newTitle !== oldTitle) {
1079 this._treeElement.titleText = newTitle;
1080 this._uiSourceCode.rename(newTitle, renameCallback.bind(this));
1083 afterEditing.call(this, true);
1087 * @param {boolean} success
1088 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1090 function renameCallback(success)
1093 WebInspector.markBeingEdited(treeOutlineElement, false);
1095 this.rename(callback);
1098 afterEditing.call(this, true);
1102 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1104 function cancelHandler()
1106 afterEditing.call(this, false);
1110 * @param {boolean} committed
1111 * @this {WebInspector.NavigatorUISourceCodeTreeNode}
1113 function afterEditing(committed)
1115 WebInspector.markBeingEdited(treeOutlineElement, false);
1117 this._treeElement.treeOutline.childrenListElement.focus();
1119 callback(committed);
1122 var editingConfig = new WebInspector.EditingConfig(commitHandler.bind(this), cancelHandler.bind(this));
1123 this.updateTitle(true);
1124 WebInspector.startEditing(this._treeElement.titleElement, editingConfig);
1125 window.getSelection().setBaseAndExtent(this._treeElement.titleElement, 0, this._treeElement.titleElement, 1);
1128 __proto__: WebInspector.NavigatorTreeNode.prototype
1133 * @extends {WebInspector.NavigatorTreeNode}
1134 * @param {!WebInspector.NavigatorView} navigatorView
1135 * @param {?WebInspector.Project} project
1136 * @param {string} id
1137 * @param {string} type
1138 * @param {string} folderPath
1139 * @param {string} title
1141 WebInspector.NavigatorFolderTreeNode = function(navigatorView, project, id, type, folderPath, title)
1143 WebInspector.NavigatorTreeNode.call(this, id);
1144 this._navigatorView = navigatorView;
1145 this._project = project;
1147 this._folderPath = folderPath;
1148 this._title = title;
1151 WebInspector.NavigatorFolderTreeNode.prototype = {
1153 * @return {!TreeElement}
1155 treeElement: function()
1157 if (this._treeElement)
1158 return this._treeElement;
1159 this._treeElement = this._createTreeElement(this._title, this);
1160 return this._treeElement;
1164 * @return {!TreeElement}
1166 _createTreeElement: function(title, node)
1168 var treeElement = new WebInspector.NavigatorFolderTreeElement(this._navigatorView, this._type, title);
1169 treeElement.setNode(node);
1173 wasPopulated: function()
1175 if (!this._treeElement || this._treeElement._node !== this)
1177 this._addChildrenRecursive();
1180 _addChildrenRecursive: function()
1182 var children = this.children();
1183 for (var i = 0; i < children.length; ++i) {
1184 var child = children[i];
1185 this.didAddChild(child);
1186 if (child instanceof WebInspector.NavigatorFolderTreeNode)
1187 child._addChildrenRecursive();
1191 _shouldMerge: function(node)
1193 return this._type !== WebInspector.NavigatorTreeOutline.Types.Domain && node instanceof WebInspector.NavigatorFolderTreeNode;
1196 didAddChild: function(node)
1198 function titleForNode(node)
1203 if (!this._treeElement)
1206 var children = this.children();
1208 if (children.length === 1 && this._shouldMerge(node)) {
1209 node._isMerged = true;
1210 this._treeElement.titleText = this._treeElement.titleText + "/" + node._title;
1211 node._treeElement = this._treeElement;
1212 this._treeElement.setNode(node);
1217 if (children.length === 2)
1218 oldNode = children[0] !== node ? children[0] : children[1];
1219 if (oldNode && oldNode._isMerged) {
1220 delete oldNode._isMerged;
1221 var mergedToNodes = [];
1222 mergedToNodes.push(this);
1223 var treeNode = this;
1224 while (treeNode._isMerged) {
1225 treeNode = treeNode.parent;
1226 mergedToNodes.push(treeNode);
1228 mergedToNodes.reverse();
1229 var titleText = mergedToNodes.map(titleForNode).join("/");
1234 nodes.push(treeNode);
1235 children = treeNode.children();
1236 treeNode = children.length === 1 ? children[0] : null;
1237 } while (treeNode && treeNode._isMerged);
1239 if (!this.isPopulated()) {
1240 this._treeElement.titleText = titleText;
1241 this._treeElement.setNode(this);
1242 for (var i = 0; i < nodes.length; ++i) {
1243 delete nodes[i]._treeElement;
1244 delete nodes[i]._isMerged;
1248 var oldTreeElement = this._treeElement;
1249 var treeElement = this._createTreeElement(titleText, this);
1250 for (var i = 0; i < mergedToNodes.length; ++i)
1251 mergedToNodes[i]._treeElement = treeElement;
1252 oldTreeElement.parent.appendChild(treeElement);
1254 oldTreeElement.setNode(nodes[nodes.length - 1]);
1255 oldTreeElement.titleText = nodes.map(titleForNode).join("/");
1256 oldTreeElement.parent.removeChild(oldTreeElement);
1257 this._treeElement.appendChild(oldTreeElement);
1258 if (oldTreeElement.expanded)
1259 treeElement.expand();
1261 if (this.isPopulated())
1262 this._treeElement.appendChild(node.treeElement());
1265 willRemoveChild: function(node)
1267 if (node._isMerged || !this.isPopulated())
1269 this._treeElement.removeChild(node._treeElement);
1272 __proto__: WebInspector.NavigatorTreeNode.prototype