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

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

Issue 9839009: [filebrowser] Show progress indication, while files from GData are being downloaded. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Setting the src of an img to an empty string can crash the browser, so we 5 // Setting the src of an img to an empty string can crash the browser, so we
6 // use an empty 1x1 gif instead. 6 // use an empty 1x1 gif instead.
7 7
8 /** 8 /**
9 * FileManager constructor. 9 * FileManager constructor.
10 * 10 *
(...skipping 4024 matching lines...) Expand 10 before | Expand all | Expand 10 after
4035 } 4035 }
4036 } 4036 }
4037 callback(fileUrls); 4037 callback(fileUrls);
4038 }); 4038 });
4039 } else { 4039 } else {
4040 callback(fileUrls); 4040 callback(fileUrls);
4041 } 4041 }
4042 }, 4042 },
4043 4043
4044 /** 4044 /**
4045 * Selects a file. 4045 * Closes this modal dialog with some files selected.
4046 * 4046 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
4047 * @param {string} fileUrl The filename as a URL. 4047 * @param {Object} selection Contains urls, filterIndex and multiple fields.
4048 * @param {number} filterIndex The integer file filter index.
4049 */ 4048 */
4050 FileManager.prototype.selectFile_ = function(fileUrl, filterIndex) { 4049 FileManager.prototype.callSelectFilesApiAndClose_ = function(selection) {
4051 this.resolveSelectResults_( 4050 if (selection.multiple) {
4052 [fileUrl], 4051 chrome.fileBrowserPrivate.selectFiles(selection.urls);
4053 function(resolvedUrls) { 4052 } else {
4054 // Call doSelectFiles_ on a timeout, as it's unsafe to 4053 chrome.fileBrowserPrivate.selectFile(
4055 // close a window from a callback. 4054 selection.urls[0], selection.filterIndex);
4056 setTimeout( 4055 }
4057 this.doSelectFile_.bind(this, resolvedUrls[0], filterIndex), 0);
4058 }.bind(this));
4059 };
4060
4061 /**
4062 * Selects a file. Closes the window.
4063 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
4064 *
4065 * @param {string} fileUrl The filename as a URL.
4066 * @param {number} filterIndex The integer file filter index.
4067 */
4068 FileManager.prototype.doSelectFile_ = function(fileUrl, filterIndex) {
4069 chrome.fileBrowserPrivate.selectFile(fileUrl, filterIndex);
4070 this.onUnload_();
4071 window.close();
4072 };
4073
4074
4075 /**
4076 * Selects a file. Starts getting gdata files if needed.
4077 *
4078 * @param {Array.<string>} fileUrls Array of filename URLs.
4079 */
4080 FileManager.prototype.selectFiles_ = function(fileUrls) {
4081 this.resolveSelectResults_(
4082 fileUrls,
4083 function(resolvedUrls) {
4084 // Call doSelectFiles_ on a timeout, as it's unsafe to
4085 // close a window from a callback.
4086 setTimeout(this.doSelectFiles_.bind(this, resolvedUrls), 0);
4087 }.bind(this));
4088 };
4089
4090 /**
4091 * Selects multiple files. Closes the window.
4092 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811
4093 *
4094 * @param {Array.<string>} fileUrls Array of filename URLs.
4095 */
4096 FileManager.prototype.doSelectFiles_ = function(fileUrls) {
4097 chrome.fileBrowserPrivate.selectFiles(fileUrls);
4098 this.onUnload_(); 4056 this.onUnload_();
4099 window.close(); 4057 window.close();
4100 }; 4058 };
4101 4059
4102 /** 4060 /**
4061 * Tries to close this modal dialog with some files selected.
4062 * Performs preprocessing if needed (e.g. for GData).
4063 * @param {Object} selection Contains urls, filterIndex and multiple fields.
4064 */
4065 FileManager.prototype.selectFilesAndClose_ = function(selection) {
4066 if (!this.isOnGData()) {
4067 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
4068 return;
4069 }
4070
4071 var shade = this.document_.createElement('div');
4072 shade.className = 'shade';
4073 var footer = this.document_.querySelector('.dialog-footer');
4074 var progress = footer.querySelector('.progress-track');
4075 progress.style.width = '0%';
4076 var cancelled = false;
4077
4078 var progressMap = {};
4079 var filesStarted = 0;
4080 var filesTotal = selection.urls.length;
4081 for (var index = 0; index < selection.urls.length; index++) {
4082 progressMap[selection.urls[index]] = -1;
4083 }
4084 var lastPercent = 0;
4085 var bytesTotal = 0;
4086 var bytesDone = 0;
4087
4088 var onFileTransfersUpdated = function(statusList) {
4089 for (var index = 0; index < statusList.length; index++) {
4090 var status = statusList[index];
4091 var escaped = encodeURI(status.fileUrl);
4092 if (!(escaped in progressMap)) continue;
4093 if (status.total == -1) continue;
4094
4095 var old = progressMap[escaped];
4096 if (old == -1) {
4097 // -1 means we don't know file size yet.
4098 bytesTotal += status.total;
4099 filesStarted++;
4100 old = 0;
4101 }
4102 bytesDone += status.processed - old;
4103 progressMap[escaped] = status.processed;
4104 }
4105
4106 var percent = bytesTotal == 0 ? 0 : bytesDone / bytesTotal;
4107 // For files we don't have information about, assume the progress is zero.
4108 percent = percent * filesStarted / filesTotal * 100;
4109 // Do not decrease the progress. This may happen, if first downloaded
4110 // file is small, and the second one is large.
4111 lastPercent = Math.max(lastPercent, percent);
4112 progress.style.width = lastPercent + '%';
4113 }.bind(this);
4114
4115 var setup = function() {
4116 this.document_.querySelector('.dialog-container').appendChild(shade);
4117 setTimeout(function() { shade.setAttribute('fadein', 'fadein') }, 100);
4118 footer.setAttribute('progress', 'progress');
4119 this.cancelButton_.removeEventListener('click', this.onCancelBound_);
4120 this.cancelButton_.addEventListener('click', onCancel);
4121 chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener(
4122 onFileTransfersUpdated);
4123 }.bind(this);
4124
4125 var cleanup = function() {
4126 shade.parentNode.removeChild(shade);
4127 footer.removeAttribute('progress');
4128 this.cancelButton_.removeEventListener('click', onCancel);
4129 this.cancelButton_.addEventListener('click', this.onCancelBound_);
4130 chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener(
4131 onFileTransfersUpdated);
4132 }.bind(this);
4133
4134 var onCancel = function() {
4135 cancelled = true;
4136 // According to API cancel may fail, but there is no proper UI to reflect
4137 // this. So, we just silently assume that everything is cancelled.
4138 chrome.fileBrowserPrivate.cancelFileTransfers(
4139 selection.urls, function(response) {});
4140 cleanup();
4141 }.bind(this);
4142
4143 var onResolved = function(resolvedUrls) {
4144 if (cancelled) return;
4145 cleanup();
4146 selection.urls = resolvedUrls;
4147 // Call next method on a timeout, as it's unsafe to
4148 // close a window from a callback.
4149 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0);
4150 }.bind(this);
4151
4152 var onGotProperties = function(properties) {
4153 for (var i = 0; i < properties.length; i++) {
4154 if (properties[i].isPresent) {
4155 // For files already in GCache, we don't get any transfer updates.
4156 filesTotal--;
4157 }
4158 }
4159 this.resolveSelectResults_(selection.urls, onResolved);
4160 }.bind(this);
4161
4162 setup();
4163 chrome.fileBrowserPrivate.getGDataFileProperties(
4164 selection.urls, onGotProperties);
4165 };
4166
4167 /**
4103 * Handle a click of the ok button. 4168 * Handle a click of the ok button.
4104 * 4169 *
4105 * The ok button has different UI labels depending on the type of dialog, but 4170 * The ok button has different UI labels depending on the type of dialog, but
4106 * in code it's always referred to as 'ok'. 4171 * in code it's always referred to as 'ok'.
4107 * 4172 *
4108 * @param {Event} event The click event. 4173 * @param {Event} event The click event.
4109 */ 4174 */
4110 FileManager.prototype.onOk_ = function(event) { 4175 FileManager.prototype.onOk_ = function(event) {
4111 var currentDirUrl = this.getCurrentDirectoryURL(); 4176 var currentDirUrl = this.getCurrentDirectoryURL();
4112 4177
4113 if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') 4178 if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/')
4114 currentDirUrl += '/'; 4179 currentDirUrl += '/';
4115 4180
4116 var self = this; 4181 var self = this;
4117 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { 4182 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) {
4118 // Save-as doesn't require a valid selection from the list, since 4183 // Save-as doesn't require a valid selection from the list, since
4119 // we're going to take the filename from the text input. 4184 // we're going to take the filename from the text input.
4120 var filename = this.filenameInput_.value; 4185 var filename = this.filenameInput_.value;
4121 if (!filename) 4186 if (!filename)
4122 throw new Error('Missing filename!'); 4187 throw new Error('Missing filename!');
4123 if (!this.validateFileName_(filename)) 4188 if (!this.validateFileName_(filename))
4124 return; 4189 return;
4125 4190
4191 var singleSelection = {
4192 urls: [currentDirUrl + encodeURIComponent(filename)],
4193 multiple: false,
4194 filterIndex: self.getSelectedFilterIndex_(filename)
4195 };
4196
4126 function resolveCallback(victim) { 4197 function resolveCallback(victim) {
4127 if (victim instanceof FileError) { 4198 if (victim instanceof FileError) {
4128 // File does not exist. Closes the window and does not return. 4199 // File does not exist.
4129 self.selectFile_( 4200 self.selectFilesAndClose_(singleSelection);
4130 currentDirUrl + encodeURIComponent(filename), 4201 return;
4131 self.getSelectedFilterIndex_(filename));
4132 } 4202 }
4133 4203
4134 if (victim.isDirectory) { 4204 if (victim.isDirectory) {
4135 // Do not allow to overwrite directory. 4205 // Do not allow to overwrite directory.
4136 self.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename)); 4206 self.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename));
4137 } else { 4207 } else {
4138 self.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename), 4208 self.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename),
4139 function() { 4209 function() {
4140 // User selected Ok from the confirm dialog. 4210 // User selected Ok from the confirm dialog.
4141 self.selectFile_( 4211 self.selectFilesAndClose_(singleSelection);
4142 currentDirUrl + encodeURIComponent(filename),
4143 self.getSelectedFilterIndex_(filename));
4144 }); 4212 });
4145 } 4213 }
4146 return;
4147 } 4214 }
4148 4215
4149 this.resolvePath(this.getCurrentDirectory() + '/' + filename, 4216 this.resolvePath(this.getCurrentDirectory() + '/' + filename,
4150 resolveCallback, resolveCallback); 4217 resolveCallback, resolveCallback);
4151 return; 4218 return;
4152 } 4219 }
4153 4220
4154 var files = []; 4221 var files = [];
4155 var selectedIndexes = this.currentList_.selectionModel.selectedIndexes; 4222 var selectedIndexes = this.currentList_.selectionModel.selectedIndexes;
4156 4223
4157 // All other dialog types require at least one selected list item. 4224 // All other dialog types require at least one selected list item.
4158 // The logic to control whether or not the ok button is enabled should 4225 // The logic to control whether or not the ok button is enabled should
4159 // prevent us from ever getting here, but we sanity check to be sure. 4226 // prevent us from ever getting here, but we sanity check to be sure.
4160 if (!selectedIndexes.length) 4227 if (!selectedIndexes.length)
4161 throw new Error('Nothing selected!'); 4228 throw new Error('Nothing selected!');
4162 4229
4163 var dm = this.directoryModel_.fileList; 4230 var dm = this.directoryModel_.fileList;
4164 for (var i = 0; i < selectedIndexes.length; i++) { 4231 for (var i = 0; i < selectedIndexes.length; i++) {
4165 var entry = dm.item(selectedIndexes[i]); 4232 var entry = dm.item(selectedIndexes[i]);
4166 if (!entry) { 4233 if (!entry) {
4167 console.log('Error locating selected file at index: ' + i); 4234 console.log('Error locating selected file at index: ' + i);
4168 continue; 4235 continue;
4169 } 4236 }
4170 4237
4171 files.push(currentDirUrl + encodeURIComponent(entry.name)); 4238 files.push(currentDirUrl + encodeURIComponent(entry.name));
4172 } 4239 }
4173 4240
4174 // Multi-file selection has no other restrictions. 4241 // Multi-file selection has no other restrictions.
4175 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_MULTI_FILE) { 4242 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_MULTI_FILE) {
4176 // Closes the window and does not return. 4243 var multipleSelection = {
4177 this.selectFiles_(files); 4244 urls: files,
4245 multiple: true
4246 };
4247 this.selectFilesAndClose_(multipleSelection);
4178 return; 4248 return;
4179 } 4249 }
4180 4250
4181 // Everything else must have exactly one. 4251 // Everything else must have exactly one.
4182 if (files.length > 1) 4252 if (files.length > 1)
4183 throw new Error('Too many files selected!'); 4253 throw new Error('Too many files selected!');
4184 4254
4185 var selectedEntry = dm.item(selectedIndexes[0]); 4255 var selectedEntry = dm.item(selectedIndexes[0]);
4186 4256
4187 if (this.dialogType_ == FileManager.DialogType.SELECT_FOLDER) { 4257 if (this.dialogType_ == FileManager.DialogType.SELECT_FOLDER) {
4188 if (!selectedEntry.isDirectory) 4258 if (!selectedEntry.isDirectory)
4189 throw new Error('Selected entry is not a folder!'); 4259 throw new Error('Selected entry is not a folder!');
4190 } else if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE) { 4260 } else if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE) {
4191 if (!selectedEntry.isFile) 4261 if (!selectedEntry.isFile)
4192 throw new Error('Selected entry is not a file!'); 4262 throw new Error('Selected entry is not a file!');
4193 } 4263 }
4194 4264
4195 // Closes the window and does not return. 4265 var singleSelection = {
4196 this.selectFile_(files[0], this.getSelectedFilterIndex_(files[0])); 4266 urls: [files[0]],
4267 multiple: false,
4268 filterIndex: this.getSelectedFilterIndex_(files[0])
4269 };
4270 this.selectFilesAndClose_(singleSelection);
4197 }; 4271 };
4198 4272
4199 /** 4273 /**
4200 * Verifies the user entered name for file or folder to be created or 4274 * Verifies the user entered name for file or folder to be created or
4201 * renamed to. Name restrictions must correspond to File API restrictions 4275 * renamed to. Name restrictions must correspond to File API restrictions
4202 * (see DOMFilePath::isValidPath). Curernt WebKit implementation is 4276 * (see DOMFilePath::isValidPath). Curernt WebKit implementation is
4203 * out of date (spec is 4277 * out of date (spec is
4204 * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to 4278 * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to
4205 * be fixed. Shows message box if the name is invalid. 4279 * be fixed. Shows message box if the name is invalid.
4206 * 4280 *
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
4279 }); 4353 });
4280 }, onError); 4354 }, onError);
4281 4355
4282 function onError(err) { 4356 function onError(err) {
4283 console.log('Error while checking free space: ' + err); 4357 console.log('Error while checking free space: ' + err);
4284 setTimeout(doCheck, 1000 * 60); 4358 setTimeout(doCheck, 1000 * 60);
4285 } 4359 }
4286 } 4360 }
4287 } 4361 }
4288 })(); 4362 })();
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/css/file_manager.css ('k') | chrome/browser/resources/file_manager/js/mock_chrome.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698