1 // Copyright (c) 2012 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.
8 * Butter bar is shown on top of the file list and is used to show the copy
9 * progress and other messages.
10 * @param {HTMLElement} dialogDom FileManager top-level div.
11 * @param {FileOperationManagerWrapper} fileOperationManager The operation
15 function ButterBar(dialogDom, fileOperationManager) {
16 this.dialogDom_ = dialogDom;
17 this.butter_ = this.dialogDom_.querySelector('#butter-bar');
18 this.document_ = this.butter_.ownerDocument;
19 this.fileOperationManager_ = fileOperationManager;
20 this.hideTimeout_ = null;
21 this.showTimeout_ = null;
22 this.lastShowTime_ = 0;
23 this.deleteTaskId_ = null;
24 this.currentMode_ = null;
25 this.totalDeleted_ = 0;
26 this.lastProgressValue_ = 0;
27 this.alert_ = new ErrorDialog(this.dialogDom_);
29 this.onCopyProgressBound_ = this.onCopyProgress_.bind(this);
30 this.fileOperationManager_.addEventListener(
31 'copy-progress', this.onCopyProgressBound_);
32 this.onDeleteBound_ = this.onDelete_.bind(this);
33 this.fileOperationManager_.addEventListener('delete', this.onDeleteBound_);
37 * The default amount of milliseconds time, before a butter bar will hide after
43 ButterBar.HIDE_DELAY_TIME_MS_ = 2000;
46 * Name of action which should be displayed as an 'x' button instead of
50 ButterBar.ACTION_X = '--action--x--';
62 * Disposes the instance. No methods should be called after this method's
65 ButterBar.prototype.dispose = function() {
66 // Unregister listeners from FileOperationManager.
67 this.fileOperationManager_.removeEventListener(
68 'copy-progress', this.onCopyProgressBound_);
69 this.fileOperationManager_.removeEventListener('delete', this.onDeleteBound_);
73 * @return {boolean} True if visible.
76 ButterBar.prototype.isVisible_ = function() {
77 return this.butter_.classList.contains('visible');
82 * @param {ButterBar.Mode} mode Butter bar mode.
83 * @param {string} message The message to be shown.
84 * @param {Object=} opt_options Options: 'actions', 'progress', 'timeout'. If
85 * 'timeout' is not specified, HIDE_DELAY_TIME_MS_ is used. If 'timeout' is
86 * false, the butter bar will not be hidden.
88 ButterBar.prototype.show = function(mode, message, opt_options) {
89 this.currentMode_ = mode;
91 this.clearShowTimeout_();
92 this.clearHideTimeout_();
94 var actions = this.butter_.querySelector('.actions');
95 actions.textContent = '';
96 if (opt_options && 'actions' in opt_options) {
97 for (var label in opt_options.actions) {
98 var link = this.document_.createElement('a');
99 link.addEventListener('click', function(callback) {
102 }.bind(null, opt_options.actions[label]));
103 if (label == ButterBar.ACTION_X) {
104 link.className = 'x';
106 link.textContent = label;
108 actions.appendChild(link);
110 actions.hidden = false;
112 actions.hidden = true;
115 this.butter_.querySelector('.progress-bar').hidden =
116 !(opt_options && 'progress' in opt_options);
118 this.butter_.classList.remove('error');
119 this.butter_.classList.remove('visible'); // Will be shown in update_
120 this.update_(message, opt_options);
124 * Show an error message in a popup dialog.
125 * @param {string} message Message.
128 ButterBar.prototype.showError_ = function(message) {
129 // Wait in case there are previous dialogs being closed.
130 setTimeout(function() {
131 this.alert_.showHtml('', // Title.
134 }.bind(this), cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION);
138 * Set message and/or progress.
139 * @param {string} message Message.
140 * @param {Object=} opt_options Same as in show().
143 ButterBar.prototype.update_ = function(message, opt_options) {
147 this.clearHideTimeout_();
149 var butterMessage = this.butter_.querySelector('.butter-message');
150 butterMessage.textContent = message;
151 if (message && !this.isVisible_()) {
152 // The butter bar is made visible on the first non-empty message.
153 this.butter_.classList.add('visible');
155 if (opt_options && 'progress' in opt_options) {
156 butterMessage.classList.add('single-line');
157 var progressTrack = this.butter_.querySelector('.progress-track');
158 // Smoothen the progress only when it goes forward. Especially do not
159 // do the transition effect if resetting to 0.
160 if (opt_options.progress > this.lastProgressValue_)
161 progressTrack.classList.add('smoothed');
163 progressTrack.classList.remove('smoothed');
164 progressTrack.style.width = (opt_options.progress * 100) + '%';
165 this.lastProgressValue_ = opt_options.progress;
167 butterMessage.classList.remove('single-line');
170 if (opt_options.timeout !== false)
171 this.hide_(opt_options.timeout);
175 * Hide butter bar. There might be the delay before hiding so that butter bar
176 * would be shown for no less than the minimal time.
177 * @param {number=} opt_timeout Delay time in milliseconds before hidding. If it
178 * is zero, butter bar is hidden immediatelly. If it is not specified,
179 * HIDE_DELAY_TIME_MS_ is used.
182 ButterBar.prototype.hide_ = function(opt_timeout) {
183 this.clearHideTimeout_();
185 if (!this.isVisible_())
188 var delay = typeof opt_timeout != 'undefined' ?
189 opt_timeout : ButterBar.HIDE_DELAY_TIME_MS_;
191 this.currentMode_ = null;
192 this.butter_.classList.remove('visible');
193 this.butter_.querySelector('.progress-bar').hidden = true;
195 // Reschedule hide to comply with the minimal display time.
196 this.hideTimeout_ = setTimeout(function() {
197 this.hideTimeout_ = null;
199 }.bind(this), delay);
204 * Clear the show timeout if it is set.
207 ButterBar.prototype.clearShowTimeout_ = function() {
208 if (this.showTimeout_) {
209 clearTimeout(this.showTimeout_);
210 this.showTimeout_ = null;
215 * Clear the hide timeout if it is set.
218 ButterBar.prototype.clearHideTimeout_ = function() {
219 if (this.hideTimeout_) {
220 clearTimeout(this.hideTimeout_);
221 this.hideTimeout_ = null;
226 * @return {string} The type of operation.
229 ButterBar.prototype.transferType_ = function() {
230 var progress = this.progress_;
231 if (progress && progress.operationType)
232 return progress.operationType;
238 * Set up butter bar for showing copy progress.
240 * @param {Object} progress Copy status object created by
241 * FileOperationManager.getStatus().
244 ButterBar.prototype.showProgress_ = function(progress) {
245 this.progress_ = progress;
247 progress: progress.processedBytes / progress.totalBytes,
252 if (this.currentMode_ == ButterBar.Mode.COPY) {
253 this.update_('', options);
255 // Ignore the cancel behavior because the butter bar is already obsoleted.
256 options.actions[ButterBar.ACTION_X] = function() {
258 this.show(ButterBar.Mode.COPY, '', options);
263 * 'copy-progress' event handler. Show progress or an appropriate message.
264 * @param {Event} event A 'copy-progress' event from FileOperationManager.
267 ButterBar.prototype.onCopyProgress_ = function(event) {
268 // Delete operation has higher priority.
269 if (this.currentMode_ == ButterBar.Mode.DELETE)
272 if (event.reason != 'PROGRESS')
273 this.clearShowTimeout_();
275 switch (event.reason) {
277 this.showTimeout_ = setTimeout(function() {
278 this.showTimeout_ = null;
279 this.showProgress_(event.status);
284 this.showProgress_(event.status);
292 this.show(ButterBar.Mode.DELETE, '');
296 this.progress_ = event.status;
297 var error = event.error;
298 if (error.code === util.FileOperationErrorType.TARGET_EXISTS) {
299 var name = error.data.name;
300 if (error.data.isDirectory)
303 strf(this.transferType_() + '_TARGET_EXISTS_ERROR', name));
304 } else if (error.code === util.FileOperationErrorType.FILESYSTEM_ERROR) {
305 if (error.data.toDrive &&
306 error.data.code === FileError.QUOTA_EXCEEDED_ERR) {
307 // The alert will be shown in FileManager.onCopyProgress_.
310 this.showError_(strf(this.transferType_() + '_FILESYSTEM_ERROR',
311 util.getFileErrorString(error.data.code)));
315 strf(this.transferType_() + '_UNEXPECTED_ERROR', error));
320 console.warn('Unknown "copy-progress" event reason: ' + event.code);
325 * 'delete' event handler. Shows information about deleting files.
326 * @param {Event} event A 'delete' event from FileOperationManager.
329 ButterBar.prototype.onDelete_ = function(event) {
330 switch (event.reason) {
332 if (this.currentMode_ != ButterBar.Mode.DELETE)
333 this.totalDeleted_ = 0;
336 this.totalDeleted_ += event.urls.length;
338 if (this.totalDeleted_ == 1) {
339 var fullPath = util.extractFilePath(event.urls[0]);
340 var fileName = PathUtil.split(fullPath).pop();
344 if (this.currentMode_ == ButterBar.Mode.DELETE)
347 this.show(ButterBar.Mode.DELETE, title);
354 this.showError_(str('DELETE_ERROR'));
358 console.warn('Unknown "delete" event reason: ' + event.reason);