aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/components/FileEntry.vue
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@protonmail.com>2023-04-18 09:43:29 +0200
committerJohn Molakvoæ <skjnldsv@protonmail.com>2023-04-20 09:06:57 +0200
commitbb4d7969b93c806e4f578ecc5a6d04bb6bebee73 (patch)
treee6247c554d7e136042e0913f370f37ff1467ac37 /apps/files/src/components/FileEntry.vue
parentc85c04e4a8495eb04419a27a8e162c03acad6282 (diff)
downloadnextcloud-server-bb4d7969b93c806e4f578ecc5a6d04bb6bebee73.tar.gz
nextcloud-server-bb4d7969b93c806e4f578ecc5a6d04bb6bebee73.zip
feat(files): add default action support
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/files/src/components/FileEntry.vue')
-rw-r--r--apps/files/src/components/FileEntry.vue93
1 files changed, 67 insertions, 26 deletions
diff --git a/apps/files/src/components/FileEntry.vue b/apps/files/src/components/FileEntry.vue
index 7db22482220..00ff8a3d533 100644
--- a/apps/files/src/components/FileEntry.vue
+++ b/apps/files/src/components/FileEntry.vue
@@ -33,7 +33,7 @@
<!-- Link to file -->
<td class="files-list__row-name">
- <a ref="name" v-bind="linkTo">
+ <a ref="name" v-bind="linkTo" @click="execDefaultAction">
<!-- Icon or preview -->
<span class="files-list__row-icon">
<FolderIcon v-if="source.type === 'folder'" />
@@ -49,6 +49,13 @@
:style="{ backgroundImage: mimeIconUrl }" />
<FileIcon v-else />
+
+ <!-- Favorite icon -->
+ <span v-if="isFavorite"
+ class="files-list__row-icon-favorite"
+ :aria-label="t('files', 'Favorite')">
+ <StarIcon aria-hidden="true" :size="20" />
+ </span>
</span>
<!-- File name -->
@@ -64,6 +71,8 @@
<!-- Menu actions -->
<NcActions v-if="active"
ref="actionsMenu"
+ :boundaries-element="boundariesElement"
+ :container="boundariesElement"
:disabled="source._loading"
:force-title="true"
:inline="enabledInlineActions.length"
@@ -84,7 +93,8 @@
<!-- Size -->
<td v-if="isSizeAvailable"
:style="{ opacity: sizeOpacity }"
- class="files-list__row-size">
+ class="files-list__row-size"
+ @click="execDefaultAction">
<span>{{ size }}</span>
</td>
@@ -92,7 +102,8 @@
<td v-for="column in columns"
:key="column.id"
:class="`files-list__row-${currentView?.id}-${column.id}`"
- class="files-list__row-column-custom">
+ class="files-list__row-column-custom"
+ @click="execDefaultAction">
<CustomElementRender v-if="active"
:current-view="currentView"
:render="column.render"
@@ -115,9 +126,11 @@ 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 NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
+import StarIcon from 'vue-material-design-icons/Star.vue'
import Vue from 'vue'
import { getFileActions } from '../services/FileAction.ts'
+import { hashCode } from '../utils/hashUtils.ts'
import { isCachedPreview } from '../services/PreviewService.ts'
import { useActionsMenuStore } from '../store/actionsmenu.ts'
import { useFilesStore } from '../store/files.ts'
@@ -144,6 +157,7 @@ export default Vue.extend({
NcActions,
NcCheckboxRadioSwitch,
NcLoadingIcon,
+ StarIcon,
},
props: {
@@ -192,6 +206,7 @@ export default Vue.extend({
return {
backgroundFailed: false,
backgroundImage: '',
+ boundariesElement: document.querySelector('.app-content > .files-list'),
loading: '',
}
},
@@ -204,7 +219,6 @@ export default Vue.extend({
currentView() {
return this.$navigation.active
},
-
columns() {
// Hide columns if the list is too small
if (this.filesListWidth < 512) {
@@ -217,7 +231,6 @@ export default Vue.extend({
// Remove any trailing slash but leave root slash
return (this.$route?.query?.dir || '/').replace(/^(.+)\/$/, '$1')
},
-
fileid() {
return this.source?.fileid?.toString?.()
},
@@ -225,6 +238,7 @@ export default Vue.extend({
return this.source.attributes.displayName
|| this.source.basename
},
+
size() {
const size = parseInt(this.source.size, 10) || 0
if (typeof size !== 'number' || size < 0) {
@@ -232,7 +246,6 @@ export default Vue.extend({
}
return formatFileSize(size, true)
},
-
sizeOpacity() {
const size = parseInt(this.source.size, 10) || 0
if (!size || size < 0) {
@@ -247,6 +260,15 @@ export default Vue.extend({
},
linkTo() {
+ if (this.enabledDefaultActions.length > 0) {
+ const action = this.enabledDefaultActions[0]
+ const displayName = action.displayName([this.source], this.currentView)
+ return {
+ title: displayName,
+ role: 'button',
+ }
+ }
+
if (this.source.type === 'folder') {
const to = { ...this.$route, query: { dir: join(this.dir, this.source.basename) } }
return {
@@ -272,7 +294,6 @@ export default Vue.extend({
cropPreviews() {
return this.userConfig.crop_image_previews
},
-
previewUrl() {
try {
const url = new URL(window.location.origin + this.source.attributes.previewUrl)
@@ -280,13 +301,12 @@ export default Vue.extend({
url.searchParams.set('x', '32')
url.searchParams.set('y', '32')
// Handle cropping
- url.searchParams.set('a', this.cropPreviews === true ? '1' : '0')
+ url.searchParams.set('a', this.cropPreviews === true ? '0' : '1')
return url.href
} catch (e) {
return null
}
},
-
mimeIconUrl() {
const mimeType = this.source.mime || 'application/octet-stream'
const mimeIconUrl = window.OC?.MimeType?.getIconUrl?.(mimeType)
@@ -301,29 +321,38 @@ export default Vue.extend({
.filter(action => !action.enabled || action.enabled([this.source], this.currentView))
.sort((a, b) => (a.order || 0) - (b.order || 0))
},
-
enabledInlineActions() {
if (this.filesListWidth < 768) {
return []
}
return this.enabledActions.filter(action => action?.inline?.(this.source, this.currentView))
},
-
enabledMenuActions() {
if (this.filesListWidth < 768) {
+ // If we have a default action, do not render the first one
+ if (this.enabledDefaultActions.length > 0) {
+ return this.enabledActions.slice(1)
+ }
return this.enabledActions
}
- return [
+ const actions = [
...this.enabledInlineActions,
...this.enabledActions.filter(action => !action.inline),
]
- },
- uniqueId() {
- return this.hashCode(this.source.source)
- },
+ // If we have a default action, do not render the first one
+ if (this.enabledDefaultActions.length > 0) {
+ return actions.slice(1)
+ }
+ return actions
+ },
+ enabledDefaultActions() {
+ return [
+ ...this.enabledActions.filter(action => action.default),
+ ]
+ },
openedMenu: {
get() {
return this.actionsMenuStore.opened === this.uniqueId
@@ -332,6 +361,14 @@ export default Vue.extend({
this.actionsMenuStore.opened = opened ? this.uniqueId : null
},
},
+
+ uniqueId() {
+ return hashCode(this.source.source)
+ },
+
+ isFavorite() {
+ return this.source.attributes.favorite === 1
+ },
},
watch: {
@@ -457,16 +494,6 @@ export default Vue.extend({
}
},
- hashCode(str) {
- let hash = 0
- for (let i = 0, len = str.length; i < len; i++) {
- const chr = str.charCodeAt(i)
- hash = (hash << 5) - hash + chr
- hash |= 0 // Convert to 32bit integer
- }
- return hash
- },
-
async onActionClick(action) {
const displayName = action.displayName([this.source], this.currentView)
try {
@@ -475,6 +502,12 @@ export default Vue.extend({
Vue.set(this.source, '_loading', true)
const success = await action.exec(this.source, this.currentView)
+
+ // If the action returns null, we stay silent
+ if (success === null) {
+ return
+ }
+
if (success) {
showSuccess(this.t('files', '"{displayName}" action executed successfully', { displayName }))
return
@@ -489,6 +522,14 @@ export default Vue.extend({
Vue.set(this.source, '_loading', false)
}
},
+ execDefaultAction(event) {
+ if (this.enabledDefaultActions.length > 0) {
+ event.preventDefault()
+ event.stopPropagation()
+ // Execute the first default action if any
+ this.enabledDefaultActions[0].exec(this.source, this.currentView)
+ }
+ },
onSelectionChange(selection) {
const newSelectedIndex = this.index