Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 3967 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3978 } | 3978 } |
| 3979 } | 3979 } |
| 3980 callback(fileUrls); | 3980 callback(fileUrls); |
| 3981 }); | 3981 }); |
| 3982 } else { | 3982 } else { |
| 3983 callback(fileUrls); | 3983 callback(fileUrls); |
| 3984 } | 3984 } |
| 3985 }, | 3985 }, |
| 3986 | 3986 |
| 3987 /** | 3987 /** |
| 3988 * Selects a file. | 3988 * Closes this modal dialog with some files selected. |
| 3989 * | 3989 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811 |
| 3990 * @param {string} fileUrl The filename as a URL. | 3990 * @param {Object} selection Contains urls, filterIndex and multiple fields. |
| 3991 * @param {number} filterIndex The integer file filter index. | |
| 3992 */ | 3991 */ |
| 3993 FileManager.prototype.selectFile_ = function(fileUrl, filterIndex) { | 3992 FileManager.prototype.callSelectFilesApiAndClose_ = function(selection) { |
| 3994 this.resolveSelectResults_( | 3993 if (selection.multiple) { |
| 3995 [fileUrl], | 3994 chrome.fileBrowserPrivate.selectFiles(selection.urls); |
| 3996 function(resolvedUrls) { | 3995 } else { |
| 3997 // Call doSelectFiles_ on a timeout, as it's unsafe to | 3996 chrome.fileBrowserPrivate.selectFile( |
| 3998 // close a window from a callback. | 3997 selection.urls[0], selection.filterIndex); |
| 3999 setTimeout( | 3998 } |
| 4000 this.doSelectFile_.bind(this, resolvedUrls[0], filterIndex), 0); | |
| 4001 }.bind(this)); | |
| 4002 }; | |
| 4003 | |
| 4004 /** | |
| 4005 * Selects a file. Closes the window. | |
| 4006 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811 | |
| 4007 * | |
| 4008 * @param {string} fileUrl The filename as a URL. | |
| 4009 * @param {number} filterIndex The integer file filter index. | |
| 4010 */ | |
| 4011 FileManager.prototype.doSelectFile_ = function(fileUrl, filterIndex) { | |
| 4012 chrome.fileBrowserPrivate.selectFile(fileUrl, filterIndex); | |
| 4013 this.onUnload_(); | |
| 4014 window.close(); | |
| 4015 }; | |
| 4016 | |
| 4017 | |
| 4018 /** | |
| 4019 * Selects a file. Starts getting gdata files if needed. | |
| 4020 * | |
| 4021 * @param {Array.<string>} fileUrls Array of filename URLs. | |
| 4022 */ | |
| 4023 FileManager.prototype.selectFiles_ = function(fileUrls) { | |
| 4024 this.resolveSelectResults_( | |
| 4025 fileUrls, | |
| 4026 function(resolvedUrls) { | |
| 4027 // Call doSelectFiles_ on a timeout, as it's unsafe to | |
| 4028 // close a window from a callback. | |
| 4029 setTimeout(this.doSelectFiles_.bind(this, resolvedUrls), 0); | |
| 4030 }.bind(this)); | |
| 4031 }; | |
| 4032 | |
| 4033 /** | |
| 4034 * Selects multiple files. Closes the window. | |
| 4035 * TODO(jamescook): Make unload handler work automatically, crbug.com/104811 | |
| 4036 * | |
| 4037 * @param {Array.<string>} fileUrls Array of filename URLs. | |
| 4038 */ | |
| 4039 FileManager.prototype.doSelectFiles_ = function(fileUrls) { | |
| 4040 chrome.fileBrowserPrivate.selectFiles(fileUrls); | |
| 4041 this.onUnload_(); | 3999 this.onUnload_(); |
| 4042 window.close(); | 4000 window.close(); |
| 4043 }; | 4001 }; |
| 4044 | 4002 |
| 4045 /** | 4003 /** |
| 4004 * Tries to close this modal dialog with some files selected. | |
| 4005 * Performs preprocessing if needed (e.g. for GData). | |
| 4006 * @param {Object} selection Contains urls, filterIndex and multiple fields. | |
| 4007 */ | |
| 4008 FileManager.prototype.selectFilesAndClose_ = function(selection) { | |
| 4009 if (!this.isOnGData()) { | |
| 4010 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); | |
| 4011 return; | |
| 4012 } | |
| 4013 | |
| 4014 var shade = this.document_.createElement('div'); | |
| 4015 shade.className = 'shade'; | |
| 4016 var footer = this.document_.querySelector('.dialog-footer'); | |
| 4017 var progress = footer.querySelector('.progress-track'); | |
| 4018 progress.style.width = '0%'; | |
| 4019 var cancelled = false; | |
| 4020 | |
| 4021 var progressMap = {}; | |
| 4022 var started = 0; | |
| 4023 for (var index = 0; index < selection.urls.length; index++) { | |
| 4024 progressMap[selection.urls[index]] = -1; | |
| 4025 } | |
| 4026 var lastPercent = 0; | |
| 4027 var total = 0; | |
| 4028 var done = 0; | |
| 4029 | |
| 4030 var onFileTransfersUpdated = function(statusList) { | |
| 4031 for (var index = 0; index < statusList.length; index++) { | |
| 4032 var status = statusList[index]; | |
| 4033 var escaped = encodeURI(status.fileUrl); | |
| 4034 if (!(escaped in progressMap)) continue; | |
| 4035 if (status.total == -1) continue; | |
| 4036 | |
| 4037 var old = progressMap[escaped]; | |
| 4038 if (old == -1) { | |
| 4039 // -1 means we don't know file size yet. | |
| 4040 total += status.total; | |
| 4041 started++; | |
| 4042 } | |
| 4043 done += status.processed - old; | |
|
Vladislav Kaznacheev
2012/03/23 14:32:10
if old == 1 it will still participate in the compu
dgozman
2012/03/23 14:37:31
Fixed.
| |
| 4044 progressMap[escaped] = status.processed; | |
| 4045 } | |
| 4046 | |
| 4047 var percent = total == 0 ? 0 : done / total; | |
| 4048 // For files we don't have information about, assume the progress is zero. | |
| 4049 percent = percent * started / selection.urls.length * 100; | |
| 4050 // Do not decrease the progress. This may happen, if first downloaded | |
| 4051 // file is small, and the second one is large. | |
| 4052 lastPercent = Math.max(lastPercent, percent); | |
| 4053 progress.style.width = lastPercent + '%'; | |
| 4054 }.bind(this); | |
| 4055 | |
| 4056 var setup = function() { | |
| 4057 this.document_.querySelector('.dialog-container').appendChild(shade); | |
| 4058 setTimeout(function() { shade.setAttribute('fadein', 'fadein') }, 100); | |
| 4059 footer.setAttribute('progress', 'progress'); | |
| 4060 this.cancelButton_.removeEventListener('click', this.onCancelBound_); | |
| 4061 this.cancelButton_.addEventListener('click', onCancel); | |
| 4062 chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener( | |
| 4063 onFileTransfersUpdated); | |
| 4064 }.bind(this); | |
| 4065 | |
| 4066 var cleanup = function() { | |
| 4067 shade.parentNode.removeChild(shade); | |
| 4068 footer.removeAttribute('progress'); | |
| 4069 this.cancelButton_.removeEventListener('click', onCancel); | |
| 4070 this.cancelButton_.addEventListener('click', this.onCancelBound_); | |
| 4071 chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener( | |
| 4072 onFileTransfersUpdated); | |
| 4073 }.bind(this); | |
| 4074 | |
| 4075 var onCancel = function() { | |
| 4076 cancelled = true; | |
| 4077 // Accroding to API cancel may fail, but there is no proper UI to reflect | |
| 4078 // this. So, we just silently assume that everything is cancelled. | |
| 4079 chrome.fileBrowserPrivate.cancelFileTransfers( | |
| 4080 selection.urls, function(response) {}); | |
| 4081 cleanup(); | |
| 4082 }.bind(this); | |
| 4083 | |
| 4084 var onResolved = function(resolvedUrls) { | |
| 4085 if (cancelled) return; | |
| 4086 cleanup(); | |
| 4087 selection.urls = resolvedUrls; | |
| 4088 // Call next method on a timeout, as it's unsafe to | |
| 4089 // close a window from a callback. | |
| 4090 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); | |
| 4091 }.bind(this); | |
| 4092 | |
| 4093 setup(); | |
| 4094 this.resolveSelectResults_(selection.urls, onResolved); | |
| 4095 }; | |
| 4096 | |
| 4097 /** | |
| 4046 * Handle a click of the ok button. | 4098 * Handle a click of the ok button. |
| 4047 * | 4099 * |
| 4048 * The ok button has different UI labels depending on the type of dialog, but | 4100 * The ok button has different UI labels depending on the type of dialog, but |
| 4049 * in code it's always referred to as 'ok'. | 4101 * in code it's always referred to as 'ok'. |
| 4050 * | 4102 * |
| 4051 * @param {Event} event The click event. | 4103 * @param {Event} event The click event. |
| 4052 */ | 4104 */ |
| 4053 FileManager.prototype.onOk_ = function(event) { | 4105 FileManager.prototype.onOk_ = function(event) { |
| 4054 var currentDirUrl = this.getCurrentDirectoryURL(); | 4106 var currentDirUrl = this.getCurrentDirectoryURL(); |
| 4055 | 4107 |
| 4056 if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') | 4108 if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') |
| 4057 currentDirUrl += '/'; | 4109 currentDirUrl += '/'; |
| 4058 | 4110 |
| 4059 var self = this; | 4111 var self = this; |
| 4060 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { | 4112 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { |
| 4061 // Save-as doesn't require a valid selection from the list, since | 4113 // Save-as doesn't require a valid selection from the list, since |
| 4062 // we're going to take the filename from the text input. | 4114 // we're going to take the filename from the text input. |
| 4063 var filename = this.filenameInput_.value; | 4115 var filename = this.filenameInput_.value; |
| 4064 if (!filename) | 4116 if (!filename) |
| 4065 throw new Error('Missing filename!'); | 4117 throw new Error('Missing filename!'); |
| 4066 if (!this.validateFileName_(filename)) | 4118 if (!this.validateFileName_(filename)) |
| 4067 return; | 4119 return; |
| 4068 | 4120 |
| 4121 var singleSelection = { | |
| 4122 urls: [currentDirUrl + encodeURIComponent(filename)], | |
| 4123 multiple: false, | |
| 4124 filterIndex: self.getSelectedFilterIndex_(filename) | |
| 4125 }; | |
| 4126 | |
| 4069 function resolveCallback(victim) { | 4127 function resolveCallback(victim) { |
| 4070 if (victim instanceof FileError) { | 4128 if (victim instanceof FileError) { |
| 4071 // File does not exist. Closes the window and does not return. | 4129 // File does not exist. |
| 4072 self.selectFile_( | 4130 self.selectFilesAndClose_(singleSelection); |
| 4073 currentDirUrl + encodeURIComponent(filename), | 4131 return; |
| 4074 self.getSelectedFilterIndex_(filename)); | |
| 4075 } | 4132 } |
| 4076 | 4133 |
| 4077 if (victim.isDirectory) { | 4134 if (victim.isDirectory) { |
| 4078 // Do not allow to overwrite directory. | 4135 // Do not allow to overwrite directory. |
| 4079 self.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename)); | 4136 self.alert.show(strf('DIRECTORY_ALREADY_EXISTS', filename)); |
| 4080 } else { | 4137 } else { |
| 4081 self.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename), | 4138 self.confirm.show(strf('CONFIRM_OVERWRITE_FILE', filename), |
| 4082 function() { | 4139 function() { |
| 4083 // User selected Ok from the confirm dialog. | 4140 // User selected Ok from the confirm dialog. |
| 4084 self.selectFile_( | 4141 self.selectFilesAndClose_(singleSelection); |
| 4085 currentDirUrl + encodeURIComponent(filename), | |
| 4086 self.getSelectedFilterIndex_(filename)); | |
| 4087 }); | 4142 }); |
| 4088 } | 4143 } |
| 4089 return; | |
| 4090 } | 4144 } |
| 4091 | 4145 |
| 4092 this.resolvePath(this.getCurrentDirectory() + '/' + filename, | 4146 this.resolvePath(this.getCurrentDirectory() + '/' + filename, |
| 4093 resolveCallback, resolveCallback); | 4147 resolveCallback, resolveCallback); |
| 4094 return; | 4148 return; |
| 4095 } | 4149 } |
| 4096 | 4150 |
| 4097 var files = []; | 4151 var files = []; |
| 4098 var selectedIndexes = this.currentList_.selectionModel.selectedIndexes; | 4152 var selectedIndexes = this.currentList_.selectionModel.selectedIndexes; |
| 4099 | 4153 |
| 4100 // All other dialog types require at least one selected list item. | 4154 // All other dialog types require at least one selected list item. |
| 4101 // The logic to control whether or not the ok button is enabled should | 4155 // The logic to control whether or not the ok button is enabled should |
| 4102 // prevent us from ever getting here, but we sanity check to be sure. | 4156 // prevent us from ever getting here, but we sanity check to be sure. |
| 4103 if (!selectedIndexes.length) | 4157 if (!selectedIndexes.length) |
| 4104 throw new Error('Nothing selected!'); | 4158 throw new Error('Nothing selected!'); |
| 4105 | 4159 |
| 4106 var dm = this.directoryModel_.fileList; | 4160 var dm = this.directoryModel_.fileList; |
| 4107 for (var i = 0; i < selectedIndexes.length; i++) { | 4161 for (var i = 0; i < selectedIndexes.length; i++) { |
| 4108 var entry = dm.item(selectedIndexes[i]); | 4162 var entry = dm.item(selectedIndexes[i]); |
| 4109 if (!entry) { | 4163 if (!entry) { |
| 4110 console.log('Error locating selected file at index: ' + i); | 4164 console.log('Error locating selected file at index: ' + i); |
| 4111 continue; | 4165 continue; |
| 4112 } | 4166 } |
| 4113 | 4167 |
| 4114 files.push(currentDirUrl + encodeURIComponent(entry.name)); | 4168 files.push(currentDirUrl + encodeURIComponent(entry.name)); |
| 4115 } | 4169 } |
| 4116 | 4170 |
| 4117 // Multi-file selection has no other restrictions. | 4171 // Multi-file selection has no other restrictions. |
| 4118 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_MULTI_FILE) { | 4172 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_MULTI_FILE) { |
| 4119 // Closes the window and does not return. | 4173 var multipleSelection = { |
| 4120 this.selectFiles_(files); | 4174 urls: files, |
| 4175 multiple: true | |
| 4176 }; | |
| 4177 this.selectFilesAndClose_(multipleSelection); | |
| 4121 return; | 4178 return; |
| 4122 } | 4179 } |
| 4123 | 4180 |
| 4124 // Everything else must have exactly one. | 4181 // Everything else must have exactly one. |
| 4125 if (files.length > 1) | 4182 if (files.length > 1) |
| 4126 throw new Error('Too many files selected!'); | 4183 throw new Error('Too many files selected!'); |
| 4127 | 4184 |
| 4128 var selectedEntry = dm.item(selectedIndexes[0]); | 4185 var selectedEntry = dm.item(selectedIndexes[0]); |
| 4129 | 4186 |
| 4130 if (this.dialogType_ == FileManager.DialogType.SELECT_FOLDER) { | 4187 if (this.dialogType_ == FileManager.DialogType.SELECT_FOLDER) { |
| 4131 if (!selectedEntry.isDirectory) | 4188 if (!selectedEntry.isDirectory) |
| 4132 throw new Error('Selected entry is not a folder!'); | 4189 throw new Error('Selected entry is not a folder!'); |
| 4133 } else if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE) { | 4190 } else if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE) { |
| 4134 if (!selectedEntry.isFile) | 4191 if (!selectedEntry.isFile) |
| 4135 throw new Error('Selected entry is not a file!'); | 4192 throw new Error('Selected entry is not a file!'); |
| 4136 } | 4193 } |
| 4137 | 4194 |
| 4138 // Closes the window and does not return. | 4195 var singleSelection = { |
| 4139 this.selectFile_(files[0], this.getSelectedFilterIndex_(files[0])); | 4196 urls: [files[0]], |
| 4197 multiple: false, | |
| 4198 filterIndex: this.getSelectedFilterIndex_(files[0]) | |
| 4199 }; | |
| 4200 this.selectFilesAndClose_(singleSelection); | |
| 4140 }; | 4201 }; |
| 4141 | 4202 |
| 4142 /** | 4203 /** |
| 4143 * Verifies the user entered name for file or folder to be created or | 4204 * Verifies the user entered name for file or folder to be created or |
| 4144 * renamed to. Name restrictions must correspond to File API restrictions | 4205 * renamed to. Name restrictions must correspond to File API restrictions |
| 4145 * (see DOMFilePath::isValidPath). Curernt WebKit implementation is | 4206 * (see DOMFilePath::isValidPath). Curernt WebKit implementation is |
| 4146 * out of date (spec is | 4207 * out of date (spec is |
| 4147 * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to | 4208 * http://dev.w3.org/2009/dap/file-system/file-dir-sys.html, 8.3) and going to |
| 4148 * be fixed. Shows message box if the name is invalid. | 4209 * be fixed. Shows message box if the name is invalid. |
| 4149 * | 4210 * |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4222 }); | 4283 }); |
| 4223 }, onError); | 4284 }, onError); |
| 4224 | 4285 |
| 4225 function onError(err) { | 4286 function onError(err) { |
| 4226 console.log('Error while checking free space: ' + err); | 4287 console.log('Error while checking free space: ' + err); |
| 4227 setTimeout(doCheck, 1000 * 60); | 4288 setTimeout(doCheck, 1000 * 60); |
| 4228 } | 4289 } |
| 4229 } | 4290 } |
| 4230 } | 4291 } |
| 4231 })(); | 4292 })(); |
| OLD | NEW |