diff --git a/src/components/filetree.js b/src/components/filetree.js index 4559f5ba9..93a406d1d 100644 --- a/src/components/filetree.js +++ b/src/components/filetree.js @@ -8,6 +8,7 @@ angular.module('Application').component('filetree', { backendId: '<', backendType: '<', view: '<', + clipboard: '<', onUploadFile: '&', onUploadFolder: '&', onNewFile: '&', @@ -15,7 +16,10 @@ angular.module('Application').component('filetree', { onRenameEntry: '&', onExtractEntry: '&', onChownEntries: '&', - onDeleteEntries: '&' + onDeleteEntries: '&', + onCopyEntries: '&', + onCutEntries: '&', + onPasteEntries: '&' }, templateUrl: 'components/filetree.html?<%= revision %>', controller: [ '$scope', '$translate', '$timeout', 'Client', FileTreeController ] @@ -36,8 +40,6 @@ function FileTreeController($scope, $translate, $timeout, Client) { $scope.rootDirLabel = ''; $scope.entries = []; $scope.selected = []; // holds selected entries - $scope.clipboard = []; // holds cut or copied entries - $scope.clipboardCut = false; // if action is cut or copy $scope.dropToBody = false; $scope.applicationLink = ''; @@ -348,109 +350,6 @@ function FileTreeController($scope, $translate, $timeout, Client) { $scope.selected.push(entry); }; - $scope.actionCut = function () { - $scope.clipboard = $scope.selected.slice(); - $scope.clipboard.forEach(function (entry) { - entry.fullFilePath = sanitize($scope.cwd + '/' + entry.fileName); - }); - $scope.clipboardCut = true; - }; - - $scope.actionCopy = function () { - $scope.clipboard = $scope.selected.slice(); - $scope.clipboard.forEach(function (entry) { - entry.fullFilePath = sanitize($scope.cwd + '/' + entry.fileName); - entry.pathFrom = $scope.cwd; // we stash the original path for pasting - }); - $scope.clipboardCut = false; - }; - - function collectFiles(entry, callback) { - var pathFrom = entry.pathFrom; - - if (entry.isDirectory) { - Client.filesGet($scope.backendId, $scope.backendType, entry.fullFilePath, 'data', function (error, result) { - if (error) return callback(error); - if (!result.entries) return callback(new Error('not a folder')); - - // amend fullFilePath - result.entries.forEach(function (e) { - e.fullFilePath = sanitize(entry.fullFilePath + '/' + e.fileName); - e.pathFrom = pathFrom; // we stash the original path for pasting - }); - - var collectedFiles = []; - async.eachLimit(result.entries, 5, function (entry, callback) { - collectFiles(entry, function (error, result) { - if (error) return callback(error); - - collectedFiles = collectedFiles.concat(result); - - callback(); - }); - }, function (error) { - if (error) return callback(error); - - callback(null, collectedFiles); - }); - }); - return; - } - - callback(null, [ entry ]); - } - - $scope.actionPaste = function (destinationEntry) { - if ($scope.clipboardCut) { - // move files - async.eachLimit($scope.clipboard, 5, function (entry, callback) { - var newFilePath = sanitize($scope.cwd + '/' + ((destinationEntry && destinationEntry.isDirectory) ? destinationEntry.fileName : '') + '/' + entry.fileName); - - // TODO this will overwrite files in destination! - Client.filesRename($scope.backendId, $scope.backendType, entry.fullFilePath, newFilePath, callback); - }, function (error) { - if (error) return Client.error(error); - - // clear clipboard - $scope.clipboard = []; - - $scope.refresh(); - }); - } else { - // copy files - - // first collect all files recursively - var collectedFiles = []; - - async.eachLimit($scope.clipboard, 5, function (entry, callback) { - collectFiles(entry, function (error, result) { - if (error) return callback(error); - - collectedFiles = collectedFiles.concat(result); - - callback(); - }); - }, function (error) { - if (error) return Client.error(error); - - async.eachLimit(collectedFiles, 5, function (entry, callback) { - var newFilePath = sanitize($scope.cwd + '/' + ((destinationEntry && destinationEntry.isDirectory) ? destinationEntry.fileName : '') + '/' + entry.fullFilePath.slice(entry.pathFrom.length)); - - // This will NOT overwrite but finds a unique new name to copy to - // we prefix with a / to ensure we don't do relative target paths - Client.filesCopy($scope.backendId, $scope.backendType, entry.fullFilePath, '/' + newFilePath, callback); - }, function (error) { - if (error) return Client.error(error); - - // clear clipboard - $scope.clipboard = []; - - $scope.refresh(); - }); - }); - } - }; - $scope.actionSelectAll = function () { $scope.selected = $scope.entries.slice(); }; @@ -494,15 +393,15 @@ function FileTreeController($scope, $translate, $timeout, Client) { click: function ($itemScope, $event, entry) { $scope.open(entry); } }, { text: tr['filemanager.list.menu.cut'], - click: function ($itemScope, $event, entry) { $scope.actionCut(); } + click: function ($itemScope, $event, entry) { ctrl.onCutEntries({ cwd: $scope.cwd, entries: $scope.selected.slice() }); } }, { text: tr['filemanager.list.menu.copy'], - click: function ($itemScope, $event, entry) { $scope.actionCopy(); } + click: function ($itemScope, $event, entry) { ctrl.onCopyEntries({ cwd: $scope.cwd, entries: $scope.selected.slice() }); } }, { text: tr['filemanager.list.menu.paste'], hasBottomDivider: true, - enabled: function () { return $scope.clipboard.length; }, - click: function ($itemScope, $event, entry) { $scope.actionPaste(entry); } + enabled: function () { return ctrl.clipboard.length; }, + click: function ($itemScope, $event, entry) { ctrl.onPasteEntries({ cwd: $scope.cwd, entry: entry }); } }, { text: tr['filemanager.list.menu.rename'], enabled: function () { return $scope.selected.length === 1; }, @@ -538,8 +437,8 @@ function FileTreeController($scope, $translate, $timeout, Client) { text: tr['filemanager.list.menu.paste'], hasTopDivider: true, hasBottomDivider: true, - enabled: function () { return $scope.clipboard.length; }, - click: function ($itemScope, $event) { $scope.actionPaste(); } + enabled: function () { return ctrl.clipboard.length; }, + click: function ($itemScope, $event) { ctrl.onPasteEntries({ cwd: $scope.cwd, entry: null }); } }, { text: tr['filemanager.list.menu.selectAll'], click: function ($itemScope, $event) { $scope.actionSelectAll(); } diff --git a/src/filemanager.html b/src/filemanager.html index 0261ae589..66efd1036 100644 --- a/src/filemanager.html +++ b/src/filemanager.html @@ -305,22 +305,28 @@ on-upload-file="onUploadFile(cwd)" on-new-file="newFile.show(cwd)" on-new-folder="newFolder.show(cwd)" + on-copy-entries="actionCopy(cwd, entries)" + on-cut-entries="actionCut(cwd, entries)" + on-paste-entries="actionPaste(cwd, entries)" on-delete-entries="deleteEntries.show(cwd, entries)" on-rename-entry="renameEntry.show(cwd, entry)" on-extract-entry="extractEntry(cwd, entry)" on-chown-entries="chownEntries.show(cwd, entries)" - backend-type="backendType" backend-id="backendId" view="VIEW.LEFT" + backend-type="backendType" backend-id="backendId" view="VIEW.LEFT" clipboard="clipboard" ng-click="setActiveView(VIEW.LEFT)"> diff --git a/src/js/filemanager.js b/src/js/filemanager.js index cc809445d..5cd898b5e 100644 --- a/src/js/filemanager.js +++ b/src/js/filemanager.js @@ -104,6 +104,9 @@ app.controller('FileManagerController', ['$scope', '$translate', '$timeout', 'Cl $scope.activeView = VIEW.LEFT; $scope.viewerOpen = false; + $scope.clipboard = []; // holds cut or copied entries + $scope.clipboardCut = false; // if action is cut or copy + // add a hook for children to refresh both tree views @@ -115,6 +118,111 @@ app.controller('FileManagerController', ['$scope', '$translate', '$timeout', 'Cl }); }; + function collectFiles(entry, callback) { + var pathFrom = entry.pathFrom; + + if (entry.isDirectory) { + Client.filesGet($scope.backendId, $scope.backendType, entry.fullFilePath, 'data', function (error, result) { + if (error) return callback(error); + if (!result.entries) return callback(new Error('not a folder')); + + // amend fullFilePath + result.entries.forEach(function (e) { + e.fullFilePath = sanitize(entry.fullFilePath + '/' + e.fileName); + e.pathFrom = pathFrom; // we stash the original path for pasting + }); + + var collectedFiles = []; + async.eachLimit(result.entries, 5, function (entry, callback) { + collectFiles(entry, function (error, result) { + if (error) return callback(error); + + collectedFiles = collectedFiles.concat(result); + + callback(); + }); + }, function (error) { + if (error) return callback(error); + + callback(null, collectedFiles); + }); + }); + return; + } + + callback(null, [ entry ]); + } + + // entries need to be an actual copy + $scope.actionCut = function (cwd, entries) { + $scope.clipboard = entries; //$scope.selected.slice(); + $scope.clipboard.forEach(function (entry) { + entry.fullFilePath = sanitize(cwd + '/' + entry.fileName); + }); + $scope.clipboardCut = true; + }; + + // entries need to be an actual copy + $scope.actionCopy = function (cwd, entries) { + $scope.clipboard = entries; //$scope.selected.slice(); + $scope.clipboard.forEach(function (entry) { + entry.fullFilePath = sanitize(cwd + '/' + entry.fileName); + entry.pathFrom = cwd; // we stash the original path for pasting + }); + $scope.clipboardCut = false; + }; + + $scope.actionPaste = function (cwd, destinationEntry) { + if ($scope.clipboardCut) { + // move files + async.eachLimit($scope.clipboard, 5, function (entry, callback) { + var newFilePath = sanitize(cwd + '/' + ((destinationEntry && destinationEntry.isDirectory) ? destinationEntry.fileName : '') + '/' + entry.fileName); + + // TODO this will overwrite files in destination! + Client.filesRename($scope.backendId, $scope.backendType, entry.fullFilePath, newFilePath, callback); + }, function (error) { + if (error) return Client.error(error); + + // clear clipboard + $scope.clipboard = []; + + $scope.refresh(); + }); + } else { + // copy files + + // first collect all files recursively + var collectedFiles = []; + + async.eachLimit($scope.clipboard, 5, function (entry, callback) { + collectFiles(entry, function (error, result) { + if (error) return callback(error); + + collectedFiles = collectedFiles.concat(result); + + callback(); + }); + }, function (error) { + if (error) return Client.error(error); + + async.eachLimit(collectedFiles, 5, function (entry, callback) { + var newFilePath = sanitize(cwd + '/' + ((destinationEntry && destinationEntry.isDirectory) ? destinationEntry.fileName : '') + '/' + entry.fullFilePath.slice(entry.pathFrom.length)); + + // This will NOT overwrite but finds a unique new name to copy to + // we prefix with a / to ensure we don't do relative target paths + Client.filesCopy($scope.backendId, $scope.backendType, entry.fullFilePath, '/' + newFilePath, callback); + }, function (error) { + if (error) return Client.error(error); + + // clear clipboard + $scope.clipboard = []; + + $scope.refresh(); + }); + }); + } + }; + // handle uploads $scope.uploadStatus = {