Merge pull request #37669 from nextcloud/feat/files-right-click

pull/37680/head
John Molakvoæ 2023-04-11 15:47:41 +07:00 committed by GitHub
commit 920174222c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 10 deletions

@ -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,
},

@ -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: {

@ -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),
})

@ -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
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long