Commit 38799850 authored by oleg@chromium.org's avatar oleg@chromium.org

Move all the butter bar code to a separate class. Fix some style, method &...

Move all the butter bar code to a separate class. Fix some style, method & variable names and simplify code.

BUG=134601
TEST=Progress is shown while copying files. Error messages in butter bar are shown and hidden appropriately.


Review URL: https://chromiumcodereview.appspot.com/10824145

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149634 0039d316-1c4b-4281-b951-d872f2087c98
parent abb77e62
...@@ -80,7 +80,7 @@ input[type='submit'][disabled]:hover { ...@@ -80,7 +80,7 @@ input[type='submit'][disabled]:hover {
opacity: 0.8; opacity: 0.8;
} }
.butter-bar { #butter-bar {
-webkit-box-align: end; -webkit-box-align: end;
-webkit-box-orient: horizontal; -webkit-box-orient: horizontal;
-webkit-transform: translate3d(0, 1px, 0); -webkit-transform: translate3d(0, 1px, 0);
...@@ -96,17 +96,17 @@ input[type='submit'][disabled]:hover { ...@@ -96,17 +96,17 @@ input[type='submit'][disabled]:hover {
top: 0; top: 0;
} }
.butter-bar.before-show { #butter-bar.before-show {
-webkit-transform: translate3d(0, -30px, 0); -webkit-transform: translate3d(0, -30px, 0);
opacity: 0; opacity: 0;
} }
.butter-bar.after-show { #butter-bar.after-show {
-webkit-transform: translate3d(0, 50px, 0); -webkit-transform: translate3d(0, 50px, 0);
opacity: 0; opacity: 0;
} }
.butter-bar .content { #butter-bar .content {
padding-bottom: 8px; padding-bottom: 8px;
padding-right: 5px; padding-right: 5px;
} }
...@@ -115,13 +115,13 @@ input[type='submit'][disabled]:hover { ...@@ -115,13 +115,13 @@ input[type='submit'][disabled]:hover {
display: none; display: none;
} }
.butter-bar .actions { #butter-bar .actions {
-webkit-box-orient: horizontal; -webkit-box-orient: horizontal;
-webkit-box-pack: end; -webkit-box-pack: end;
display: -webkit-box; display: -webkit-box;
} }
.butter-bar .actions a { #butter-bar .actions a {
background: center center no-repeat; background: center center no-repeat;
background-image: -webkit-image-set( background-image: -webkit-image-set(
url('../images/files/ui/close_bar.png') 1x, url('../images/files/ui/close_bar.png') 1x,
...@@ -132,7 +132,7 @@ input[type='submit'][disabled]:hover { ...@@ -132,7 +132,7 @@ input[type='submit'][disabled]:hover {
width: 12px; width: 12px;
} }
.butter-bar.error { #butter-bar.error {
background-color: rgba(221, 75, 57, 0.2); background-color: rgba(221, 75, 57, 0.2);
border: 1px solid rgba(221, 75, 57, 0.5); border: 1px solid rgba(221, 75, 57, 0.5);
border-radius: 2px; border-radius: 2px;
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* The minimum about of time to display the butter bar for, in ms.
* Justification is 1000ms for minimum display time plus 300ms for transition
* duration.
*/
var MINIMUM_BUTTER_DISPLAY_TIME_MS = 1300;
/**
* Butter bar is shown on top of the file list and is used to show the copy
* progress and other messages.
* @constructor
* @param {HTMLElement} dialogDom FileManager top-level div.
* @param {FileCopyManagerWrapper} copyManager The copy manager.
*/
function ButterBar(dialogDom, copyManager) {
this.dialogDom_ = dialogDom;
this.butter_ = this.dialogDom_.querySelector('#butter-bar');
this.document_ = this.butter_.ownerDocument;
this.copyManager_ = copyManager;
this.hideTimeout_ = null;
this.showTimeout_ = null;
this.visible_ = false;
this.lastShowTime_ = 0;
this.isError_ = false;
this.copyManager_.addEventListener('copy-progress',
this.onCopyProgress_.bind(this));
}
/**
* Show butter bar.
* @param {string} message The message to be shown.
* @param {object} opt_options Options: 'actions', 'progress', 'timeout'.
*/
ButterBar.prototype.show = function(message, opt_options) {
if (opt_options) {
if ('actions' in opt_options) {
var actions = this.butter_.querySelector('.actions');
while (actions.childNodes.length)
actions.removeChild(actions.firstChild);
for (var label in opt_options.actions) {
var link = this.document_.createElement('a');
link.addEventListener('click', function() {
opt_options.actions[label]();
return false;
});
actions.appendChild(link);
}
actions.classList.remove('hide-in-butter');
}
if ('progress' in opt_options) {
this.butter_.querySelector('.progress-bar').classList.remove(
'hide-in-butter');
}
}
this.visible_ = true;
this.isError_ = false;
this.update_(message, opt_options);
this.lastShowTime_ = Date.now();
};
/**
* Show error message in butter bar.
* @private
* @param {string} message Message.
* @param {object} opt_options Same as in show().
*/
ButterBar.prototype.showError_ = function(message, opt_options) {
this.show(message, opt_options);
this.isError_ = true;
this.butter_.classList.add('error');
};
/**
* Set message and/or progress.
* @private
* @param {string} message Message.
* @param {object} opt_options Same as in show().
*/
ButterBar.prototype.update_ = function(message, opt_options) {
if (!opt_options)
opt_options = {};
var timeout = ('timeout' in opt_options) ? opt_options.timeout : 10 * 1000;
if (this.hideTimeout_)
clearTimeout(this.hideTimeout_);
if (timeout) {
this.hideTimeout_ = setTimeout(function() {
this.hideButter();
this.hideTimeout_ = null;
}.bind(this), timeout);
}
this.butter_.querySelector('.butter-message').textContent = message;
if (message) {
// The butter bar is made visible on the first non-empty message.
this.butter_.classList.remove('before-show');
}
if (opt_options && 'progress' in opt_options) {
this.butter_.querySelector('.progress-track').style.width =
(opt_options.progress * 100) + '%';
}
this.butter_.style.left =
(this.dialogDom_.clientWidth - this.butter_.clientWidth) / 2 + 'px';
};
/**
* Hide butter bar. There might be some delay before hiding so that butter bar
* would be shown for no less than the minimal time.
* @private
*/
ButterBar.prototype.hide_ = function() {
if (this.visible_) {
var delay = Math.max(
MINIMUM_BUTTER_DISPLAY_TIME_MS - (Date.now() - this.lastShowTime_), 0);
var butter = this.butter_;
function hideButter() {
butter.classList.remove('error');
butter.classList.remove('after-show');
butter.classList.add('before-show');
butter.querySelector('.actions').classList.add('hide-in-butter');
butter.querySelector('.progress-bar').classList.add('hide-in-butter');
}
setTimeout(function() { butter.classList.add('after-show'); }, delay);
setTimeout(hideButter, delay + 1000);
this.visible_ = false;
}
};
/**
* If butter bar shows an error message, close it.
* @return {boolean} True if butter bar was closed.
*/
ButterBar.prototype.hideError = function() {
if (this.visible_ && this.isError_) {
this.hide_();
clearTimeout(this.hideTimeout_);
return true;
} else {
return false;
}
};
/**
* Init butter bar for showing copy progress.
* @private
*/
ButterBar.prototype.init_ = function() {
var progress = this.copyManager_.getProgress();
var options = {progress: progress.percentage, actions: {}, timeout: 0};
options.actions[str('CANCEL_LABEL')] =
this.copyManager_.requestCancel.bind(this.copyManager_);
this.show(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), options);
};
/**
* 'copy-progress' event handler. Show progress or an appropriate message.
* @private
* @param {cr.Event} event A 'copy-progress' event from FileCopyManager.
*/
ButterBar.prototype.onCopyProgress_ = function(event) {
var progress = this.copyManager_.getProgress();
switch (event.reason) {
case 'BEGIN':
this.hide_();
clearTimeout(this.timeout_);
// If the copy process lasts more than 500 ms, we show a progress bar.
this.showTimeout_ = setTimeout(this.init_.bind(this), 500);
break;
case 'PROGRESS':
if (this.visible_) {
var options = {'progress': progress.percentage, timeout: 0};
this.update_(strf('PASTE_ITEMS_REMAINING', progress.pendingItems),
options);
}
break;
case 'SUCCESS':
clearTimeout(this.showTimeout_);
this.hide_();
break;
case 'CANCELLED':
this.show(str('PASTE_CANCELLED'), {timeout: 1000});
break;
case 'ERROR':
clearTimeout(this.showTimeout_);
if (event.error.reason === 'TARGET_EXISTS') {
var name = event.error.data.name;
if (event.error.data.isDirectory)
name += '/';
this.showError_(strf('PASTE_TARGET_EXISTS_ERROR', name));
} else if (event.error.reason === 'FILESYSTEM_ERROR') {
if (event.error.data.toGDrive &&
event.error.data.code === FileError.QUOTA_EXCEEDED_ERR) {
// The alert will be shown in FileManager.onCopyProgress_.
this.hide_();
} else {
this.showError_(strf('PASTE_FILESYSTEM_ERROR',
getFileErrorString(event.error.data.code)));
}
} else {
this.showError_(strf('PASTE_UNEXPECTED_ERROR', event.error));
}
break;
default:
console.log('Unknown "copy-progress" event reason: ' + event.reason);
}
};
...@@ -24,10 +24,6 @@ function FileManager(dialogDom) { ...@@ -24,10 +24,6 @@ function FileManager(dialogDom) {
this.selection = null; this.selection = null;
this.butterTimer_ = null;
this.currentButter_ = null;
this.butterLastShowTime_ = 0;
this.filesystemObserverId_ = null; this.filesystemObserverId_ = null;
this.gdataObserverId_ = null; this.gdataObserverId_ = null;
...@@ -114,13 +110,6 @@ FileManager.prototype = { ...@@ -114,13 +110,6 @@ FileManager.prototype = {
*/ */
var IMAGE_HOVER_PREVIEW_SIZE = 200; var IMAGE_HOVER_PREVIEW_SIZE = 200;
/**
* The minimum about of time to display the butter bar for, in ms.
* Justification is 1000ms for minimum display time plus 300ms for transition
* duration.
*/
var MINIMUM_BUTTER_DISPLAY_TIME_MS = 1300;
/** /**
* Number of milliseconds in a day. * Number of milliseconds in a day.
*/ */
...@@ -162,33 +151,6 @@ FileManager.prototype = { ...@@ -162,33 +151,6 @@ FileManager.prototype = {
fileManager.decorateThumbnail_(li, showCheckbox, entry); fileManager.decorateThumbnail_(li, showCheckbox, entry);
}; };
/**
* Return a translated string.
*
* Wrapper function to make dealing with translated strings more concise.
* Equivalent to loadTimeData.getString(id).
*
* @param {string} id The id of the string to return.
* @return {string} The translated string.
*/
function str(id) {
return loadTimeData.getString(id);
}
/**
* Return a translated string with arguments replaced.
*
* Wrapper function to make dealing with translated strings more concise.
* Equivilant to loadTimeData.getStringF(id, ...).
*
* @param {string} id The id of the string to return.
* @param {...string} The values to replace into the string.
* @return {string} The translated string with replaced values.
*/
function strf(id, var_args) {
return loadTimeData.getStringF.apply(loadTimeData, arguments);
}
/** /**
* @param {number} code File error code (from FileError object). * @param {number} code File error code (from FileError object).
* @return {string} Translated file error string. * @return {string} Translated file error string.
...@@ -527,6 +489,8 @@ FileManager.prototype = { ...@@ -527,6 +489,8 @@ FileManager.prototype = {
this.copyManager_.addEventListener('copy-operation-complete', this.copyManager_.addEventListener('copy-operation-complete',
this.onCopyManagerOperationComplete_.bind(this)); this.onCopyManagerOperationComplete_.bind(this));
this.butterBar_ = new ButterBar(this.dialogDom_, this.copyManager_);
var controller = this.fileTransferController_ = new FileTransferController( var controller = this.fileTransferController_ = new FileTransferController(
GridItem.bind(null, this, false /* no checkbox */), GridItem.bind(null, this, false /* no checkbox */),
this.copyManager_, this.copyManager_,
...@@ -613,7 +577,6 @@ FileManager.prototype = { ...@@ -613,7 +577,6 @@ FileManager.prototype = {
this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid');
this.spinner_ = this.dialogDom_.querySelector('#spinner-with-text'); this.spinner_ = this.dialogDom_.querySelector('#spinner-with-text');
this.showSpinner_(false); this.showSpinner_(false);
this.butter_ = this.dialogDom_.querySelector('.butter-bar');
this.unmountedPanel_ = this.dialogDom_.querySelector('#unmounted-panel'); this.unmountedPanel_ = this.dialogDom_.querySelector('#unmounted-panel');
this.breadcrumbs_ = new BreadcrumbsController( this.breadcrumbs_ = new BreadcrumbsController(
...@@ -939,106 +902,6 @@ FileManager.prototype = { ...@@ -939,106 +902,6 @@ FileManager.prototype = {
this.currentList_.focus(); this.currentList_.focus();
}; };
FileManager.prototype.showButter = function(message, opt_options) {
var butter = this.butter_;
if (opt_options) {
if ('actions' in opt_options) {
var actions = butter.querySelector('.actions');
while (actions.childNodes.length)
actions.removeChild(actions.firstChild);
for (var label in opt_options.actions) {
var link = this.document_.createElement('a');
link.addEventListener('click', function() {
opt_options.actions[label]();
return false;
});
actions.appendChild(link);
}
actions.classList.remove('hide-in-butter');
}
if ('progress' in opt_options) {
butter.querySelector('.progress-bar')
.classList.remove('hide-in-butter');
}
}
var self = this;
setTimeout(function() {
self.currentButter_ = butter;
self.updateButter(message, opt_options);
self.butterLastShowTime_ = new Date();
});
return butter;
};
FileManager.prototype.showButterError = function(message, opt_options) {
var butter = this.showButter(message, opt_options);
butter.classList.add('error');
return butter;
};
FileManager.prototype.updateButter = function(message, opt_options) {
if (!opt_options)
opt_options = {};
var timeout;
if ('timeout' in opt_options) {
timeout = opt_options.timeout;
} else {
timeout = 10 * 1000;
}
if (this.butterTimer_)
clearTimeout(this.butterTimer_);
if (timeout) {
var self = this;
this.butterTimer_ = setTimeout(function() {
self.hideButter();
self.butterTimer_ = null;
}, timeout);
}
var butter = this.currentButter_;
butter.querySelector('.butter-message').textContent = message;
if (message) {
// The butter bar is made visible on the first non-empty message.
butter.classList.remove('before-show');
}
if (opt_options && 'progress' in opt_options) {
butter.querySelector('.progress-track').style.width =
(opt_options.progress * 100) + '%';
}
butter.style.left = ((this.dialogDom_.clientWidth -
butter.clientWidth) / 2) + 'px';
};
FileManager.prototype.hideButter = function() {
if (this.currentButter_) {
var delay = Math.max(MINIMUM_BUTTER_DISPLAY_TIME_MS -
(new Date() - this.butterLastShowTime_), 0);
var butter = this.currentButter_;
setTimeout(function() {
butter.classList.add('after-show');
}, delay);
setTimeout(function() {
butter.classList.remove('error');
butter.classList.remove('after-show');
butter.classList.add('before-show');
butter.querySelector('.actions').classList.add('hide-in-butter');
butter.querySelector('.progress-bar').classList.add('hide-in-butter');
}, delay + 1000);
this.currentButter_ = null;
}
};
/** /**
* Index of selected item in the typeList of the dialog params. * Index of selected item in the typeList of the dialog params.
* @return {number} 1-based index of selected type or 0 if no type selected. * @return {number} 1-based index of selected type or 0 if no type selected.
...@@ -1265,79 +1128,17 @@ FileManager.prototype = { ...@@ -1265,79 +1128,17 @@ FileManager.prototype = {
this.fileContextMenu_); this.fileContextMenu_);
}; };
FileManager.prototype.initButter_ = function() {
var self = this;
var progress = this.copyManager_.getProgress();
var options = {progress: progress.percentage, actions: {}, timeout: 0};
options.actions[str('CANCEL_LABEL')] = function cancelPaste() {
self.copyManager_.requestCancel();
};
this.showButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems),
options);
};
FileManager.prototype.onCopyProgress_ = function(event) { FileManager.prototype.onCopyProgress_ = function(event) {
var progress = this.copyManager_.getProgress(); if (event.reason === 'ERROR' &&
event.error.reason === 'FILESYSTEM_ERROR' &&
if (event.reason == 'BEGIN') { event.error.data.toGDrive &&
if (this.currentButter_) event.error.data.code == FileError.QUOTA_EXCEEDED_ERR) {
this.hideButter(); this.alert.showHtml(
strf('GDATA_SERVER_OUT_OF_SPACE_HEADER'),
clearTimeout(this.butterTimeout_); strf('GDATA_SERVER_OUT_OF_SPACE_MESSAGE',
// If the copy process lasts more than 500 ms, we show a progress bar. decodeURIComponent(
this.butterTimeout_ = setTimeout(this.initButter_.bind(this), 500); event.error.data.sourceFileUrl.split('/').pop()),
return; GOOGLE_DRIVE_BUY_STORAGE));
}
if (event.reason == 'PROGRESS') {
// Perform this check inside Progress event handler, avoid to log error
// message 'Unknown event reason: PROGRESS' in console.
if (this.currentButter_) {
var options = {progress: progress.percentage, timeout: 0};
this.updateButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems),
options);
}
return;
}
if (event.reason == 'SUCCESS') {
clearTimeout(this.butterTimeout_);
if (this.currentButter_)
this.hideButter();
} else if (event.reason == 'ERROR') {
clearTimeout(this.butterTimeout_);
switch (event.error.reason) {
case 'TARGET_EXISTS':
var name = event.error.data.name;
if (event.error.data.isDirectory)
name += '/';
this.showButterError(strf('PASTE_TARGET_EXISTS_ERROR', name));
break;
case 'FILESYSTEM_ERROR':
if (event.error.data.toGDrive &&
event.error.data.code == FileError.QUOTA_EXCEEDED_ERR) {
this.hideButter();
this.alert.showHtml(
strf('GDATA_SERVER_OUT_OF_SPACE_HEADER'),
strf('GDATA_SERVER_OUT_OF_SPACE_MESSAGE',
decodeURIComponent(
event.error.data.sourceFileUrl.split('/').pop()),
GOOGLE_DRIVE_BUY_STORAGE));
} else {
this.showButterError(
strf('PASTE_FILESYSTEM_ERROR',
getFileErrorString(event.error.data.code)));
}
break;
default:
this.showButterError(strf('PASTE_UNEXPECTED_ERROR', event.error));
break;
}
} else if (event.reason == 'CANCELLED') {
this.showButter(str('PASTE_CANCELLED'), {timeout: 1000});
} else {
console.log('Unknown event reason: ' + event.reason);
} }
// TODO(benchan): Currently, there is no FileWatcher emulation for // TODO(benchan): Currently, there is no FileWatcher emulation for
...@@ -1354,7 +1155,7 @@ FileManager.prototype = { ...@@ -1354,7 +1155,7 @@ FileManager.prototype = {
/** /**
* Handler of file manager operations. Update directory model * Handler of file manager operations. Update directory model
* to reflect operation result iimediatelly (not waiting directory * to reflect operation result immediatelly (not waiting directory
* update event). * update event).
*/ */
FileManager.prototype.onCopyManagerOperationComplete_ = function(event) { FileManager.prototype.onCopyManagerOperationComplete_ = function(event) {
...@@ -3075,9 +2876,9 @@ FileManager.prototype = { ...@@ -3075,9 +2876,9 @@ FileManager.prototype = {
var mountError = this.volumeManager_.getMountError( var mountError = this.volumeManager_.getMountError(
PathUtil.getRootPath(entry.fullPath)); PathUtil.getRootPath(entry.fullPath));
if (mountError == VolumeManager.Error.UNKNOWN_FILESYSTEM) { if (mountError == VolumeManager.Error.UNKNOWN_FILESYSTEM) {
return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING')); return this.butterBar_.show(str('UNKNOWN_FILESYSTEM_WARNING'));
} else if (mountError == VolumeManager.Error.UNSUPPORTED_FILESYSTEM) { } else if (mountError == VolumeManager.Error.UNSUPPORTED_FILESYSTEM) {
return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); return this.butterBar_.show(str('UNSUPPORTED_FILESYSTEM_WARNING'));
} }
return this.directoryModel_.changeDirectory(entry.fullPath); return this.directoryModel_.changeDirectory(entry.fullPath);
...@@ -3439,10 +3240,8 @@ FileManager.prototype = { ...@@ -3439,10 +3240,8 @@ FileManager.prototype = {
return; return;
} }
if (this.butterTimer_) { if (this.butterBar_.hideError()) {
// Allow the user to manually dismiss timed butter messages.
event.preventDefault(); event.preventDefault();
this.hideButter();
return; return;
} }
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
//<include src="path_util.js"/> //<include src="path_util.js"/>
//<include src="util.js"/> //<include src="util.js"/>
//<include src="breadcrumbs_controller.js"/> //<include src="breadcrumbs_controller.js"/>
//<include src="butter_bar.js"/>
//<include src="directory_contents.js"> //<include src="directory_contents.js">
//<include src="directory_model.js"/> //<include src="directory_model.js"/>
//<include src="file_copy_manager_wrapper.js"/> //<include src="file_copy_manager_wrapper.js"/>
......
...@@ -610,3 +610,31 @@ util.traverseTree = function(root, callback, max_depth) { ...@@ -610,3 +610,31 @@ util.traverseTree = function(root, callback, max_depth) {
readEntry(root, 0); readEntry(root, 0);
}; };
/**
* Return a translated string.
*
* Wrapper function to make dealing with translated strings more concise.
* Equivalent to loadTimeData.getString(id).
*
* @param {string} id The id of the string to return.
* @return {string} The translated string.
*/
function str(id) {
return loadTimeData.getString(id);
}
/**
* Return a translated string with arguments replaced.
*
* Wrapper function to make dealing with translated strings more concise.
* Equivilant to loadTimeData.getStringF(id, ...).
*
* @param {string} id The id of the string to return.
* @param {...string} var_args The values to replace into the string.
* @return {string} The translated string with replaced values.
*/
function strf(id, var_args) {
return loadTimeData.getStringF.apply(loadTimeData, arguments);
}
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
<script src="js/path_util.js"></script> <script src="js/path_util.js"></script>
<script src="js/util.js"></script> <script src="js/util.js"></script>
<script src="js/breadcrumbs_controller.js"></script> <script src="js/breadcrumbs_controller.js"></script>
<script src="js/butter_bar.js"></script>
<script src="js/directory_contents.js"></script> <script src="js/directory_contents.js"></script>
<script src="js/directory_model.js"></script> <script src="js/directory_model.js"></script>
<script src="js/file_copy_manager_wrapper.js"></script> <script src="js/file_copy_manager_wrapper.js"></script>
...@@ -237,7 +238,7 @@ ...@@ -237,7 +238,7 @@
</div> </div>
<button class=cancel i18n-content=CANCEL_LABEL>[CANCEL]</button> <button class=cancel i18n-content=CANCEL_LABEL>[CANCEL]</button>
</div> </div>
<div class="butter-bar before-show"> <div id="butter-bar" class="before-show">
<div class="content"> <div class="content">
<div class="butter-message"></div> <div class="butter-message"></div>
<div class="progress-bar hide-in-butter"> <div class="progress-bar hide-in-butter">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment