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

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: addressed comments 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} parentDirEntry 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(parentDirEntry, parentDirItem, directoryModel) {
60 var item = cr.doc.createElement('div');
61 DirectoryItem.decorate(item, parentDirEntry, parentDirItem, directoryModel);
62 return item;
63 }
64
65 /**
66 * @param {HTMLElement} el Element to be DirectoryItem.
67 * @param {DirectoryEntry} parentDirEntry 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, parentDirEntry, parentDirItem, directoryModel) {
73 el.__proto__ = DirectoryItem.prototype;
74 (/** @type {DirectoryItem} */ el).decorate(
75 parentDirEntry, 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} parentDirEntry 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 parentDirEntry, parentDirItem, directoryModel) {
98 var path = parentDirEntry.fullPath;
99 var label = PathUtil.isRootPath(path) ?
100 PathUtil.getRootLabel(path) : parentDirEntry.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
118 // Sets hasChildren=true tentatively. This will be overridden after
119 // scanning sub-directories in updateSubElementsFromList.
120 this.hasChildren = true;
121
122 this.addEventListener('expand', this.onExpand_.bind(this), true);
123
124 var volumeManager = VolumeManager.getInstance();
125 var icon = this.querySelector('.icon');
126 if (PathUtil.isRootPath(path)) {
127 icon.classList.add('volume-icon');
128 var iconType = PathUtil.getRootType(path);
129 icon.setAttribute('volume-type-icon', iconType);
130
131 if (iconType == RootType.REMOVABLE)
132 icon.setAttribute('volume-subtype', volumeManager.getDeviceType(path));
133 }
134
135 var eject = this.querySelector('.root-eject');
136 eject.hidden = !PathUtil.isUnmountableByUser(path);
137 eject.addEventListener('click',
138 function(event) {
139 event.stopPropagation();
140 if (!PathUtil.isUnmountableByUser(path))
141 return;
142
143 volumeManager.unmount(path, function() {}, function() {});
144 }.bind(this));
145
146 if ('expanded' in parentDirItem || parentDirItem.expanded)
147 this.updateSubDirectoriesWithEntry_(parentDirEntry);
148 };
149
150 /**
151 * Invoked when the item is being expanded.
152 * @param {!UIEvent} e Event.
153 * @private
154 **/
155 DirectoryItem.prototype.onExpand_ = function(e) {
156 this.updateSubDirectories(function() {
157 this.expanded = false;
158 }.bind(this));
159
160 e.stopPropagation();
161 };
162
163 /**
164 * Retrieve the latest subdirectories and update them on the tree.
mtomasz 2013/03/15 04:23:20 Retrieve -> retrieves and in other places, please
yoshiki 2013/03/15 08:01:06 Done.
165 * @param {function()=} opt_errorCallback Callback called on error.
166 */
167 DirectoryItem.prototype.updateSubDirectories = function(opt_errorCallback) {
168 this.directoryModel_.resolveDirectory(
169 this.fullPath,
170 function(entry) {
171 this.updateSubDirectoriesWithEntry_(entry, opt_errorCallback);
172 }.bind(this),
173 opt_errorCallback);
174 };
175
176 /**
177 * Retrieve the latest subdirectories and update them on the tree.
178 * @param {!DirectoryEntry} dirEntry DirectoryEntry to read from.
179 * @param {function()=} opt_errorCallback Callback called on error.
180 * @private
181 */
182 DirectoryItem.prototype.updateSubDirectoriesWithEntry_ =
183 function(dirEntry, opt_errorCallback) {
184 // Skips if the entry is dummy.
185 if (!('createReader' in dirEntry)) {
186 if (opt_errorCallback)
187 opt_errorCallback();
188 return;
189 }
190
191 var reader = dirEntry.createReader();
192 var entries = [];
193
194 var readEntry = function() {
195 reader.readEntries(function(results) {
196 if (!results.length) {
197 this.entries_ = entries.sort();
198 this.redrawSubDirectoryList_();
199 return;
200 }
201
202 for (var i = 0; i < results.length; i++) {
203 var entry = results[i];
204 if (entry.isDirectory)
205 entries.push(entry);
206 }
207 readEntry();
208 }.bind(this));
209 }.bind(this);
210 readEntry();
211 };
212
213 /**
214 * @private
215 */
216 DirectoryItem.prototype.redrawSubDirectoryList_ = function() {
217 var entries = this.entries_;
218 updateSubElementsFromList(this,
219 function(i) { return entries[i]; },
220 this.directoryModel_);
221 };
222
223 /**
224 * Tree of directories on the sidebar. This element is also the root of items,
225 * in other words, this is the parent of the top-level items.
226 *
227 * @constructor
228 * @extends {cr.ui.Tree}
229 */
230 function DirectoryTree() {}
231
232 /**
233 * Decorates an element.
234 * @param {HTMLElement} el Element to be DirectoryTree.
235 * @param {DirectoryModel} directoryModel Current DirectoryModel.
236 */
237 DirectoryTree.decorate = function(el, directoryModel) {
238 el.__proto__ = DirectoryTree.prototype;
239 (/** @type {DirectoryTree} */ el).decorate(directoryModel);
240 };
241
242 DirectoryTree.prototype = {
243 __proto__: cr.ui.Tree.prototype,
244 };
245
246 /**
247 * Decorates an element.
248 * @param {DirectoryModel} directoryModel Current DirectoryModel.
249 */
250 DirectoryTree.prototype.decorate = function(directoryModel) {
251 cr.ui.Tree.prototype.decorate.call(this);
252
253 this.directoryModel_ = directoryModel;
254
255 this.rootsList_ = this.directoryModel_.getRootsList();
256 this.rootsList_.addEventListener('change',
257 this.onRootsListChanged_.bind(this));
258 this.rootsList_.addEventListener('permuted',
259 this.onRootsListChanged_.bind(this));
260 this.onRootsListChanged_();
261 };
262
263 /**
264 * Sets a context menu. Context menu is enabled only on archive and removable
265 * volumes as of now.
266 *
267 * @param {cr.ui.Menu} menu Context menu.
268 */
269 DirectoryTree.prototype.setContextMenu = function(menu) {
270 this.contextMenu_ = menu;
271
272 for (var i = 0; i < this.rootsList_.length; i++) {
273 var item = this.rootsList_.item(i);
274 var type = PathUtil.getRootType(item.fullPath);
275 // Context menu is set only to archive and removable volumes.
276 if (type == RootType.ARCHIVE || type == RootType.REMOVABLE) {
277 cr.ui.contextMenuHandler.setContextMenu(this.items[i].rowElement,
278 this.contextMenu_);
279 }
280 }
281 };
282
283 /**
284 * Invoked when the root list is changed.
285 * @private
286 */
287 DirectoryTree.prototype.onRootsListChanged_ = function() {
288 var rootsList = this.rootsList_;
289 updateSubElementsFromList(this,
290 rootsList.item.bind(rootsList),
291 this.directoryModel_);
292 this.setContextMenu(this.contextMenu_);
293 };
294
295 /**
296 * Returns the path of the selected item.
297 * @return {string} The current path.
298 */
299 DirectoryTree.prototype.getCurrentPath = function() {
300 return this.selectedItem ? this.selectedItem.fullPath : null;
301 };
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