]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(files): split FileEntry Checkbox and fix range selection
authorJohn Molakvoæ <skjnldsv@protonmail.com>
Thu, 12 Oct 2023 08:05:02 +0000 (10:05 +0200)
committerJohn Molakvoæ <skjnldsv@protonmail.com>
Tue, 17 Oct 2023 09:19:01 +0000 (11:19 +0200)
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
apps/files/src/components/FileEntry.vue
apps/files/src/components/FileEntry/FileEntryCheckbox.vue [new file with mode: 0644]

index 1a1bf6d9bafc7444480c2fc25de8ae4275d4a521..87c3635621077b2c6a5a98e1d3d608fa49b1b812 100644 (file)
                <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 (file)
index 0000000..376d14d
--- /dev/null
@@ -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>