]> source.dussan.org Git - nextcloud-server.git/commitdiff
Fix file selection for infinite scrolling
authorVincent Petry <pvince81@owncloud.com>
Wed, 12 Feb 2014 13:50:23 +0000 (14:50 +0100)
committerVincent Petry <pvince81@owncloud.com>
Mon, 28 Apr 2014 12:55:00 +0000 (14:55 +0200)
- moved file selection code to FileList
- fix selection summary when all files are selected
- nextPage now auto-selects files if "select all" checkbox is checked
- fixed trashbin to use the same selection logic as FileList

apps/files/css/files.css
apps/files/js/filelist.js
apps/files/js/files.js
apps/files/tests/js/filelistSpec.js
apps/files/tests/js/filesSpec.js
apps/files_trashbin/js/filelist.js
apps/files_trashbin/js/trash.js
core/js/js.js

index 474f1af0720f52fd73b9e1deee3a151825644a49..533050691d5e75b94bce6bcf047eec6828dfa1ea 100644 (file)
@@ -310,7 +310,6 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
 
 /* Actions for selected files */
 .selectedActions {
-       display: none;
        position: absolute;
        top: -1px;
        right: 0;
index 223f4bb44098f9d35bacbc7022d6f0a474019bc3..02754d7acbb907517a5be9be637dd2fcd6f08af0 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /* global OC, t, n, FileList, FileActions, Files, FileSummary, BreadCrumb */
-/* global procesSelection, dragOptions, folderDropOptions */
+/* global dragOptions, folderDropOptions */
 window.FileList = {
        appName: t('files', 'Files'),
        isEmpty: true,
@@ -60,6 +60,142 @@ window.FileList = {
                        var width = $(this).width();
                        FileList.breadcrumb.resize(width, false);
                });
+
+               this.$fileList.on('click','td.filename a', this._onClickFile);
+               this.$fileList.on('change', 'td.filename input:checkbox', this._onClickFileCheckbox);
+               this.$el.find('#select_all').click(this._onClickSelectAll);
+               this.$el.find('.download').click(this._onClickDownloadSelected);
+               this.$el.find('.delete-selected').click(this._onClickDeleteSelected);
+       },
+
+       /**
+        * Event handler for when clicking on files to select them
+        */
+       _onClickFile: function(event) {
+               if (event.ctrlKey || event.shiftKey) {
+                       event.preventDefault();
+                       if (event.shiftKey) {
+                               var last = $(FileList._lastChecked).parent().parent().prevAll().length;
+                               var first = $(this).parent().parent().prevAll().length;
+                               var start = Math.min(first, last);
+                               var end = Math.max(first, last);
+                               var rows = $(this).parent().parent().parent().children('tr');
+                               for (var i = start; i < end; i++) {
+                                       $(rows).each(function(index) {
+                                               if (index === i) {
+                                                       var checkbox = $(this).children().children('input:checkbox');
+                                                       $(checkbox).attr('checked', 'checked');
+                                                       $(checkbox).parent().parent().addClass('selected');
+                                               }
+                                       });
+                               }
+                       }
+                       var checkbox = $(this).parent().children('input:checkbox');
+                       FileList._lastChecked = checkbox;
+                       if ($(checkbox).attr('checked')) {
+                               $(checkbox).removeAttr('checked');
+                               $(checkbox).parent().parent().removeClass('selected');
+                               $('#select_all').removeAttr('checked');
+                       } else {
+                               $(checkbox).attr('checked', 'checked');
+                               $(checkbox).parent().parent().toggleClass('selected');
+                               var selectedCount = $('td.filename input:checkbox:checked').length;
+                               if (selectedCount === $('td.filename input:checkbox').length) {
+                                       $('#select_all').attr('checked', 'checked');
+                               }
+                       }
+                       FileList.updateSelectionSummary();
+               } else {
+                       var filename=$(this).parent().parent().attr('data-file');
+                       var tr = FileList.findFileEl(filename);
+                       var renaming=tr.data('renaming');
+                       if (!renaming) {
+                               FileActions.currentFile = $(this).parent();
+                               var mime=FileActions.getCurrentMimeType();
+                               var type=FileActions.getCurrentType();
+                               var permissions = FileActions.getCurrentPermissions();
+                               var action=FileActions.getDefault(mime,type, permissions);
+                               if (action) {
+                                       event.preventDefault();
+                                       action(filename);
+                               }
+                       }
+               }
+
+       },
+
+       /**
+        * Event handler for when clicking on a file's checkbox
+        */
+       _onClickFileCheckbox: function(event) {
+               // FIXME: not sure what the difference is supposed to be with FileList._onClickFile
+               if (event.shiftKey) {
+                       var last = $(FileList._lastChecked).parent().parent().prevAll().length;
+                       var first = $(this).parent().parent().prevAll().length;
+                       var start = Math.min(first, last);
+                       var end = Math.max(first, last);
+                       var rows = $(this).parent().parent().parent().children('tr');
+                       for (var i = start; i < end; i++) {
+                               $(rows).each(function(index) {
+                                       if (index === i) {
+                                               var checkbox = $(this).children().children('input:checkbox');
+                                               $(checkbox).attr('checked', 'checked');
+                                               $(checkbox).parent().parent().addClass('selected');
+                                       }
+                               });
+                       }
+               }
+               var selectedCount=$('td.filename input:checkbox:checked').length;
+               $(this).parent().parent().toggleClass('selected');
+               if (!$(this).attr('checked')) {
+                       $('#select_all').attr('checked',false);
+               } else {
+                       if (selectedCount===$('td.filename input:checkbox').length) {
+                               $('#select_all').attr('checked',true);
+                       }
+               }
+               FileList.updateSelectionSummary();
+       },
+
+       /**
+        * Event handler for when selecting/deselecting all files
+        */
+       _onClickSelectAll: function(e) {
+               var checked = $(this).prop('checked');
+               FileList.$fileList.find('td.filename input:checkbox').prop('checked', checked)
+                       .parent().parent().toggleClass('selected', checked);
+               FileList.updateSelectionSummary();
+       },
+
+       /**
+        * Event handler for when clicking on "Download" for the selected files
+        */
+       _onClickDownloadSelected: function(event) {
+               var files;
+               var dir = FileList.getCurrentDirectory();
+               if (FileList.isAllSelected()) {
+                       files = OC.basename(dir);
+                       dir = OC.dirname(dir) || '/';
+               }
+               else {
+                       files = FileList.getSelectedFiles('name');
+               }
+               OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
+               OC.redirect(Files.getDownloadUrl(files, dir));
+               return false;
+       },
+
+       /**
+        * Event handler for when clicking on "Delete" for the selected files
+        */
+       _onClickDeleteSelected: function(event) {
+               var files = null;
+               if (!FileList.isAllSelected()) {
+                       files = FileList.getSelectedFiles('name');
+               }
+               FileList.do_delete(files);
+               event.preventDefault();
+               return false;
        },
 
        /**
@@ -79,7 +215,7 @@ window.FileList = {
                if (this.pageNumber + 1 >= this.totalPages) {
                        return;
                }
-               if ($(window).scrollTop() + $(window).height() > $(document).height() - 20) {
+               if ($(window).scrollTop() + $(window).height() > $(document).height() - 500) {
                        this._nextPage(true);
                }
        },
@@ -113,7 +249,7 @@ window.FileList = {
                                if (result) {
                                        if (result.status === 'success') {
                                                FileList.remove(file);
-                                               procesSelection();
+                                               FileList.updateSelectionSummary();
                                                $('#notification').hide();
                                        } else {
                                                $('#notification').hide();
@@ -152,13 +288,30 @@ window.FileList = {
                return this.$fileList.find('tr').filterAttr('data-file', fileName);
        },
 
+       /**
+        * Returns the file data from a given file element.
+        * @param $el file tr element
+        * @return file data
+        */
+       elementToFile: function($el){
+               return {
+                       id: parseInt($el.attr('data-id'), 10),
+                       name: $el.attr('data-file'),
+                       mimetype: $el.attr('data-mime'),
+                       type: $el.attr('data-type'),
+                       size: parseInt($el.attr('data-size'), 10),
+                       etag: $el.attr('data-etag'),
+               };
+       },
+
        /**
         * Appends the next page of files into the table
         * @param animate true to animate the new elements
         */
        _nextPage: function(animate) {
                var tr, index, count = this.pageSize,
-                       newTrs = [];
+                       newTrs = [],
+                       selected = this.isAllSelected();
 
                if (this.pageNumber + 1 >= this.totalPages) {
                        return;
@@ -169,6 +322,10 @@ window.FileList = {
 
                while (count > 0 && index < this.files.length) {
                        tr = this.add(this.files[index], {updateSummary: false});
+                       if (selected) {
+                               tr.addClass('selected');
+                               tr.find('input:checkbox').prop('checked', true);
+                       }
                        if (animate) {
                                tr.addClass('appear transparent'); // TODO
                                newTrs.push(tr);
@@ -201,6 +358,9 @@ window.FileList = {
                this.$fileList.detach();
                this.$fileList.empty();
 
+               // clear "Select all" checkbox
+               $('#select_all').prop('checked', false);
+
                this.isEmpty = this.files.length === 0;
                this._nextPage();
 
@@ -215,7 +375,7 @@ window.FileList = {
 
                this.fileSummary.calculate(filesArray);
 
-               procesSelection();
+               FileList.updateSelectionSummary();
                $(window).scrollTop(0);
 
                this.$fileList.trigger(jQuery.Event("updated"));
@@ -580,10 +740,14 @@ window.FileList = {
         * @param name name of the file to remove
         * @param options optional options as map:
         * "updateSummary": true to update the summary (default), false otherwise
+        * @return deleted element
         */
        remove:function(name, options){
                options = options || {};
                var fileEl = FileList.findFileEl(name);
+               if (!fileEl.length) {
+                       return null;
+               }
                if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
                        // file is only draggable when delete permissions are set
                        fileEl.find('td.filename').draggable('destroy');
@@ -824,21 +988,22 @@ window.FileList = {
                                function(result) {
                                        if (result.status === 'success') {
                                                if (params.allfiles) {
-                                                       // clear whole list
-                                                       $('#fileList tr').remove();
+                                                       FileList.setFiles([]);
                                                }
                                                else {
                                                        $.each(files,function(index,file) {
                                                                var fileEl = FileList.remove(file, {updateSummary: false});
+                                                               // FIXME: not sure why we need this after the
+                                                               // element isn't even in the DOM any more
                                                                fileEl.find('input[type="checkbox"]').prop('checked', false);
                                                                fileEl.removeClass('selected');
                                                                FileList.fileSummary.remove({type: fileEl.attr('data-type'), size: fileEl.attr('data-size')});
                                                        });
                                                }
-                                               procesSelection();
                                                checkTrashStatus();
                                                FileList.updateEmptyContent();
                                                FileList.fileSummary.update();
+                                               FileList.updateSelectionSummary();
                                                Files.updateStorageStatistics();
                                        } else {
                                                if (result.status === 'error' && result.data.message) {
@@ -941,14 +1106,95 @@ window.FileList = {
                        $(e).removeClass("searchresult");
                });
        },
+       /**
+        * Update UI based on the current selection
+        */
+       updateSelectionSummary: function() {
+               var allSelected = this.isAllSelected();
+               var selected;
+               var summary = {
+                       totalFiles: 0,
+                       totalDirs: 0,
+                       totalSize: 0
+               };
+
+               if (allSelected) {
+                       summary = this.fileSummary.summary;
+               }
+               else {
+                       selected = this.getSelectedFiles();
+                       for (var i = 0; i < selected.length; i++ ){
+                               if (selected[i].type === 'dir') {
+                                       summary.totalDirs++;
+                               }
+                               else {
+                                       summary.totalFiles++;
+                               }
+                               summary.totalSize += parseInt(selected[i].size, 10) || 0;
+                       }
+               }
+               if (summary.totalFiles === 0 && summary.totalDirs === 0) {
+                       $('#headerName span.name').text(t('files','Name'));
+                       $('#headerSize').text(t('files','Size'));
+                       $('#modified').text(t('files','Modified'));
+                       $('table').removeClass('multiselect');
+                       $('.selectedActions').addClass('hidden');
+                       $('#select_all').removeAttr('checked');
+               }
+               else {
+                       $('.selectedActions').removeClass('hidden');
+                       $('#headerSize').text(humanFileSize(summary.totalSize));
+                       var selection = '';
+                       if (summary.totalDirs > 0) {
+                               selection += n('files', '%n folder', '%n folders', summary.totalDirs);
+                               if (summary.totalFiles > 0) {
+                                       selection += ' & ';
+                               }
+                       }
+                       if (summary.totalFiles > 0) {
+                               selection += n('files', '%n file', '%n files', summary.totalFiles);
+                       }
+                       $('#headerName span.name').text(selection);
+                       $('#modified').text('');
+                       $('table').addClass('multiselect');
+               }
+       },
+
        /**
         * Returns whether all files are selected
         * @return true if all files are selected, false otherwise
         */
        isAllSelected: function() {
-               return $('#select_all').prop('checked');
+               return this.$el.find('#select_all').prop('checked');
+       },
+
+       /**
+        * @brief get a list of selected files
+        * @param {string} property (option) the property of the file requested
+        * @return {array}
+        *
+        * possible values for property: name, mime, size and type
+        * if property is set, an array with that property for each file is returnd
+        * if it's ommited an array of objects with all properties is returned
+        */
+       getSelectedFiles: function(property) {
+               var elements=$('td.filename input:checkbox:checked').parent().parent();
+               var files=[];
+               elements.each(function(i,element) {
+                       // TODO: make the json format the same as in FileList.add()
+                       var file = FileList.elementToFile($(element));
+                       // FIXME: legacy attributes
+                       file.origin = file.id;
+                       file.mime = file.mimetype;
+                       if (property) {
+                               files.push(file[property]);
+                       } else {
+                               files.push(file);
+                       }
+               });
+               return files;
        }
-};
+}
 
 $(document).ready(function() {
        FileList.initialize();
index 5e669a796a9efdb95f95f0f69cebb59822408619..6cb0d41a611fecd6d3eeaa021ab61b38b5e42145 100644 (file)
@@ -209,7 +209,7 @@ $(document).ready(function() {
        // Trigger cancelling of file upload
        $('#uploadprogresswrapper .stop').on('click', function() {
                OC.Upload.cancelUploads();
-               procesSelection();
+               FileList.updateSelectionSummary();
        });
 
        // Show trash bin
@@ -217,130 +217,6 @@ $(document).ready(function() {
                window.location=OC.filePath('files_trashbin', '', 'index.php');
        });
 
-       var lastChecked;
-
-       // Sets the file link behaviour :
-       $('#fileList').on('click','td.filename a',function(event) {
-               if (event.ctrlKey || event.shiftKey) {
-                       event.preventDefault();
-                       if (event.shiftKey) {
-                               var last = $(lastChecked).parent().parent().prevAll().length;
-                               var first = $(this).parent().parent().prevAll().length;
-                               var start = Math.min(first, last);
-                               var end = Math.max(first, last);
-                               var rows = $(this).parent().parent().parent().children('tr');
-                               for (var i = start; i < end; i++) {
-                                       $(rows).each(function(index) {
-                                               if (index === i) {
-                                                       var checkbox = $(this).children().children('input:checkbox');
-                                                       $(checkbox).attr('checked', 'checked');
-                                                       $(checkbox).parent().parent().addClass('selected');
-                                               }
-                                       });
-                               }
-                       }
-                       var checkbox = $(this).parent().children('input:checkbox');
-                       lastChecked = checkbox;
-                       if ($(checkbox).attr('checked')) {
-                               $(checkbox).removeAttr('checked');
-                               $(checkbox).parent().parent().removeClass('selected');
-                               $('#select_all').removeAttr('checked');
-                       } else {
-                               $(checkbox).attr('checked', 'checked');
-                               $(checkbox).parent().parent().toggleClass('selected');
-                               var selectedCount = $('td.filename input:checkbox:checked').length;
-                               if (selectedCount === $('td.filename input:checkbox').length) {
-                                       $('#select_all').attr('checked', 'checked');
-                               }
-                       }
-                       procesSelection();
-               } else {
-                       var filename=$(this).parent().parent().attr('data-file');
-                       var tr = FileList.findFileEl(filename);
-                       var renaming=tr.data('renaming');
-                       if (!renaming) {
-                               FileActions.currentFile = $(this).parent();
-                               var mime=FileActions.getCurrentMimeType();
-                               var type=FileActions.getCurrentType();
-                               var permissions = FileActions.getCurrentPermissions();
-                               var action=FileActions.getDefault(mime,type, permissions);
-                               if (action) {
-                                       event.preventDefault();
-                                       action(filename);
-                               }
-                       }
-               }
-
-       });
-
-       // Sets the select_all checkbox behaviour :
-       $('#select_all').click(function() {
-               if ($(this).attr('checked')) {
-                       // Check all
-                       $('td.filename input:checkbox').attr('checked', true);
-                       $('td.filename input:checkbox').parent().parent().addClass('selected');
-               } else {
-                       // Uncheck all
-                       $('td.filename input:checkbox').attr('checked', false);
-                       $('td.filename input:checkbox').parent().parent().removeClass('selected');
-               }
-               procesSelection();
-       });
-
-       $('#fileList').on('change', 'td.filename input:checkbox',function(event) {
-               if (event.shiftKey) {
-                       var last = $(lastChecked).parent().parent().prevAll().length;
-                       var first = $(this).parent().parent().prevAll().length;
-                       var start = Math.min(first, last);
-                       var end = Math.max(first, last);
-                       var rows = $(this).parent().parent().parent().children('tr');
-                       for (var i = start; i < end; i++) {
-                               $(rows).each(function(index) {
-                                       if (index === i) {
-                                               var checkbox = $(this).children().children('input:checkbox');
-                                               $(checkbox).attr('checked', 'checked');
-                                               $(checkbox).parent().parent().addClass('selected');
-                                       }
-                               });
-                       }
-               }
-               var selectedCount=$('td.filename input:checkbox:checked').length;
-               $(this).parent().parent().toggleClass('selected');
-               if (!$(this).attr('checked')) {
-                       $('#select_all').attr('checked',false);
-               } else {
-                       if (selectedCount===$('td.filename input:checkbox').length) {
-                               $('#select_all').attr('checked',true);
-                       }
-               }
-               procesSelection();
-       });
-
-       $('.download').click('click',function(event) {
-               var files;
-               var dir = FileList.getCurrentDirectory();
-               if (FileList.isAllSelected()) {
-                       files = OC.basename(dir);
-                       dir = OC.dirname(dir) || '/';
-               }
-               else {
-                       files = Files.getSelectedFiles('name');
-               }
-               OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
-               OC.redirect(Files.getDownloadUrl(files, dir));
-               return false;
-       });
-
-       $('.delete-selected').click(function(event) {
-               var files = Files.getSelectedFiles('name');
-               event.preventDefault();
-               if (FileList.isAllSelected()) {
-                       files = null;
-               }
-               FileList.do_delete(files);
-               return false;
-       });
-
        // drag&drop support using jquery.fileupload
        // TODO use OC.dialogs
        $(document).bind('drop dragover', function (e) {
@@ -440,7 +316,7 @@ var createDragShadow = function(event) {
                $(event.target).parents('tr').find('td input:first').prop('checked',true);
        }
 
-       var selectedFiles = Files.getSelectedFiles();
+       var selectedFiles = FileList.getSelectedFiles();
 
        if (!isDragSelected && selectedFiles.length === 1) {
                //revert the selection
@@ -539,7 +415,7 @@ var folderDropOptions={
                                                oldFile.find('td.filesize').text(humanFileSize(newSize));
 
                                                FileList.remove(file);
-                                               procesSelection();
+                                               FileList.updateSelectionSummary();
                                                $('#notification').hide();
                                        } else {
                                                $('#notification').hide();
@@ -556,78 +432,6 @@ var folderDropOptions={
        tolerance: 'pointer'
 };
 
-function procesSelection() {
-       var selected = Files.getSelectedFiles();
-       var selectedFiles = selected.filter(function(el) {
-               return el.type==='file';
-       });
-       var selectedFolders = selected.filter(function(el) {
-               return el.type==='dir';
-       });
-       if (selectedFiles.length === 0 && selectedFolders.length === 0) {
-               $('#headerName span.name').text(t('files','Name'));
-               $('#headerSize').text(t('files','Size'));
-               $('#modified').text(t('files','Modified'));
-               $('table').removeClass('multiselect');
-               $('.selectedActions').hide();
-               $('#select_all').removeAttr('checked');
-       }
-       else {
-               $('.selectedActions').show();
-               var totalSize = 0;
-               for(var i=0; i<selectedFiles.length; i++) {
-                       totalSize+=selectedFiles[i].size;
-               }
-               for(var i=0; i<selectedFolders.length; i++) {
-                       totalSize+=selectedFolders[i].size;
-               }
-               $('#headerSize').text(humanFileSize(totalSize));
-               var selection = '';
-               if (selectedFolders.length > 0) {
-                       selection += n('files', '%n folder', '%n folders', selectedFolders.length);
-                       if (selectedFiles.length > 0) {
-                               selection += ' & ';
-                       }
-               }
-               if (selectedFiles.length>0) {
-                       selection += n('files', '%n file', '%n files', selectedFiles.length);
-               }
-               $('#headerName span.name').text(selection);
-               $('#modified').text('');
-               $('table').addClass('multiselect');
-       }
-}
-
-/**
- * @brief get a list of selected files
- * @param {string} property (option) the property of the file requested
- * @return {array}
- *
- * possible values for property: name, mime, size and type
- * if property is set, an array with that property for each file is returnd
- * if it's ommited an array of objects with all properties is returned
- */
-Files.getSelectedFiles = function(property) {
-       var elements=$('td.filename input:checkbox:checked').parent().parent();
-       var files=[];
-       elements.each(function(i,element) {
-               var file={
-                       name:$(element).attr('data-file'),
-                       mime:$(element).data('mime'),
-                       type:$(element).data('type'),
-                       size:$(element).data('size'),
-                       etag:$(element).data('etag'),
-                       origin: $(element).data('id')
-               };
-               if (property) {
-                       files.push(file[property]);
-               } else {
-                       files.push(file);
-               }
-       });
-       return files;
-}
-
 Files.getMimeIcon = function(mime, ready) {
        if (Files.getMimeIcon.cache[mime]) {
                ready(Files.getMimeIcon.cache[mime]);
index 6e80d78eee049618cbb5a00392c707e387fd8a05..93e7c81cb1f799e9bf21206d5c7bfcf97132694a 100644 (file)
@@ -48,8 +48,15 @@ describe('FileList tests', function() {
                        '   <div class="notCreatable"></div>' +
                        '</div>' +
                        // dummy table
+                       // TODO: at some point this will be rendered by the FileList class itself!
                        '<table id="filestable">' +
-                       '<thead><tr><th class="hidden">Name</th></tr></thead>' +
+                       '<thead><tr><th id="headerName" class="hidden">' +
+                       '<input type="checkbox" id="select_all">' +
+                       '<span class="name">Name</span>' +
+                       '<span class="selectedActions hidden">' +
+                       '<a href class="download">Download</a>' +
+                       '<a href class="delete-selected">Delete</a></span>' +
+                       '</th></tr></thead>' +
                        '<tbody id="fileList"></tbody>' +
                        '<tfoot></tfoot>' +
                        '</table>' +
@@ -61,25 +68,29 @@ describe('FileList tests', function() {
                        type: 'file',
                        name: 'One.txt',
                        mimetype: 'text/plain',
-                       size: 12
+                       size: 12,
+                       etag: 'abc'
                }, {
                        id: 2,
                        type: 'file',
                        name: 'Two.jpg',
                        mimetype: 'image/jpeg',
-                       size: 12049
+                       size: 12049,
+                       etag: 'def',
                }, {
                        id: 3,
                        type: 'file',
                        name: 'Three.pdf',
                        mimetype: 'application/pdf',
-                       size: 58009
+                       size: 58009,
+                       etag: '123',
                }, {
                        id: 4,
                        type: 'dir',
                        name: 'somedir',
                        mimetype: 'httpd/unix-directory',
-                       size: 250
+                       size: 250,
+                       etag: '456'
                }];
 
                FileList.initialize();
@@ -380,7 +391,7 @@ describe('FileList tests', function() {
                        $input.val('One_renamed.txt').blur();
 
                        expect(fakeServer.requests.length).toEqual(1);
-                       var request = fakeServer.requests[0];
+                       request = fakeServer.requests[0];
                        expect(request.url.substr(0, request.url.indexOf('?'))).toEqual(OC.webroot + '/index.php/apps/files/ajax/rename.php');
                        expect(OC.parseQueryString(request.url)).toEqual({'dir': '/subdir', newname: 'One_renamed.txt', file: 'One.txt'});
 
@@ -519,6 +530,16 @@ describe('FileList tests', function() {
                        FileList.setFiles(testFiles);
                        expect(handler.calledOnce).toEqual(true);
                });
+               it('does not update summary when removing non-existing files', function() {
+                       // single file
+                       FileList.setFiles([testFiles[0]]);
+                       $summary = $('#filestable .summary');
+                       expect($summary.hasClass('hidden')).toEqual(false);
+                       expect($summary.find('.info').text()).toEqual('0 folders and 1 file');
+                       FileList.remove('unexist.txt');
+                       expect($summary.hasClass('hidden')).toEqual(false);
+                       expect($summary.find('.info').text()).toEqual('0 folders and 1 file');
+               });
        });
        describe('file previews', function() {
                var previewLoadStub;
@@ -811,4 +832,188 @@ describe('FileList tests', function() {
                        expect(Files.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
                });
        });
+       describe('File selection', function() {
+               beforeEach(function() {
+                       FileList.setFiles(testFiles);
+               });
+               it('Selects a file when clicking its checkbox', function() {
+                       var $tr = FileList.findFileEl('One.txt');
+                       expect($tr.find('input:checkbox').prop('checked')).toEqual(false);
+                       $tr.find('td.filename input:checkbox').click();
+
+                       expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
+               });
+               it('Selecting all files will automatically check "select all" checkbox', function() {
+                       expect($('#select_all').prop('checked')).toEqual(false);
+                       $('#fileList tr td.filename input:checkbox').click();
+                       expect($('#select_all').prop('checked')).toEqual(true);
+               });
+               it('Clicking "select all" will select/deselect all files', function() {
+                       $('#select_all').click();
+                       expect($('#select_all').prop('checked')).toEqual(true);
+                       $('#fileList tr input:checkbox').each(function() {
+                               expect($(this).prop('checked')).toEqual(true);
+                       });
+
+                       $('#select_all').click();
+                       expect($('#select_all').prop('checked')).toEqual(false);
+
+                       $('#fileList tr input:checkbox').each(function() {
+                               expect($(this).prop('checked')).toEqual(false);
+                       });
+               });
+               it('Clicking "select all" then deselecting a file will uncheck "select all"', function() {
+                       $('#select_all').click();
+                       expect($('#select_all').prop('checked')).toEqual(true);
+
+                       var $tr = FileList.findFileEl('One.txt');
+                       $tr.find('input:checkbox').click();
+
+                       expect($('#select_all').prop('checked')).toEqual(false);
+               });
+               it('Selecting files updates selection summary', function() {
+                       var $summary = $('#headerName span.name');
+                       expect($summary.text()).toEqual('Name');
+                       FileList.findFileEl('One.txt').find('input:checkbox').click();
+                       FileList.findFileEl('Three.pdf').find('input:checkbox').click();
+                       FileList.findFileEl('somedir').find('input:checkbox').click();
+                       expect($summary.text()).toEqual('1 folder & 2 files');
+               });
+               it('Unselecting files hides selection summary', function() {
+                       var $summary = $('#headerName span.name');
+                       FileList.findFileEl('One.txt').find('input:checkbox').click().click();
+                       expect($summary.text()).toEqual('Name');
+               });
+               it('Select/deselect files shows/hides file actions', function() {
+                       var $actions = $('#headerName .selectedActions');
+                       var $checkbox = FileList.findFileEl('One.txt').find('input:checkbox');
+                       expect($actions.hasClass('hidden')).toEqual(true);
+                       $checkbox.click();
+                       expect($actions.hasClass('hidden')).toEqual(false);
+                       $checkbox.click();
+                       expect($actions.hasClass('hidden')).toEqual(true);
+               });
+               it('Selection is cleared when switching dirs', function() {
+                       $('#select_all').click();
+                       var data = {
+                               status: 'success',
+                               data: {
+                                       files: testFiles,
+                                       permissions: 31
+                               }
+                       };
+                       fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php/, [
+                                       200, {
+                                               "Content-Type": "application/json"
+                                       },
+                                       JSON.stringify(data)
+                       ]);
+                       FileList.changeDirectory('/');
+                       fakeServer.respond();
+                       expect($('#select_all').prop('checked')).toEqual(false);
+               });
+               describe('Actions', function() {
+                       beforeEach(function() {
+                               FileList.findFileEl('One.txt').find('input:checkbox').click();
+                               FileList.findFileEl('Three.pdf').find('input:checkbox').click();
+                               FileList.findFileEl('somedir').find('input:checkbox').click();
+                       });
+                       it('getSelectedFiles returns the selected files', function() {
+                               var files = FileList.getSelectedFiles();
+                               expect(files.length).toEqual(3);
+                               expect(files[0]).toEqual({
+                                       id: 1,
+                                       name: 'One.txt',
+                                       mime: 'text/plain',
+                                       mimetype: 'text/plain',
+                                       type: 'file',
+                                       size: 12,
+                                       etag: 'abc',
+                                       origin: 1
+                               });
+                               expect(files[1]).toEqual({
+                                       id: 3,
+                                       type: 'file',
+                                       name: 'Three.pdf',
+                                       mime: 'application/pdf',
+                                       mimetype: 'application/pdf',
+                                       size: 58009,
+                                       etag: '123',
+                                       origin: 3
+                               });
+                               expect(files[2]).toEqual({
+                                       id: 4,
+                                       type: 'dir',
+                                       name: 'somedir',
+                                       mime: 'httpd/unix-directory',
+                                       mimetype: 'httpd/unix-directory',
+                                       size: 250,
+                                       etag: '456',
+                                       origin: 4
+                               });
+                       });
+                       describe('Download', function() {
+                               it('Opens download URL when clicking "Download"', function() {
+                                       var redirectStub = sinon.stub(OC, 'redirect');
+                                       $('.selectedActions .download').click();
+                                       expect(redirectStub.calledOnce).toEqual(true);
+                                       expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22One.txt%22%2C%22Three.pdf%22%2C%22somedir%22%5D');
+                                       redirectStub.restore();
+                               });
+                               it('Downloads root folder when all selected in root folder', function() {
+                                       $('#dir').val('/');
+                                       $('#select_all').click();
+                                       var redirectStub = sinon.stub(OC, 'redirect');
+                                       $('.selectedActions .download').click();
+                                       expect(redirectStub.calledOnce).toEqual(true);
+                                       expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=');
+                                       redirectStub.restore();
+                               });
+                               it('Downloads parent folder when all selected in subfolder', function() {
+                                       $('#select_all').click();
+                                       var redirectStub = sinon.stub(OC, 'redirect');
+                                       $('.selectedActions .download').click();
+                                       expect(redirectStub.calledOnce).toEqual(true);
+                                       expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=subdir');
+                                       redirectStub.restore();
+                               });
+                       });
+                       describe('Delete', function() {
+                               it('Deletes selected files when "Delete" clicked', function() {
+                                       var request;
+                                       $('.selectedActions .delete-selected').click();
+                                       expect(fakeServer.requests.length).toEqual(1);
+                                       request = fakeServer.requests[0];
+                                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
+                                       expect(OC.parseQueryString(request.requestBody))
+                                               .toEqual({'dir': '/subdir', files: '["One.txt","Three.pdf","somedir"]'});
+                                       fakeServer.requests[0].respond(
+                                               200,
+                                               { 'Content-Type': 'application/json' },
+                                               JSON.stringify({status: 'success'})
+                                       );
+                                       expect(FileList.findFileEl('One.txt').length).toEqual(0);
+                                       expect(FileList.findFileEl('Three.pdf').length).toEqual(0);
+                                       expect(FileList.findFileEl('somedir').length).toEqual(0);
+                                       expect(FileList.findFileEl('Two.jpg').length).toEqual(1);
+                               });
+                               it('Deletes all files when all selected when "Delete" clicked', function() {
+                                       var request;
+                                       $('#select_all').click();
+                                       $('.selectedActions .delete-selected').click();
+                                       expect(fakeServer.requests.length).toEqual(1);
+                                       request = fakeServer.requests[0];
+                                       expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
+                                       expect(OC.parseQueryString(request.requestBody))
+                                               .toEqual({'dir': '/subdir', allfiles: 'true'});
+                                       fakeServer.requests[0].respond(
+                                               200,
+                                               { 'Content-Type': 'application/json' },
+                                               JSON.stringify({status: 'success'})
+                                       );
+                                       expect(FileList.isEmpty).toEqual(true);
+                               });
+                       });
+               });
+       });
 });
index 018c8ef0f3cff215a718a9491e9fbad12a47c1b2..7f8848619f500c57b795439783d3d29237a3a689 100644 (file)
@@ -19,7 +19,7 @@
 *
 */
 
-/* global Files */
+/* global OC, Files */
 describe('Files tests', function() {
        describe('File name validation', function() {
                it('Validates correct file names', function() {
@@ -82,4 +82,30 @@ describe('Files tests', function() {
                        }
                });
        });
+       describe('getDownloadUrl', function() {
+               var curDirStub;
+               beforeEach(function() {
+                       curDirStub = sinon.stub(FileList, 'getCurrentDirectory');
+               });
+               afterEach(function() {
+                       curDirStub.restore();
+               });
+               it('returns the ajax download URL when only filename specified', function() {
+                       curDirStub.returns('/subdir');
+                       var url = Files.getDownloadUrl('test file.txt');
+                       expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20file.txt');
+               });
+               it('returns the ajax download URL when filename and dir specified', function() {
+                       var url = Files.getDownloadUrl('test file.txt', '/subdir');
+                       expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20file.txt');
+               });
+               it('returns the ajax download URL when filename and root dir specific', function() {
+                       var url = Files.getDownloadUrl('test file.txt', '/');
+                       expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=test%20file.txt');
+               });
+               it('returns the ajax download URL when multiple files specified', function() {
+                       var url = Files.getDownloadUrl(['test file.txt', 'abc.txt'], '/subdir');
+                       expect(url).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22test%20file.txt%22%2C%22abc.txt%22%5D');
+               });
+       });
 });
index 7795daf2775bbc609c82c7dfcac868d565cccc48..6c9b345086a8a731e4a0e2418e895f92c29742d4 100644 (file)
                $('#emptycontent').toggleClass('hidden', exists);
                $('#filestable th').toggleClass('hidden', !exists);
        };
+
+       var oldInit = FileList.initialize;
+       FileList.initialize = function() {
+               var result = oldInit.apply(this, arguments);
+               $('.undelete').click('click', FileList._onClickRestoreSelected);
+               return result;
+       };
+
+       FileList._removeCallback = function(result) {
+               if (result.status !== 'success') {
+                       OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
+               }
+
+               var files = result.data.success;
+               var $el;
+               for (var i = 0; i < files.length; i++) {
+                       $el = FileList.remove(OC.basename(files[i].filename), {updateSummary: false});
+                       FileList.fileSummary.remove({type: $el.attr('data-type'), size: $el.attr('data-size')});
+               }
+               FileList.fileSummary.update();
+               FileList.updateEmptyContent();
+               enableActions();
+       }
+
+       FileList._onClickRestoreSelected = function(event) {
+               event.preventDefault();
+               var allFiles = $('#select_all').is(':checked');
+               var files = [];
+               var params = {};
+               disableActions();
+               if (allFiles) {
+                       FileList.showMask();
+                       params = {
+                               allfiles: true,
+                               dir: FileList.getCurrentDirectory()
+                       };
+               }
+               else {
+                       files = FileList.getSelectedFiles('name');
+                       for (var i = 0; i < files.length; i++) {
+                               var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
+                               deleteAction.removeClass('delete-icon').addClass('progress-icon');
+                       }
+                       params = {
+                               files: JSON.stringify(files),
+                               dir: FileList.getCurrentDirectory()
+                       };
+               }
+
+               $.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'),
+                       params,
+                       function(result) {
+                               if (allFiles) {
+                                       if (result.status !== 'success') {
+                                               OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
+                                       }
+                                       FileList.hideMask();
+                                       // simply remove all files
+                                       FileList.update('');
+                                       enableActions();
+                               }
+                               else {
+                                       FileList._removeCallback(result);
+                               }
+                       }
+               );
+       };
+
+       FileList._onClickDeleteSelected = function(event) {
+               event.preventDefault();
+               var allFiles = $('#select_all').is(':checked');
+               var files = [];
+               var params = {};
+               if (allFiles) {
+                       params = {
+                               allfiles: true,
+                               dir: FileList.getCurrentDirectory()
+                       };
+               }
+               else {
+                       files = FileList.getSelectedFiles('name');
+                       params = {
+                               files: JSON.stringify(files),
+                               dir: FileList.getCurrentDirectory()
+                       };
+               }
+
+               disableActions();
+               if (allFiles) {
+                       FileList.showMask();
+               }
+               else {
+                       for (var i = 0; i < files.length; i++) {
+                               var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
+                               deleteAction.removeClass('delete-icon').addClass('progress-icon');
+                       }
+               }
+
+               $.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'),
+                               params,
+                               function(result) {
+                                       if (allFiles) {
+                                               if (result.status !== 'success') {
+                                                       OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
+                                               }
+                                               FileList.hideMask();
+                                               // simply remove all files
+                                               FileList.setFiles([]);
+                                               enableActions();
+                                       }
+                                       else {
+                                               FileList._removeCallback(result);
+                                       }
+                               }
+               );
+       };
+
+       var oldClickFile = FileList._onClickFile;
+       FileList._onClickFile = function(event) {
+               var mime = $(this).parent().parent().data('mime');
+               if (mime !== 'httpd/unix-directory') {
+                       event.preventDefault();
+               }
+               return oldClickFile.apply(this, arguments);
+       };
+
 })();
index 4ed5ba1c76e22042dce67f89a69e65694ffb40c7..5f2436de8096c78bb7eaffdc50c0dc29f9ee1713 100644 (file)
@@ -28,22 +28,6 @@ $(document).ready(function() {
                return name;
        }
 
-       function removeCallback(result) {
-               if (result.status !== 'success') {
-                       OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
-               }
-
-               var files = result.data.success;
-               var $el;
-               for (var i = 0; i < files.length; i++) {
-                       $el = FileList.remove(OC.basename(files[i].filename), {updateSummary: false});
-                       FileList.fileSummary.remove({type: $el.attr('data-type'), size: $el.attr('data-size')});
-               }
-               FileList.fileSummary.update();
-               FileList.updateEmptyContent();
-               enableActions();
-       }
-
        Files.updateStorageStatistics = function() {
                // no op because the trashbin doesn't have
                // storage info like free space / used space
@@ -59,7 +43,7 @@ $(document).ready(function() {
                                        files: JSON.stringify([filename]),
                                        dir: FileList.getCurrentDirectory()
                                },
-                           removeCallback
+                           FileList._removeCallback
                        );
                }, t('files_trashbin', 'Restore'));
        };
@@ -76,153 +60,10 @@ $(document).ready(function() {
                                files: JSON.stringify([filename]),
                                dir: FileList.getCurrentDirectory()
                        },
-                       removeCallback
+                       FileList._removeCallback
                );
        });
 
-       // Sets the select_all checkbox behaviour :
-       $('#select_all').click(function() {
-               if ($(this).attr('checked')) {
-                       // Check all
-                       $('td.filename input:checkbox').attr('checked', true);
-                       $('td.filename input:checkbox').parent().parent().addClass('selected');
-               } else {
-                       // Uncheck all
-                       $('td.filename input:checkbox').attr('checked', false);
-                       $('td.filename input:checkbox').parent().parent().removeClass('selected');
-               }
-               procesSelection();
-       });
-       $('.undelete').click('click', function(event) {
-               event.preventDefault();
-               var allFiles = $('#select_all').is(':checked');
-               var files = [];
-               var params = {};
-               disableActions();
-               if (allFiles) {
-                       FileList.showMask();
-                       params = {
-                               allfiles: true,
-                               dir: FileList.getCurrentDirectory()
-                       };
-               }
-               else {
-                       files = Files.getSelectedFiles('name');
-                       for (var i = 0; i < files.length; i++) {
-                               var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
-                               deleteAction.removeClass('delete-icon').addClass('progress-icon');
-                       }
-                       params = {
-                               files: JSON.stringify(files),
-                               dir: FileList.getCurrentDirectory()
-                       };
-               }
-
-               $.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'),
-                       params,
-                       function(result) {
-                               if (allFiles) {
-                                       if (result.status !== 'success') {
-                                               OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
-                                       }
-                                       FileList.hideMask();
-                                       // simply remove all files
-                                       FileList.update('');
-                                       enableActions();
-                               }
-                               else {
-                                       removeCallback(result);
-                               }
-                       }
-               );
-       });
-
-       $('.delete').click('click', function(event) {
-               event.preventDefault();
-               var allFiles = $('#select_all').is(':checked');
-               var files = [];
-               var params = {};
-               if (allFiles) {
-                       params = {
-                               allfiles: true,
-                               dir: FileList.getCurrentDirectory()
-                       };
-               }
-               else {
-                       files = Files.getSelectedFiles('name');
-                       params = {
-                               files: JSON.stringify(files),
-                               dir: FileList.getCurrentDirectory()
-                       };
-               }
-
-               disableActions();
-               if (allFiles) {
-                       FileList.showMask();
-               }
-               else {
-                       for (var i = 0; i < files.length; i++) {
-                               var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
-                               deleteAction.removeClass('delete-icon').addClass('progress-icon');
-                       }
-               }
-
-               $.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'),
-                               params,
-                               function(result) {
-                                       if (allFiles) {
-                                               if (result.status !== 'success') {
-                                                       OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error'));
-                                               }
-                                               FileList.hideMask();
-                                               // simply remove all files
-                                               FileList.setFiles([]);
-                                               enableActions();
-                                       }
-                                       else {
-                                               removeCallback(result);
-                                       }
-                               }
-               );
-
-       });
-
-       $('#fileList').on('click', 'td.filename input', function() {
-               var checkbox = $(this).parent().children('input:checkbox');
-               $(checkbox).parent().parent().toggleClass('selected');
-               if ($(checkbox).is(':checked')) {
-                       var selectedCount = $('td.filename input:checkbox:checked').length;
-                       if (selectedCount === $('td.filename input:checkbox').length) {
-                               $('#select_all').prop('checked', true);
-                       }
-               } else {
-                       $('#select_all').prop('checked',false);
-               }
-               procesSelection();
-       });
-
-       $('#fileList').on('click', 'td.filename a', function(event) {
-               var mime = $(this).parent().parent().data('mime');
-               if (mime !== 'httpd/unix-directory') {
-                       event.preventDefault();
-               }
-               var filename = $(this).parent().parent().attr('data-file');
-               var tr = FileList.findFileEl(filename);
-               var renaming = tr.data('renaming');
-               if(!renaming){
-                       if(mime.substr(0, 5) === 'text/'){ //no texteditor for now
-                               return;
-                       }
-                       var type = $(this).parent().parent().data('type');
-                       var permissions = $(this).parent().parent().data('permissions');
-                       var action = FileActions.getDefault(mime, type, permissions);
-                       if(action){
-                               event.preventDefault();
-                               action(filename);
-                       }
-               }
-       });
-
        /**
         * Override crumb URL maker (hacky!)
         */
index 325be6cdc53dd942cdd0faf7092575ec1ac92433..27bc3c651e33125ef27986314b3576df4ac27477 100644 (file)
@@ -1250,7 +1250,7 @@ function relative_modified_date(timestamp) {
 }
 
 /**
- *  @todo Write documentation
+ * Utility functions
  */
 OC.Util = {
        // TODO: remove original functions from global namespace