diff options
author | John Molakvoæ <skjnldsv@protonmail.com> | 2023-10-12 10:05:02 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@protonmail.com> | 2023-10-17 11:19:01 +0200 |
commit | 0f1f73478a59f59d92c4542aa42dc61973c600de (patch) | |
tree | e7ece617499984de35973536b4470f8e17bd8018 | |
parent | 60260bb58e22a9309c126d54441e0ac28d2b140f (diff) | |
download | nextcloud-server-0f1f73478a59f59d92c4542aa42dc61973c600de.tar.gz nextcloud-server-0f1f73478a59f59d92c4542aa42dc61973c600de.zip |
fix(files): split FileEntry Checkbox and fix range selection
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
-rw-r--r-- | apps/files/src/components/FileEntry.vue | 59 | ||||
-rw-r--r-- | apps/files/src/components/FileEntry/FileEntryCheckbox.vue | 130 |
2 files changed, 137 insertions, 52 deletions
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue index 1a1bf6d9baf..87c36356210 100644 --- a/apps/files/src/components/FileEntry.vue +++ b/apps/files/src/components/FileEntry.vue @@ -37,13 +37,11 @@ <span v-if="source.attributes.failed" class="files-list__row--failed" /> <!-- Checkbox --> - <td class="files-list__row-checkbox"> - <NcLoadingIcon v-if="isLoading" /> - <NcCheckboxRadioSwitch v-else-if="visible" - :aria-label="t('files', 'Select the row for {displayName}', { displayName })" - :checked="isSelected" - @update:checked="onSelectionChange" /> - </td> + <FileEntryCheckbox v-if="visible" + :display-name="displayName" + :fileid="fileid" + :loading="isLoading" + :nodes="nodes"/> <!-- Link to file --> <td class="files-list__row-name" data-cy-files-list-row-name> @@ -177,7 +175,6 @@ import Vue from 'vue' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' -import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js' import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' @@ -190,10 +187,10 @@ import { hashCode } from '../utils/hashUtils.ts' import { useActionsMenuStore } from '../store/actionsmenu.ts' import { useDragAndDropStore } from '../store/dragging.ts' import { useFilesStore } from '../store/files.ts' -import { useKeyboardStore } from '../store/keyboard.ts' import { useRenamingStore } from '../store/renaming.ts' import { useSelectionStore } from '../store/selection.ts' import CustomElementRender from './CustomElementRender.vue' +import FileEntryCheckbox from './FileEntry/FileEntryCheckbox.vue' import FileEntryPreview from './FileEntry/FileEntryPreview.vue' import logger from '../logger.js' @@ -212,10 +209,10 @@ export default Vue.extend({ FileEntryPreview, NcActionButton, NcActions, - NcCheckboxRadioSwitch, NcIconSvgWrapper, NcLoadingIcon, NcTextField, + FileEntryCheckbox, }, props: { @@ -235,10 +232,6 @@ export default Vue.extend({ type: [Folder, NcFile, Node] as PropType<Node>, required: true, }, - index: { - type: Number, - required: true, - }, nodes: { type: Array as PropType<Node[]>, required: true, @@ -253,14 +246,12 @@ export default Vue.extend({ const actionsMenuStore = useActionsMenuStore() const draggingStore = useDragAndDropStore() const filesStore = useFilesStore() - const keyboardStore = useKeyboardStore() const renamingStore = useRenamingStore() const selectionStore = useSelectionStore() return { actionsMenuStore, draggingStore, filesStore, - keyboardStore, renamingStore, selectionStore, } @@ -276,7 +267,6 @@ export default Vue.extend({ }, computed: { - currentView() { return this.$navigation.active }, @@ -600,41 +590,6 @@ export default Vue.extend({ } }, - onSelectionChange(selected: boolean) { - const newSelectedIndex = this.index - const lastSelectedIndex = this.selectionStore.lastSelectedIndex - - // Get the last selected and select all files in between - if (this.keyboardStore?.shiftKey && lastSelectedIndex !== null) { - const isAlreadySelected = this.selectedFiles.includes(this.fileid) - - const start = Math.min(newSelectedIndex, lastSelectedIndex) - const end = Math.max(lastSelectedIndex, newSelectedIndex) - - const lastSelection = this.selectionStore.lastSelection - const filesToSelect = this.nodes - .map(file => file.fileid?.toString?.()) - .slice(start, end + 1) - - // If already selected, update the new selection _without_ the current file - const selection = [...lastSelection, ...filesToSelect] - .filter(fileid => !isAlreadySelected || fileid !== this.fileid) - - logger.debug('Shift key pressed, selecting all files in between', { start, end, filesToSelect, isAlreadySelected }) - // Keep previous lastSelectedIndex to be use for further shift selections - this.selectionStore.set(selection) - return - } - - const selection = selected - ? [...this.selectedFiles, this.fileid] - : this.selectedFiles.filter(fileid => fileid !== this.fileid) - - logger.debug('Updating selection', { selection }) - this.selectionStore.set(selection) - this.selectionStore.setLastIndex(newSelectedIndex) - }, - // Open the actions menu on right click onRightClick(event) { // If already opened, fallback to default browser diff --git a/apps/files/src/components/FileEntry/FileEntryCheckbox.vue b/apps/files/src/components/FileEntry/FileEntryCheckbox.vue new file mode 100644 index 00000000000..376d14d4073 --- /dev/null +++ b/apps/files/src/components/FileEntry/FileEntryCheckbox.vue @@ -0,0 +1,130 @@ +<!-- + - @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + - + - @author John Molakvoæ <skjnldsv@protonmail.com> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program 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 program. If not, see <http://www.gnu.org/licenses/>. + - + --> +<template> + <td class="files-list__row-checkbox"> + <NcLoadingIcon v-if="loading" /> + <NcCheckboxRadioSwitch :aria-label="t('files', 'Select the row for {displayName}', { displayName })" + :checked="isSelected" + @update:checked="onSelectionChange" /> + </td> +</template> + +<script lang="ts"> +import { Node } from '@nextcloud/files' +import { translate as t } from '@nextcloud/l10n' +import Vue, { PropType } from 'vue' + +import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' +import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' + +import { useKeyboardStore } from '../../store/keyboard.ts' +import { useSelectionStore } from '../../store/selection.ts' +import logger from '../../logger.js' + +export default Vue.extend({ + name: 'FileEntryCheckbox', + + components: { + NcCheckboxRadioSwitch, + NcLoadingIcon, + }, + + props: { + displayName: { + type: String, + required: true, + }, + fileid: { + type: String, + required: true, + }, + loading: { + type: Boolean, + default: false, + }, + nodes: { + type: Array as PropType<Node[]>, + required: true, + }, + }, + + setup() { + const selectionStore = useSelectionStore() + const keyboardStore = useKeyboardStore() + return { + keyboardStore, + selectionStore, + } + }, + + computed: { + selectedFiles() { + return this.selectionStore.selected + }, + isSelected() { + return this.selectedFiles.includes(this.fileid) + }, + index() { + return this.nodes.findIndex((node: Node) => node.fileid === parseInt(this.fileid)) + }, + }, + + methods: { + onSelectionChange(selected: boolean) { + const newSelectedIndex = this.index + const lastSelectedIndex = this.selectionStore.lastSelectedIndex + + // Get the last selected and select all files in between + if (this.keyboardStore?.shiftKey && lastSelectedIndex !== null) { + const isAlreadySelected = this.selectedFiles.includes(this.fileid) + + const start = Math.min(newSelectedIndex, lastSelectedIndex) + const end = Math.max(lastSelectedIndex, newSelectedIndex) + + const lastSelection = this.selectionStore.lastSelection + const filesToSelect = this.nodes + .map(file => file.fileid?.toString?.()) + .slice(start, end + 1) + + // If already selected, update the new selection _without_ the current file + const selection = [...lastSelection, ...filesToSelect] + .filter(fileid => !isAlreadySelected || fileid !== this.fileid) + + logger.debug('Shift key pressed, selecting all files in between', { start, end, filesToSelect, isAlreadySelected }) + // Keep previous lastSelectedIndex to be use for further shift selections + this.selectionStore.set(selection) + return + } + + const selection = selected + ? [...this.selectedFiles, this.fileid] + : this.selectedFiles.filter(fileid => fileid !== this.fileid) + + logger.debug('Updating selection', { selection }) + this.selectionStore.set(selection) + this.selectionStore.setLastIndex(newSelectedIndex) + }, + + t, + }, +}) +</script> |