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

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

Powered by Google App Engine
This is Rietveld 408576698