|
|
|
@ -20,91 +20,79 @@
|
|
|
|
|
-
|
|
|
|
|
-->
|
|
|
|
|
<template>
|
|
|
|
|
<Fragment>
|
|
|
|
|
<!-- Drag and drop notice -->
|
|
|
|
|
<DragAndDropNotice v-if="canUpload && filesListWidth >= 512"
|
|
|
|
|
:current-folder="currentFolder"
|
|
|
|
|
:dragover.sync="dragover"
|
|
|
|
|
:style="{ height: dndNoticeHeight }" />
|
|
|
|
|
|
|
|
|
|
<VirtualList ref="table"
|
|
|
|
|
:data-component="userConfig.grid_view ? FileEntryGrid : FileEntry"
|
|
|
|
|
:data-key="'source'"
|
|
|
|
|
:data-sources="nodes"
|
|
|
|
|
:grid-mode="userConfig.grid_view"
|
|
|
|
|
:extra-props="{
|
|
|
|
|
isMtimeAvailable,
|
|
|
|
|
isSizeAvailable,
|
|
|
|
|
nodes,
|
|
|
|
|
filesListWidth,
|
|
|
|
|
}"
|
|
|
|
|
:scroll-to-index="scrollToIndex"
|
|
|
|
|
:caption="caption"
|
|
|
|
|
@scroll="onScroll">
|
|
|
|
|
<template #before>
|
|
|
|
|
<!-- Headers -->
|
|
|
|
|
<FilesListHeader v-for="header in sortedHeaders"
|
|
|
|
|
:key="header.id"
|
|
|
|
|
:current-folder="currentFolder"
|
|
|
|
|
:current-view="currentView"
|
|
|
|
|
:header="header" />
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Thead-->
|
|
|
|
|
<template #header>
|
|
|
|
|
<!-- Table header and sort buttons -->
|
|
|
|
|
<FilesListTableHeader ref="thead"
|
|
|
|
|
:files-list-width="filesListWidth"
|
|
|
|
|
:is-mtime-available="isMtimeAvailable"
|
|
|
|
|
:is-size-available="isSizeAvailable"
|
|
|
|
|
:nodes="nodes" />
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Tfoot-->
|
|
|
|
|
<template #footer>
|
|
|
|
|
<FilesListTableFooter :files-list-width="filesListWidth"
|
|
|
|
|
:is-mtime-available="isMtimeAvailable"
|
|
|
|
|
:is-size-available="isSizeAvailable"
|
|
|
|
|
:nodes="nodes"
|
|
|
|
|
:summary="summary" />
|
|
|
|
|
</template>
|
|
|
|
|
</VirtualList>
|
|
|
|
|
</Fragment>
|
|
|
|
|
<VirtualList ref="table"
|
|
|
|
|
:data-component="userConfig.grid_view ? FileEntryGrid : FileEntry"
|
|
|
|
|
:data-key="'source'"
|
|
|
|
|
:data-sources="nodes"
|
|
|
|
|
:grid-mode="userConfig.grid_view"
|
|
|
|
|
:extra-props="{
|
|
|
|
|
isMtimeAvailable,
|
|
|
|
|
isSizeAvailable,
|
|
|
|
|
nodes,
|
|
|
|
|
filesListWidth,
|
|
|
|
|
}"
|
|
|
|
|
:scroll-to-index="scrollToIndex"
|
|
|
|
|
:caption="caption">
|
|
|
|
|
<template #before>
|
|
|
|
|
<!-- Headers -->
|
|
|
|
|
<FilesListHeader v-for="header in sortedHeaders"
|
|
|
|
|
:key="header.id"
|
|
|
|
|
:current-folder="currentFolder"
|
|
|
|
|
:current-view="currentView"
|
|
|
|
|
:header="header" />
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Thead-->
|
|
|
|
|
<template #header>
|
|
|
|
|
<!-- Table header and sort buttons -->
|
|
|
|
|
<FilesListTableHeader ref="thead"
|
|
|
|
|
:files-list-width="filesListWidth"
|
|
|
|
|
:is-mtime-available="isMtimeAvailable"
|
|
|
|
|
:is-size-available="isSizeAvailable"
|
|
|
|
|
:nodes="nodes" />
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- Tfoot-->
|
|
|
|
|
<template #footer>
|
|
|
|
|
<FilesListTableFooter :files-list-width="filesListWidth"
|
|
|
|
|
:is-mtime-available="isMtimeAvailable"
|
|
|
|
|
:is-size-available="isSizeAvailable"
|
|
|
|
|
:nodes="nodes"
|
|
|
|
|
:summary="summary" />
|
|
|
|
|
</template>
|
|
|
|
|
</VirtualList>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
import type { Node as NcNode } from '@nextcloud/files'
|
|
|
|
|
import type { PropType } from 'vue'
|
|
|
|
|
import type { UserConfig } from '../types.ts'
|
|
|
|
|
import type { UserConfig } from '../types'
|
|
|
|
|
|
|
|
|
|
import { Fragment } from 'vue-frag'
|
|
|
|
|
import { getFileListHeaders, Folder, View, Permission, getFileActions } from '@nextcloud/files'
|
|
|
|
|
import { getFileListHeaders, Folder, View, getFileActions } from '@nextcloud/files'
|
|
|
|
|
import { showError } from '@nextcloud/dialogs'
|
|
|
|
|
import { loadState } from '@nextcloud/initial-state'
|
|
|
|
|
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
|
|
|
|
|
import Vue from 'vue'
|
|
|
|
|
import { defineComponent } from 'vue'
|
|
|
|
|
|
|
|
|
|
import { action as sidebarAction } from '../actions/sidebarAction.ts'
|
|
|
|
|
import { useUserConfigStore } from '../store/userconfig.ts'
|
|
|
|
|
import DragAndDropNotice from './DragAndDropNotice.vue'
|
|
|
|
|
|
|
|
|
|
import FileEntry from './FileEntry.vue'
|
|
|
|
|
import FileEntryGrid from './FileEntryGrid.vue'
|
|
|
|
|
import FilesListHeader from './FilesListHeader.vue'
|
|
|
|
|
import FilesListTableFooter from './FilesListTableFooter.vue'
|
|
|
|
|
import FilesListTableHeader from './FilesListTableHeader.vue'
|
|
|
|
|
import filesListWidthMixin from '../mixins/filesListWidth.ts'
|
|
|
|
|
import logger from '../logger.js'
|
|
|
|
|
import VirtualList from './VirtualList.vue'
|
|
|
|
|
import logger from '../logger.js'
|
|
|
|
|
|
|
|
|
|
export default Vue.extend({
|
|
|
|
|
export default defineComponent({
|
|
|
|
|
name: 'FilesListVirtual',
|
|
|
|
|
|
|
|
|
|
components: {
|
|
|
|
|
DragAndDropNotice,
|
|
|
|
|
FilesListHeader,
|
|
|
|
|
FilesListTableFooter,
|
|
|
|
|
FilesListTableHeader,
|
|
|
|
|
Fragment,
|
|
|
|
|
VirtualList,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
@ -140,7 +128,6 @@ export default Vue.extend({
|
|
|
|
|
FileEntryGrid,
|
|
|
|
|
headers: getFileListHeaders(),
|
|
|
|
|
scrollToIndex: 0,
|
|
|
|
|
dragover: false,
|
|
|
|
|
dndNoticeHeight: 0,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -192,10 +179,6 @@ export default Vue.extend({
|
|
|
|
|
return [...this.headers].sort((a, b) => a.order - b.order)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
canUpload() {
|
|
|
|
|
return this.currentFolder && (this.currentFolder.permissions & Permission.CREATE) !== 0
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
caption() {
|
|
|
|
|
const defaultCaption = t('files', 'List of files and folders.')
|
|
|
|
|
const viewCaption = this.currentView.caption || defaultCaption
|
|
|
|
@ -214,12 +197,15 @@ export default Vue.extend({
|
|
|
|
|
// Add events on parent to cover both the table and DragAndDrop notice
|
|
|
|
|
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
|
|
|
|
|
mainContent.addEventListener('dragover', this.onDragOver)
|
|
|
|
|
mainContent.addEventListener('dragleave', this.onDragLeave)
|
|
|
|
|
|
|
|
|
|
this.scrollToFile(this.fileId)
|
|
|
|
|
this.openSidebarForFile(this.fileId)
|
|
|
|
|
this.handleOpenFile()
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
|
|
|
|
|
mainContent.removeEventListener('dragover', this.onDragOver)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
@ -273,9 +259,7 @@ export default Vue.extend({
|
|
|
|
|
// Detect if we're only dragging existing files or not
|
|
|
|
|
const isForeignFile = event.dataTransfer?.types.includes('Files')
|
|
|
|
|
if (isForeignFile) {
|
|
|
|
|
this.dragover = true
|
|
|
|
|
} else {
|
|
|
|
|
this.dragover = false
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.preventDefault()
|
|
|
|
@ -295,21 +279,6 @@ export default Vue.extend({
|
|
|
|
|
this.$refs.table.$el.scrollTop = this.$refs.table.$el.scrollTop + 25
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onDragLeave(event: DragEvent) {
|
|
|
|
|
// Counter bubbling, make sure we're ending the drag
|
|
|
|
|
// only when we're leaving the current element
|
|
|
|
|
const currentTarget = event.currentTarget as HTMLElement
|
|
|
|
|
if (currentTarget?.contains(event.relatedTarget as HTMLElement)) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.dragover = false
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onScroll() {
|
|
|
|
|
// Update the sticky position of the thead to adapt to the scroll
|
|
|
|
|
this.dndNoticeHeight = (this.$refs.thead.$el?.getBoundingClientRect?.()?.top ?? 0) + 'px'
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
t,
|
|
|
|
|
},
|
|
|
|
|