/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global OC, t, n, FileList, FileActions, Files, FileSummary, BreadCrumb */
/* global dragOptions, folderDropOptions */
window.FileList = {
appName: t('files', 'Files'),
isEmpty: true,
useUndo:true,
$el: $('#filestable'),
$fileList: $('#fileList'),
breadcrumb: null,
/**
* Instance of FileSummary
*/
fileSummary: null,
initialized: false,
// number of files per page
pageSize: 20,
totalPages: 0,
/**
* Compare two file info objects, sorting by
* folders first, then by name.
*/
_fileInfoCompare: function(fileInfo1, fileInfo2) {
if (fileInfo1.type === 'dir' && fileInfo2.type !== 'dir') {
return -1;
}
if (fileInfo1.type !== 'dir' && fileInfo2.type === 'dir') {
return 1;
}
return fileInfo1.name.localeCompare(fileInfo2.name);
},
/**
* Initialize the file list and its components
*/
initialize: function() {
var self = this;
if (this.initialized) {
return;
}
// TODO: FileList should not know about global elements
this.$el = $('#filestable');
this.$fileList = $('#fileList');
this.files = [];
this.fileSummary = this._createSummary();
this.breadcrumb = new BreadCrumb({
onClick: this._onClickBreadCrumb,
onDrop: this._onDropOnBreadCrumb,
getCrumbUrl: function(part, index) {
return self.linkTo(part.dir);
}
});
$('#controls').prepend(this.breadcrumb.$el);
$(window).resize(function() {
// TODO: debounce this ?
var width = $(this).width();
FileList.breadcrumb.resize(width, false);
});
this.$fileList.on('click','td.filename a', this._onClickFile);
this.$fileList.on('change', 'td.filename input:checkbox', this._onClickFileCheckbox);
this.$el.find('#select_all').click(this._onClickSelectAll);
this.$el.find('.download').click(this._onClickDownloadSelected);
this.$el.find('.delete-selected').click(this._onClickDeleteSelected);
},
/**
* Event handler for when clicking on files to select them
*/
_onClickFile: function(event) {
if (event.ctrlKey || event.shiftKey) {
event.preventDefault();
if (event.shiftKey) {
var last = $(FileList._lastChecked).parent().parent().prevAll().length;
var first = $(this).parent().parent().prevAll().length;
var start = Math.min(first, last);
var end = Math.max(first, last);
var rows = $(this).parent().parent().parent().children('tr');
for (var i = start; i < end; i++) {
$(rows).each(function(index) {
if (index === i) {
var checkbox = $(this).children().children('input:checkbox');
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().addClass('selected');
}
});
}
}
var checkbox = $(this).parent().children('input:checkbox');
FileList._lastChecked = checkbox;
if ($(checkbox).attr('checked')) {
$(checkbox).removeAttr('checked');
$(checkbox).parent().parent().removeClass('selected');
$('#select_all').removeAttr('checked');
} else {
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().toggleClass('selected');
var selectedCount = $('td.filename input:checkbox:checked').length;
if (selectedCount === $('td.filename input:checkbox').length) {
$('#select_all').attr('checked', 'checked');
}
}
FileList.updateSelectionSummary();
} else {
var filename=$(this).parent().parent().attr('data-file');
var tr = FileList.findFileEl(filename);
var renaming=tr.data('renaming');
if (!renaming) {
FileActions.currentFile = $(this).parent();
var mime=FileActions.getCurrentMimeType();
var type=FileActions.getCurrentType();
var permissions = FileActions.getCurrentPermissions();
var action=FileActions.getDefault(mime,type, permissions);
if (action) {
event.preventDefault();
action(filename);
}
}
}
},
/**
* Event handler for when clicking on a file's checkbox
*/
_onClickFileCheckbox: function(event) {
// FIXME: not sure what the difference is supposed to be with FileList._onClickFile
if (event.shiftKey) {
var last = $(FileList._lastChecked).parent().parent().prevAll().length;
var first = $(this).parent().parent().prevAll().length;
var start = Math.min(first, last);
var end = Math.max(first, last);
var rows = $(this).parent().parent().parent().children('tr');
for (var i = start; i < end; i++) {
$(rows).each(function(index) {
if (index === i) {
var checkbox = $(this).children().children('input:checkbox');
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().addClass('selected');
}
});
}
}
var selectedCount=$('td.filename input:checkbox:checked').length;
$(this).parent().parent().toggleClass('selected');
if (!$(this).attr('checked')) {
$('#select_all').attr('checked',false);
} else {
if (selectedCount===$('td.filename input:checkbox').length) {
$('#select_all').attr('checked',true);
}
}
FileList.updateSelectionSummary();
},
/**
* Event handler for when selecting/deselecting all files
*/
_onClickSelectAll: function(e) {
var checked = $(this).prop('checked');
FileList.$fileList.find('td.filename input:checkbox').prop('checked', checked)
.parent().parent().toggleClass('selected', checked);
FileList.updateSelectionSummary();
},
/**
* Event handler for when clicking on "Download" for the selected files
*/
_onClickDownloadSelected: function(event) {
var files;
var dir = FileList.getCurrentDirectory();
if (FileList.isAllSelected()) {
files = OC.basename(dir);
dir = OC.dirname(dir) || '/';
}
else {
files = FileList.getSelectedFiles('name');
}
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
OC.redirect(Files.getDownloadUrl(files, dir));
return false;
},
/**
* Event handler for when clicking on "Delete" for the selected files
*/
_onClickDeleteSelected: function(event) {
var files = null;
if (!FileList.isAllSelected()) {
files = FileList.getSelectedFiles('name');
}
FileList.do_delete(files);
event.preventDefault();
return false;
},
/**
* Event handler when clicking on a bread crumb
*/
_onClickBreadCrumb: function(e) {
var $el = $(e.target).closest('.crumb'),
$targetDir = $el.data('dir');
if ($targetDir !== undefined) {
e.preventDefault();
FileList.changeDirectory($targetDir);
}
},
_onScroll: function(e) {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 500) {
this._nextPage(true);
}
},
/**
* Event handler when dropping on a breadcrumb
*/
_onDropOnBreadCrumb: function( event, ui ) {
var target=$(this).data('dir');
var dir = FileList.getCurrentDirectory();
while(dir.substr(0,1) === '/') {//remove extra leading /'s
dir=dir.substr(1);
}
dir = '/' + dir;
if (dir.substr(-1,1) !== '/') {
dir = dir + '/';
}
if (target === dir || target+'/' === dir) {
return;
}
var files = ui.helper.find('tr');
$(files).each(function(i,row) {
var dir = $(row).data('dir');
var file = $(row).data('filename');
//slapdash selector, tracking down our original element that the clone budded off of.
var origin = $('tr[data-id=' + $(row).data('origin') + ']');
var td = origin.children('td.filename');
var oldBackgroundImage = td.css('background-image');
td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
$.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
if (result) {
if (result.status === 'success') {
FileList.remove(file);
FileList.updateSelectionSummary();
$('#notification').hide();
} else {
$('#notification').hide();
$('#notification').text(result.data.message);
$('#notification').fadeIn();
}
} else {
OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
}
td.css('background-image', oldBackgroundImage);
});
});
},
/**
* Sets a new page title
*/
setPageTitle: function(title){
if (title) {
title += ' - ';
} else {
title = '';
}
title += FileList.appName;
// Sets the page title with the " - ownCloud" suffix as in templates
window.document.title = title + ' - ' + oc_defaults.title;
return true;
},
/**
* Returns the tr element for a given file name
* @param fileName file name
*/
findFileEl: function(fileName){
// use filterAttr to avoid escaping issues
return this.$fileList.find('tr').filterAttr('data-file', fileName);
},
/**
* Returns the file data from a given file element.
* @param $el file tr element
* @return file data
*/
elementToFile: function($el){
return {
id: parseInt($el.attr('data-id'), 10),
name: $el.attr('data-file'),
mimetype: $el.attr('data-mime'),
type: $el.attr('data-type'),
size: parseInt($el.attr('data-size'), 10),
etag: $el.attr('data-etag'),
};
},
/**
* Appends the next page of files into the table
* @param animate true to animate the new elements
*/
_nextPage: function(animate) {
var index = this.$fileList.children().length,
count = this.pageSize,
tr,
newTrs = [],
selected = this.isAllSelected();
if (index >= this.files.length) {
return;
}
this.pageNumber++;
while (count > 0 && index < this.files.length) {
tr = this._renderRow(this.files[index], {updateSummary: false});
this.$fileList.append(tr);
if (selected) {
tr.addClass('selected');
tr.find('input:checkbox').prop('checked', true);
}
if (animate) {
tr.addClass('appear transparent');
newTrs.push(tr);
}
index++;
count--;
}
if (animate) {
// defer, for animation
window.setTimeout(function() {
for (var i = 0; i < newTrs.length; i++ ) {
newTrs[i].removeClass('transparent');
}
}, 0);
}
},
/**
* Sets the files to be displayed in the list.
* This operation will rerender the list and update the summary.
* @param filesArray array of file data (map)
*/
setFiles: function(filesArray) {
// detach to make adding multiple rows faster
this.files = filesArray;
this.pageNumber = -1;
this.totalPages = Math.ceil(filesArray.length / this.pageSize);
this.$fileList.detach();
this.$fileList.empty();
// clear "Select all" checkbox
$('#select_all').prop('checked', false);
this.isEmpty = this.files.length === 0;
this._nextPage();
this.$el.find('thead').after(this.$fileList);
this.updateEmptyContent();
this.$fileList.trigger(jQuery.Event("fileActionsReady"));
// "Files" might not be loaded in extending apps
if (window.Files) {
Files.setupDragAndDrop();
}
this.fileSummary.calculate(filesArray);
FileList.updateSelectionSummary();
$(window).scrollTop(0);
this.$fileList.trigger(jQuery.Event("updated"));
},
/**
* Creates a new table row element using the given file data.
* @param fileData map of file attributes
* @param options map of attribute "loading" whether the entry is currently loading
* @return new tr element (not appended to the table)
*/
_createRow: function(fileData, options) {
var td, simpleSize, basename, extension, sizeColor,
icon = OC.Util.replaceSVGIcon(fileData.icon),
name = fileData.name,
type = fileData.type || 'file',
mtime = parseInt(fileData.mtime, 10) || new Date().getTime(),
mime = fileData.mimetype,
linkUrl;
options = options || {};
if (type === 'dir') {
mime = mime || 'httpd/unix-directory';
}
// user should always be able to rename a share mount point
var allowRename = 0;
if (fileData.isShareMountPoint) {
allowRename = OC.PERMISSION_UPDATE;
}
//containing tr
var tr = $('