Infinite scrolling for files apptags/v7.0.0alpha2
/* Actions for selected files */ | /* Actions for selected files */ | ||||
.selectedActions { | .selectedActions { | ||||
display: none; | |||||
position: absolute; | position: absolute; | ||||
top: -1px; | top: -1px; | ||||
right: 0; | right: 0; |
OCP\Util::addscript('files', 'jquery.iframe-transport'); | OCP\Util::addscript('files', 'jquery.iframe-transport'); | ||||
OCP\Util::addscript('files', 'jquery.fileupload'); | OCP\Util::addscript('files', 'jquery.fileupload'); | ||||
OCP\Util::addscript('files', 'jquery-visibility'); | OCP\Util::addscript('files', 'jquery-visibility'); | ||||
OCP\Util::addscript('files', 'filesummary'); | |||||
OCP\Util::addscript('files', 'breadcrumb'); | OCP\Util::addscript('files', 'breadcrumb'); | ||||
OCP\Util::addscript('files', 'filelist'); | OCP\Util::addscript('files', 'filelist'); | ||||
{dir:$('#dir').val(), filename:name}, | {dir:$('#dir').val(), filename:name}, | ||||
function(result) { | function(result) { | ||||
if (result.status === 'success') { | if (result.status === 'success') { | ||||
FileList.add(result.data, {hidden: hidden, insert: true}); | |||||
FileList.add(result.data, {hidden: hidden, animate: true}); | |||||
} else { | } else { | ||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create file')); | OC.dialogs.alert(result.data.message, t('core', 'Could not create file')); | ||||
} | } | ||||
{dir:$('#dir').val(), foldername:name}, | {dir:$('#dir').val(), foldername:name}, | ||||
function(result) { | function(result) { | ||||
if (result.status === 'success') { | if (result.status === 'success') { | ||||
FileList.add(result.data, {hidden: hidden, insert: true}); | |||||
FileList.add(result.data, {hidden: hidden, animate: true}); | |||||
} else { | } else { | ||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); | OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); | ||||
} | } | ||||
var file = data; | var file = data; | ||||
$('#uploadprogressbar').fadeOut(); | $('#uploadprogressbar').fadeOut(); | ||||
FileList.add(file, {hidden: hidden, insert: true}); | |||||
FileList.add(file, {hidden: hidden, animate: true}); | |||||
}); | }); | ||||
eventSource.listen('error',function(error) { | eventSource.listen('error',function(error) { | ||||
$('#uploadprogressbar').fadeOut(); | $('#uploadprogressbar').fadeOut(); |
* | * | ||||
*/ | */ | ||||
/* global OC, t, n, FileList, FileActions */ | |||||
/* global getURLParameter, isPublic */ | |||||
/* global OC, t, FileList */ | |||||
/* global getURLParameter */ | |||||
var Files = { | var Files = { | ||||
// file space size sync | // file space size sync | ||||
_updateStorageStatistics: function() { | _updateStorageStatistics: function() { | ||||
throw t('files', 'File name cannot be empty.'); | throw t('files', 'File name cannot be empty.'); | ||||
} | } | ||||
// check for invalid characters | // check for invalid characters | ||||
var invalid_characters = | |||||
var invalidCharacters = | |||||
['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\n']; | ['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\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."); | throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."); | ||||
} | } | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (usedSpacePercent > 90) { | 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})); | |||||
} | } | ||||
}, | }, | ||||
} | } | ||||
}, | }, | ||||
// TODO: move to FileList class | |||||
setupDragAndDrop: function() { | setupDragAndDrop: function() { | ||||
var $fileList = $('#fileList'); | var $fileList = $('#fileList'); | ||||
// Trigger cancelling of file upload | // Trigger cancelling of file upload | ||||
$('#uploadprogresswrapper .stop').on('click', function() { | $('#uploadprogresswrapper .stop').on('click', function() { | ||||
OC.Upload.cancelUploads(); | OC.Upload.cancelUploads(); | ||||
procesSelection(); | |||||
FileList.updateSelectionSummary(); | |||||
}); | }); | ||||
// Show trash bin | // Show trash bin | ||||
window.location=OC.filePath('files_trashbin', '', 'index.php'); | 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 | // drag&drop support using jquery.fileupload | ||||
// TODO use OC.dialogs | // TODO use OC.dialogs | ||||
$(document).bind('drop dragover', function (e) { | $(document).bind('drop dragover', function (e) { | ||||
e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone | e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone | ||||
}); | |||||
}); | |||||
//do a background scan if needed | //do a background scan if needed | ||||
scanFiles(); | scanFiles(); | ||||
} | } | ||||
scanFiles.scanning=false; | 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) { | var createDragShadow = function(event) { | ||||
//select dragged file | //select dragged file | ||||
var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked'); | var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked'); | ||||
if (!isDragSelected) { | if (!isDragSelected) { | ||||
//select dragged file | //select dragged file | ||||
$(event.target).parents('tr').find('td input:first').prop('checked',true); | |||||
FileList._selectFileEl($(event.target).parents('tr:first'), true); | |||||
} | } | ||||
var selectedFiles = Files.getSelectedFiles(); | |||||
// 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) { | if (!isDragSelected && selectedFiles.length === 1) { | ||||
//revert the selection | //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 | // build dragshadow | ||||
var dir=$('#dir').val(); | var dir=$('#dir').val(); | ||||
$(selectedFiles).each(function(i,elem) { | $(selectedFiles).each(function(i,elem) { | ||||
var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name).attr('data-origin', elem.origin); | |||||
var newtr = $('<tr/>') | |||||
.attr('data-dir', dir) | |||||
.attr('data-file', elem.name) | |||||
.attr('data-origin', elem.origin); | |||||
newtr.append($('<td/>').addClass('filename').text(elem.name)); | newtr.append($('<td/>').addClass('filename').text(elem.name)); | ||||
newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size))); | |||||
newtr.append($('<td/>').addClass('size').text(OC.Util.humanFileSize(elem.size))); | |||||
tbody.append(newtr); | tbody.append(newtr); | ||||
if (elem.type === 'dir') { | if (elem.type === 'dir') { | ||||
newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')'); | newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')'); | ||||
//options for file drag/drop | //options for file drag/drop | ||||
//start&stop handlers needs some cleaning up | //start&stop handlers needs some cleaning up | ||||
// TODO: move to FileList class | |||||
var dragOptions={ | var dragOptions={ | ||||
revert: 'invalid', revertDuration: 300, | revert: 'invalid', revertDuration: 300, | ||||
opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 }, | opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: 24, top: 18 }, | ||||
helper: createDragShadow, cursor: 'move', | 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 | // sane browsers support using the distance option | ||||
if ( $('html.ie').length === 0) { | if ( $('html.ie').length === 0) { | ||||
dragOptions['distance'] = 20; | dragOptions['distance'] = 20; | ||||
} | } | ||||
var folderDropOptions={ | |||||
// TODO: move to FileList class | |||||
var folderDropOptions = { | |||||
hoverClass: "canDrop", | hoverClass: "canDrop", | ||||
drop: function( event, ui ) { | 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) { | if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) { | ||||
return false; | 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); | |||||
procesSelection(); | |||||
$('#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); | |||||
}); | |||||
}); | |||||
}, | |||||
tolerance: 'pointer' | |||||
}; | |||||
var targetPath = FileList.getCurrentDirectory() + '/' + $(this).closest('tr').data('file'); | |||||
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 += ' & '; | |||||
} | |||||
var files = FileList.getSelectedFiles(); | |||||
if (files.length === 0) { | |||||
// single one selected without checkbox? | |||||
files = _.map(ui.helper.find('tr'), FileList.elementToFile); | |||||
} | } | ||||
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; | |||||
} | |||||
FileList.move(_.pluck(files, 'name'), targetPath); | |||||
}, | |||||
tolerance: 'pointer' | |||||
}; | |||||
Files.getMimeIcon = function(mime, ready) { | Files.getMimeIcon = function(mime, ready) { | ||||
if (Files.getMimeIcon.cache[mime]) { | if (Files.getMimeIcon.cache[mime]) { | ||||
urlSpec.x *= window.devicePixelRatio; | urlSpec.x *= window.devicePixelRatio; | ||||
urlSpec.forceIcon = 0; | urlSpec.forceIcon = 0; | ||||
return OC.generateUrl('/core/preview.png?') + $.param(urlSpec); | return OC.generateUrl('/core/preview.png?') + $.param(urlSpec); | ||||
} | |||||
}; | |||||
Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { | Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { | ||||
// get mime icon url | // get mime icon url |
/** | |||||
* ownCloud | |||||
* | |||||
* @author Vincent Petry | |||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com> | |||||
* | |||||
* This library is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or any later version. | |||||
* | |||||
* This library is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public | |||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
/* global OC, n, t */ | |||||
(function() { | |||||
/** | |||||
* The FileSummary class encapsulates the file summary values and | |||||
* the logic to render it in the given container | |||||
* @param $tr table row element | |||||
* $param summary optional initial summary value | |||||
*/ | |||||
var FileSummary = function($tr) { | |||||
this.$el = $tr; | |||||
this.clear(); | |||||
this.render(); | |||||
}; | |||||
FileSummary.prototype = { | |||||
summary: { | |||||
totalFiles: 0, | |||||
totalDirs: 0, | |||||
totalSize: 0 | |||||
}, | |||||
/** | |||||
* Adds file | |||||
* @param file file to add | |||||
* @param update whether to update the display | |||||
*/ | |||||
add: function(file, update) { | |||||
if (file.type === 'dir' || file.mime === 'httpd/unix-directory') { | |||||
this.summary.totalDirs++; | |||||
} | |||||
else { | |||||
this.summary.totalFiles++; | |||||
} | |||||
this.summary.totalSize += parseInt(file.size, 10) || 0; | |||||
if (!!update) { | |||||
this.update(); | |||||
} | |||||
}, | |||||
/** | |||||
* Removes file | |||||
* @param file file to remove | |||||
* @param update whether to update the display | |||||
*/ | |||||
remove: function(file, update) { | |||||
if (file.type === 'dir' || file.mime === 'httpd/unix-directory') { | |||||
this.summary.totalDirs--; | |||||
} | |||||
else { | |||||
this.summary.totalFiles--; | |||||
} | |||||
this.summary.totalSize -= parseInt(file.size, 10) || 0; | |||||
if (!!update) { | |||||
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 | |||||
*/ | |||||
calculate: function(files) { | |||||
var file; | |||||
var summary = { | |||||
totalDirs: 0, | |||||
totalFiles: 0, | |||||
totalSize: 0 | |||||
}; | |||||
for (var i = 0; i < files.length; i++) { | |||||
file = files[i]; | |||||
if (file.type === 'dir' || file.mime === 'httpd/unix-directory') { | |||||
summary.totalDirs++; | |||||
} | |||||
else { | |||||
summary.totalFiles++; | |||||
} | |||||
summary.totalSize += parseInt(file.size, 10) || 0; | |||||
} | |||||
this.setSummary(summary); | |||||
}, | |||||
/** | |||||
* Clears the summary | |||||
*/ | |||||
clear: function() { | |||||
this.calculate([]); | |||||
}, | |||||
/** | |||||
* Sets the current summary values | |||||
* @param summary map | |||||
*/ | |||||
setSummary: function(summary) { | |||||
this.summary = summary; | |||||
this.update(); | |||||
}, | |||||
/** | |||||
* Renders the file summary element | |||||
*/ | |||||
update: function() { | |||||
if (!this.$el) { | |||||
return; | |||||
} | |||||
if (!this.summary.totalFiles && !this.summary.totalDirs) { | |||||
this.$el.addClass('hidden'); | |||||
return; | |||||
} | |||||
// There's a summary and data -> Update the summary | |||||
this.$el.removeClass('hidden'); | |||||
var $dirInfo = this.$el.find('.dirinfo'); | |||||
var $fileInfo = this.$el.find('.fileinfo'); | |||||
var $connector = this.$el.find('.connector'); | |||||
// Substitute old content with new translations | |||||
$dirInfo.html(n('files', '%n folder', '%n folders', this.summary.totalDirs)); | |||||
$fileInfo.html(n('files', '%n file', '%n files', this.summary.totalFiles)); | |||||
this.$el.find('.filesize').html(OC.Util.humanFileSize(this.summary.totalSize)); | |||||
// Show only what's necessary (may be hidden) | |||||
if (this.summary.totalDirs === 0) { | |||||
$dirInfo.addClass('hidden'); | |||||
$connector.addClass('hidden'); | |||||
} else { | |||||
$dirInfo.removeClass('hidden'); | |||||
} | |||||
if (this.summary.totalFiles === 0) { | |||||
$fileInfo.addClass('hidden'); | |||||
$connector.addClass('hidden'); | |||||
} else { | |||||
$fileInfo.removeClass('hidden'); | |||||
} | |||||
if (this.summary.totalDirs > 0 && this.summary.totalFiles > 0) { | |||||
$connector.removeClass('hidden'); | |||||
} | |||||
}, | |||||
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); | |||||
var infoVars = { | |||||
dirs: '<span class="dirinfo">'+directoryInfo+'</span><span class="connector">', | |||||
files: '</span><span class="fileinfo">'+fileInfo+'</span>' | |||||
}; | |||||
// don't show the filesize column, if filesize is NaN (e.g. in trashbin) | |||||
var fileSize = ''; | |||||
if (!isNaN(summary.totalSize)) { | |||||
fileSize = '<td class="filesize">' + OC.Util.humanFileSize(summary.totalSize) + '</td>'; | |||||
} | |||||
var info = t('files', '{dirs} and {files}', infoVars); | |||||
var $summary = $('<td><span class="info">'+info+'</span></td>'+fileSize+'<td></td>'); | |||||
if (!this.summary.totalFiles && !this.summary.totalDirs) { | |||||
this.$el.addClass('hidden'); | |||||
} | |||||
this.$el.append($summary); | |||||
} | |||||
}; | |||||
window.FileSummary = FileSummary; | |||||
})(); | |||||
</thead> | </thead> | ||||
<tbody id="fileList"> | <tbody id="fileList"> | ||||
</tbody> | </tbody> | ||||
<tfoot> | |||||
</tfoot> | |||||
</table> | </table> | ||||
<div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! --> | <div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! --> | ||||
<div id="uploadsize-message" title="<?php p($l->t('Upload too large'))?>"> | <div id="uploadsize-message" title="<?php p($l->t('Upload too large'))?>"> |
$body.append('<input type="hidden" id="permissions" value="31"></input>'); | $body.append('<input type="hidden" id="permissions" value="31"></input>'); | ||||
// dummy files table | // dummy files table | ||||
$filesTable = $body.append('<table id="filestable"></table>'); | $filesTable = $body.append('<table id="filestable"></table>'); | ||||
FileList.files = []; | |||||
}); | }); | ||||
afterEach(function() { | afterEach(function() { | ||||
$('#dir, #permissions, #filestable').remove(); | $('#dir, #permissions, #filestable').remove(); |
var testFiles, alertStub, notificationStub, | var testFiles, alertStub, notificationStub, | ||||
pushStateStub; | 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() { | beforeEach(function() { | ||||
// init horrible parameters | // init horrible parameters | ||||
var $body = $('body'); | var $body = $('body'); | ||||
' <div class="notCreatable"></div>' + | ' <div class="notCreatable"></div>' + | ||||
'</div>' + | '</div>' + | ||||
// dummy table | // dummy table | ||||
// TODO: at some point this will be rendered by the FileList class itself! | |||||
'<table id="filestable">' + | '<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>' + | '<tbody id="fileList"></tbody>' + | ||||
'<tfoot></tfoot>' + | |||||
'</table>' + | '</table>' + | ||||
'<div id="emptycontent">Empty content message</div>' | '<div id="emptycontent">Empty content message</div>' | ||||
); | ); | ||||
type: 'file', | type: 'file', | ||||
name: 'One.txt', | name: 'One.txt', | ||||
mimetype: 'text/plain', | mimetype: 'text/plain', | ||||
size: 12 | |||||
size: 12, | |||||
etag: 'abc' | |||||
}, { | }, { | ||||
id: 2, | id: 2, | ||||
type: 'file', | type: 'file', | ||||
name: 'Two.jpg', | name: 'Two.jpg', | ||||
mimetype: 'image/jpeg', | mimetype: 'image/jpeg', | ||||
size: 12049 | |||||
size: 12049, | |||||
etag: 'def', | |||||
}, { | }, { | ||||
id: 3, | id: 3, | ||||
type: 'file', | type: 'file', | ||||
name: 'Three.pdf', | name: 'Three.pdf', | ||||
mimetype: 'application/pdf', | mimetype: 'application/pdf', | ||||
size: 58009 | |||||
size: 58009, | |||||
etag: '123', | |||||
}, { | }, { | ||||
id: 4, | id: 4, | ||||
type: 'dir', | type: 'dir', | ||||
name: 'somedir', | name: 'somedir', | ||||
mimetype: 'httpd/unix-directory', | mimetype: 'httpd/unix-directory', | ||||
size: 250 | |||||
size: 250, | |||||
etag: '456' | |||||
}]; | }]; | ||||
FileList.initialize(); | FileList.initialize(); | ||||
var $tr = FileList.add(fileData); | var $tr = FileList.add(fileData); | ||||
expect($tr.find('.filesize').text()).toEqual('0 B'); | expect($tr.find('.filesize').text()).toEqual('0 B'); | ||||
}); | }); | ||||
it('adds new file to the end of the list before the summary', function() { | |||||
it('adds new file to the end of the list', function() { | |||||
var $tr; | |||||
var fileData = { | var fileData = { | ||||
type: 'file', | type: 'file', | ||||
name: 'P comes after O.txt' | |||||
name: 'ZZZ.txt' | |||||
}; | }; | ||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
$tr = FileList.add(fileData); | $tr = FileList.add(fileData); | ||||
expect($tr.index()).toEqual(4); | expect($tr.index()).toEqual(4); | ||||
expect($tr.next().hasClass('summary')).toEqual(true); | |||||
}); | }); | ||||
it('adds new file at correct position in insert mode', function() { | |||||
it('inserts files in a sorted manner when insert option is enabled', function() { | |||||
var $tr; | |||||
for (var i = 0; i < testFiles.length; i++) { | |||||
FileList.add(testFiles[i]); | |||||
} | |||||
expect(FileList.files[0].name).toEqual('somedir'); | |||||
expect(FileList.files[1].name).toEqual('One.txt'); | |||||
expect(FileList.files[2].name).toEqual('Three.pdf'); | |||||
expect(FileList.files[3].name).toEqual('Two.jpg'); | |||||
}); | |||||
it('inserts new file at correct position', function() { | |||||
var $tr; | |||||
var fileData = { | var fileData = { | ||||
type: 'file', | type: 'file', | ||||
name: 'P comes after O.txt' | name: 'P comes after O.txt' | ||||
}; | }; | ||||
FileList.setFiles(testFiles); | |||||
$tr = FileList.add(fileData, {insert: true}); | |||||
for (var i = 0; i < testFiles.length; i++) { | |||||
FileList.add(testFiles[i]); | |||||
} | |||||
$tr = FileList.add(fileData); | |||||
// after "One.txt" | // after "One.txt" | ||||
expect($tr.index()).toEqual(2); | |||||
expect(FileList.files[2]).toEqual(fileData); | |||||
}); | |||||
it('inserts new folder at correct position in insert mode', function() { | |||||
var $tr; | |||||
var fileData = { | |||||
type: 'dir', | |||||
name: 'somedir2 comes after somedir' | |||||
}; | |||||
for (var i = 0; i < testFiles.length; i++) { | |||||
FileList.add(testFiles[i]); | |||||
} | |||||
$tr = FileList.add(fileData); | |||||
expect($tr.index()).toEqual(1); | expect($tr.index()).toEqual(1); | ||||
expect(FileList.files[1]).toEqual(fileData); | |||||
}); | |||||
it('inserts new file at the end correctly', function() { | |||||
var $tr; | |||||
var fileData = { | |||||
type: 'file', | |||||
name: 'zzz.txt' | |||||
}; | |||||
for (var i = 0; i < testFiles.length; i++) { | |||||
FileList.add(testFiles[i]); | |||||
} | |||||
$tr = FileList.add(fileData); | |||||
expect($tr.index()).toEqual(4); | |||||
expect(FileList.files[4]).toEqual(fileData); | |||||
}); | }); | ||||
it('removes empty content message and shows summary when adding first file', function() { | it('removes empty content message and shows summary when adding first file', function() { | ||||
var fileData = { | var fileData = { | ||||
FileList.setFiles([]); | FileList.setFiles([]); | ||||
expect(FileList.isEmpty).toEqual(true); | expect(FileList.isEmpty).toEqual(true); | ||||
FileList.add(fileData); | FileList.add(fileData); | ||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(1); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(false); | |||||
// yes, ugly... | // yes, ugly... | ||||
expect($summary.find('.info').text()).toEqual('0 folders and 1 file'); | expect($summary.find('.info').text()).toEqual('0 folders and 1 file'); | ||||
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(true); | expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(true); | ||||
$removedEl = FileList.remove('One.txt'); | $removedEl = FileList.remove('One.txt'); | ||||
expect($removedEl).toBeDefined(); | expect($removedEl).toBeDefined(); | ||||
expect($removedEl.attr('data-file')).toEqual('One.txt'); | expect($removedEl.attr('data-file')).toEqual('One.txt'); | ||||
expect($('#fileList tr:not(.summary)').length).toEqual(3); | |||||
expect($('#fileList tr').length).toEqual(3); | |||||
expect(FileList.files.length).toEqual(3); | |||||
expect(FileList.findFileEl('One.txt').length).toEqual(0); | expect(FileList.findFileEl('One.txt').length).toEqual(0); | ||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(1); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(false); | |||||
expect($summary.find('.info').text()).toEqual('1 folder and 2 files'); | expect($summary.find('.info').text()).toEqual('1 folder and 2 files'); | ||||
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); | expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); | ||||
expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); | expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); | ||||
it('Shows empty content when removing last file', function() { | it('Shows empty content when removing last file', function() { | ||||
FileList.setFiles([testFiles[0]]); | FileList.setFiles([testFiles[0]]); | ||||
FileList.remove('One.txt'); | FileList.remove('One.txt'); | ||||
expect($('#fileList tr:not(.summary)').length).toEqual(0); | |||||
expect($('#fileList tr').length).toEqual(0); | |||||
expect(FileList.files.length).toEqual(0); | |||||
expect(FileList.findFileEl('One.txt').length).toEqual(0); | expect(FileList.findFileEl('One.txt').length).toEqual(0); | ||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(0); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(true); | |||||
expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | ||||
expect($('#emptycontent').hasClass('hidden')).toEqual(false); | expect($('#emptycontent').hasClass('hidden')).toEqual(false); | ||||
expect(FileList.isEmpty).toEqual(true); | expect(FileList.isEmpty).toEqual(true); | ||||
expect(FileList.findFileEl('One.txt').length).toEqual(0); | expect(FileList.findFileEl('One.txt').length).toEqual(0); | ||||
expect(FileList.findFileEl('Two.jpg').length).toEqual(0); | expect(FileList.findFileEl('Two.jpg').length).toEqual(0); | ||||
expect(FileList.findFileEl('Three.pdf').length).toEqual(1); | expect(FileList.findFileEl('Three.pdf').length).toEqual(1); | ||||
expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(2); | |||||
expect(FileList.$fileList.find('tr').length).toEqual(2); | |||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(1); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(false); | |||||
expect($summary.find('.info').text()).toEqual('1 folder and 1 file'); | expect($summary.find('.info').text()).toEqual('1 folder and 1 file'); | ||||
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); | expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false); | ||||
expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); | expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false); | ||||
JSON.stringify({status: 'success'}) | JSON.stringify({status: 'success'}) | ||||
); | ); | ||||
expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(0); | |||||
expect(FileList.$fileList.find('tr').length).toEqual(0); | |||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(0); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(true); | |||||
expect(FileList.isEmpty).toEqual(true); | expect(FileList.isEmpty).toEqual(true); | ||||
expect(FileList.files.length).toEqual(0); | |||||
expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | ||||
expect($('#emptycontent').hasClass('hidden')).toEqual(false); | expect($('#emptycontent').hasClass('hidden')).toEqual(false); | ||||
}); | }); | ||||
// files are still in the list | // files are still in the list | ||||
expect(FileList.findFileEl('One.txt').length).toEqual(1); | expect(FileList.findFileEl('One.txt').length).toEqual(1); | ||||
expect(FileList.findFileEl('Two.jpg').length).toEqual(1); | expect(FileList.findFileEl('Two.jpg').length).toEqual(1); | ||||
expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(4); | |||||
expect(FileList.$fileList.find('tr').length).toEqual(4); | |||||
expect(notificationStub.calledOnce).toEqual(true); | expect(notificationStub.calledOnce).toEqual(true); | ||||
}); | }); | ||||
function doRename() { | function doRename() { | ||||
var $input, request; | var $input, request; | ||||
FileList.setFiles(testFiles); | |||||
for (var i = 0; i < testFiles.length; i++) { | |||||
FileList.add(testFiles[i]); | |||||
} | |||||
// trigger rename prompt | // trigger rename prompt | ||||
FileList.rename('One.txt'); | FileList.rename('One.txt'); | ||||
$input = FileList.$fileList.find('input.filename'); | $input = FileList.$fileList.find('input.filename'); | ||||
$input.val('One_renamed.txt').blur(); | |||||
$input.val('Tu_after_three.txt').blur(); | |||||
expect(fakeServer.requests.length).toEqual(1); | 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(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'}); | |||||
expect(OC.parseQueryString(request.url)).toEqual({'dir': '/subdir', newname: 'Tu_after_three.txt', file: 'One.txt'}); | |||||
// element is renamed before the request finishes | // element is renamed before the request finishes | ||||
expect(FileList.findFileEl('One.txt').length).toEqual(0); | expect(FileList.findFileEl('One.txt').length).toEqual(0); | ||||
expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1); | |||||
expect(FileList.findFileEl('Tu_after_three.txt').length).toEqual(1); | |||||
// input is gone | // input is gone | ||||
expect(FileList.$fileList.find('input.filename').length).toEqual(0); | expect(FileList.$fileList.find('input.filename').length).toEqual(0); | ||||
} | } | ||||
it('Keeps renamed file entry if rename ajax call suceeded', function() { | |||||
it('Inserts renamed file entry at correct position if rename ajax call suceeded', function() { | |||||
doRename(); | doRename(); | ||||
fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | ||||
status: 'success', | status: 'success', | ||||
data: { | data: { | ||||
name: 'One_renamed.txt' | |||||
name: 'Tu_after_three.txt', | |||||
type: 'file' | |||||
} | } | ||||
})); | })); | ||||
// element stays renamed | // element stays renamed | ||||
expect(FileList.findFileEl('One.txt').length).toEqual(0); | expect(FileList.findFileEl('One.txt').length).toEqual(0); | ||||
expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1); | |||||
expect(FileList.findFileEl('Tu_after_three.txt').length).toEqual(1); | |||||
expect(FileList.findFileEl('Tu_after_three.txt').index()).toEqual(2); // after Two.txt | |||||
expect(alertStub.notCalled).toEqual(true); | expect(alertStub.notCalled).toEqual(true); | ||||
}); | }); | ||||
// element was reverted | // element was reverted | ||||
expect(FileList.findFileEl('One.txt').length).toEqual(1); | expect(FileList.findFileEl('One.txt').length).toEqual(1); | ||||
expect(FileList.findFileEl('One_renamed.txt').length).toEqual(0); | |||||
expect(FileList.findFileEl('One.txt').index()).toEqual(1); // after somedir | |||||
expect(FileList.findFileEl('Tu_after_three.txt').length).toEqual(0); | |||||
expect(alertStub.calledOnce).toEqual(true); | expect(alertStub.calledOnce).toEqual(true); | ||||
}); | }); | ||||
fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | ||||
status: 'success', | status: 'success', | ||||
data: { | data: { | ||||
name: 'One_renamed.txt' | |||||
name: 'Tu_after_three.txt' | |||||
} | } | ||||
})); | })); | ||||
$tr = FileList.findFileEl('One_renamed.txt'); | |||||
expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One_renamed.txt'); | |||||
$tr = FileList.findFileEl('Tu_after_three.txt'); | |||||
expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=Tu_after_three.txt'); | |||||
}); | }); | ||||
// FIXME: fix this in the source code! | // FIXME: fix this in the source code! | ||||
xit('Correctly updates file link after rename when path has same name', function() { | xit('Correctly updates file link after rename when path has same name', function() { | ||||
fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({ | ||||
status: 'success', | status: 'success', | ||||
data: { | data: { | ||||
name: 'One_renamed.txt' | |||||
name: 'Tu_after_three.txt' | |||||
} | } | ||||
})); | })); | ||||
$tr = FileList.findFileEl('One_renamed.txt'); | |||||
$tr = FileList.findFileEl('Tu_after_three.txt'); | |||||
expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One.txt'); | 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() { | describe('List rendering', function() { | ||||
it('renders a list of files using add()', function() { | it('renders a list of files using add()', function() { | ||||
var addSpy = sinon.spy(FileList, 'add'); | |||||
expect(FileList.files.length).toEqual(0); | |||||
expect(FileList.files).toEqual([]); | |||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
expect(addSpy.callCount).toEqual(4); | |||||
expect($('#fileList tr:not(.summary)').length).toEqual(4); | |||||
addSpy.restore(); | |||||
expect($('#fileList tr').length).toEqual(4); | |||||
expect(FileList.files.length).toEqual(4); | |||||
expect(FileList.files).toEqual(testFiles); | |||||
}); | }); | ||||
it('updates summary using the file sizes', function() { | it('updates summary using the file sizes', function() { | ||||
var $summary; | var $summary; | ||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
$summary = $('#fileList .summary'); | |||||
expect($summary.length).toEqual(1); | |||||
$summary = $('#filestable .summary'); | |||||
expect($summary.hasClass('hidden')).toEqual(false); | |||||
expect($summary.find('.info').text()).toEqual('1 folder and 3 files'); | expect($summary.find('.info').text()).toEqual('1 folder and 3 files'); | ||||
expect($summary.find('.filesize').text()).toEqual('69 kB'); | expect($summary.find('.filesize').text()).toEqual('69 kB'); | ||||
}); | }); | ||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
expect($('#filestable thead th').hasClass('hidden')).toEqual(false); | expect($('#filestable thead th').hasClass('hidden')).toEqual(false); | ||||
expect($('#emptycontent').hasClass('hidden')).toEqual(true); | expect($('#emptycontent').hasClass('hidden')).toEqual(true); | ||||
expect(FileList.$fileList.find('.summary').length).toEqual(1); | |||||
expect(FileList.$el.find('.summary').hasClass('hidden')).toEqual(false); | |||||
}); | }); | ||||
it('hides headers, summary and show empty content message after setting empty file list', function(){ | it('hides headers, summary and show empty content message after setting empty file list', function(){ | ||||
FileList.setFiles([]); | FileList.setFiles([]); | ||||
expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | ||||
expect($('#emptycontent').hasClass('hidden')).toEqual(false); | expect($('#emptycontent').hasClass('hidden')).toEqual(false); | ||||
expect(FileList.$fileList.find('.summary').length).toEqual(0); | |||||
expect(FileList.$el.find('.summary').hasClass('hidden')).toEqual(true); | |||||
}); | }); | ||||
it('hides headers, empty content message, and summary when list is empty and user has no creation permission', function(){ | it('hides headers, empty content message, and summary when list is empty and user has no creation permission', function(){ | ||||
$('#permissions').val(0); | $('#permissions').val(0); | ||||
FileList.setFiles([]); | FileList.setFiles([]); | ||||
expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | expect($('#filestable thead th').hasClass('hidden')).toEqual(true); | ||||
expect($('#emptycontent').hasClass('hidden')).toEqual(true); | expect($('#emptycontent').hasClass('hidden')).toEqual(true); | ||||
expect(FileList.$fileList.find('.summary').length).toEqual(0); | |||||
expect(FileList.$el.find('.summary').hasClass('hidden')).toEqual(true); | |||||
}); | }); | ||||
it('calling findFileEl() can find existing file element', function() { | it('calling findFileEl() can find existing file element', function() { | ||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
FileList.setFiles(testFiles); | FileList.setFiles(testFiles); | ||||
expect(handler.calledOnce).toEqual(true); | 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('Rendering next page on scroll', function() { | |||||
beforeEach(function() { | |||||
FileList.setFiles(generateFiles(0, 64)); | |||||
}); | |||||
it('renders only the first page', function() { | |||||
expect(FileList.files.length).toEqual(65); | |||||
expect($('#fileList tr').length).toEqual(20); | |||||
}); | |||||
it('renders the second page when scrolling down (trigger nextPage)', function() { | |||||
// TODO: can't simulate scrolling here, so calling nextPage directly | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(40); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(60); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(65); | |||||
FileList._nextPage(true); | |||||
// stays at 65 | |||||
expect($('#fileList tr').length).toEqual(65); | |||||
}); | |||||
it('inserts into the DOM if insertion point is in the visible page ', function() { | |||||
FileList.add({ | |||||
id: 2000, | |||||
type: 'file', | |||||
name: 'File with index 15b.txt' | |||||
}); | |||||
expect($('#fileList tr').length).toEqual(21); | |||||
expect(FileList.findFileEl('File with index 15b.txt').index()).toEqual(16); | |||||
}); | |||||
it('does not inserts into the DOM if insertion point is not the visible page ', function() { | |||||
FileList.add({ | |||||
id: 2000, | |||||
type: 'file', | |||||
name: 'File with index 28b.txt' | |||||
}); | |||||
expect($('#fileList tr').length).toEqual(20); | |||||
expect(FileList.findFileEl('File with index 28b.txt').length).toEqual(0); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(40); | |||||
expect(FileList.findFileEl('File with index 28b.txt').index()).toEqual(29); | |||||
}); | |||||
it('appends into the DOM when inserting a file after the last visible element', function() { | |||||
FileList.add({ | |||||
id: 2000, | |||||
type: 'file', | |||||
name: 'File with index 19b.txt' | |||||
}); | |||||
expect($('#fileList tr').length).toEqual(21); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(41); | |||||
}); | |||||
it('appends into the DOM when inserting a file on the last page when visible', function() { | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(40); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(60); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(65); | |||||
FileList._nextPage(true); | |||||
FileList.add({ | |||||
id: 2000, | |||||
type: 'file', | |||||
name: 'File with index 88.txt' | |||||
}); | |||||
expect($('#fileList tr').length).toEqual(66); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(66); | |||||
}); | |||||
it('shows additional page when appending a page of files and scrolling down', function() { | |||||
var newFiles = generateFiles(66, 81); | |||||
for (var i = 0; i < newFiles.length; i++) { | |||||
FileList.add(newFiles[i]); | |||||
} | |||||
expect($('#fileList tr').length).toEqual(20); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(40); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(60); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(80); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(81); | |||||
FileList._nextPage(true); | |||||
expect($('#fileList tr').length).toEqual(81); | |||||
}); | |||||
it('automatically renders next page when there are not enough elements visible', function() { | |||||
// delete the 15 first elements | |||||
for (var i = 0; i < 15; i++) { | |||||
FileList.remove(FileList.files[0].name); | |||||
} | |||||
// still makes sure that there are 20 elements visible, if any | |||||
expect($('#fileList tr').length).toEqual(25); | |||||
}); | |||||
}); | }); | ||||
describe('file previews', function() { | describe('file previews', function() { | ||||
var previewLoadStub; | var previewLoadStub; | ||||
var query = url.substr(url.indexOf('?') + 1); | var query = url.substr(url.indexOf('?') + 1); | ||||
expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir'}); | expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir'}); | ||||
fakeServer.respond(); | fakeServer.respond(); | ||||
expect($('#fileList tr:not(.summary)').length).toEqual(4); | |||||
expect($('#fileList tr').length).toEqual(4); | |||||
expect(FileList.findFileEl('One.txt').length).toEqual(1); | expect(FileList.findFileEl('One.txt').length).toEqual(1); | ||||
}); | }); | ||||
it('switches dir and fetches file list when calling changeDirectory()', function() { | it('switches dir and fetches file list when calling changeDirectory()', function() { | ||||
} | } | ||||
}; | }; | ||||
// returns a list of tr that were dragged | // returns a list of tr that were dragged | ||||
// FIXME: why are their attributes different than the | |||||
// regular file trs ? | |||||
ui.helper.find.returns([ | ui.helper.find.returns([ | ||||
$('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'), | |||||
$('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>') | |||||
$('<tr data-file="One.txt" data-dir="' + testDir + '"></tr>'), | |||||
$('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>') | |||||
]); | ]); | ||||
// simulate drop event | // 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) | // will trigger two calls to move.php (first one was previous list.php) | ||||
expect(fakeServer.requests.length).toEqual(3); | expect(fakeServer.requests.length).toEqual(3); | ||||
} | } | ||||
}; | }; | ||||
// returns a list of tr that were dragged | // returns a list of tr that were dragged | ||||
// FIXME: why are their attributes different than the | |||||
// regular file trs ? | |||||
ui.helper.find.returns([ | ui.helper.find.returns([ | ||||
$('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'), | |||||
$('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>') | |||||
$('<tr data-file="One.txt" data-dir="' + testDir + '"></tr>'), | |||||
$('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>') | |||||
]); | ]); | ||||
// simulate drop event | // simulate drop event | ||||
FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui); | |||||
FileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui); | |||||
// no extra server request | // no extra server request | ||||
expect(fakeServer.requests.length).toEqual(1); | expect(fakeServer.requests.length).toEqual(1); | ||||
expect(Files.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y'); | 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('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); | |||||
$('#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(); | |||||
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); | |||||
expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(3); | |||||
}); | |||||
it('Updates the selection summary when doing a few manipulations with "Select all"', function() { | |||||
$('#select_all').click(); | |||||
expect($('#select_all').prop('checked')).toEqual(true); | |||||
var $tr = FileList.findFileEl('One.txt'); | |||||
// unselect one | |||||
$tr.find('input:checkbox').click(); | |||||
expect($('#select_all').prop('checked')).toEqual(false); | |||||
expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(3); | |||||
// select all | |||||
$('#select_all').click(); | |||||
expect($('#select_all').prop('checked')).toEqual(true); | |||||
expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(4); | |||||
// unselect one | |||||
$tr.find('input:checkbox').click(); | |||||
expect($('#select_all').prop('checked')).toEqual(false); | |||||
expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(3); | |||||
// re-select it | |||||
$tr.find('input:checkbox').click(); | |||||
expect($('#select_all').prop('checked')).toEqual(true); | |||||
expect(_.pluck(FileList.getSelectedFiles(), 'name').length).toEqual(4); | |||||
}); | |||||
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'); | |||||
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); | |||||
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() { | |||||
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 file data', function() { | |||||
var files = FileList.getSelectedFiles(); | |||||
expect(files.length).toEqual(3); | |||||
expect(files[0]).toEqual({ | |||||
id: 1, | |||||
name: 'One.txt', | |||||
mimetype: 'text/plain', | |||||
type: 'file', | |||||
size: 12, | |||||
etag: 'abc' | |||||
}); | |||||
expect(files[1]).toEqual({ | |||||
id: 3, | |||||
type: 'file', | |||||
name: 'Three.pdf', | |||||
mimetype: 'application/pdf', | |||||
size: 58009, | |||||
etag: '123' | |||||
}); | |||||
expect(files[2]).toEqual({ | |||||
id: 4, | |||||
type: 'dir', | |||||
name: 'somedir', | |||||
mimetype: 'httpd/unix-directory', | |||||
size: 250, | |||||
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() { | |||||
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); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | }); |
* | * | ||||
*/ | */ | ||||
/* global Files */ | |||||
/* global OC, Files */ | |||||
describe('Files tests', function() { | describe('Files tests', function() { | ||||
describe('File name validation', function() { | describe('File name validation', function() { | ||||
it('Validates correct file names', function() { | it('Validates correct file names', 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'); | |||||
}); | |||||
}); | |||||
}); | }); |
/** | |||||
* ownCloud | |||||
* | |||||
* @author Vincent Petry | |||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com> | |||||
* | |||||
* This library is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or any later version. | |||||
* | |||||
* This library is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public | |||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
/* global FileSummary */ | |||||
describe('FileSummary tests', function() { | |||||
var $container; | |||||
beforeEach(function() { | |||||
$container = $('<table><tr></tr></table>').find('tr'); | |||||
}); | |||||
afterEach(function() { | |||||
$container = null; | |||||
}); | |||||
it('renders summary as text', function() { | |||||
var s = new FileSummary($container); | |||||
s.setSummary({ | |||||
totalDirs: 5, | |||||
totalFiles: 2, | |||||
totalSize: 256000 | |||||
}); | |||||
expect($container.hasClass('hidden')).toEqual(false); | |||||
expect($container.find('.info').text()).toEqual('5 folders and 2 files'); | |||||
expect($container.find('.filesize').text()).toEqual('250 kB'); | |||||
}); | |||||
it('hides summary when no files or folders', function() { | |||||
var s = new FileSummary($container); | |||||
s.setSummary({ | |||||
totalDirs: 0, | |||||
totalFiles: 0, | |||||
totalSize: 0 | |||||
}); | |||||
expect($container.hasClass('hidden')).toEqual(true); | |||||
}); | |||||
it('increases summary when adding files', function() { | |||||
var s = new FileSummary($container); | |||||
s.setSummary({ | |||||
totalDirs: 5, | |||||
totalFiles: 2, | |||||
totalSize: 256000 | |||||
}); | |||||
s.add({type: 'file', size: 256000}); | |||||
s.add({type: 'dir', size: 100}); | |||||
s.update(); | |||||
expect($container.hasClass('hidden')).toEqual(false); | |||||
expect($container.find('.info').text()).toEqual('6 folders and 3 files'); | |||||
expect($container.find('.filesize').text()).toEqual('500 kB'); | |||||
expect(s.summary.totalDirs).toEqual(6); | |||||
expect(s.summary.totalFiles).toEqual(3); | |||||
expect(s.summary.totalSize).toEqual(512100); | |||||
}); | |||||
it('decreases summary when removing files', function() { | |||||
var s = new FileSummary($container); | |||||
s.setSummary({ | |||||
totalDirs: 5, | |||||
totalFiles: 2, | |||||
totalSize: 256000 | |||||
}); | |||||
s.remove({type: 'file', size: 128000}); | |||||
s.remove({type: 'dir', size: 100}); | |||||
s.update(); | |||||
expect($container.hasClass('hidden')).toEqual(false); | |||||
expect($container.find('.info').text()).toEqual('4 folders and 1 file'); | |||||
expect($container.find('.filesize').text()).toEqual('125 kB'); | |||||
expect(s.summary.totalDirs).toEqual(4); | |||||
expect(s.summary.totalFiles).toEqual(1); | |||||
expect(s.summary.totalSize).toEqual(127900); | |||||
}); | |||||
}); |
OCP\Util::addStyle('files', 'files'); | OCP\Util::addStyle('files', 'files'); | ||||
OCP\Util::addStyle('files', 'upload'); | OCP\Util::addStyle('files', 'upload'); | ||||
OCP\Util::addScript('files', 'filesummary'); | |||||
OCP\Util::addScript('files', 'breadcrumb'); | OCP\Util::addScript('files', 'breadcrumb'); | ||||
OCP\Util::addScript('files', 'files'); | OCP\Util::addScript('files', 'files'); | ||||
OCP\Util::addScript('files', 'filelist'); | OCP\Util::addScript('files', 'filelist'); |
OCP\Util::addStyle('files', 'files'); | OCP\Util::addStyle('files', 'files'); | ||||
OCP\Util::addStyle('files_trashbin', 'trash'); | OCP\Util::addStyle('files_trashbin', 'trash'); | ||||
OCP\Util::addScript('files', 'filesummary'); | |||||
OCP\Util::addScript('files', 'breadcrumb'); | OCP\Util::addScript('files', 'breadcrumb'); | ||||
OCP\Util::addScript('files', 'filelist'); | OCP\Util::addScript('files', 'filelist'); | ||||
// filelist overrides | // filelist overrides |
} | } | ||||
}; | }; | ||||
var oldAdd = FileList.add; | |||||
FileList.add = function(fileData, options) { | |||||
var oldRenderRow = FileList._renderRow; | |||||
FileList._renderRow = function(fileData, options) { | |||||
options = options || {}; | options = options || {}; | ||||
var dir = FileList.getCurrentDirectory(); | var dir = FileList.getCurrentDirectory(); | ||||
var dirListing = dir !== '' && dir !== '/'; | var dirListing = dir !== '' && dir !== '/'; | ||||
fileData.displayName = fileData.name; | fileData.displayName = fileData.name; | ||||
fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000); | fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000); | ||||
} | } | ||||
return oldAdd.call(this, fileData, options); | |||||
return oldRenderRow.call(this, fileData, options); | |||||
}; | }; | ||||
FileList.linkTo = function(dir){ | FileList.linkTo = function(dir){ | ||||
$('#emptycontent').toggleClass('hidden', exists); | $('#emptycontent').toggleClass('hidden', exists); | ||||
$('#filestable th').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 = _.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'); | |||||
} | |||||
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.setFiles([]); | |||||
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 = _.pluck(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); | |||||
}; | |||||
})(); | })(); |
return name; | return name; | ||||
} | } | ||||
function removeCallback(result) { | |||||
if (result.status !== 'success') { | |||||
OC.dialogs.alert(result.data.message, t('files_trashbin', 'Error')); | |||||
} | |||||
var files = result.data.success; | |||||
for (var i = 0; i < files.length; i++) { | |||||
FileList.remove(OC.basename(files[i].filename), {updateSummary: false}); | |||||
} | |||||
FileList.updateFileSummary(); | |||||
FileList.updateEmptyContent(); | |||||
enableActions(); | |||||
} | |||||
Files.updateStorageStatistics = function() { | Files.updateStorageStatistics = function() { | ||||
// no op because the trashbin doesn't have | // no op because the trashbin doesn't have | ||||
// storage info like free space / used space | // storage info like free space / used space | ||||
files: JSON.stringify([filename]), | files: JSON.stringify([filename]), | ||||
dir: FileList.getCurrentDirectory() | dir: FileList.getCurrentDirectory() | ||||
}, | }, | ||||
removeCallback | |||||
FileList._removeCallback | |||||
); | ); | ||||
}, t('files_trashbin', 'Restore')); | }, t('files_trashbin', 'Restore')); | ||||
}; | }; | ||||
files: JSON.stringify([filename]), | files: JSON.stringify([filename]), | ||||
dir: FileList.getCurrentDirectory() | 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!) | * Override crumb URL maker (hacky!) | ||||
*/ | */ |
<th id="headerDate"> | <th id="headerDate"> | ||||
<span id="modified"><?php p($l->t( 'Deleted' )); ?></span> | <span id="modified"><?php p($l->t( 'Deleted' )); ?></span> | ||||
<span class="selectedActions"> | <span class="selectedActions"> | ||||
<a href="" class="delete"> | |||||
<a href="" class="delete-selected"> | |||||
<?php p($l->t('Delete'))?> | <?php p($l->t('Delete'))?> | ||||
<img class="svg" alt="<?php p($l->t('Delete'))?>" | <img class="svg" alt="<?php p($l->t('Delete'))?>" | ||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" /> | src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" /> | ||||
</thead> | </thead> | ||||
<tbody id="fileList"> | <tbody id="fileList"> | ||||
</tbody> | </tbody> | ||||
<tfoot> | |||||
</tfoot> | |||||
</table> | </table> |
padding-right: 30px; | padding-right: 30px; | ||||
} | } | ||||
/* general styles for the content area */ | /* general styles for the content area */ | ||||
.section { | .section { | ||||
display: block; | display: block; | ||||
vertical-align: -2px; | vertical-align: -2px; | ||||
margin-right: 4px; | margin-right: 4px; | ||||
} | } | ||||
.appear { | |||||
opacity: 1; | |||||
transition: opacity 500ms ease 0s; | |||||
-moz-transition: opacity 500ms ease 0s; | |||||
-ms-transition: opacity 500ms ease 0s; | |||||
-o-transition: opacity 500ms ease 0s; | |||||
-webkit-transition: opacity 500ms ease 0s; | |||||
} | |||||
.appear.transparent { | |||||
opacity: 0; | |||||
} |
} | } | ||||
/** | /** | ||||
* @todo Write documentation | |||||
* Utility functions | |||||
*/ | */ | ||||
OC.Util = { | OC.Util = { | ||||
// TODO: remove original functions from global namespace | |||||
humanFileSize: humanFileSize, | |||||
formatDate: formatDate, | |||||
/** | /** | ||||
* Returns whether the browser supports SVG | * Returns whether the browser supports SVG | ||||
* @return {boolean} true if the browser supports SVG, false otherwise | * @return {boolean} true if the browser supports SVG, false otherwise |
); | ); | ||||
}); | }); | ||||
}); | }); | ||||
describe('Util', function() { | |||||
describe('humanFileSize', function() { | |||||
it('renders file sizes with the correct unit', function() { | |||||
var data = [ | |||||
[0, '0 B'], | |||||
[125, '125 B'], | |||||
[128000, '125 kB'], | |||||
[128000000, '122.1 MB'], | |||||
[128000000000, '119.2 GB'], | |||||
[128000000000000, '116.4 TB'] | |||||
]; | |||||
for (var i = 0; i < data.length; i++) { | |||||
expect(OC.Util.humanFileSize(data[i][0])).toEqual(data[i][1]); | |||||
} | |||||
}); | |||||
}); | |||||
}); | |||||
}); | }); | ||||