aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/js')
-rw-r--r--apps/files/js/file-upload.js106
-rw-r--r--apps/files/js/filelist.js143
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;
+ }
+};
+