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 * @constructor 33 * @extends {WebInspector.SidebarView} 34 * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem 35 */ 36WebInspector.FileSystemView = function(fileSystem) 37{ 38 WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start, "FileSystemViewSidebarWidth"); 39 this.element.classList.add("file-system-view"); 40 this.element.classList.add("storage-view"); 41 42 var directoryTreeElement = this.element.createChild("ol", "filesystem-directory-tree"); 43 this._directoryTree = new TreeOutline(directoryTreeElement); 44 this.sidebarElement.appendChild(directoryTreeElement); 45 this.sidebarElement.classList.add("outline-disclosure"); 46 this.sidebarElement.classList.add("sidebar"); 47 48 var rootItem = new WebInspector.FileSystemView.EntryTreeElement(this, fileSystem.root); 49 rootItem.expanded = true; 50 this._directoryTree.appendChild(rootItem); 51 this._visibleView = null; 52 53 this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); 54 this._refreshButton.visible = true; 55 this._refreshButton.addEventListener("click", this._refresh, this); 56 57 this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); 58 this._deleteButton.visible = true; 59 this._deleteButton.addEventListener("click", this._confirmDelete, this); 60} 61 62WebInspector.FileSystemView.prototype = { 63 /** 64 * @type {!Array.<!Element>} 65 */ 66 get statusBarItems() 67 { 68 return [this._refreshButton.element, this._deleteButton.element]; 69 }, 70 71 /** 72 * @type {!WebInspector.View} 73 */ 74 get visibleView() 75 { 76 return this._visibleView; 77 }, 78 79 /** 80 * @param {!WebInspector.View} view 81 */ 82 showView: function(view) 83 { 84 if (this._visibleView === view) 85 return; 86 if (this._visibleView) 87 this._visibleView.detach(); 88 this._visibleView = view; 89 view.show(this.mainElement); 90 }, 91 92 _refresh: function() 93 { 94 this._directoryTree.children[0].refresh(); 95 }, 96 97 _confirmDelete: function() 98 { 99 if (confirm(WebInspector.UIString("Are you sure you want to delete the selected entry?"))) 100 this._delete(); 101 }, 102 103 _delete: function() 104 { 105 this._directoryTree.selectedTreeElement.deleteEntry(); 106 }, 107 108 __proto__: WebInspector.SidebarView.prototype 109} 110 111/** 112 * @constructor 113 * @extends {TreeElement} 114 * @param {!WebInspector.FileSystemView} fileSystemView 115 * @param {!WebInspector.FileSystemModel.Entry} entry 116 */ 117WebInspector.FileSystemView.EntryTreeElement = function(fileSystemView, entry) 118{ 119 TreeElement.call(this, entry.name, null, entry.isDirectory); 120 121 this._entry = entry; 122 this._fileSystemView = fileSystemView; 123} 124 125WebInspector.FileSystemView.EntryTreeElement.prototype = { 126 /** 127 * @override 128 */ 129 onattach: function() 130 { 131 var selection = this.listItemElement.createChild("div", "selection"); 132 this.listItemElement.insertBefore(selection, this.listItemElement.firstChild); 133 }, 134 135 /** 136 * @override 137 */ 138 onselect: function() 139 { 140 if (!this._view) { 141 if (this._entry.isDirectory) 142 this._view = new WebInspector.DirectoryContentView(); 143 else { 144 var file = /** @type {!WebInspector.FileSystemModel.File} */ (this._entry); 145 this._view = new WebInspector.FileContentView(file); 146 } 147 } 148 this._fileSystemView.showView(this._view); 149 this.refresh(); 150 return false; 151 }, 152 153 /** 154 * @override 155 */ 156 onpopulate: function() 157 { 158 this.refresh(); 159 }, 160 161 /** 162 * @param {number} errorCode 163 * @param {!Array.<!WebInspector.FileSystemModel.Entry>=} entries 164 */ 165 _directoryContentReceived: function(errorCode, entries) 166 { 167 if (errorCode === FileError.NOT_FOUND_ERR) { 168 if (this.parent !== this.treeOutline) 169 this.parent.refresh(); 170 return; 171 } 172 173 if (errorCode !== 0 || !entries) { 174 console.error("Failed to read directory: " + errorCode); 175 return; 176 } 177 178 entries.sort(WebInspector.FileSystemModel.Entry.compare); 179 if (this._view) 180 this._view.showEntries(entries); 181 182 var oldChildren = this.children.slice(0); 183 184 var newEntryIndex = 0; 185 var oldChildIndex = 0; 186 var currentTreeItem = 0; 187 while (newEntryIndex < entries.length && oldChildIndex < oldChildren.length) { 188 var newEntry = entries[newEntryIndex]; 189 var oldChild = oldChildren[oldChildIndex]; 190 var order = newEntry.name.compareTo(oldChild._entry.name); 191 192 if (order === 0) { 193 if (oldChild._entry.isDirectory) 194 oldChild.shouldRefreshChildren = true; 195 else 196 oldChild.refresh(); 197 198 ++newEntryIndex; 199 ++oldChildIndex; 200 ++currentTreeItem; 201 continue; 202 } 203 if (order < 0) { 204 this.insertChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, newEntry), currentTreeItem); 205 ++newEntryIndex; 206 ++currentTreeItem; 207 continue; 208 } 209 210 this.removeChildAtIndex(currentTreeItem); 211 ++oldChildIndex; 212 } 213 for (; newEntryIndex < entries.length; ++newEntryIndex) 214 this.appendChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, entries[newEntryIndex])); 215 216 for (; oldChildIndex < oldChildren.length; ++oldChildIndex) 217 this.removeChild(oldChildren[oldChildIndex]); 218 }, 219 220 refresh: function() 221 { 222 if (!this._entry.isDirectory) { 223 if (this._view && this._view === this._fileSystemView.visibleView) { 224 var fileContentView = /** @type {!WebInspector.FileContentView} */ (this._view); 225 fileContentView.refresh(); 226 } 227 } else 228 this._entry.requestDirectoryContent(this._directoryContentReceived.bind(this)); 229 }, 230 231 deleteEntry: function() 232 { 233 this._entry.deleteEntry(this._deletionCompleted.bind(this)); 234 }, 235 236 _deletionCompleted: function() 237 { 238 if (this._entry != this._entry.fileSystem.root) 239 this.parent.refresh(); 240 }, 241 242 __proto__: TreeElement.prototype 243} 244