508c580e67
The trashbin code does some gymnastics with the file data at render time. This fix makes sure that the modifications done on the file data are only local to the rendering code and doesn't affect the actual file data from the file list.
368 lines
9.6 KiB
JavaScript
368 lines
9.6 KiB
JavaScript
/*
|
|
* Copyright (c) 2014
|
|
*
|
|
* This file is licensed under the Affero General Public License version 3
|
|
* or later.
|
|
*
|
|
* See the COPYING-README file.
|
|
*
|
|
*/
|
|
(function() {
|
|
var DELETED_REGEXP = new RegExp(/^(.+)\.d[0-9]+$/);
|
|
|
|
/**
|
|
* Convert a file name in the format filename.d12345 to the real file name.
|
|
* This will use basename.
|
|
* The name will not be changed if it has no ".d12345" suffix.
|
|
* @param {String} name file name
|
|
* @return {String} converted file name
|
|
*/
|
|
function getDeletedFileName(name) {
|
|
name = OC.basename(name);
|
|
var match = DELETED_REGEXP.exec(name);
|
|
if (match && match.length > 1) {
|
|
name = match[1];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* @class OCA.Trashbin.FileList
|
|
* @augments OCA.Files.FileList
|
|
* @classdesc List of deleted files
|
|
*
|
|
* @param $el container element with existing markup for the #controls
|
|
* and a table
|
|
* @param [options] map of options
|
|
*/
|
|
var FileList = function($el, options) {
|
|
this.initialize($el, options);
|
|
};
|
|
FileList.prototype = _.extend({}, OCA.Files.FileList.prototype,
|
|
/** @lends OCA.Trashbin.FileList.prototype */ {
|
|
id: 'trashbin',
|
|
appName: t('files_trashbin', 'Deleted files'),
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
initialize: function() {
|
|
var result = OCA.Files.FileList.prototype.initialize.apply(this, arguments);
|
|
this.$el.find('.undelete').click('click', _.bind(this._onClickRestoreSelected, this));
|
|
|
|
this.setSort('mtime', 'desc');
|
|
/**
|
|
* Override crumb making to add "Deleted Files" entry
|
|
* and convert files with ".d" extensions to a more
|
|
* user friendly name.
|
|
*/
|
|
this.breadcrumb._makeCrumbs = function() {
|
|
var parts = OCA.Files.BreadCrumb.prototype._makeCrumbs.apply(this, arguments);
|
|
for (var i = 1; i < parts.length; i++) {
|
|
parts[i].name = getDeletedFileName(parts[i].name);
|
|
}
|
|
return parts;
|
|
};
|
|
|
|
OC.Plugins.attach('OCA.Trashbin.FileList', this);
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Override to only return read permissions
|
|
*/
|
|
getDirectoryPermissions: function() {
|
|
return OC.PERMISSION_READ | OC.PERMISSION_DELETE;
|
|
},
|
|
|
|
_setCurrentDir: function(targetDir) {
|
|
OCA.Files.FileList.prototype._setCurrentDir.apply(this, arguments);
|
|
|
|
var baseDir = OC.basename(targetDir);
|
|
if (baseDir !== '') {
|
|
this.setPageTitle(getDeletedFileName(baseDir));
|
|
}
|
|
},
|
|
|
|
_createRow: function() {
|
|
// FIXME: MEGAHACK until we find a better solution
|
|
var tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments);
|
|
tr.find('td.filesize').remove();
|
|
return tr;
|
|
},
|
|
|
|
_renderRow: function(fileData, options) {
|
|
options = options || {};
|
|
// make a copy to avoid changing original object
|
|
fileData = _.extend({}, fileData);
|
|
var dir = this.getCurrentDirectory();
|
|
var dirListing = dir !== '' && dir !== '/';
|
|
// show deleted time as mtime
|
|
if (fileData.mtime) {
|
|
fileData.mtime = parseInt(fileData.mtime, 10);
|
|
}
|
|
if (!dirListing) {
|
|
fileData.displayName = fileData.name;
|
|
fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000);
|
|
}
|
|
return OCA.Files.FileList.prototype._renderRow.call(this, fileData, options);
|
|
},
|
|
|
|
getAjaxUrl: function(action, params) {
|
|
var q = '';
|
|
if (params) {
|
|
q = '?' + OC.buildQueryString(params);
|
|
}
|
|
return OC.filePath('files_trashbin', 'ajax', action + '.php') + q;
|
|
},
|
|
|
|
setupUploadEvents: function() {
|
|
// override and do nothing
|
|
},
|
|
|
|
linkTo: function(dir){
|
|
return OC.linkTo('files', 'index.php')+"?view=trashbin&dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
|
},
|
|
|
|
elementToFile: function($el) {
|
|
var fileInfo = OCA.Files.FileList.prototype.elementToFile($el);
|
|
if (this.getCurrentDirectory() === '/') {
|
|
fileInfo.displayName = getDeletedFileName(fileInfo.name);
|
|
}
|
|
// no size available
|
|
delete fileInfo.size;
|
|
return fileInfo;
|
|
},
|
|
|
|
updateEmptyContent: function(){
|
|
var exists = this.$fileList.find('tr:first').exists();
|
|
this.$el.find('#emptycontent').toggleClass('hidden', exists);
|
|
this.$el.find('#filestable th').toggleClass('hidden', !exists);
|
|
},
|
|
|
|
_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 = this.remove(OC.basename(files[i].filename), {updateSummary: false});
|
|
this.fileSummary.remove({type: $el.attr('data-type'), size: $el.attr('data-size')});
|
|
}
|
|
this.fileSummary.update();
|
|
this.updateEmptyContent();
|
|
this.enableActions();
|
|
},
|
|
|
|
_onClickRestoreSelected: function(event) {
|
|
event.preventDefault();
|
|
var self = this;
|
|
var allFiles = this.$el.find('.select-all').is(':checked');
|
|
var files = [];
|
|
var params = {};
|
|
this.disableActions();
|
|
if (allFiles) {
|
|
this.showMask();
|
|
params = {
|
|
allfiles: true,
|
|
dir: this.getCurrentDirectory()
|
|
};
|
|
}
|
|
else {
|
|
files = _.pluck(this.getSelectedFiles(), 'name');
|
|
for (var i = 0; i < files.length; i++) {
|
|
var deleteAction = this.findFileEl(files[i]).children("td.date").children(".action.delete");
|
|
deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
|
|
}
|
|
params = {
|
|
files: JSON.stringify(files),
|
|
dir: this.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'));
|
|
}
|
|
self.hideMask();
|
|
// simply remove all files
|
|
self.setFiles([]);
|
|
self.enableActions();
|
|
}
|
|
else {
|
|
self._removeCallback(result);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
_onClickDeleteSelected: function(event) {
|
|
event.preventDefault();
|
|
var self = this;
|
|
var allFiles = this.$el.find('.select-all').is(':checked');
|
|
var files = [];
|
|
var params = {};
|
|
if (allFiles) {
|
|
params = {
|
|
allfiles: true,
|
|
dir: this.getCurrentDirectory()
|
|
};
|
|
}
|
|
else {
|
|
files = _.pluck(this.getSelectedFiles(), 'name');
|
|
params = {
|
|
files: JSON.stringify(files),
|
|
dir: this.getCurrentDirectory()
|
|
};
|
|
}
|
|
|
|
this.disableActions();
|
|
if (allFiles) {
|
|
this.showMask();
|
|
}
|
|
else {
|
|
for (var i = 0; i < files.length; i++) {
|
|
var deleteAction = this.findFileEl(files[i]).children("td.date").children(".action.delete");
|
|
deleteAction.removeClass('icon-delete').addClass('icon-loading-small');
|
|
}
|
|
}
|
|
|
|
$.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'));
|
|
}
|
|
self.hideMask();
|
|
// simply remove all files
|
|
self.setFiles([]);
|
|
self.enableActions();
|
|
}
|
|
else {
|
|
self._removeCallback(result);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
_onClickFile: function(event) {
|
|
var mime = $(this).parent().parent().data('mime');
|
|
if (mime !== 'httpd/unix-directory') {
|
|
event.preventDefault();
|
|
}
|
|
return OCA.Files.FileList.prototype._onClickFile.apply(this, arguments);
|
|
},
|
|
|
|
generatePreviewUrl: function(urlSpec) {
|
|
return OC.generateUrl('/apps/files_trashbin/ajax/preview.php?') + $.param(urlSpec);
|
|
},
|
|
|
|
getDownloadUrl: function() {
|
|
// no downloads
|
|
return '#';
|
|
},
|
|
|
|
enableActions: function() {
|
|
this.$el.find('.action').css('display', 'inline');
|
|
this.$el.find('input:checkbox').removeClass('u-hidden');
|
|
},
|
|
|
|
disableActions: function() {
|
|
this.$el.find('.action').css('display', 'none');
|
|
this.$el.find('input:checkbox').addClass('u-hidden');
|
|
},
|
|
|
|
updateStorageStatistics: function() {
|
|
// no op because the trashbin doesn't have
|
|
// storage info like free space / used space
|
|
},
|
|
|
|
isSelectedDeletable: function() {
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Reloads the file list using ajax call
|
|
*
|
|
* @return ajax call object
|
|
*/
|
|
reload: function() {
|
|
this._selectedFiles = {};
|
|
this._selectionSummary.clear();
|
|
this.$el.find('.select-all').prop('checked', false);
|
|
this.showMask();
|
|
if (this._reloadCall) {
|
|
this._reloadCall.abort();
|
|
}
|
|
this._reloadCall = $.ajax({
|
|
url: this.getAjaxUrl('list'),
|
|
data: {
|
|
dir : this.getCurrentDirectory(),
|
|
sort: this._sort,
|
|
sortdirection: this._sortDirection
|
|
}
|
|
});
|
|
var callBack = this.reloadCallback.bind(this);
|
|
return this._reloadCall.then(callBack, callBack);
|
|
},
|
|
reloadCallback: function(result) {
|
|
delete this._reloadCall;
|
|
this.hideMask();
|
|
|
|
if (!result || result.status === 'error') {
|
|
// if the error is not related to folder we're trying to load, reload the page to handle logout etc
|
|
if (result.data.error === 'authentication_error' ||
|
|
result.data.error === 'token_expired' ||
|
|
result.data.error === 'application_not_enabled'
|
|
) {
|
|
OC.redirect(OC.generateUrl('apps/files'));
|
|
}
|
|
OC.Notification.show(result.data.message);
|
|
return false;
|
|
}
|
|
|
|
if (result.status === 401) {
|
|
return false;
|
|
}
|
|
|
|
// Firewall Blocked request?
|
|
if (result.status === 403) {
|
|
// Go home
|
|
this.changeDirectory('/');
|
|
OC.Notification.show(t('files', 'This operation is forbidden'));
|
|
return false;
|
|
}
|
|
|
|
// Did share service die or something else fail?
|
|
if (result.status === 500) {
|
|
// Go home
|
|
this.changeDirectory('/');
|
|
OC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));
|
|
return false;
|
|
}
|
|
|
|
if (result.status === 404) {
|
|
// go back home
|
|
this.changeDirectory('/');
|
|
return false;
|
|
}
|
|
// aborted ?
|
|
if (result.status === 0){
|
|
return true;
|
|
}
|
|
|
|
this.setFiles(result.data.files);
|
|
return true;
|
|
},
|
|
|
|
});
|
|
|
|
OCA.Trashbin.FileList = FileList;
|
|
})();
|
|
|