From 907deab278d1c89784e26aa46fb0ff471ab04546 Mon Sep 17 00:00:00 2001 From: Tomasz Grobelny Date: Sun, 13 Jan 2019 17:15:43 +0100 Subject: Add more accessible method of selecting file ranges Signed-off-by: Tomasz Grobelny --- apps/files/css/files.scss | 5 ++ apps/files/js/app.js | 3 +- apps/files/js/filelist.js | 141 ++++++++++++++++++++++++++++------- apps/files/js/filemultiselectmenu.js | 1 + 4 files changed, 124 insertions(+), 26 deletions(-) (limited to 'apps/files') diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss index 8ad255a34bf..83a7abddd13 100644 --- a/apps/files/css/files.scss +++ b/apps/files/css/files.scss @@ -427,6 +427,11 @@ table td.selection { opacity: 1; } +/* Show checkbox with half opacity when selecting range */ +#fileList tr.halfselected td.selection>.selectCheckBox + label:before { + opacity: 0.5; +} + /* Use label to have bigger clickable size for checkbox */ #fileList tr td.selection>.selectCheckBox + label, .select-all + label { diff --git a/apps/files/js/app.js b/apps/files/js/app.js index c7393b871b8..4597dc9529a 100644 --- a/apps/files/js/app.js +++ b/apps/files/js/app.js @@ -100,11 +100,12 @@ displayName: t('files', 'Download'), iconClass: 'icon-download', }, + OCA.Files.FileList.MultiSelectMenuActions.ToggleSelectionModeAction, { name: 'delete', displayName: t('files', 'Delete'), iconClass: 'icon-delete', - } + }, ], sorting: { mode: $('#defaultFileSorting').val(), diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index bcecdb697fe..9965a894ad8 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -299,7 +299,13 @@ this.fileSummary = this._createSummary(); if (options.multiSelectMenu) { - this.fileMultiSelectMenu = new OCA.Files.FileMultiSelectMenu(options.multiSelectMenu); + this.multiSelectMenuItems = options.multiSelectMenu; + for (var i=0; i.selectCheckBox', _.bind(this._onClickFileCheckbox, this)); + this.$fileList.on('mouseover', 'td.selection', _.bind(this._onMouseOverCheckbox, this)); this.$el.on('show', _.bind(this._onShow, this)); this.$el.on('urlChanged', _.bind(this._onUrlChanged, this)); this.$el.find('.select-all').click(_.bind(this._onClickSelectAll, this)); @@ -418,7 +425,23 @@ $('#app-content').off('appresized', this._onResize); }, + _selectionMode: 'single', + _getCurrentSelectionMode: function () { + return this._selectionMode; + }, + _onClickToggleSelectionMode: function () { + this._selectionMode = (this._selectionMode === 'range') ? 'single' : 'range'; + if (this._selectionMode === 'single') { + this._removeHalfSelection(); + } + }, + multiSelectMenuClick: function (ev, action) { + var actionFunction = _.find(this.multiSelectMenuItems, function (item) {return item.name === action;}).action; + if (actionFunction) { + actionFunction(ev); + return; + } switch (action) { case 'delete': this._onClickDeleteSelected(ev) @@ -685,7 +708,7 @@ * @param {Object} $tr single file row element * @param {bool} state true to select, false to deselect */ - _selectFileEl: function($tr, state, showDetailsView) { + _selectFileEl: function($tr, state) { var $checkbox = $tr.find('td.selection>.selectCheckBox'); var oldData = !!this._selectedFiles[$tr.data('id')]; var data; @@ -711,6 +734,73 @@ this.$el.find('.select-all').prop('checked', this._selectionSummary.getTotal() === this.files.length); }, + _selectRange: function($tr) { + var checked = $tr.hasClass('selected'); + var $lastTr = $(this._lastChecked); + var lastIndex = $lastTr.index(); + var currentIndex = $tr.index(); + var $rows = this.$fileList.children('tr'); + + // last clicked checkbox below current one ? + if (lastIndex > currentIndex) { + var aux = lastIndex; + lastIndex = currentIndex; + currentIndex = aux; + } + + // auto-select everything in-between + for (var i = lastIndex; i <= currentIndex; i++) { + this._selectFileEl($rows.eq(i), !checked); + } + this._removeHalfSelection(); + this._selectionMode = 'single'; + }, + + _selectSingle: function($tr) { + var state = !$tr.hasClass('selected'); + this._selectFileEl($tr, state); + }, + + _onMouseOverCheckbox: function(e) { + if (this._getCurrentSelectionMode() !== 'range') { + return; + } + var $currentTr = $(e.target).closest('tr'); + + var $lastTr = $(this._lastChecked); + var lastIndex = $lastTr.index(); + var currentIndex = $currentTr.index(); + var $rows = this.$fileList.children('tr'); + + // last clicked checkbox below current one ? + if (lastIndex > currentIndex) { + var aux = lastIndex; + lastIndex = currentIndex; + currentIndex = aux; + } + + // auto-select everything in-between + this._removeHalfSelection(); + for (var i = 0; i <= $rows.length; i++) { + var $tr = $rows.eq(i); + var $checkbox = $tr.find('td.selection>.selectCheckBox'); + if(lastIndex <= i && i <= currentIndex) { + $tr.addClass('halfselected'); + $checkbox.prop('checked', true); + } + } + }, + + _removeHalfSelection: function() { + var $rows = this.$fileList.children('tr'); + for (var i = 0; i <= $rows.length; i++) { + var $tr = $rows.eq(i); + $tr.removeClass('halfselected'); + var $checkbox = $tr.find('td.selection>.selectCheckBox'); + $checkbox.prop('checked', !!this._selectedFiles[$tr.data('id')]); + } + }, + /** * Event handler for when clicking on files to select them */ @@ -722,28 +812,11 @@ if (this._allowSelection && (event.ctrlKey || event.shiftKey)) { event.preventDefault(); if (event.shiftKey) { - var $lastTr = $(this._lastChecked); - var lastIndex = $lastTr.index(); - var currentIndex = $tr.index(); - var $rows = this.$fileList.children('tr'); - - // last clicked checkbox below current one ? - if (lastIndex > currentIndex) { - var aux = lastIndex; - lastIndex = currentIndex; - currentIndex = aux; - } - - // auto-select everything in-between - for (var i = lastIndex + 1; i < currentIndex; i++) { - this._selectFileEl($rows.eq(i), true); - } - } - else { - this._lastChecked = $tr; + this._selectRange($tr); + } else { + this._selectSingle($tr); } - var $checkbox = $tr.find('td.selection>.selectCheckBox'); - this._selectFileEl($tr, !$checkbox.prop('checked')); + this._lastChecked = $tr; this.updateSelectionSummary(); } else { // clicked directly on the name @@ -802,8 +875,11 @@ */ _onClickFileCheckbox: function(e) { var $tr = $(e.target).closest('tr'); - var state = !$tr.hasClass('selected'); - this._selectFileEl($tr, state); + if(this._getCurrentSelectionMode() === 'range') { + this._selectRange($tr); + } else { + this._selectSingle($tr); + } this._lastChecked = $tr; this.updateSelectionSummary(); if (this._detailsView && !this._detailsView.$el.hasClass('disappear')) { @@ -3536,6 +3612,21 @@ } }; + FileList.MultiSelectMenuActions = { + ToggleSelectionModeAction: function(fileList) { + return { + name: 'toggleSelectionMode', + displayName: function(context) { + return t('files', 'Select file range'); + }, + iconClass: 'icon-fullscreen', + action: function() { + fileList._onClickToggleSelectionMode(); + }, + }; + }, + }, + /** * Sort comparators. * @namespace OCA.Files.FileList.Comparators diff --git a/apps/files/js/filemultiselectmenu.js b/apps/files/js/filemultiselectmenu.js index d50fe28eace..c0ee1d163c7 100644 --- a/apps/files/js/filemultiselectmenu.js +++ b/apps/files/js/filemultiselectmenu.js @@ -36,6 +36,7 @@ */ show: function(context) { this._context = context; + this.render(); this.$el.removeClass('hidden'); if (window.innerWidth < 480) { this.$el.removeClass('menu-center').addClass('menu-right'); -- cgit v1.2.3