]> source.dussan.org Git - nextcloud-server.git/commitdiff
Fixed drag and drop into folder and onto breadcrumb
authorVincent Petry <pvince81@owncloud.com>
Fri, 11 Apr 2014 10:46:12 +0000 (12:46 +0200)
committerVincent Petry <pvince81@owncloud.com>
Mon, 28 Apr 2014 12:55:01 +0000 (14:55 +0200)
Fixed drag and drop code to use FileList.getSelectedFiles() instead of
the visible DOM elements.

apps/files/js/filelist.js
apps/files/js/files.js
apps/files/tests/js/filelistSpec.js

index f9916b647b2436f8ad227de1d0b75f919d02fdc8..5667d07ede7f3464478fba168ce926d5e77ea5e2 100644 (file)
@@ -78,7 +78,7 @@ window.FileList = {
 
                this.breadcrumb = new BreadCrumb({
                        onClick: this._onClickBreadCrumb,
-                       onDrop: this._onDropOnBreadCrumb,
+                       onDrop: _.bind(this._onDropOnBreadCrumb, this),
                        getCrumbUrl: function(part, index) {
                                return self.linkTo(part.dir);
                        }
@@ -259,44 +259,31 @@ window.FileList = {
         * Event handler when dropping on a breadcrumb
         */
        _onDropOnBreadCrumb: function( event, ui ) {
-               var target=$(this).data('dir');
-               var dir = FileList.getCurrentDirectory();
-               while(dir.substr(0,1) === '/') {//remove extra leading /'s
-                       dir=dir.substr(1);
+               var $target = $(event.target);
+               if (!$target.is('.crumb')) {
+                       $target = $target.closest('.crumb');
+               }
+               var targetPath = $(event.target).data('dir');
+               var dir = this.getCurrentDirectory();
+               while (dir.substr(0,1) === '/') {//remove extra leading /'s
+                       dir = dir.substr(1);
                }
                dir = '/' + dir;
                if (dir.substr(-1,1) !== '/') {
                        dir = dir + '/';
                }
-               if (target === dir || target+'/' === dir) {
+               // do nothing if dragged on current dir
+               if (targetPath === dir || targetPath + '/' === dir) {
                        return;
                }
-               var files = ui.helper.find('tr');
-               $(files).each(function(i,row) {
-                       var dir = $(row).data('dir');
-                       var file = $(row).data('filename');
-                       //slapdash selector, tracking down our original element that the clone budded off of.
-                       var origin = $('tr[data-id=' + $(row).data('origin') + ']');
-                       var td = origin.children('td.filename');
-                       var oldBackgroundImage = td.css('background-image');
-                       td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
-                       $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
-                               if (result) {
-                                       if (result.status === 'success') {
-                                               FileList.remove(file);
-                                               FileList.updateSelectionSummary();
-                                               $('#notification').hide();
-                                       } else {
-                                               $('#notification').hide();
-                                               $('#notification').text(result.data.message);
-                                               $('#notification').fadeIn();
-                                       }
-                               } else {
-                                       OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
-                               }
-                               td.css('background-image', oldBackgroundImage);
-                       });
-               });
+
+               var files = this.getSelectedFiles();
+               if (files.length === 0) {
+                       // single one selected without checkbox?
+                       files = _.map(ui.helper.find('tr'), FileList.elementToFile);
+               }
+
+               FileList.move(_.pluck(files, 'name'), targetPath);
        },
 
        /**
@@ -329,6 +316,7 @@ window.FileList = {
         * @return file data
         */
        elementToFile: function($el){
+               $el = $($el);
                return {
                        id: parseInt($el.attr('data-id'), 10),
                        name: $el.attr('data-file'),
@@ -877,6 +865,77 @@ window.FileList = {
                }
                return index;
        },
+       /**
+        * Moves a file to a given target folder.
+        *
+        * @param fileNames array of file names to move
+        * @param targetPath absolute target path
+        */
+       move: function(fileNames, targetPath) {
+               var self = this;
+               var dir = this.getCurrentDirectory();
+               var target = OC.basename(targetPath);
+               if (!_.isArray(fileNames)) {
+                       fileNames = [fileNames];
+               }
+               _.each(fileNames, function(fileName) {
+                       var $tr = self.findFileEl(fileName);
+                       var $td = $tr.children('td.filename');
+                       var oldBackgroundImage = $td.css('background-image');
+                       $td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
+                       // TODO: improve performance by sending all file names in a single call
+                       $.post(
+                               OC.filePath('files', 'ajax', 'move.php'),
+                               {
+                                       dir: dir,
+                                       file: fileName,
+                                       target: targetPath
+                               },
+                               function(result) {
+                                       if (result) {
+                                               if (result.status === 'success') {
+                                                       // if still viewing the same directory
+                                                       if (self.getCurrentDirectory() === dir) {
+                                                               // recalculate folder size
+                                                               var oldFile = self.findFileEl(target);
+                                                               var newFile = self.findFileEl(fileName);
+                                                               var oldSize = oldFile.data('size');
+                                                               var newSize = oldSize + newFile.data('size');
+                                                               oldFile.data('size', newSize);
+                                                               oldFile.find('td.filesize').text(OC.Util.humanFileSize(newSize));
+
+                                                               // TODO: also update entry in FileList.files
+
+                                                               self.remove(fileName);
+                                                       }
+                                               } else {
+                                                       OC.Notification.hide();
+                                                       if (result.status === 'error' && result.data.message) {
+                                                               OC.Notification.show(result.data.message);
+                                                       }
+                                                       else {
+                                                               OC.Notification.show(t('files', 'Error moving file.'));
+                                                       }
+                                                       // hide notification after 10 sec
+                                                       setTimeout(function() {
+                                                               OC.Notification.hide();
+                                                       }, 10000);
+                                               }
+                                       } else {
+                                               OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
+                                       }
+                                       $td.css('background-image', oldBackgroundImage);
+                       });
+               });
+
+       },
+
+       /**
+        * Triggers file rename input field for the given file name.
+        * If the user enters a new name, the file will be renamed.
+        *
+        * @param oldname file name of the file to rename
+        */
        rename: function(oldname) {
                var tr, td, input, form;
                tr = FileList.findFileEl(oldname);
index f4c99d1128c1b4371198483ad1f481fa5603b452..6857450602c6079465d652a04748aef4933ac866 100644 (file)
@@ -142,6 +142,7 @@ var Files = {
                }
        },
 
+       // TODO: move to FileList class
        setupDragAndDrop: function() {
                var $fileList = $('#fileList');
 
@@ -308,6 +309,7 @@ function boolOperationFinished(data, callback) {
        }
 }
 
+// TODO: move to FileList
 var createDragShadow = function(event) {
        //select dragged file
        var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
@@ -333,9 +335,12 @@ var createDragShadow = function(event) {
        var dir=$('#dir').val();
 
        $(selectedFiles).each(function(i,elem) {
-               var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name).attr('data-origin', elem.origin);
+               var newtr = $('<tr/>')
+                       .attr('data-dir', dir)
+                       .attr('data-file', elem.name)
+                       .attr('data-origin', elem.origin);
                newtr.append($('<td/>').addClass('filename').text(elem.name));
-               newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
+               newtr.append($('<td/>').addClass('size').text(OC.Util.humanFileSize(elem.size)));
                tbody.append(newtr);
                if (elem.type === 'dir') {
                        newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')');
@@ -352,6 +357,7 @@ var createDragShadow = function(event) {
 
 //options for file drag/drop
 //start&stop handlers needs some cleaning up
+// TODO: move to FileList class
 var dragOptions={
        revert: 'invalid', revertDuration: 300,
        opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 },
@@ -381,50 +387,24 @@ if ( $('html.ie').length === 0) {
        dragOptions['distance'] = 20;
 }
 
-var folderDropOptions={
+// TODO: move to FileList class
+var folderDropOptions = {
        hoverClass: "canDrop",
        drop: function( event, ui ) {
-               //don't allow moving a file into a selected folder
+               // don't allow moving a file into a selected folder
                if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
                        return false;
                }
 
-               var target = $(this).closest('tr').data('file');
-
-               var files = ui.helper.find('tr');
-               $(files).each(function(i,row) {
-                       var dir = $(row).data('dir');
-                       var file = $(row).data('filename');
-                                                       //slapdash selector, tracking down our original element that the clone budded off of.
-                               var origin = $('tr[data-id=' + $(row).data('origin') + ']');
-                               var td = origin.children('td.filename');
-                               var oldBackgroundImage = td.css('background-image');
-                               td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
-                       $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: dir+'/'+target }, function(result) {
-                               if (result) {
-                                       if (result.status === 'success') {
-                                               //recalculate folder size
-                                               var oldFile = FileList.findFileEl(target);
-                                               var newFile = FileList.findFileEl(file);
-                                               var oldSize = oldFile.data('size');
-                                               var newSize = oldSize + newFile.data('size');
-                                               oldFile.data('size', newSize);
-                                               oldFile.find('td.filesize').text(humanFileSize(newSize));
-
-                                               FileList.remove(file);
-                                               FileList.updateSelectionSummary();
-                                               $('#notification').hide();
-                                       } else {
-                                               $('#notification').hide();
-                                               $('#notification').text(result.data.message);
-                                               $('#notification').fadeIn();
-                                       }
-                               } else {
-                                       OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
-                               }
-                               td.css('background-image', oldBackgroundImage);
-                       });
-               });
+               var targetPath = FileList.getCurrentDirectory() + '/' + $(this).closest('tr').data('file');
+
+               var files = FileList.getSelectedFiles();
+               if (files.length === 0) {
+                       // single one selected without checkbox?
+                       files = _.map(ui.helper.find('tr'), FileList.elementToFile);
+               }
+
+               FileList.move(_.pluck(files, 'name'), targetPath);
        },
        tolerance: 'pointer'
 };
index da209220cca1d17dbdd02f17c8d5db6252c85b99..eab364644cdef10fdcc59bded34c893c90fd81eb 100644 (file)
@@ -541,6 +541,100 @@ describe('FileList tests', function() {
                        expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One.txt');
                });
        });
+       describe('Moving files', function() {
+               beforeEach(function() {
+                       FileList.setFiles(testFiles);
+               });
+               it('Moves single file to target folder', function() {
+                       var request;
+                       FileList.move('One.txt', '/somedir');
+
+                       expect(fakeServer.requests.length).toEqual(1);
+                       request = fakeServer.requests[0];
+                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+                       expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+
+                       fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+                               status: 'success',
+                               data: {
+                                       name: 'One.txt',
+                                       type: 'file'
+                               }
+                       }));
+
+                       expect(FileList.findFileEl('One.txt').length).toEqual(0);
+
+                       // folder size has increased
+                       expect(FileList.findFileEl('somedir').data('size')).toEqual(262);
+                       expect(FileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
+
+                       expect(notificationStub.notCalled).toEqual(true);
+               });
+               it('Moves list of files to target folder', function() {
+                       var request;
+                       FileList.move(['One.txt', 'Two.jpg'], '/somedir');
+
+                       expect(fakeServer.requests.length).toEqual(2);
+                       request = fakeServer.requests[0];
+                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+                       expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+
+                       request = fakeServer.requests[1];
+                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+                       expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'Two.jpg', target: '/somedir'});
+
+                       fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+                               status: 'success',
+                               data: {
+                                       name: 'One.txt',
+                                       type: 'file'
+                               }
+                       }));
+
+                       expect(FileList.findFileEl('One.txt').length).toEqual(0);
+
+                       // folder size has increased
+                       expect(FileList.findFileEl('somedir').data('size')).toEqual(262);
+                       expect(FileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
+
+                       fakeServer.requests[1].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+                               status: 'success',
+                               data: {
+                                       name: 'Two.jpg',
+                                       type: 'file'
+                               }
+                       }));
+
+                       expect(FileList.findFileEl('Two.jpg').length).toEqual(0);
+
+                       // folder size has increased
+                       expect(FileList.findFileEl('somedir').data('size')).toEqual(12311);
+                       expect(FileList.findFileEl('somedir').find('.filesize').text()).toEqual('12 kB');
+
+                       expect(notificationStub.notCalled).toEqual(true);
+               });
+               it('Shows notification if a file could not be moved', function() {
+                       var request;
+                       FileList.move('One.txt', '/somedir');
+
+                       expect(fakeServer.requests.length).toEqual(1);
+                       request = fakeServer.requests[0];
+                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+                       expect(OC.parseQueryString(request.requestBody)).toEqual({dir: '/subdir', file: 'One.txt', target: '/somedir'});
+
+                       fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+                               status: 'error',
+                               data: {
+                                       message: 'Error while moving file',
+                               }
+                       }));
+
+                       expect(FileList.findFileEl('One.txt').length).toEqual(1);
+
+                       expect(notificationStub.calledOnce).toEqual(true);
+                       expect(notificationStub.getCall(0).args[0]).toEqual('Error while moving file');
+               });
+       });
        describe('List rendering', function() {
                it('renders a list of files using add()', function() {
                        expect(FileList.files.length).toEqual(0);
@@ -932,14 +1026,12 @@ describe('FileList tests', function() {
                                }
                        };
                        // returns a list of tr that were dragged
-                       // FIXME: why are their attributes different than the
-                       // regular file trs ?
                        ui.helper.find.returns([
-                               $('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'),
-                               $('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>')
+                               $('<tr data-file="One.txt" data-dir="' + testDir + '"></tr>'),
+                               $('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>')
                        ]);
                        // simulate drop event
-                       FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui);
+                       FileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
 
                        // will trigger two calls to move.php (first one was previous list.php)
                        expect(fakeServer.requests.length).toEqual(3);
@@ -976,14 +1068,12 @@ describe('FileList tests', function() {
                                }
                        };
                        // returns a list of tr that were dragged
-                       // FIXME: why are their attributes different than the
-                       // regular file trs ?
                        ui.helper.find.returns([
-                               $('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'),
-                               $('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>')
+                               $('<tr data-file="One.txt" data-dir="' + testDir + '"></tr>'),
+                               $('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>')
                        ]);
                        // simulate drop event
-                       FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui);
+                       FileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
 
                        // no extra server request
                        expect(fakeServer.requests.length).toEqual(1);