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

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: 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) 2012 The Chromium Authors. All rights reserved.
mtomasz 2013/03/14 02:52:05 2012 -> 2013
yoshiki 2013/03/14 07:57:53 Done.
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 * Update 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 * @param {DirectoryEntry} parentDirEntry DirectoryEntry of this item.
51 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
52 * @param {DirectoryModel} directoryModel Current DirectoryModel.
53 * @extends {cr.ui.TreeItem}
54 * @constructor
55 */
56 function DirectoryItem(parentDirEntry, parentDirItem, directoryModel) {
57 var item = cr.doc.createElement('div');
58 DirectoryItem.decorate(item, parentDirEntry, parentDirItem, directoryModel);
59 return item;
60 }
61
62 /**
63 * @param {HTMLElement} el Element to be DirectoryItem.
64 * @param {DirectoryEntry} parentDirEntry DirectoryEntry of this item.
65 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
66 * @param {DirectoryModel} directoryModel Current DirectoryModel.
67 */
mtomasz 2013/03/14 02:52:05 Can we move to Class.prototype.method = function()
yoshiki 2013/03/14 07:57:53 Done.
68 DirectoryItem.decorate =
69 function(el, parentDirEntry, parentDirItem, directoryModel) {
70 el.__proto__ = DirectoryItem.prototype;
71 (/** @type {DirectoryItem} */ el).decorate(
72 parentDirEntry, parentDirItem, directoryModel);
73 };
74
75 DirectoryItem.prototype = {
76 __proto__: cr.ui.TreeItem.prototype,
77
78 /**
79 * @param {DirectoryEntry} parentDirEntry DirectoryEntry of this item.
80 * @param {DirectoryItem|DirectoryTree} parentDirItem Parent of this item.
81 * @param {DirectoryModel} directoryModel Current DirectoryModel.
82 */
83 decorate: function(parentDirEntry, parentDirItem, directoryModel) {
84 var path = parentDirEntry.fullPath;
85 var label = PathUtil.isRootPath(path) ?
86 PathUtil.getRootLabel(path) : parentDirEntry.name;
87
88 this.className = 'tree-item';
89 this.innerHTML =
90 '<div class=tree-row>' +
91 '<span class=expand-icon></span>' +
92 '<span class=icon></span>' +
93 '<span class=label></span>' +
94 '<div class=root-eject></div>' +
95 '</div>' +
96 '<div class=tree-children></div>';
97 this.setAttribute('role', 'treeitem');
98
99 this.directoryModel_ = directoryModel;
100 this.parent_ = parentDirItem;
101 this.label = label;
102 this.fullPath = path;
103
104 // Sets hasChildren=true tentatively. This will be overridden after
105 // scanning sub-directories in updateSubElementsFromList.
106 this.hasChildren = true;
107
108 this.addEventListener('expand', this.onExpand_.bind(this), true);
109
110 var icon = this.querySelector('.icon');
111 if (PathUtil.isRootPath(path)) {
112 var iconType = PathUtil.getRootType(path);
113 if (iconType === RootType.REMOVABLE)
114 iconType = this.volumeManager_.getDeviceType(path);
115
116 icon.classList.add('volume-icon');
117 icon.setAttribute('volume-type-icon', iconType);
118 }
119
120 var eject = this.querySelector('.root-eject');
121 eject.hidden = !PathUtil.isUnmountableByUser(path);
122 eject.addEventListener('click',
123 function(event) {
124 event.stopPropagation();
mtomasz 2013/03/14 02:52:05 1. Is stopPropagation() necessary here? 2. Is chec
yoshiki 2013/03/14 07:57:53 Yes, it prevents selecting the item when user trys
yoshiki 2013/03/14 09:05:48 I found some bugs on removable device, but it is f
125 if (!PathUtil.isUnmountableByUser(path))
126 return;
127
128 var volumeManager = VolumeManager.getInstance();
129 volumeManager.unmount(path, function() {}, function() {});
130 }.bind(this));
131
132 if ('expanded' in parentDirItem || parentDirItem.expanded)
133 this.updateSubDirectoriesWithEntry_(parentDirEntry);
134 },
135
136 /**
137 * The element containing the label text and the icon.
138 * @type {!HTMLElement}
139 * @override
140 **/
141 get labelElement() {
142 return this.firstElementChild.querySelector('.label');
mtomasz 2013/03/14 02:52:05 Indentation is off?
yoshiki 2013/03/14 07:57:53 Done.
143 },
144
145 /**
146 * Invoked when the item is being expended.
mtomasz 2013/03/14 02:52:05 expended -> expanded
yoshiki 2013/03/14 07:57:53 Done.
147 * @param {!UIEvent} e Event.
148 * @private
149 **/
150 onExpand_: function(e) {
151 this.updateSubDirectories(function() {
152 this.expanded = false;
153 });
mtomasz 2013/03/14 02:52:05 Add .bind(this)? UpdateSubDirectories calls resolv
yoshiki 2013/03/14 07:57:53 Done.
154
155 e.stopPropagation();
mtomasz 2013/03/14 02:52:05 Is this necessary?
yoshiki 2013/03/14 07:57:53 It prevents selecting the item when clicking expan
156 },
157
158 /**
mtomasz 2013/03/14 02:52:05 Please add a short description.
yoshiki 2013/03/14 07:57:53 Done.
159 * @param {function()=} opt_errorCallback Callback called on error.
160 */
161 updateSubDirectories: function(opt_errorCallback) {
162 this.directoryModel_.resolveDirectory(
163 this.fullPath,
164 function(entry) {
165 this.updateSubDirectoriesWithEntry_(entry, opt_errorCallback);
166 },
mtomasz 2013/03/14 02:52:05 .bind(this) missing. Causes js errors.
yoshiki 2013/03/14 07:57:53 Done.
167 opt_errorCallback);
168 },
169
170 /**
171 * @param {!DirectoryEntry} dirEntry DirectoryEntry to read from.
172 * @param {function()=} opt_errorCallback Callback called on error.
173 * @private
174 */
175 updateSubDirectoriesWithEntry_: function(dirEntry, opt_errorCallback) {
176 // Skips if the entry is dummy.
177 if (!dirEntry.createReader) {
mtomasz 2013/03/14 02:52:05 nit: How about instanceof? Sounds cleaner and less
yoshiki 2013/03/14 07:57:53 Done.
178 if (opt_errorCallback)
179 opt_errorCallback();
180 return;
181 }
182
183 var reader = dirEntry.createReader();
184 var entries = [];
185
186 var readEntry = function() {
187 reader.readEntries(function(results) {
188 if (results.length === 0) {
189 this.entries_ = entries.sort();
190 this.redrawSubDirectoryList_();
191 return;
192 }
193
194 for (var i = 0; i < results.length; i++) {
195 var entry = results[i];
196 if (entry.isDirectory)
197 entries.push(entry);
198 }
199 readEntry();
200 }.bind(this));
201 }.bind(this);
202 readEntry();
203 },
204
205 /**
206 * @private
207 */
208 redrawSubDirectoryList_: function() {
209 var entries = this.entries_;
210 updateSubElementsFromList(this,
211 function(i) { return entries[i]; },
212 this.directoryModel_);
213 }
214 };
215
216 /**
mtomasz 2013/03/14 02:52:05 I think we should have description for the classes
yoshiki 2013/03/14 07:57:53 Done.
217 * @constructor
218 * @extends {cr.ui.Tree}
219 */
220 function DirectoryTree() {}
221
222 /**
223 * Decorate element.
mtomasz 2013/03/14 02:52:05 nit: I think we should consistently use passive fo
yoshiki 2013/03/14 07:57:53 Done.
224 * @param {HTMLElement} el Element to be DirectoryTree.
225 * @param {DirectoryModel} directoryModel Current DirectoryModel.
226 */
227 DirectoryTree.decorate = function(el, directoryModel) {
228 el.__proto__ = DirectoryTree.prototype;
229 (/** @type {DirectoryTree} */ el).decorate(directoryModel);
mtomasz 2013/03/14 02:52:05 I think this virtual cast is unnecessary, since el
yoshiki 2013/03/14 07:57:53 This does nothing on JavaScript interpreter. It's
230 };
231
232 DirectoryTree.prototype = {
233 __proto__: cr.ui.Tree.prototype,
234
235 /**
236 * Decorate element.
237 * @param {DirectoryModel} directoryModel Current DirectoryModel.
238 */
239 decorate: function(directoryModel) {
240 cr.ui.Tree.prototype.decorate.call(this);
241
242 this.directoryModel_ = directoryModel;
243
244 this.rootsList_ = this.directoryModel_.getRootsList();
245 this.rootsList_.addEventListener('change',
246 this.onRootsListChanged_.bind(this));
247 this.rootsList_.addEventListener('permuted',
248 this.onRootsListChanged_.bind(this));
249 this.onRootsListChanged_();
250 },
251
252 /**
253 * @param {cr.ui.Menu} menu Context menu.
254 */
255 setContextMenu: function(menu) {
256 this.contextMenu_ = menu;
257
258 for (var i = 0; i < this.rootsList_.length; i++) {
259 var item = this.rootsList_.item(i);
260 var type = PathUtil.getRootType(item.fullPath);
261 // Context menu is set only to archive and removable volumes.
262 if (type === RootType.ARCHIVE || type === RootType.REMOVABLE) {
263 cr.ui.contextMenuHandler.setContextMenu(this.items[i].rowElement,
264 this.contextMenu_);
265 }
266 }
267 },
268
269 /**
270 * Invoked when the root list is changed.
271 * @private
272 */
273 onRootsListChanged_: function() {
274 var rootsList = this.rootsList_;
275 updateSubElementsFromList(this,
276 rootsList.item.bind(rootsList),
277 this.directoryModel_);
278 this.setContextMenu(this.contextMenu_);
279 },
280
281 /**
282 * Returns the path of the current selected item.
283 * @return {string} The current path.
284 */
285 getCurrentPath: function() {
286 return this.selectedItem ? this.selectedItem.fullPath : null;
287 }
288 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698