diff options
Diffstat (limited to 'apps/files/js')
-rw-r--r-- | apps/files/js/file-upload.js | 106 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 143 |
2 files changed, 182 insertions, 67 deletions
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 963fc647828..67775b22c54 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -18,7 +18,7 @@ * - TODO music upload button */ -/* global OC, t, n */ +/* global Files, FileList, jQuery, oc_requesttoken, humanFileSize, getUniqueName */ /** * Function that will allow us to know if Ajax uploads are supported @@ -65,7 +65,7 @@ OC.Upload = { */ cancelUploads:function() { this.log('canceling uploads'); - jQuery.each(this._uploads,function(i, jqXHR) { + jQuery.each(this._uploads, function(i, jqXHR) { jqXHR.abort(); }); this._uploads = []; @@ -83,7 +83,7 @@ OC.Upload = { isProcessing:function() { var count = 0; - jQuery.each(this._uploads,function(i, data) { + jQuery.each(this._uploads, function(i, data) { if (data.state() === 'pending') { count++; } @@ -205,14 +205,16 @@ OC.Upload = { */ add: function(e, data) { OC.Upload.log('add', e, data); - var that = $(this); - var freeSpace; + var that = $(this), freeSpace; - // we need to collect all data upload objects before starting the upload so we can check their existence - // and set individual conflict actions. unfortunately there is only one variable that we can use to identify - // the selection a data upload is part of, so we have to collect them in data.originalFiles - // turning singleFileUploads off is not an option because we want to gracefully handle server errors like - // already exists + // we need to collect all data upload objects before + // starting the upload so we can check their existence + // and set individual conflict actions. Unfortunately, + // there is only one variable that we can use to identify + // the selection a data upload is part of, so we have to + // collect them in data.originalFiles turning + // singleFileUploads off is not an option because we want + // to gracefully handle server errors like 'already exists' // create a container where we can store the data objects if ( ! data.originalFiles.selection ) { @@ -244,14 +246,15 @@ OC.Upload = { // in case folder drag and drop is not supported file will point to a directory // http://stackoverflow.com/a/20448357 - if (!file.type && file.size%4096 === 0 && file.size <= 102400) { + if ( ! file.type && file.size%4096 === 0 && file.size <= 102400) { try { - reader = new FileReader(); - reader.readAsBinaryString(f); + var reader = new FileReader(); + reader.readAsBinaryString(file); } catch (NS_ERROR_FILE_ACCESS_DENIED) { //file is a directory data.textStatus = 'dirorzero'; - data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes', + data.errorThrown = t('files', + 'Unable to upload {filename} as it is a directory or has 0 bytes', {filename: file.name} ); } @@ -263,7 +266,8 @@ OC.Upload = { // check PHP upload limit if (selection.totalBytes > $('#upload_limit').val()) { data.textStatus = 'sizeexceedlimit'; - data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', { + data.errorThrown = t('files', + 'Total file size {size1} exceeds upload limit {size2}', { 'size1': humanFileSize(selection.totalBytes), 'size2': humanFileSize($('#upload_limit').val()) }); @@ -273,7 +277,8 @@ OC.Upload = { freeSpace = $('#free_space').val(); if (freeSpace >= 0 && selection.totalBytes > freeSpace) { data.textStatus = 'notenoughspace'; - data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', { + data.errorThrown = t('files', + 'Not enough free space, you are uploading {size1} but only {size2} is left', { 'size1': humanFileSize(selection.totalBytes), 'size2': humanFileSize($('#free_space').val()) }); @@ -384,31 +389,29 @@ OC.Upload = { //fetch response from iframe response = data.result[0].body.innerText; } - var result=$.parseJSON(response); + var result = $.parseJSON(response); delete data.jqXHR; + var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); + if (result.status === 'error' && result.data && result.data.message){ data.textStatus = 'servererror'; data.errorThrown = result.data.message; - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); fu._trigger('fail', e, data); } else if (typeof result[0] === 'undefined') { data.textStatus = 'servererror'; data.errorThrown = t('files', 'Could not get result from server.'); - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); fu._trigger('fail', e, data); } else if (result[0].status === 'existserror') { //show "file already exists" dialog var original = result[0]; var replacement = data.files[0]; - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); OC.dialogs.fileexists(data, original, replacement, OC.Upload, fu); } else if (result[0].status !== 'success') { //delete data.jqXHR; data.textStatus = 'servererror'; data.errorThrown = result[0].data.message; // error message has been translated on server - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); fu._trigger('fail', e, data); } }, @@ -440,7 +443,7 @@ OC.Upload = { fileupload.on('fileuploadstart', function(e, data) { OC.Upload.log('progress handle fileuploadstart', e, data); $('#uploadprogresswrapper input.stop').show(); - $('#uploadprogressbar').progressbar({value:0}); + $('#uploadprogressbar').progressbar({value: 0}); $('#uploadprogressbar').fadeIn(); }); fileupload.on('fileuploadprogress', function(e, data) { @@ -509,7 +512,7 @@ OC.Upload = { $('#new li').each(function(i,element) { if ($(element).children('p').length === 0) { $(element).children('form').remove(); - $(element).append('<p>'+$(element).data('text')+'</p>'); + $(element).append('<p>' + $(element).data('text') + '</p>'); } }); }); @@ -527,16 +530,16 @@ OC.Upload = { $('#new .error').tipsy('hide'); - $('#new li').each(function(i,element) { + $('#new li').each(function(i, element) { if ($(element).children('p').length === 0) { $(element).children('form').remove(); - $(element).append('<p>'+$(element).data('text')+'</p>'); + $(element).append('<p>' + $(element).data('text') + '</p>'); } }); - var type=$(this).data('type'); - var text=$(this).children('p').text(); - $(this).data('text',text); + var type = $(this).data('type'); + var text = $(this).children('p').text(); + $(this).data('text', text); $(this).children('p').remove(); // add input field @@ -553,7 +556,7 @@ OC.Upload = { var filename = input.val(); if (type === 'web' && filename.length === 0) { throw t('files', 'URL cannot be empty'); - } else if (type !== 'web' && !Files.isFileNameValid(filename)) { + } else if (type !== 'web' && ! Files.isFileNameValid(filename)) { // Files.isFileNameValid(filename) throws an exception itself } else if (FileList.inList(filename)) { throw t('files', '{new_name} already exists', {new_name: filename}); @@ -603,7 +606,10 @@ OC.Upload = { case 'file': $.post( OC.filePath('files', 'ajax', 'newfile.php'), - {dir:$('#dir').val(), filename:name}, + { + dir: $('#dir').val(), + filename: name + }, function(result) { if (result.status === 'success') { FileList.add(result.data, {hidden: hidden, animate: true}); @@ -616,7 +622,10 @@ OC.Upload = { case 'folder': $.post( OC.filePath('files','ajax','newfolder.php'), - {dir:$('#dir').val(), foldername:name}, + { + dir: $('#dir').val(), + foldername: name + }, function(result) { if (result.status === 'success') { FileList.add(result.data, {hidden: hidden, animate: true}); @@ -627,39 +636,46 @@ OC.Upload = { ); break; case 'web': - if (name.substr(0,8) !== 'https://' && name.substr(0,7) !== 'http://') { + if (name.substr(0, 8) !== 'https://' && name.substr(0, 7) !== 'http://') { name = 'http://' + name; } - var localName=name; - if (localName.substr(localName.length-1,1)==='/') {//strip / - localName=localName.substr(0,localName.length-1); + var localName = name; + if (localName.substr(localName.length-1, 1) === '/') {//strip / + localName = localName.substr(0, localName.length-1); } - if (localName.indexOf('/')) {//use last part of url - localName=localName.split('/').pop(); + if (localName.indexOf('/')) { //use last part of url + localName = localName.split('/').pop(); } else { //or the domain - localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.',''); + localName = (localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.', ''); } localName = getUniqueName(localName); //IE < 10 does not fire the necessary events for the progress bar. if ($('html.lte9').length === 0) { - $('#uploadprogressbar').progressbar({value:0}); + $('#uploadprogressbar').progressbar({value: 0}); $('#uploadprogressbar').fadeIn(); } - var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName}); - eventSource.listen('progress',function(progress) { + var eventSource = new OC.EventSource( + OC.filePath('files', 'ajax', 'newfile.php'), + { + dir: $('#dir').val(), + source: name, + filename: localName + } + ); + eventSource.listen('progress', function(progress) { //IE < 10 does not fire the necessary events for the progress bar. if ($('html.lte9').length === 0) { $('#uploadprogressbar').progressbar('value',progress); } }); - eventSource.listen('success',function(data) { + eventSource.listen('success', function(data) { var file = data; $('#uploadprogressbar').fadeOut(); FileList.add(file, {hidden: hidden, animate: true}); }); - eventSource.listen('error',function(error) { + eventSource.listen('error', function(error) { $('#uploadprogressbar').fadeOut(); var message = (error && error.message) || t('core', 'Error fetching URL'); OC.Notification.show(message); @@ -670,12 +686,12 @@ OC.Upload = { }); break; } - var li=form.parent(); + var li = form.parent(); form.remove(); /* workaround for IE 9&10 click event trap, 2 lines: */ $('input').first().focus(); $('#content').focus(); - li.append('<p>'+li.data('text')+'</p>'); + li.append('<p>' + li.data('text') + '</p>'); $('#new>a').click(); } catch (error) { input.attr('title', error); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 8896a8e23a8..73a441368bb 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -11,6 +11,9 @@ /* global OC, t, n, FileList, FileActions, Files, FileSummary, BreadCrumb */ /* global dragOptions, folderDropOptions */ window.FileList = { + SORT_INDICATOR_ASC_CLASS: 'icon-triangle-s', + SORT_INDICATOR_DESC_CLASS: 'icon-triangle-n', + appName: t('files', 'Files'), isEmpty: true, useUndo:true, @@ -45,18 +48,19 @@ window.FileList = { _selectionSummary: null, /** - * Compare two file info objects, sorting by - * folders first, then by name. + * Sort attribute */ - _fileInfoCompare: function(fileInfo1, fileInfo2) { - if (fileInfo1.type === 'dir' && fileInfo2.type !== 'dir') { - return -1; - } - if (fileInfo1.type !== 'dir' && fileInfo2.type === 'dir') { - return 1; - } - return fileInfo1.name.localeCompare(fileInfo2.name); - }, + _sort: 'name', + + /** + * Sort direction: 'asc' or 'desc' + */ + _sortDirection: 'asc', + + /** + * Sort comparator function for the current sort + */ + _sortComparator: null, /** * Initialize the file list and its components @@ -76,6 +80,8 @@ window.FileList = { this.fileSummary = this._createSummary(); + this.setSort('name', 'asc'); + this.breadcrumb = new BreadCrumb({ onClick: this._onClickBreadCrumb, onDrop: _.bind(this._onDropOnBreadCrumb, this), @@ -86,6 +92,8 @@ window.FileList = { $('#controls').prepend(this.breadcrumb.$el); + this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this)); + $(window).resize(function() { // TODO: debounce this ? var width = $(this).width(); @@ -237,6 +245,27 @@ window.FileList = { }, /** + * Event handler when clicking on a table header + */ + _onClickHeader: function(e) { + var $target = $(e.target); + var sort; + if (!$target.is('a')) { + $target = $target.closest('a'); + } + sort = $target.attr('data-sort'); + if (sort) { + if (this._sort === sort) { + this.setSort(sort, (this._sortDirection === 'desc')?'asc':'desc'); + } + else { + this.setSort(sort, 'asc'); + } + this.reload(); + } + }, + + /** * Event handler when clicking on a bread crumb */ _onClickBreadCrumb: function(e) { @@ -685,8 +714,6 @@ window.FileList = { previousDir: currentDir } )); - this._selectedFiles = {}; - this._selectionSummary.clear(); this.reload(); }, linkTo: function(dir) { @@ -723,9 +750,33 @@ window.FileList = { this.breadcrumb.setDirectory(this.getCurrentDirectory()); }, /** + * Sets the current sorting and refreshes the list + * + * @param sort sort attribute name + * @param direction sort direction, one of "asc" or "desc" + */ + setSort: function(sort, direction) { + var comparator = this.Comparators[sort] || this.Comparators.name; + this._sort = sort; + this._sortDirection = (direction === 'desc')?'desc':'asc'; + this._sortComparator = comparator; + if (direction === 'desc') { + this._sortComparator = function(fileInfo1, fileInfo2) { + return -comparator(fileInfo1, fileInfo2); + }; + } + this.$el.find('thead th .sort-indicator') + .removeClass(this.SORT_INDICATOR_ASC_CLASS + ' ' + this.SORT_INDICATOR_DESC_CLASS); + this.$el.find('thead th.column-' + sort + ' .sort-indicator') + .addClass(direction === 'desc' ? this.SORT_INDICATOR_DESC_CLASS : this.SORT_INDICATOR_ASC_CLASS); + }, + /** * @brief Reloads the file list using ajax call */ reload: function() { + this._selectedFiles = {}; + this._selectionSummary.clear(); + this.$el.find('#select_all').prop('checked', false); FileList.showMask(); if (FileList._reloadCall) { FileList._reloadCall.abort(); @@ -733,7 +784,9 @@ window.FileList = { FileList._reloadCall = $.ajax({ url: Files.getAjaxUrl('list'), data: { - dir : $('#dir').val() + dir: $('#dir').val(), + sort: FileList._sort, + sortdirection: FileList._sortDirection }, error: function(result) { FileList.reloadCallback(result); @@ -859,7 +912,7 @@ window.FileList = { */ _findInsertionIndex: function(fileData) { var index = 0; - while (index < this.files.length && this._fileInfoCompare(fileData, this.files[index]) > 0) { + while (index < this.files.length && this._sortComparator(fileData, this.files[index]) > 0) { index++; } return index; @@ -924,7 +977,7 @@ window.FileList = { OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); } $td.css('background-image', oldBackgroundImage); - }); + }); }); }, @@ -1221,15 +1274,15 @@ window.FileList = { updateSelectionSummary: function() { 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')); + $('#headerName a.name>span:first').text(t('files','Name')); + $('#headerSize a>span:first').text(t('files','Size')); + $('#modified a>span:first').text(t('files','Modified')); $('table').removeClass('multiselect'); $('.selectedActions').addClass('hidden'); } else { $('.selectedActions').removeClass('hidden'); - $('#headerSize').text(OC.Util.humanFileSize(summary.totalSize)); + $('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize)); var selection = ''; if (summary.totalDirs > 0) { selection += n('files', '%n folder', '%n folders', summary.totalDirs); @@ -1240,8 +1293,8 @@ window.FileList = { if (summary.totalFiles > 0) { selection += n('files', '%n file', '%n files', summary.totalFiles); } - $('#headerName span.name').text(selection); - $('#modified').text(''); + $('#headerName a.name>span:first').text(selection); + $('#modified a>span:first').text(''); $('table').addClass('multiselect'); } }, @@ -1545,3 +1598,49 @@ $(document).ready(function() { }, 0); }); +/** + * Sort comparators. + */ +FileList.Comparators = { + /** + * Compares two file infos by name, making directories appear + * first. + * + * @param fileInfo1 file info + * @param fileInfo2 file info + * @return -1 if the first file must appear before the second one, + * 0 if they are identify, 1 otherwise. + */ + name: function(fileInfo1, fileInfo2) { + if (fileInfo1.type === 'dir' && fileInfo2.type !== 'dir') { + return -1; + } + if (fileInfo1.type !== 'dir' && fileInfo2.type === 'dir') { + return 1; + } + return fileInfo1.name.localeCompare(fileInfo2.name); + }, + /** + * Compares two file infos by size. + * + * @param fileInfo1 file info + * @param fileInfo2 file info + * @return -1 if the first file must appear before the second one, + * 0 if they are identify, 1 otherwise. + */ + size: function(fileInfo1, fileInfo2) { + return fileInfo1.size - fileInfo2.size; + }, + /** + * Compares two file infos by timestamp. + * + * @param fileInfo1 file info + * @param fileInfo2 file info + * @return -1 if the first file must appear before the second one, + * 0 if they are identify, 1 otherwise. + */ + mtime: function(fileInfo1, fileInfo2) { + return fileInfo1.mtime - fileInfo2.mtime; + } +}; + |