summaryrefslogtreecommitdiffstats
path: root/apps/files/js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/js')
-rw-r--r--apps/files/js/filelist.js225
-rw-r--r--apps/files/js/files.js12
-rw-r--r--apps/files/js/filesummary.js22
3 files changed, 135 insertions, 124 deletions
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 0847edd02bb..7c82ec92473 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -29,6 +29,23 @@ window.FileList = {
totalPages: 0,
/**
+ * Array of files in the current folder.
+ * The entries are of file data.
+ */
+ files: [],
+
+ /**
+ * Map of file id to file data
+ */
+ _selectedFiles: {},
+
+ /**
+ * Summary of selected files.
+ * Instance of FileSummary.
+ */
+ _selectionSummary: null,
+
+ /**
* Compare two file info objects, sorting by
* folders first, then by name.
*/
@@ -55,6 +72,8 @@ window.FileList = {
this.$el = $('#filestable');
this.$fileList = $('#fileList');
this.files = [];
+ this._selectedFiles = {};
+ this._selectionSummary = new FileSummary();
this.fileSummary = this._createSummary();
@@ -82,48 +101,70 @@ window.FileList = {
},
/**
+ * Selected/deselects the given file element and updated
+ * the internal selection cache.
+ *
+ * @param $tr single file row element
+ * @param state true to select, false to deselect
+ */
+ _selectFileEl: function($tr, state) {
+ var $checkbox = $tr.find('input:checkbox');
+ var oldData = !!this._selectedFiles[$tr.data('id')];
+ var data;
+ $checkbox.prop('checked', state);
+ $tr.toggleClass('selected', state);
+ // already selected ?
+ if (state === oldData) {
+ return;
+ }
+ data = this.elementToFile($tr);
+ if (state) {
+ this._selectedFiles[$tr.data('id')] = data;
+ this._selectionSummary.add(data);
+ }
+ else {
+ delete this._selectedFiles[$tr.data('id')];
+ this._selectionSummary.remove(data);
+ }
+ this.$el.find('#select_all').prop('checked', this._selectionSummary.getTotal() === this.files.length);
+ },
+
+ /**
* Event handler for when clicking on files to select them
*/
_onClickFile: function(event) {
+ var $tr = $(this).closest('tr');
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 $lastTr = $(FileList._lastChecked);
+ var lastIndex = $lastTr.index();
+ var currentIndex = $tr.index();
+ var $rows = FileList.$fileList.children('tr');
+
+ // last clicked checkbox below current one ?
+ if (lastIndex > currentIndex) {
+ var aux = lastIndex;
+ lastIndex = currentIndex;
+ currentIndex = aux;
}
- }
- 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');
+
+ // auto-select everything in-between
+ for (var i = lastIndex + 1; i < currentIndex; i++) {
+ FileList._selectFileEl($rows.eq(i), true);
}
}
+ else {
+ FileList._lastChecked = $tr;
+ }
+ var $checkbox = $tr.find('input:checkbox');
+ FileList._selectFileEl($tr, !$checkbox.prop('checked'));
FileList.updateSelectionSummary();
} else {
- var filename=$(this).parent().parent().attr('data-file');
- var tr = FileList.findFileEl(filename);
- var renaming=tr.data('renaming');
+ var filename = $tr.attr('data-file');
+ var renaming = $tr.data('renaming');
if (!renaming) {
- FileActions.currentFile = $(this).parent();
+ FileActions.currentFile = $tr.find('td');
var mime=FileActions.getCurrentMimeType();
var type=FileActions.getCurrentType();
var permissions = FileActions.getCurrentPermissions();
@@ -134,49 +175,36 @@ window.FileList = {
}
}
}
-
},
/**
* 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);
- }
- }
+ _onClickFileCheckbox: function() {
+ var $tr = $(this).closest('tr');
+ FileList._selectFileEl($tr, !$tr.hasClass('selected'));
+ FileList._lastChecked = $tr;
FileList.updateSelectionSummary();
},
/**
* Event handler for when selecting/deselecting all files
*/
- _onClickSelectAll: function(e) {
+ _onClickSelectAll: function() {
var checked = $(this).prop('checked');
FileList.$fileList.find('td.filename input:checkbox').prop('checked', checked)
- .parent().parent().toggleClass('selected', checked);
+ .closest('tr').toggleClass('selected', checked);
+ FileList._selectedFiles = {};
+ if (checked) {
+ for (var i = 0; i < FileList.files.length; i++) {
+ var fileData = FileList.files[i];
+ FileList._selectedFiles[fileData.id] = fileData;
+ FileList._selectionSummary.add(fileData);
+ }
+ }
+ else {
+ FileList._selectionSummary.clear();
+ }
FileList.updateSelectionSummary();
},
@@ -191,7 +219,7 @@ window.FileList = {
dir = OC.dirname(dir) || '/';
}
else {
- files = FileList.getSelectedFiles('name');
+ files = _.pluck(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));
@@ -204,7 +232,7 @@ window.FileList = {
_onClickDeleteSelected: function(event) {
var files = null;
if (!FileList.isAllSelected()) {
- files = FileList.getSelectedFiles('name');
+ files = _.pluck(FileList.getSelectedFiles(), 'name');
}
FileList.do_delete(files);
event.preventDefault();
@@ -322,8 +350,9 @@ window.FileList = {
var index = this.$fileList.children().length,
count = this.pageSize,
tr,
+ fileData,
newTrs = [],
- selected = this.isAllSelected();
+ isAllSelected = this.isAllSelected();
if (index >= this.files.length) {
return;
@@ -332,9 +361,10 @@ window.FileList = {
this.pageNumber++;
while (count > 0 && index < this.files.length) {
- tr = this._renderRow(this.files[index], {updateSummary: false});
+ fileData = this.files[index];
+ tr = this._renderRow(fileData, {updateSummary: false});
this.$fileList.append(tr);
- if (selected) {
+ if (isAllSelected || this._selectedFiles[fileData.id]) {
tr.addClass('selected');
tr.find('input:checkbox').prop('checked', true);
}
@@ -371,7 +401,7 @@ window.FileList = {
this.$fileList.empty();
// clear "Select all" checkbox
- $('#select_all').prop('checked', false);
+ this.$el.find('#select_all').prop('checked', false);
this.isEmpty = this.files.length === 0;
this._nextPage();
@@ -675,7 +705,9 @@ window.FileList = {
previousDir: currentDir
}
));
- FileList.reload();
+ this._selectedFiles = {};
+ this._selectionSummary.clear();
+ this.reload();
},
linkTo: function(dir) {
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
@@ -812,6 +844,10 @@ window.FileList = {
if (!fileEl.length) {
return null;
}
+ if (this._selectedFiles[fileEl.data('id')]) {
+ // remove from selection first
+ this._selectFileEl(fileEl, false);
+ }
if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
// file is only draggable when delete permissions are set
fileEl.find('td.filename').draggable('destroy');
@@ -1131,40 +1167,17 @@ window.FileList = {
* Update UI based on the current selection
*/
updateSelectionSummary: function() {
- var allSelected = this.isAllSelected();
- var selected;
- var summary = {
- totalFiles: 0,
- totalDirs: 0,
- totalSize: 0
- };
-
- if (allSelected) {
- summary = this.fileSummary.summary;
- }
- else {
- selected = this.getSelectedFiles();
- for (var i = 0; i < selected.length; i++ ){
- if (selected[i].type === 'dir') {
- summary.totalDirs++;
- }
- else {
- summary.totalFiles++;
- }
- summary.totalSize += parseInt(selected[i].size, 10) || 0;
- }
- }
+ var summary = this._selectionSummary.summary;
if (summary.totalFiles === 0 && summary.totalDirs === 0) {
$('#headerName span.name').text(t('files','Name'));
$('#headerSize').text(t('files','Size'));
$('#modified').text(t('files','Modified'));
$('table').removeClass('multiselect');
$('.selectedActions').addClass('hidden');
- $('#select_all').removeAttr('checked');
}
else {
$('.selectedActions').removeClass('hidden');
- $('#headerSize').text(humanFileSize(summary.totalSize));
+ $('#headerSize').text(OC.Util.humanFileSize(summary.totalSize));
var selection = '';
if (summary.totalDirs > 0) {
selection += n('files', '%n folder', '%n folders', summary.totalDirs);
@@ -1190,32 +1203,14 @@ window.FileList = {
},
/**
- * @brief get a list of selected files
- * @param {string} property (option) the property of the file requested
- * @return {array}
+ * Returns the file info of the selected files
*
- * 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
+ * @return array of file names
*/
- getSelectedFiles: function(property) {
- var elements=$('td.filename input:checkbox:checked').parent().parent();
- var files=[];
- elements.each(function(i,element) {
- // TODO: make the json format the same as in FileList.add()
- var file = FileList.elementToFile($(element));
- // FIXME: legacy attributes
- file.origin = file.id;
- file.mime = file.mimetype;
- if (property) {
- files.push(file[property]);
- } else {
- files.push(file);
- }
- });
- return files;
+ getSelectedFiles: function() {
+ return _.values(this._selectedFiles);
}
-}
+};
$(document).ready(function() {
FileList.initialize();
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 6cb0d41a611..41c762f0fa1 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -313,19 +313,15 @@ var createDragShadow = function(event) {
var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
if (!isDragSelected) {
//select dragged file
- $(event.target).parents('tr').find('td input:first').prop('checked',true);
+ FileList._selectFileEl($(event.target).parents('tr:first'), true);
}
- var selectedFiles = FileList.getSelectedFiles();
+ // do not show drag shadow for too many files
+ var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize);
if (!isDragSelected && selectedFiles.length === 1) {
//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
diff --git a/apps/files/js/filesummary.js b/apps/files/js/filesummary.js
index bbe4d43ba49..b3e3beeb24a 100644
--- a/apps/files/js/filesummary.js
+++ b/apps/files/js/filesummary.js
@@ -28,8 +28,9 @@
* @param $tr table row element
* $param summary optional initial summary value
*/
- var FileSummary = function($tr, summary) {
+ var FileSummary = function($tr) {
this.$el = $tr;
+ this.clear();
this.render();
};
@@ -75,6 +76,12 @@
}
},
/**
+ * 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
*/
@@ -99,6 +106,12 @@
this.setSummary(summary);
},
/**
+ * Clears the summary
+ */
+ clear: function() {
+ this.calculate([]);
+ },
+ /**
* Sets the current summary values
* @param summary map
*/
@@ -111,6 +124,9 @@
* Renders the file summary element
*/
update: function() {
+ if (!this.$el) {
+ return;
+ }
if (!this.summary.totalFiles && !this.summary.totalDirs) {
this.$el.addClass('hidden');
return;
@@ -144,6 +160,10 @@
}
},
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);