diff options
author | John Molakvoæ <skjnldsv@protonmail.com> | 2023-04-11 09:31:30 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@protonmail.com> | 2023-04-11 14:38:53 +0200 |
commit | b7df4196e2883da9028f8c5d646fbbf5ae10cf49 (patch) | |
tree | bf25c4448b898ca83e0671a3d4888573b5550e47 /apps/files/src | |
parent | a05176a1f592d06b24725cd158baaf85e4456c6d (diff) | |
download | nextcloud-server-b7df4196e2883da9028f8c5d646fbbf5ae10cf49.tar.gz nextcloud-server-b7df4196e2883da9028f8c5d646fbbf5ae10cf49.zip |
feat(files): right click
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files/src')
-rw-r--r-- | apps/files/src/components/FileEntry.vue | 47 | ||||
-rw-r--r-- | apps/files/src/components/FilesListHeaderActions.vue | 15 | ||||
-rw-r--r-- | apps/files/src/store/actionsmenu.ts | 31 | ||||
-rw-r--r-- | apps/files/src/types.ts | 7 |
4 files changed, 93 insertions, 7 deletions
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue index eb6ad9f7e18..337e4c7b6ac 100644 --- a/apps/files/src/components/FileEntry.vue +++ b/apps/files/src/components/FileEntry.vue @@ -66,7 +66,8 @@ ref="actionsMenu" :disabled="source._loading" :force-title="true" - :inline="enabledInlineActions.length"> + :inline="enabledInlineActions.length" + :open.sync="openedMenu"> <NcActionButton v-for="action in enabledMenuActions" :key="action.id" :class="'files-list__row-action-' + action.id" @@ -116,12 +117,13 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadi import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import Vue from 'vue' -import { isCachedPreview } from '../services/PreviewService.ts' import { getFileActions } from '../services/FileAction.ts' +import { isCachedPreview } from '../services/PreviewService.ts' +import { useActionsMenuStore } from '../store/actionsmenu.ts' import { useFilesStore } from '../store/files.ts' +import { useKeyboardStore } from '../store/keyboard.ts' import { useSelectionStore } from '../store/selection.ts' import { useUserConfigStore } from '../store/userconfig.ts' -import { useKeyboardStore } from '../store/keyboard.ts' import CustomElementRender from './CustomElementRender.vue' import CustomSvgIconRender from './CustomSvgIconRender.vue' import logger from '../logger.js' @@ -168,15 +170,17 @@ export default Vue.extend({ }, setup() { + const actionsMenuStore = useActionsMenuStore() const filesStore = useFilesStore() + const keyboardStore = useKeyboardStore() const selectionStore = useSelectionStore() const userConfigStore = useUserConfigStore() - const keyboardStore = useKeyboardStore() return { + actionsMenuStore, filesStore, + keyboardStore, selectionStore, userConfigStore, - keyboardStore, } }, @@ -253,6 +257,9 @@ export default Vue.extend({ selectedFiles() { return this.selectionStore.selected }, + isSelected() { + return this.selectedFiles.includes(this.source?.fileid?.toString?.()) + }, cropPreviews() { return this.userConfig.crop_image_previews @@ -301,6 +308,15 @@ export default Vue.extend({ uniqueId() { return this.hashCode(this.source.source) }, + + openedMenu: { + get() { + return this.actionsMenuStore.opened === this + }, + set(opened) { + this.actionsMenuStore.opened = opened ? this : null + }, + }, }, watch: { @@ -342,6 +358,9 @@ export default Vue.extend({ // Fetch the preview on init this.debounceIfNotCached() + + // Right click watcher on tr + this.$el.parentNode?.addEventListener?.('contextmenu', this.onRightClick) }, beforeDestroy() { @@ -410,7 +429,7 @@ export default Vue.extend({ this.clearImg() // Close menu - this.$refs?.actionsMenu?.closeMenu?.() + this.openedMenu = false }, clearImg() { @@ -487,6 +506,22 @@ export default Vue.extend({ this.selectionStore.setLastIndex(newSelectedIndex) }, + // Open the actions menu on right click + onRightClick(event) { + // If already opened, fallback to default browser + if (this.openedMenu) { + return + } + + // If the clicked row is in the selection, open global menu + const isMoreThanOneSelected = this.selectedFiles.length > 1 + this.actionsMenuStore.opened = this.isSelected && isMoreThanOneSelected ? 'global' : this + + // Prevent any browser defaults + event.preventDefault() + event.stopPropagation() + }, + t: translate, formatFileSize, }, diff --git a/apps/files/src/components/FilesListHeaderActions.vue b/apps/files/src/components/FilesListHeaderActions.vue index d60fd81ad00..f136e281f09 100644 --- a/apps/files/src/components/FilesListHeaderActions.vue +++ b/apps/files/src/components/FilesListHeaderActions.vue @@ -24,7 +24,8 @@ <NcActions ref="actionsMenu" :disabled="!!loading || areSomeNodesLoading" :force-title="true" - :inline="3"> + :inline="3" + :open.sync="openedMenu"> <NcActionButton v-for="action in enabledActions" :key="action.id" :class="'files-list__row-actions-batch-' + action.id" @@ -48,6 +49,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import Vue from 'vue' import { getFileActions } from '../services/FileAction.ts' +import { useActionsMenuStore } from '../store/actionsmenu.ts' import { useFilesStore } from '../store/files.ts' import { useSelectionStore } from '../store/selection.ts' import CustomSvgIconRender from './CustomSvgIconRender.vue' @@ -78,9 +80,11 @@ export default Vue.extend({ }, setup() { + const actionsMenuStore = useActionsMenuStore() const filesStore = useFilesStore() const selectionStore = useSelectionStore() return { + actionsMenuStore, filesStore, selectionStore, } @@ -109,6 +113,15 @@ export default Vue.extend({ areSomeNodesLoading() { return this.nodes.some(node => node._loading) }, + + openedMenu: { + get() { + return this.actionsMenuStore.opened === 'global' + }, + set(opened) { + this.actionsMenuStore.opened = opened ? 'global' : null + }, + }, }, methods: { diff --git a/apps/files/src/store/actionsmenu.ts b/apps/files/src/store/actionsmenu.ts new file mode 100644 index 00000000000..b68f4998470 --- /dev/null +++ b/apps/files/src/store/actionsmenu.ts @@ -0,0 +1,31 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license AGPL-3.0-or-later + * + * 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/>. + * + */ +/* eslint-disable */ +import { defineStore } from 'pinia' +import Vue from 'vue' +import type { ActionsMenuStore } from '../types' + +export const useActionsMenuStore = defineStore('actionsmenu', { + state: () => ({ + opened: null, + } as ActionsMenuStore), +}) diff --git a/apps/files/src/types.ts b/apps/files/src/types.ts index 9bbb572faaf..4c3d57d3e62 100644 --- a/apps/files/src/types.ts +++ b/apps/files/src/types.ts @@ -22,6 +22,7 @@ /* eslint-disable */ import type { Folder } from '@nextcloud/files' import type { Node } from '@nextcloud/files' +import type { ComponentInstance } from 'vue' // Global definitions export type Service = string @@ -86,3 +87,9 @@ export interface SelectionStore { lastSelection: FileId[] lastSelectedIndex: number | null } + +// Actions menu store +export type GlobalActions = 'global' +export interface ActionsMenuStore { + opened: ComponentInstance|GlobalActions|null +} |