Chromium Code Reviews| Index: ui/file_manager/file_manager/foreground/js/file_transfer_controller.js |
| diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js |
| index f368ca67e6c16c39d5c5e68f64956a04aafb4677..9c2ff51589f8f6980646c9871e6fc0d9d1a7a368 100644 |
| --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js |
| +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js |
| @@ -21,6 +21,10 @@ var FileAsyncData; |
| * @param {!ListContainer} listContainer List container. |
| * @param {!MultiProfileShareDialog} multiProfileShareDialog Share dialog to be |
| * used to share files from another profile. |
| + * @param {function(FileManagerUI.ActionType, string, !Array<string>): |
| + * !Promise<boolean>} confirmationCallback called when operation requires |
| + * user's confirmation. The opeartion will be executed if the return value |
| + * resolved to true. |
| * @param {!ProgressCenter} progressCenter To notify starting copy operation. |
| * @param {!FileOperationManager} fileOperationManager File operation manager |
| * instance. |
| @@ -34,9 +38,10 @@ var FileAsyncData; |
| * @constructor |
| */ |
| function FileTransferController( |
| - doc, listContainer, directoryTree, multiProfileShareDialog, progressCenter, |
| - fileOperationManager, metadataModel, thumbnailModel, directoryModel, |
| - volumeManager, selectionHandler, shouldShowCommandFor) { |
| + doc, listContainer, directoryTree, multiProfileShareDialog, |
| + confirmationCallback, progressCenter, fileOperationManager, metadataModel, |
| + thumbnailModel, directoryModel, volumeManager, selectionHandler, |
| + shouldShowCommandFor) { |
| /** |
| * @private {!Document} |
| * @const |
| @@ -91,6 +96,13 @@ function FileTransferController( |
| */ |
| this.multiProfileShareDialog_ = multiProfileShareDialog; |
| + /** |
| + * @private {function(FileManagerUI.ActionType, string, !Array<string>): |
| + * Promise<boolean>} |
| + * @const |
| + */ |
| + this.confirmationCallback_ = confirmationCallback; |
| + |
| /** |
| * @private {!ProgressCenter} |
| * @const |
| @@ -220,12 +232,14 @@ FileTransferController.DRAG_LABEL_Y_OFFSET_ = -32; |
| * |
| * @param {!Array<string>} sourceURLs URLs of source entries. |
| * @param {!DirectoryEntry} destinationEntry Destination directory. |
| + * @param {EntryLocation} destinationLocationInfo Location info of the |
| + * destination directory. |
| * @param {boolean} isMove true if move, false if copy. |
| * @constructor |
| * @struct |
| */ |
| FileTransferController.PastePlan = function( |
| - sourceURLs, destinationEntry, isMove) { |
| + sourceURLs, destinationEntry, destinationLocationInfo, isMove) { |
| /** |
| * @type {!Array<string>} |
| * @const |
| @@ -237,6 +251,11 @@ FileTransferController.PastePlan = function( |
| */ |
| this.destinationEntry = destinationEntry; |
| + /** |
| + * @type {EntryLocation} |
| + */ |
| + this.destinationLocationInfo = destinationLocationInfo; |
| + |
| /** |
| * @type {boolean} |
| * @const |
| @@ -244,6 +263,88 @@ FileTransferController.PastePlan = function( |
| this.isMove = isMove; |
| }; |
| +/** |
| + * Judges whether the planned operation requires user's confirmation. |
| + * |
| + * @return {!Promise<{title: string, body: !Array<string>}>} Resolves to null if |
|
fukino
2017/06/09 07:05:46
The returned value and the method description soun
yamaguchi
2017/06/09 09:49:14
Done.
|
| + * the operation doesn't require confirmation. Otherwise, the value gives |
| + * the title and the body text sentences for a confirmation dialog box. |
| + */ |
| +FileTransferController.PastePlan.prototype.shouldShowConfirmation = function() { |
| + return util.URLsToEntries(this.sourceURLs).then(function(entriesResult) { |
| + var sourceEntries = entriesResult.entries; |
| + if (sourceEntries.length == 0) { |
| + return null; |
| + } |
| + var source = { |
| + isTeamDrive: util.isTeamDriveEntry(sourceEntries[0]), |
| + teamDriveName: util.getTeamDriveName(sourceEntries[0]) |
| + }; |
| + var destination = { |
| + isTeamDrive: util.isTeamDriveEntry(this.destinationEntry), |
| + teamDriveName: util.getTeamDriveName(this.destinationEntry) |
| + }; |
| + if (!this.destinationLocationInfo) { |
| + // Unknown type of destination location. Allow without confirmation for |
|
fukino
2017/06/09 07:05:46
I think we should abort paste operation (and outpu
yamaguchi
2017/06/09 09:49:15
Done.
|
| + // backward compatibility. |
| + return null; |
| + } |
| + /** @type {!Array<string>} */ |
| + var message_body = []; |
| + var title = ''; |
| + if (this.isMove) { |
| + if (source.isTeamDrive) { |
| + if (destination.isTeamDrive && |
| + source.teamDriveName != destination.teamDriveName) { |
| + // Moving from a Team Drive to another Team Drive. |
| + title = strf( |
| + 'DRIVE_CONFIRM_MOVE_BETWEEN_TEAM_DRIVES_TITLE', |
| + destination.teamDriveName); |
| + message_body.push(strf( |
| + 'DRIVE_CONFIRM_MOVE_FROM_TEAM_DRIVE_BODY', source.teamDriveName)); |
| + message_body.push(strf( |
| + 'DRIVE_CONFIRM_COPY_TO_TEAM_DRIVE_BODY', |
| + destination.teamDriveName)); |
| + // TODO(yamaguchi): notify ownership transfer if the two Team Drives |
| + // belong to different domains. |
| + } else if (!destination.isTeamDrive) { |
| + // Moving out of Team Drive. |
| + title = strf( |
| + 'DRIVE_CONFIRM_MOVE_FROM_TEAM_DRIVE_TITLE', |
| + util.getRootTypeLabel(this.destinationLocationInfo)); |
| + message_body.push(strf( |
| + 'DRIVE_CONFIRM_MOVE_FROM_TEAM_DRIVE_BODY', source.teamDriveName)); |
| + // TODO(yamaguchi): Warn if the operation moves at least one directory |
| + // to My Drive, as it's no undoable. |
| + } |
| + } else if (destination.isTeamDrive) { |
| + title = strf( |
| + 'DRIVE_CONFIRM_MOVE_TO_TEAM_DRIVE_TITLE', |
| + destination.teamDriveName); |
| + message_body.push(strf( |
| + 'DRIVE_CONFIRM_MOVE_TO_TEAM_DRIVE_BODY', |
| + destination.teamDriveName)); |
| + } |
| + } else if (destination.isTeamDrive) { |
| + // Copying to Team Drive. |
| + if (!(source.isTeamDrive && |
| + source.teamDriveName == destination.teamDriveName)) { |
| + // This is not a copy within the same Team Drive. |
| + title = strf( |
| + 'DRIVE_CONFIRM_COPY_TO_TEAM_DRIVE_TITLE', |
| + destination.teamDriveName); |
| + message_body.push(strf( |
| + 'DRIVE_CONFIRM_COPY_TO_TEAM_DRIVE_BODY', |
| + destination.teamDriveName)); |
| + } |
| + } |
| + if (!title) { |
|
fukino
2017/06/09 07:05:46
"Confirmation is unnecessary when title is falsy v
yamaguchi
2017/06/09 09:49:14
Revised to use NONE enum value.
|
| + return null; |
| + } |
| + return {title: title, body: message_body}; |
| + }.bind(this)); |
| +}; |
| + |
| /** |
| * Converts list of urls to list of Entries with granting R/W permissions to |
| * them, which is essential when pasting files from a different profile. |
| @@ -536,12 +637,13 @@ FileTransferController.prototype.getMultiProfileShareEntries_ = |
| * Collects parameters of paste operation by the given command and the current |
| * system clipboard. |
| * |
| - * @return {FileTransferController.PastePlan} |
| + * @return {!FileTransferController.PastePlan} |
| */ |
| FileTransferController.prototype.preparePaste = function( |
| clipboardData, opt_destinationEntry, opt_effect) { |
| var sourceURLs = clipboardData.getData('fs/sources') ? |
| - clipboardData.getData('fs/sources').split('\n') : []; |
| + clipboardData.getData('fs/sources').split('\n') : |
|
fukino
2017/06/09 07:05:46
Was this line break forced by presubmit?
yamaguchi
2017/06/09 09:49:14
No, I had just overlooked it.
|
| + []; |
| // effectAllowed set in copy/paste handlers stay uninitialized. DnD handlers |
| // work fine. |
| var effectAllowed = clipboardData.effectAllowed !== 'uninitialized' ? |
| @@ -551,8 +653,10 @@ FileTransferController.prototype.preparePaste = function( |
| var toMove = util.isDropEffectAllowed(effectAllowed, 'move') && |
| (!util.isDropEffectAllowed(effectAllowed, 'copy') || |
| opt_effect === 'move'); |
| + |
| return new FileTransferController.PastePlan( |
| - sourceURLs, destinationEntry, toMove); |
| + sourceURLs, destinationEntry, |
| + this.volumeManager_.getLocationInfo(destinationEntry), toMove); |
| }; |
| /** |
| @@ -564,13 +668,26 @@ FileTransferController.prototype.preparePaste = function( |
| * @param {string=} opt_effect Desired drop/paste effect. Could be |
| * 'move'|'copy' (default is copy). Ignored if conflicts with |
| * |clipboardData.effectAllowed|. |
| - * @return {string} Either "copy" or "move". |
| + * @return {!Promise<string>} Either "copy" or "move". |
| */ |
| FileTransferController.prototype.paste = function( |
| clipboardData, opt_destinationEntry, opt_effect) { |
| var pastePlan = |
| this.preparePaste(clipboardData, opt_destinationEntry, opt_effect); |
| - return this.executePaste(pastePlan); |
| + return pastePlan.shouldShowConfirmation().then(function(message) { |
| + if (!message) { |
| + return Promise.resolve(this.executePaste(pastePlan)); |
| + } |
| + this.confirmationCallback_( |
| + pastePlan.isMove ? FileManagerUI.ActionType.MOVE : |
| + FileManagerUI.ActionType.COPY, |
| + message.title, message.body) |
| + .then(function(userApproved) { |
| + if (userApproved) { |
| + this.executePaste(pastePlan); |
| + } |
| + }.bind(this)); |
| + }.bind(this)); |
| }; |
| /** |
| @@ -1229,16 +1346,16 @@ FileTransferController.prototype.onPaste_ = function(event) { |
| return; |
| } |
| event.preventDefault(); |
| - var effect = this.paste(assert(event.clipboardData), destination); |
| - |
| - // On cut, we clear the clipboard after the file is pasted/moved so we don't |
| - // try to move/delete the original file again. |
| - if (effect === 'move') { |
| - this.simulateCommand_('cut', function(event) { |
| - event.preventDefault(); |
| - event.clipboardData.setData('fs/clear', ''); |
| - }); |
| - } |
| + this.paste(assert(event.clipboardData), destination).then(function(effect) { |
| + // On cut, we clear the clipboard after the file is pasted/moved so we don't |
| + // try to move/delete the original file again. |
| + if (effect === 'move') { |
| + this.simulateCommand_('cut', function(event) { |
| + event.preventDefault(); |
| + event.clipboardData.setData('fs/clear', ''); |
| + }); |
| + } |
| + }.bind(this)); |
| }; |
| /** |