Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: chrome/browser/resources/file_manager/js/sidebar.js

Issue 12857002: Files.app: Add subfolders in the left nav (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * Updates sub-elements of {@code parentElement} reading {@code DirectoryEntry}
7 * with calling {@code iterator}.
8 *
9 * @param {DirectoryItem|DirectoryTree} parentElement Parent element of newly
10 * created items.
11 * @param {function(number): DirectoryEntry} iterator Function which returns
12 * the n-th Entry in the directory.
13 * @param {DirectoryModel} directoryModel Current DirectoryModel.
14 */
15 function updateSubElementsFromList(parentElement, iterator, directoryModel) {
16 var index = 0;
17 while (iterator(index)) {
18 var currentEntry = iterator(index);
19 var currentElement = parentElement.items[index];
20
21 if (index >= parentElement.items.length) {
22 var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
23 parentElement.add(item);
24 index++;
25 } else if (currentEntry.fullPath == currentElement.fullPath) {
26 index++;
27 } else if (currentEntry.fullPath < currentElement.fullPath) {
28 var item = new DirectoryItem(currentEntry, parentElement, directoryModel);
29 parentElement.addAt(item, index);
30 index++;
31 } else if (currentEntry.fullPath > currentElement.fullPath) {
32 parentElement.remove(currentElement);
33 }
34 }
35
36 var removedChild;
37 while (removedChild = parentElement.items[index]) {
38 parentElement.remove(removedChild);
39 }
40
41 if (index == 0) {
42 parentElement.hasChildren = false;
43 parentElement.expanded = false;
44 } else {
45 parentElement.hasChildren = true;
46 }
47 }
48
49 /**
50 * A directory in the tree. One this element represents one directory. Each
51 * element represents one director.
52 *
53 * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
54 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
55 * @param {DirectoryModel} directoryModel Current DirectoryModel.
56 * @extends {cr.ui.TreeItem}
57 * @constructor
58 */
59 function DirectoryItem(dirEntry, parentDirItem, directoryModel) {
60 var item = cr.doc.createElement('div');
61 DirectoryItem.decorate(item, dirEntry, parentDirItem, directoryModel);
62 return item;
63 }
64
65 /**
66 * @param {HTMLElement} el Element to be DirectoryItem.
67 * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
68 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
69 * @param {DirectoryModel} directoryModel Current DirectoryModel.
70 */
71 DirectoryItem.decorate =
72 function(el, dirEntry, parentDirItem, directoryModel) {
73 el.__proto__ = DirectoryItem.prototype;
74 (/** @type {DirectoryItem} */ el).decorate(
75 dirEntry, parentDirItem, directoryModel);
76 };
77
78 DirectoryItem.prototype = {
79 __proto__: cr.ui.TreeItem.prototype,
80
81 /**
82 * The element containing the label text and the icon.
83 * @type {!HTMLElement}
84 * @override
85 **/
86 get labelElement() {
87 return this.firstElementChild.querySelector('.label');
88 }
89 };
90
91 /**
92 * @param {DirectoryEntry} dirEntry DirectoryEntry of this item.
93 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
94 * @param {DirectoryModel} directoryModel Current DirectoryModel.
95 */
96 DirectoryItem.prototype.decorate = function(
97 dirEntry, parentDirItem, directoryModel) {
98 var path = dirEntry.fullPath;
99 var label = PathUtil.isRootPath(path) ?
100 PathUtil.getRootLabel(path) : dirEntry.name;
101
102 this.className = 'tree-item';
103 this.innerHTML =
104 '<div class="tree-row">' +
105 ' <span class="expand-icon"></span>' +
106 ' <span class="icon"></span>' +
107 ' <span class="label"></span>' +
108 ' <div class="root-eject"></div>' +
109 '</div>' +
110 '<div class="tree-children"></div>';
111 this.setAttribute('role', 'treeitem');
112
113 this.directoryModel_ = directoryModel;
114 this.parent_ = parentDirItem;
115 this.label = label;
116 this.fullPath = path;
117 this.draggable = true;
118
119 // Sets hasChildren=true tentatively. This will be overridden after
120 // scanning sub-directories in updateSubElementsFromList.
121 this.hasChildren = true;
122
123 this.addEventListener('expand', this.onExpand_.bind(this), true);
124
125 var volumeManager = VolumeManager.getInstance();
126 var icon = this.querySelector('.icon');
127 if (PathUtil.isRootPath(path)) {
128 icon.classList.add('volume-icon');
129 var iconType = PathUtil.getRootType(path);
130 icon.setAttribute('volume-type-icon', iconType);
131
132 if (iconType == RootType.REMOVABLE)
133 icon.setAttribute('volume-subtype', volumeManager.getDeviceType(path));
134 }
135
136 var eject = this.querySelector('.root-eject');
137 eject.hidden = !PathUtil.isUnmountableByUser(path);
138 eject.addEventListener('click',
139 function(event) {
140 event.stopPropagation();
141 if (!PathUtil.isUnmountableByUser(path))
142 return;
143
144 volumeManager.unmount(path, function() {}, function() {});
145 }.bind(this));
146
147 if ('expanded' in parentDirItem || parentDirItem.expanded)
148 this.updateSubDirectoriesWithEntry_(dirEntry);
149 };
150
151 /**
152 * Invoked when the item is being expanded.
153 * @param {!UIEvent} e Event.
154 * @private
155 **/
156 DirectoryItem.prototype.onExpand_ = function(e) {
157 this.updateSubDirectories(function() {
158 this.expanded = false;
159 }.bind(this));
160
161 e.stopPropagation();
162 };
163
164 /**
165 * Retrieves the latest subdirectories and update them on the tree.
166 * @param {function()=} opt_errorCallback Callback called on error.
167 */
168 DirectoryItem.prototype.updateSubDirectories = function(opt_errorCallback) {
169 this.directoryModel_.resolveDirectory(
170 this.fullPath,
171 function(entry) {
172 this.updateSubDirectoriesWithEntry_(entry, opt_errorCallback);
173 }.bind(this),
174 opt_errorCallback);
175 };
176
177 /**
178 * Retrieves the latest subdirectories and update them on the tree.
179 * @param {!DirectoryEntry} dirEntry DirectoryEntry to read from.
180 * @param {function()=} opt_errorCallback Callback called on error.
181 * @private
182 */
183 DirectoryItem.prototype.updateSubDirectoriesWithEntry_ =
184 function(dirEntry, opt_errorCallback) {
185 // Skips if the entry is dummy.
186 if (!('createReader' in dirEntry)) {
187 if (opt_errorCallback)
188 opt_errorCallback();
189 return;
190 }
191
192 var reader = dirEntry.createReader();
193 var entries = [];
194
195 var readEntry = function() {
196 reader.readEntries(function(results) {
197 if (!results.length) {
198 this.entries_ = entries.sort();
199 this.redrawSubDirectoryList_();
200 return;
201 }
202
203 for (var i = 0; i < results.length; i++) {
204 var entry = results[i];
205 if (entry.isDirectory)
206 entries.push(entry);
207 }
208 readEntry();
209 }.bind(this));
210 }.bind(this);
211 readEntry();
212 };
213
214 /**
215 * @private
216 */
217 DirectoryItem.prototype.redrawSubDirectoryList_ = function() {
218 var entries = this.entries_;
219 updateSubElementsFromList(this,
220 function(i) { return entries[i]; },
221 this.directoryModel_);
222 };
223
224 /**
225 * Tree of directories on the sidebar. This element is also the root of items,
226 * in other words, this is the parent of the top-level items.
227 *
228 * @constructor
229 * @extends {cr.ui.Tree}
230 */
231 function DirectoryTree() {}
232
233 /**
234 * Decorates an element.
235 * @param {HTMLElement} el Element to be DirectoryTree.
236 * @param {DirectoryModel} directoryModel Current DirectoryModel.
237 */
238 DirectoryTree.decorate = function(el, directoryModel) {
239 el.__proto__ = DirectoryTree.prototype;
240 (/** @type {DirectoryTree} */ el).decorate(directoryModel);
241 };
242
243 DirectoryTree.prototype = {
244 __proto__: cr.ui.Tree.prototype,
245 };
246
247 /**
248 * Decorates an element.
249 * @param {DirectoryModel} directoryModel Current DirectoryModel.
250 */
251 DirectoryTree.prototype.decorate = function(directoryModel) {
252 cr.ui.Tree.prototype.decorate.call(this);
253
254 this.directoryModel_ = directoryModel;
255
256 this.rootsList_ = this.directoryModel_.getRootsList();
257 this.rootsList_.addEventListener('change',
258 this.onRootsListChanged_.bind(this));
259 this.rootsList_.addEventListener('permuted',
260 this.onRootsListChanged_.bind(this));
261 this.onRootsListChanged_();
262 };
263
264 /**
265 * Sets a context menu. Context menu is enabled only on archive and removable
266 * volumes as of now.
267 *
268 * @param {cr.ui.Menu} menu Context menu.
269 */
270 DirectoryTree.prototype.setContextMenu = function(menu) {
271 this.contextMenu_ = menu;
272
273 for (var i = 0; i < this.rootsList_.length; i++) {
274 var item = this.rootsList_.item(i);
275 var type = PathUtil.getRootType(item.fullPath);
276 // Context menu is set only to archive and removable volumes.
277 if (type == RootType.ARCHIVE || type == RootType.REMOVABLE) {
278 cr.ui.contextMenuHandler.setContextMenu(this.items[i].rowElement,
279 this.contextMenu_);
280 }
281 }
282 };
283
284 /**
285 * Invoked when the root list is changed.
286 * @private
287 */
288 DirectoryTree.prototype.onRootsListChanged_ = function() {
289 var rootsList = this.rootsList_;
290 updateSubElementsFromList(this,
291 rootsList.item.bind(rootsList),
292 this.directoryModel_);
293 this.setContextMenu(this.contextMenu_);
294 };
295
296 /**
297 * Returns the path of the selected item.
298 * @return {string} The current path.
299 */
300 DirectoryTree.prototype.getCurrentPath = function() {
301 return this.selectedItem ? this.selectedItem.fullPath : null;
302 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/js/path_util.js ('k') | chrome/browser/resources/file_manager/main.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698