From 9c2fbea6a4396a29ce8c966c9ea7646aa8fc9be5 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 12 Feb 2014 14:50:23 +0100 Subject: Fix file selection for infinite scrolling - 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/js/files.js | 202 +------------------------------------------------ 1 file changed, 3 insertions(+), 199 deletions(-) (limited to 'apps/files/js/files.js') diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 5e669a796a9..6cb0d41a611 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -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 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]); -- cgit v1.2.3 From fd982df6aea09492e02cc65de02ee8250a1a229c Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 4 Apr 2014 18:46:08 +0200 Subject: Fixed selection to be based on FileList.files The file selection is now based on the internal model array FileList.files instead of the visible checkboxes. This makes it possible to virtually select files that haven't been rendered yet (select all, then deselect a visible one) Added more unit tests for selection (with shift and ctrl as well) --- apps/files/js/filelist.js | 225 ++++++++++++++++++------------------ apps/files/js/files.js | 12 +- apps/files/js/filesummary.js | 22 +++- apps/files/tests/js/filelistSpec.js | 187 ++++++++++++++++++++++++------ apps/files_trashbin/js/filelist.js | 4 +- 5 files changed, 289 insertions(+), 161 deletions(-) (limited to 'apps/files/js/files.js') diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 0847edd02bb..7c82ec92473 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -28,6 +28,23 @@ window.FileList = { pageSize: 20, totalPages: 0, + /** + * Array of files in the current folder. + * The entries are of file data. + */ + files: [], + + /** + * Map of file id to file data + */ + _selectedFiles: {}, + + /** + * Summary of selected files. + * Instance of FileSummary. + */ + _selectionSummary: null, + /** * Compare two file info objects, sorting by * folders first, then by name. @@ -55,6 +72,8 @@ window.FileList = { this.$el = $('#filestable'); this.$fileList = $('#fileList'); this.files = []; + this._selectedFiles = {}; + this._selectionSummary = new FileSummary(); this.fileSummary = this._createSummary(); @@ -81,49 +100,71 @@ window.FileList = { this.$el.find('.delete-selected').click(this._onClickDeleteSelected); }, + /** + * Selected/deselects the given file element and updated + * the internal selection cache. + * + * @param $tr single file row element + * @param state true to select, false to deselect + */ + _selectFileEl: function($tr, state) { + var $checkbox = $tr.find('input:checkbox'); + var oldData = !!this._selectedFiles[$tr.data('id')]; + var data; + $checkbox.prop('checked', state); + $tr.toggleClass('selected', state); + // already selected ? + if (state === oldData) { + return; + } + data = this.elementToFile($tr); + if (state) { + this._selectedFiles[$tr.data('id')] = data; + this._selectionSummary.add(data); + } + else { + delete this._selectedFiles[$tr.data('id')]; + this._selectionSummary.remove(data); + } + this.$el.find('#select_all').prop('checked', this._selectionSummary.getTotal() === this.files.length); + }, + /** * Event handler for when clicking on files to select them */ _onClickFile: function(event) { + var $tr = $(this).closest('tr'); 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 $lastTr = $(FileList._lastChecked); + var lastIndex = $lastTr.index(); + var currentIndex = $tr.index(); + var $rows = FileList.$fileList.children('tr'); + + // last clicked checkbox below current one ? + if (lastIndex > currentIndex) { + var aux = lastIndex; + lastIndex = currentIndex; + currentIndex = aux; } - } - 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'); + + // auto-select everything in-between + for (var i = lastIndex + 1; i < currentIndex; i++) { + FileList._selectFileEl($rows.eq(i), true); } } + else { + FileList._lastChecked = $tr; + } + var $checkbox = $tr.find('input:checkbox'); + FileList._selectFileEl($tr, !$checkbox.prop('checked')); FileList.updateSelectionSummary(); } else { - var filename=$(this).parent().parent().attr('data-file'); - var tr = FileList.findFileEl(filename); - var renaming=tr.data('renaming'); + var filename = $tr.attr('data-file'); + var renaming = $tr.data('renaming'); if (!renaming) { - FileActions.currentFile = $(this).parent(); + FileActions.currentFile = $tr.find('td'); var mime=FileActions.getCurrentMimeType(); var type=FileActions.getCurrentType(); var permissions = FileActions.getCurrentPermissions(); @@ -134,49 +175,36 @@ window.FileList = { } } } - }, /** * 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); - } - } + _onClickFileCheckbox: function() { + var $tr = $(this).closest('tr'); + FileList._selectFileEl($tr, !$tr.hasClass('selected')); + FileList._lastChecked = $tr; FileList.updateSelectionSummary(); }, /** * Event handler for when selecting/deselecting all files */ - _onClickSelectAll: function(e) { + _onClickSelectAll: function() { var checked = $(this).prop('checked'); FileList.$fileList.find('td.filename input:checkbox').prop('checked', checked) - .parent().parent().toggleClass('selected', checked); + .closest('tr').toggleClass('selected', checked); + FileList._selectedFiles = {}; + if (checked) { + for (var i = 0; i < FileList.files.length; i++) { + var fileData = FileList.files[i]; + FileList._selectedFiles[fileData.id] = fileData; + FileList._selectionSummary.add(fileData); + } + } + else { + FileList._selectionSummary.clear(); + } FileList.updateSelectionSummary(); }, @@ -191,7 +219,7 @@ window.FileList = { dir = OC.dirname(dir) || '/'; } else { - files = FileList.getSelectedFiles('name'); + files = _.pluck(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)); @@ -204,7 +232,7 @@ window.FileList = { _onClickDeleteSelected: function(event) { var files = null; if (!FileList.isAllSelected()) { - files = FileList.getSelectedFiles('name'); + files = _.pluck(FileList.getSelectedFiles(), 'name'); } FileList.do_delete(files); event.preventDefault(); @@ -322,8 +350,9 @@ window.FileList = { var index = this.$fileList.children().length, count = this.pageSize, tr, + fileData, newTrs = [], - selected = this.isAllSelected(); + isAllSelected = this.isAllSelected(); if (index >= this.files.length) { return; @@ -332,9 +361,10 @@ window.FileList = { this.pageNumber++; while (count > 0 && index < this.files.length) { - tr = this._renderRow(this.files[index], {updateSummary: false}); + fileData = this.files[index]; + tr = this._renderRow(fileData, {updateSummary: false}); this.$fileList.append(tr); - if (selected) { + if (isAllSelected || this._selectedFiles[fileData.id]) { tr.addClass('selected'); tr.find('input:checkbox').prop('checked', true); } @@ -371,7 +401,7 @@ window.FileList = { this.$fileList.empty(); // clear "Select all" checkbox - $('#select_all').prop('checked', false); + this.$el.find('#select_all').prop('checked', false); this.isEmpty = this.files.length === 0; this._nextPage(); @@ -675,7 +705,9 @@ window.FileList = { previousDir: currentDir } )); - FileList.reload(); + this._selectedFiles = {}; + this._selectionSummary.clear(); + this.reload(); }, linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); @@ -812,6 +844,10 @@ window.FileList = { if (!fileEl.length) { return null; } + if (this._selectedFiles[fileEl.data('id')]) { + // remove from selection first + this._selectFileEl(fileEl, false); + } if (fileEl.data('permissions') & OC.PERMISSION_DELETE) { // file is only draggable when delete permissions are set fileEl.find('td.filename').draggable('destroy'); @@ -1131,40 +1167,17 @@ window.FileList = { * 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; - } - } + var summary = this._selectionSummary.summary; 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)); + $('#headerSize').text(OC.Util.humanFileSize(summary.totalSize)); var selection = ''; if (summary.totalDirs > 0) { selection += n('files', '%n folder', '%n folders', summary.totalDirs); @@ -1190,32 +1203,14 @@ window.FileList = { }, /** - * @brief get a list of selected files - * @param {string} property (option) the property of the file requested - * @return {array} + * Returns the file info of the selected files * - * 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 + * @return array of file names */ - 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; + getSelectedFiles: function() { + return _.values(this._selectedFiles); } -} +}; $(document).ready(function() { FileList.initialize(); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 6cb0d41a611..41c762f0fa1 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -313,19 +313,15 @@ var createDragShadow = function(event) { var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked'); if (!isDragSelected) { //select dragged file - $(event.target).parents('tr').find('td input:first').prop('checked',true); + FileList._selectFileEl($(event.target).parents('tr:first'), true); } - var selectedFiles = FileList.getSelectedFiles(); + // do not show drag shadow for too many files + var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize); if (!isDragSelected && selectedFiles.length === 1) { //revert the selection - $(event.target).parents('tr').find('td input:first').prop('checked',false); - } - - //also update class when we dragged more than one file - if (selectedFiles.length > 1) { - $(event.target).parents('tr').addClass('selected'); + FileList._selectFileEl($(event.target).parents('tr:first'), false); } // build dragshadow diff --git a/apps/files/js/filesummary.js b/apps/files/js/filesummary.js index bbe4d43ba49..b3e3beeb24a 100644 --- a/apps/files/js/filesummary.js +++ b/apps/files/js/filesummary.js @@ -28,8 +28,9 @@ * @param $tr table row element * $param summary optional initial summary value */ - var FileSummary = function($tr, summary) { + var FileSummary = function($tr) { this.$el = $tr; + this.clear(); this.render(); }; @@ -74,6 +75,12 @@ this.update(); } }, + /** + * Returns the total of files and directories + */ + getTotal: function() { + return this.summary.totalDirs + this.summary.totalFiles; + }, /** * Recalculates the summary based on the given files array * @param files array of files @@ -98,6 +105,12 @@ } this.setSummary(summary); }, + /** + * Clears the summary + */ + clear: function() { + this.calculate([]); + }, /** * Sets the current summary values * @param summary map @@ -111,6 +124,9 @@ * Renders the file summary element */ update: function() { + if (!this.$el) { + return; + } if (!this.summary.totalFiles && !this.summary.totalDirs) { this.$el.addClass('hidden'); return; @@ -144,6 +160,10 @@ } }, render: function() { + if (!this.$el) { + return; + } + // TODO: ideally this should be separate to a template or something var summary = this.summary; var directoryInfo = n('files', '%n folder', '%n folders', summary.totalDirs); var fileInfo = n('files', '%n file', '%n files', summary.totalFiles); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 23261759d03..be285a7b636 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -24,6 +24,33 @@ describe('FileList tests', function() { var testFiles, alertStub, notificationStub, pushStateStub; + /** + * Generate test file data + */ + function generateFiles(startIndex, endIndex) { + var files = []; + var name; + for (var i = startIndex; i <= endIndex; i++) { + name = 'File with index '; + if (i < 10) { + // do not rely on localeCompare here + // and make the sorting predictable + // cross-browser + name += '0'; + } + name += i + '.txt'; + files.push({ + id: i, + type: 'file', + name: name, + mimetype: 'text/plain', + size: i * 2, + etag: 'abc' + }); + } + return files; + } + beforeEach(function() { // init horrible parameters var $body = $('body'); @@ -592,31 +619,6 @@ describe('FileList tests', function() { }); }); describe('Rendering next page on scroll', function() { - - function generateFiles(startIndex, endIndex) { - var files = []; - var name; - for (var i = startIndex; i <= endIndex; i++) { - name = 'File with index '; - if (i < 10) { - // do not rely on localeCompare here - // and make the sorting predictable - // cross-browser - name += '0'; - } - name += i + '.txt'; - files.push({ - id: i, - type: 'file', - name: name, - mimetype: 'text/plain', - size: i * 2, - etag: 'abc' - }); - } - return files; - } - beforeEach(function() { FileList.setFiles(generateFiles(0, 64)); }); @@ -1012,17 +1014,91 @@ describe('FileList tests', function() { expect($tr.find('input:checkbox').prop('checked')).toEqual(true); }); + it('Selects/deselect a file when clicking on the name while holding Ctrl', function() { + var $tr = FileList.findFileEl('One.txt'); + var $tr2 = FileList.findFileEl('Three.pdf'); + var e; + expect($tr.find('input:checkbox').prop('checked')).toEqual(false); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(false); + e = new $.Event('click'); + e.ctrlKey = true; + $tr.find('td.filename .name').trigger(e); + + expect($tr.find('input:checkbox').prop('checked')).toEqual(true); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(false); + + // click on second entry, does not clear the selection + e = new $.Event('click'); + e.ctrlKey = true; + $tr2.find('td.filename .name').trigger(e); + expect($tr.find('input:checkbox').prop('checked')).toEqual(true); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(true); + + expect(_.pluck(FileList.getSelectedFiles(), 'name')).toEqual(['One.txt', 'Three.pdf']); + + // deselect now + e = new $.Event('click'); + e.ctrlKey = true; + $tr2.find('td.filename .name').trigger(e); + expect($tr.find('input:checkbox').prop('checked')).toEqual(true); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(false); + expect(_.pluck(FileList.getSelectedFiles(), 'name')).toEqual(['One.txt']); + }); + it('Selects a range when clicking on one file then Shift clicking on another one', function() { + var $tr = FileList.findFileEl('One.txt'); + var $tr2 = FileList.findFileEl('Three.pdf'); + var e; + $tr.find('td.filename input:checkbox').click(); + e = new $.Event('click'); + e.shiftKey = true; + $tr2.find('td.filename .name').trigger(e); + + expect($tr.find('input:checkbox').prop('checked')).toEqual(true); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(true); + expect(FileList.findFileEl('Two.jpg').find('input:checkbox').prop('checked')).toEqual(true); + var selection = _.pluck(FileList.getSelectedFiles(), 'name'); + expect(selection.length).toEqual(3); + expect(selection).toContain('One.txt'); + expect(selection).toContain('Two.jpg'); + expect(selection).toContain('Three.pdf'); + }); + it('Selects a range when clicking on one file then Shift clicking on another one that is above the first one', function() { + var $tr = FileList.findFileEl('One.txt'); + var $tr2 = FileList.findFileEl('Three.pdf'); + var e; + $tr2.find('td.filename input:checkbox').click(); + e = new $.Event('click'); + e.shiftKey = true; + $tr.find('td.filename .name').trigger(e); + + expect($tr.find('input:checkbox').prop('checked')).toEqual(true); + expect($tr2.find('input:checkbox').prop('checked')).toEqual(true); + expect(FileList.findFileEl('Two.jpg').find('input:checkbox').prop('checked')).toEqual(true); + var selection = _.pluck(FileList.getSelectedFiles(), 'name'); + expect(selection.length).toEqual(3); + expect(selection).toContain('One.txt'); + expect(selection).toContain('Two.jpg'); + expect(selection).toContain('Three.pdf'); + }); 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('Selecting all files on the first visible page will not automatically check "select all" checkbox', function() { + FileList.setFiles(generateFiles(0, 41)); + expect($('#select_all').prop('checked')).toEqual(false); + $('#fileList tr td.filename input:checkbox').click(); + expect($('#select_all').prop('checked')).toEqual(false); + }); it('Clicking "select all" will select/deselect all files', function() { + FileList.setFiles(generateFiles(0, 41)); $('#select_all').click(); expect($('#select_all').prop('checked')).toEqual(true); $('#fileList tr input:checkbox').each(function() { expect($(this).prop('checked')).toEqual(true); }); + expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(42); $('#select_all').click(); expect($('#select_all').prop('checked')).toEqual(false); @@ -1030,6 +1106,7 @@ describe('FileList tests', function() { $('#fileList tr input:checkbox').each(function() { expect($(this).prop('checked')).toEqual(false); }); + expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(0); }); it('Clicking "select all" then deselecting a file will uncheck "select all"', function() { $('#select_all').click(); @@ -1039,6 +1116,18 @@ describe('FileList tests', function() { $tr.find('input:checkbox').click(); expect($('#select_all').prop('checked')).toEqual(false); + expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(3); + }); + it('Auto-selects files on next page when "select all" is checked', function() { + FileList.setFiles(generateFiles(0, 41)); + $('#select_all').click(); + + expect(FileList.$fileList.find('tr input:checkbox:checked').length).toEqual(20); + FileList._nextPage(true); + expect(FileList.$fileList.find('tr input:checkbox:checked').length).toEqual(40); + FileList._nextPage(true); + expect(FileList.$fileList.find('tr input:checkbox:checked').length).toEqual(42); + expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(42); }); it('Selecting files updates selection summary', function() { var $summary = $('#headerName span.name'); @@ -1080,6 +1169,19 @@ describe('FileList tests', function() { FileList.changeDirectory('/'); fakeServer.respond(); expect($('#select_all').prop('checked')).toEqual(false); + expect(_.pluck(FileList.getSelectedFiles(), 'name')).toEqual([]); + }); + it('getSelectedFiles returns the selected files even when they are on the next page', function() { + var selectedFiles; + FileList.setFiles(generateFiles(0, 41)); + $('#select_all').click(); + // unselect one to not have the "allFiles" case + FileList.$fileList.find('tr input:checkbox:first').click(); + + // only 20 files visible, must still return all the selected ones + selectedFiles = _.pluck(FileList.getSelectedFiles(), 'name'); + + expect(selectedFiles.length).toEqual(41); }); describe('Actions', function() { beforeEach(function() { @@ -1087,38 +1189,53 @@ describe('FileList tests', function() { FileList.findFileEl('Three.pdf').find('input:checkbox').click(); FileList.findFileEl('somedir').find('input:checkbox').click(); }); - it('getSelectedFiles returns the selected files', function() { + it('getSelectedFiles returns the selected file data', 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 + etag: 'abc' }); expect(files[1]).toEqual({ id: 3, type: 'file', name: 'Three.pdf', - mime: 'application/pdf', mimetype: 'application/pdf', size: 58009, - etag: '123', - origin: 3 + etag: '123' }); expect(files[2]).toEqual({ id: 4, type: 'dir', name: 'somedir', - mime: 'httpd/unix-directory', mimetype: 'httpd/unix-directory', size: 250, - etag: '456', - origin: 4 + etag: '456' + }); + }); + it('Removing a file removes it from the selection', function() { + FileList.remove('Three.pdf'); + var files = FileList.getSelectedFiles(); + expect(files.length).toEqual(2); + expect(files[0]).toEqual({ + id: 1, + name: 'One.txt', + mimetype: 'text/plain', + type: 'file', + size: 12, + etag: 'abc' + }); + expect(files[1]).toEqual({ + id: 4, + type: 'dir', + name: 'somedir', + mimetype: 'httpd/unix-directory', + size: 250, + etag: '456' }); }); describe('Download', function() { diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js index d4445e11c86..42ab89ef6a6 100644 --- a/apps/files_trashbin/js/filelist.js +++ b/apps/files_trashbin/js/filelist.js @@ -113,7 +113,7 @@ }; } else { - files = FileList.getSelectedFiles('name'); + files = _.pluck(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'); @@ -155,7 +155,7 @@ }; } else { - files = FileList.getSelectedFiles('name'); + files = _.pluck(FileList.getSelectedFiles(), 'name'); params = { files: JSON.stringify(files), dir: FileList.getCurrentDirectory() -- cgit v1.2.3 From 3159c2ee641e329c2fbaa5efbf9ac994795efa1d Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 8 Apr 2014 16:56:02 +0200 Subject: Fixed drag shadow file sorting --- apps/files/js/files.js | 1 + 1 file changed, 1 insertion(+) (limited to 'apps/files/js/files.js') diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 41c762f0fa1..f4c99d1128c 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -318,6 +318,7 @@ var createDragShadow = function(event) { // do not show drag shadow for too many files var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize); + selectedFiles.sort(FileList._fileInfoCompare); if (!isDragSelected && selectedFiles.length === 1) { //revert the selection -- cgit v1.2.3 From f99f451026ea289b6693e965ea8a3e15e6fe457a Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 11 Apr 2014 12:46:12 +0200 Subject: Fixed drag and drop into folder and onto breadcrumb Fixed drag and drop code to use FileList.getSelectedFiles() instead of the visible DOM elements. --- apps/files/js/filelist.js | 123 ++++++++++++++++++++++++++---------- apps/files/js/files.js | 60 ++++++------------ apps/files/tests/js/filelistSpec.js | 110 +++++++++++++++++++++++++++++--- 3 files changed, 211 insertions(+), 82 deletions(-) (limited to 'apps/files/js/files.js') diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index f9916b647b2..5667d07ede7 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -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); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index f4c99d1128c..6857450602c 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -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 = $('').attr('data-dir', dir).attr('data-filename', elem.name).attr('data-origin', elem.origin); + var newtr = $('') + .attr('data-dir', dir) + .attr('data-file', elem.name) + .attr('data-origin', elem.origin); newtr.append($('').addClass('filename').text(elem.name)); - newtr.append($('').addClass('size').text(humanFileSize(elem.size))); + newtr.append($('').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' }; diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index da209220cca..eab364644cd 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -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([ - $(''), - $('') + $(''), + $('') ]); // 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([ - $(''), - $('') + $(''), + $('') ]); // 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); -- cgit v1.2.3 From bf61d841a2b3305bc51de6109917725466239061 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Mon, 28 Apr 2014 16:51:57 +0200 Subject: typos, naming, remove unused code, identation --- apps/files/js/filelist.js | 28 +++++++++----------- apps/files/js/files.js | 63 +++++++++++++++++++------------------------- apps/files/js/filesummary.js | 1 - 3 files changed, 39 insertions(+), 53 deletions(-) (limited to 'apps/files/js/files.js') diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 5667d07ede7..40ec898635e 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -323,7 +323,7 @@ window.FileList = { mimetype: $el.attr('data-mime'), type: $el.attr('data-type'), size: parseInt($el.attr('data-size'), 10), - etag: $el.attr('data-etag'), + etag: $el.attr('data-etag') }; }, @@ -371,7 +371,7 @@ window.FileList = { /** * Sets the files to be displayed in the list. - * This operation will rerender the list and update the summary. + * This operation will re-render the list and update the summary. * @param filesArray array of file data (map) */ setFiles: function(filesArray) { @@ -673,7 +673,6 @@ window.FileList = { */ changeDirectory: function(targetDir, changeUrl, force) { var $dir = $('#dir'), - url, currentDir = $dir.val() || '/'; targetDir = targetDir || '/'; if (!force && currentDir === targetDir) { @@ -971,19 +970,16 @@ window.FileList = { event.stopPropagation(); event.preventDefault(); try { - var newname = input.val(); - var directory = FileList.getCurrentDirectory(); - if (newname !== oldname) { + var newName = input.val(); + if (newName !== oldname) { checkInput(); - // save background image, because it's replaced by a spinner while async request - var oldBackgroundImage = td.css('background-image'); // mark as loading td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); $.ajax({ url: OC.filePath('files','ajax','rename.php'), data: { dir : $('#dir').val(), - newname: newname, + newname: newName, file: oldname }, success: function(result) { @@ -1004,20 +1000,20 @@ window.FileList = { } input.tipsy('hide'); tr.data('renaming',false); - tr.attr('data-file', newname); + tr.attr('data-file', newName); var path = td.children('a.name').attr('href'); // FIXME this will fail if the path contains the filename. - td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname))); - var basename = newname; - if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { - basename = newname.substr(0, newname.lastIndexOf('.')); + td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newName))); + var basename = newName; + if (newName.indexOf('.') > 0 && tr.data('type') !== 'dir') { + basename = newName.substr(0, newName.lastIndexOf('.')); } td.find('a.name span.nametext').text(basename); - if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') { + if (newName.indexOf('.') > 0 && tr.data('type') !== 'dir') { if ( ! td.find('a.name span.extension').exists() ) { td.find('a.name span.nametext').append(''); } - td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.'))); + td.find('a.name span.extension').text(newName.substr(newName.lastIndexOf('.'))); } form.remove(); FileActions.display( tr.find('td.filename'), true); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 6857450602c..6d167851e64 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -8,8 +8,8 @@ * */ -/* global OC, t, n, FileList, FileActions */ -/* global getURLParameter, isPublic */ +/* global OC, t, FileList */ +/* global getURLParameter */ var Files = { // file space size sync _updateStorageStatistics: function() { @@ -96,10 +96,10 @@ var Files = { throw t('files', 'File name cannot be empty.'); } // check for invalid characters - var invalid_characters = + var invalidCharacters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\n']; - for (var i = 0; i < invalid_characters.length; i++) { - if (trimmedName.indexOf(invalid_characters[i]) !== -1) { + for (var i = 0; i < invalidCharacters.length; i++) { + if (trimmedName.indexOf(invalidCharacters[i]) !== -1) { throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."); } } @@ -116,7 +116,8 @@ var Files = { return; } if (usedSpacePercent > 90) { - OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)', {usedSpacePercent: usedSpacePercent})); + OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)', + {usedSpacePercent: usedSpacePercent})); } }, @@ -222,7 +223,7 @@ $(document).ready(function() { // TODO use OC.dialogs $(document).bind('drop dragover', function (e) { e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone - }); + }); //do a background scan if needed scanFiles(); @@ -299,16 +300,6 @@ function scanFiles(force, dir, users) { } scanFiles.scanning=false; -function boolOperationFinished(data, callback) { - result = jQuery.parseJSON(data.responseText); - Files.updateMaxUploadFilesize(result); - if (result.status === 'success') { - callback.call(); - } else { - alert(result.data.message); - } -} - // TODO: move to FileList var createDragShadow = function(event) { //select dragged file @@ -362,25 +353,25 @@ var dragOptions={ revert: 'invalid', revertDuration: 300, opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 }, helper: createDragShadow, cursor: 'move', - start: function(event, ui){ - var $selectedFiles = $('td.filename input:checkbox:checked'); - if($selectedFiles.length > 1){ - $selectedFiles.parents('tr').fadeTo(250, 0.2); - } - else{ - $(this).fadeTo(250, 0.2); - } - }, - stop: function(event, ui) { - var $selectedFiles = $('td.filename input:checkbox:checked'); - if($selectedFiles.length > 1){ - $selectedFiles.parents('tr').fadeTo(250, 1); - } - else{ - $(this).fadeTo(250, 1); - } - $('#fileList tr td.filename').addClass('ui-draggable'); + start: function(event, ui){ + var $selectedFiles = $('td.filename input:checkbox:checked'); + if($selectedFiles.length > 1){ + $selectedFiles.parents('tr').fadeTo(250, 0.2); + } + else{ + $(this).fadeTo(250, 0.2); + } + }, + stop: function(event, ui) { + var $selectedFiles = $('td.filename input:checkbox:checked'); + if($selectedFiles.length > 1){ + $selectedFiles.parents('tr').fadeTo(250, 1); } + else{ + $(this).fadeTo(250, 1); + } + $('#fileList tr td.filename').addClass('ui-draggable'); + } }; // sane browsers support using the distance option if ( $('html.ie').length === 0) { @@ -446,7 +437,7 @@ Files.generatePreviewUrl = function(urlSpec) { urlSpec.x *= window.devicePixelRatio; urlSpec.forceIcon = 0; return OC.generateUrl('/core/preview.png?') + $.param(urlSpec); -} +}; Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { // get mime icon url diff --git a/apps/files/js/filesummary.js b/apps/files/js/filesummary.js index b3e3beeb24a..b5130247cc9 100644 --- a/apps/files/js/filesummary.js +++ b/apps/files/js/filesummary.js @@ -167,7 +167,6 @@ var summary = this.summary; var directoryInfo = n('files', '%n folder', '%n folders', summary.totalDirs); var fileInfo = n('files', '%n file', '%n files', summary.totalFiles); - var fileSize; var infoVars = { dirs: ''+directoryInfo+'', -- cgit v1.2.3