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

Side by Side Diff: chrome/browser/resources/file_manager/js/ui/breadcrumbs_controller.js

Issue 39123003: [Files.app] Split the JavaScript files into subdirectories: common, background, and foreground (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed test failure. Created 7 years, 2 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 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 'use strict';
6
7 /**
8 * @extends cr.EventTarget
9 * @param {HTMLDivElement} div Div container for breadcrumbs.
10 * @param {MetadataCache} metadataCache To retrieve metadata.
11 * @constructor
12 */
13 function BreadcrumbsController(div, metadataCache) {
14 this.metadataCache_ = metadataCache;
15 this.bc_ = div;
16 this.hideLast_ = false;
17 this.rootPath_ = null;
18 this.path_ = null;
19 this.rootPathOverride_ = null;
20 div.addEventListener('click', this.onClick_.bind(this));
21 }
22
23 /**
24 * Extends cr.EventTarget.
25 */
26 BreadcrumbsController.prototype.__proto__ = cr.EventTarget.prototype;
27
28 /**
29 * Whether to hide the last part of the path.
30 * @param {boolean} value True if hide.
31 */
32 BreadcrumbsController.prototype.setHideLast = function(value) {
33 this.hideLast_ = value;
34 };
35
36 /**
37 * Update the breadcrumb display.
38 * TODO(haruki): Remove |rootPath|. It only needs |path|, as |rootPath| can be
39 * derived.
40 *
41 * @param {string} rootPath Path to root.
42 * @param {string} path Path to directory.
43 */
44 BreadcrumbsController.prototype.update = function(rootPath, path) {
45 if (path == this.path_)
46 return;
47
48 // Clear the content and store |path|.
49 this.bc_.textContent = '';
50 this.rootPath_ = rootPath;
51 this.path_ = path;
52
53 // determineRootPathOverride_() may call MetadataCache to retrieve
54 // shared-with-me property and call the callback asynchronously.
55 this.determineRootPathOverride_(
56 rootPath, path, function(requestedPath, rootPathOverride) {
57 if (requestedPath != path) {
58 // Another update() is called. Ignore this old callback.
59 return;
60 }
61 this.rootPathOverride_ = rootPathOverride;
62 this.updateInternal_(rootPath, path, rootPathOverride);
63 }.bind(this));
64 };
65
66 /**
67 * Check the given path and determines if the breadcrumb should show "Shared
68 * with me" as the first crumb. RootDirectory.DRIVE_SHARED_WITH_ME is used as
69 * the first crumb if |path| is a shared-with-me directory outside "My Drive".
70 * See updateInternal_().
71 *
72 * @param {string} rootPath Path to root.
73 * @param {string} path Path to directory.
74 * @param {function(string, !string)} callback Function to call with |path| and
75 * the determined root path override.
76 * @private
77 */
78 BreadcrumbsController.prototype.determineRootPathOverride_ =
79 function(rootPath, path, callback) {
80 if (rootPath != RootDirectory.DRIVE + '/' + DriveSubRootDirectory.OTHER ||
81 rootPath == path) {
82 callback(path, null); // No need for Drive properties.
83 return;
84 }
85
86 var delimiterPos = path.indexOf('/', rootPath.length + 1);
87 var firstDirPath = delimiterPos > 0 ? path.substring(0, delimiterPos) : path;
88 var entryUrl = util.makeFilesystemUrl(firstDirPath);
89
90 this.metadataCache_.getOne(entryUrl, 'drive', function(result) {
91 callback(path,
92 result && result.sharedWithMe ?
93 RootDirectory.DRIVE_SHARED_WITH_ME :
94 null);
95 });
96 };
97
98 /**
99 * Update the breadcrumb display.
100 * @private
101 */
102 BreadcrumbsController.prototype.updateInternal_ = function() {
103 var relativePath =
104 this.path_.substring(this.rootPath_.length).replace(/\/$/, '');
105 var pathNames = relativePath.split('/');
106 if (pathNames[0] == '')
107 pathNames.splice(0, 1);
108
109 // We need a first breadcrumb for root, so placing last name from
110 // rootPath as first name of relativePath.
111 var rootPathNames = this.rootPath_.replace(/\/$/, '').split('/');
112 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]);
113 rootPathNames.splice(rootPathNames.length - 1, 1);
114 var path = rootPathNames.join('/') + '/';
115
116 var doc = this.bc_.ownerDocument;
117
118 var divAdded = false;
119 for (var i = 0;
120 i < (this.hideLast_ ? pathNames.length - 1 : pathNames.length);
121 i++) {
122 if (divAdded) {
123 var spacer = doc.createElement('div');
124 spacer.className = 'separator';
125 this.bc_.appendChild(spacer);
126 }
127 var pathName = pathNames[i];
128 path += pathName;
129
130 // We have a special case for the root crumb /drive/other, which contains
131 // the Drive entries not in "My Drive". It is hidden as this path is not
132 // meaningful for the user.
133 if (i == 0 &&
134 path === RootDirectory.DRIVE + '/' + DriveSubRootDirectory.OTHER &&
135 this.rootPathOverride_ == null) {
136 continue;
137 }
138
139 // Create a crumb.
140 var div = doc.createElement('div');
141 div.className = 'breadcrumb-path';
142 div.textContent = i == 0 ?
143 PathUtil.getRootLabel(this.rootPathOverride_ || path) :
144 pathName;
145
146 path = path + '/';
147
148 this.bc_.appendChild(div);
149 divAdded = true;
150
151 if (i == pathNames.length - 1)
152 div.classList.add('breadcrumb-last');
153 }
154 this.truncate();
155 };
156
157 /**
158 * Updates breadcrumbs widths in order to truncate it properly.
159 */
160 BreadcrumbsController.prototype.truncate = function() {
161 if (!this.bc_.firstChild)
162 return;
163
164 // Assume style.width == clientWidth (items have no margins or paddings).
165
166 for (var item = this.bc_.firstChild; item; item = item.nextSibling) {
167 item.removeAttribute('style');
168 item.removeAttribute('collapsed');
169 }
170
171 var containerWidth = this.bc_.clientWidth;
172
173 var pathWidth = 0;
174 var currentWidth = 0;
175 var lastSeparator;
176 for (var item = this.bc_.firstChild; item; item = item.nextSibling) {
177 if (item.className == 'separator') {
178 pathWidth += currentWidth;
179 currentWidth = item.clientWidth;
180 lastSeparator = item;
181 } else {
182 currentWidth += item.clientWidth;
183 }
184 }
185 if (pathWidth + currentWidth <= containerWidth)
186 return;
187 if (!lastSeparator) {
188 this.bc_.lastChild.style.width = Math.min(currentWidth, containerWidth) +
189 'px';
190 return;
191 }
192 var lastCrumbSeparatorWidth = lastSeparator.clientWidth;
193 // Current directory name may occupy up to 70% of space or even more if the
194 // path is short.
195 var maxPathWidth = Math.max(Math.round(containerWidth * 0.3),
196 containerWidth - currentWidth);
197 maxPathWidth = Math.min(pathWidth, maxPathWidth);
198
199 var parentCrumb = lastSeparator.previousSibling;
200 var collapsedWidth = 0;
201 if (parentCrumb && pathWidth - maxPathWidth > parentCrumb.clientWidth) {
202 // At least one crumb is hidden completely (or almost completely).
203 // Show sign of hidden crumbs like this:
204 // root > some di... > ... > current directory.
205 parentCrumb.setAttribute('collapsed', '');
206 collapsedWidth = Math.min(maxPathWidth, parentCrumb.clientWidth);
207 maxPathWidth -= collapsedWidth;
208 if (parentCrumb.clientWidth != collapsedWidth)
209 parentCrumb.style.width = collapsedWidth + 'px';
210
211 lastSeparator = parentCrumb.previousSibling;
212 if (!lastSeparator)
213 return;
214 collapsedWidth += lastSeparator.clientWidth;
215 maxPathWidth = Math.max(0, maxPathWidth - lastSeparator.clientWidth);
216 }
217
218 pathWidth = 0;
219 for (var item = this.bc_.firstChild; item != lastSeparator;
220 item = item.nextSibling) {
221 // TODO(serya): Mixing access item.clientWidth and modifying style and
222 // attributes could cause multiple layout reflows.
223 if (pathWidth + item.clientWidth <= maxPathWidth) {
224 pathWidth += item.clientWidth;
225 } else if (pathWidth == maxPathWidth) {
226 item.style.width = '0';
227 } else if (item.classList.contains('separator')) {
228 // Do not truncate separator. Instead let the last crumb be longer.
229 item.style.width = '0';
230 maxPathWidth = pathWidth;
231 } else {
232 // Truncate the last visible crumb.
233 item.style.width = (maxPathWidth - pathWidth) + 'px';
234 pathWidth = maxPathWidth;
235 }
236 }
237
238 currentWidth = Math.min(currentWidth,
239 containerWidth - pathWidth - collapsedWidth);
240 this.bc_.lastChild.style.width =
241 (currentWidth - lastCrumbSeparatorWidth) + 'px';
242 };
243
244 /**
245 * Show breadcrumbs.
246 * @param {string} rootPath Path to root.
247 * @param {string} path Path to directory.
248 */
249 BreadcrumbsController.prototype.show = function(rootPath, path) {
250 this.bc_.hidden = false;
251 this.update(rootPath, path);
252 };
253
254 /**
255 * Hide breadcrumbs div.
256 */
257 BreadcrumbsController.prototype.hide = function() {
258 this.bc_.hidden = true;
259 };
260
261 /**
262 * Handle a click event on a breadcrumb element.
263 * @param {Event} event The click event.
264 * @private
265 */
266 BreadcrumbsController.prototype.onClick_ = function(event) {
267 var path = this.getTargetPath(event);
268 if (!path)
269 return;
270
271 var newEvent = new Event('pathclick');
272 newEvent.path = path;
273 this.dispatchEvent(newEvent);
274 };
275
276 /**
277 * Returns path associated with the event target. Returns empty string for
278 * inactive elements: separators, empty space and the last chunk.
279 * @param {Event} event The UI event.
280 * @return {string} Full path or empty string.
281 */
282 BreadcrumbsController.prototype.getTargetPath = function(event) {
283 if (!event.target.classList.contains('breadcrumb-path') ||
284 event.target.classList.contains('breadcrumb-last')) {
285 return '';
286 }
287
288 var items = this.bc_.querySelectorAll('.breadcrumb-path');
289 var path = this.rootPath_;
290
291 if (event.target == items[0]) {
292 // The first crumb can be overridden.
293 return this.rootPathOverride_ || path;
294 } else {
295 for (var i = 1; items[i - 1] != event.target; i++) {
296 path += '/' + items[i].textContent;
297 }
298 }
299 return path;
300 };
301
302 /**
303 * Returns the breadcrumbs container.
304 * @return {HTMLElement} Breadcumbs container HTML element.
305 */
306 BreadcrumbsController.prototype.getContainer = function() {
307 return this.bc_;
308 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/js/tree.css.js ('k') | chrome/browser/resources/file_manager/js/ui/conflict_dialog.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698