diff --git a/src/components/Editor.provider.ts b/src/components/Editor.provider.ts index 9e866078fa1..0987c16f4ad 100644 --- a/src/components/Editor.provider.ts +++ b/src/components/Editor.provider.ts @@ -6,7 +6,6 @@ import { openLink } from '../helpers/links.js' import { logger } from '../helpers/logger.js' -export const FILE = Symbol('editor:file') export const ATTACHMENT_RESOLVER = Symbol('attachment:resolver') export const IS_MOBILE = Symbol('editor:is-mobile') export const EDITOR_UPLOAD = Symbol('editor:upload') @@ -20,19 +19,6 @@ export const useIsMobileMixin = { }, } -export const useFileMixin = { - inject: { - $file: { - from: FILE, - default: () => ({ - fileId: 0, - relativePath: null, - document: null, - }), - }, - }, -} - export const useAttachmentResolver = { inject: { $attachmentResolver: { diff --git a/src/components/Editor.vue b/src/components/Editor.vue index 7a44fcaedd2..4ad3fd03d98 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -91,7 +91,7 @@ import Autofocus from '../extensions/Autofocus.js' import { provideEditor } from '../composables/useEditor.ts' import { provideEditorFlags } from '../composables/useEditorFlags.ts' -import { ATTACHMENT_RESOLVER, FILE, IS_MOBILE } from './Editor.provider.ts' +import { ATTACHMENT_RESOLVER, IS_MOBILE } from './Editor.provider.ts' import ReadonlyBar from './Menu/ReadonlyBar.vue' import { generateRemoteUrl } from '@nextcloud/router' @@ -101,6 +101,7 @@ import { useDelayedFlag } from '../composables/useDelayedFlag.ts' import { provideEditorHeadings } from '../composables/useEditorHeadings.ts' import { useEditorMethods } from '../composables/useEditorMethods.ts' import { provideEditorWidth } from '../composables/useEditorWidth.ts' +import { provideFileProps } from '../composables/useFileProps.ts' import { provideSaveService } from '../composables/useSaveService.ts' import { provideSyncService } from '../composables/useSyncService.ts' import { useSyntaxHighlighting } from '../composables/useSyntaxHighlighting.ts' @@ -156,9 +157,6 @@ export default defineComponent({ // using getters we can always provide the // actual values without being reactive Object.defineProperties(val, { - [FILE]: { - get: () => this.fileData, - }, [ATTACHMENT_RESOLVER]: { get: () => this.$attachmentResolver, }, @@ -272,6 +270,8 @@ export default defineComponent({ const syncProvider = shallowRef(null) + provideFileProps(props) + return { awareness, connection, @@ -354,15 +354,6 @@ export default defineComponent({ imagePath() { return this.relativePath.split('/').slice(0, -1).join('/') }, - fileData() { - return { - fileId: this.fileId, - relativePath: this.relativePath, - document: { - ...this.document, - }, - } - }, }, watch: { displayed() { diff --git a/src/components/Editor/MediaHandler.vue b/src/components/Editor/MediaHandler.vue index 910d9d2a402..1eee020f0d7 100644 --- a/src/components/Editor/MediaHandler.vue +++ b/src/components/Editor/MediaHandler.vue @@ -39,8 +39,9 @@ import { import { logger } from '../../helpers/logger.js' import { useEditor } from '../../composables/useEditor.ts' -import { useFileMixin } from '../Editor.provider.ts' +import { useFileProps } from '../../composables/useFileProps.ts' +import { ref } from 'vue' import { useConnection } from '../../composables/useConnection.ts' import { ACTION_ATTACHMENT_PROMPT, @@ -53,7 +54,6 @@ const getDir = (val) => val.split('/').slice(0, -1).join('/') export default { name: 'MediaHandler', - mixins: [useFileMixin], provide() { const val = {} @@ -78,15 +78,18 @@ export default { const { connection } = useConnection() const isMobile = useIsMobile() const { editor } = useEditor() + const { relativePath } = useFileProps() + const parentPath = (relativePath ?? '/').split('/').slice(0, -1).join('/') + const startPath = ref(parentPath) return { connection, editor, isMobile, + startPath, } }, data() { return { - lastFilePath: null, draggedOver: false, // make it reactive to be used inject/provide state: { @@ -94,11 +97,6 @@ export default { }, } }, - computed: { - initialFilePath() { - return this.lastFilePath ?? getDir(this.$file?.relativePath ?? '/') - }, - }, methods: { setDraggedOver(val, event) { if (event.dataTransfer.types.includes('Files')) { @@ -184,11 +182,11 @@ export default { [], true, undefined, - this.initialFilePath, + this.startPath, ) }, insertFromPath(filePath) { - this.lastFilePath = getDir(filePath) + this.startPath = getDir(filePath) this.state.isUploadingAttachments = true diff --git a/src/components/Menu/ActionInsertLink.vue b/src/components/Menu/ActionInsertLink.vue index c1bbd09fde0..d216b3d53cb 100644 --- a/src/components/Menu/ActionInsertLink.vue +++ b/src/components/Menu/ActionInsertLink.vue @@ -90,9 +90,10 @@ import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js' import { getMarkAttributes, isActive } from '@tiptap/core' import { t } from '@nextcloud/l10n' +import { ref } from 'vue' +import { useFileProps } from '../../composables/useFileProps.ts' import { useNetworkState } from '../../composables/useNetworkState.ts' import { buildFilePicker } from '../../helpers/filePicker.js' -import { useFileMixin } from '../Editor.provider.ts' import { Document, LinkOff, Loading, Shape, Web } from '../icons.js' import { BaseActionEntry } from './BaseActionEntry.js' import { useMenuIDMixin } from './MenuBar.provider.js' @@ -110,16 +111,22 @@ export default { Shape, }, extends: BaseActionEntry, - mixins: [useFileMixin, useMenuIDMixin], + mixins: [useMenuIDMixin], setup() { const { networkOnline } = useNetworkState() - return { ...BaseActionEntry.setup(), networkOnline } + const { relativePath } = useFileProps() + const parentPath = (relativePath ?? '/').split('/').slice(0, -1).join('/') + const startPath = ref(parentPath) + return { + ...BaseActionEntry.setup(), + networkOnline, + startPath, + } }, data: () => { return { href: '', isInputMode: false, - startPath: null, /** Open state of the actions menu */ menuOpen: false, isUsingDirectEditing: @@ -130,9 +137,6 @@ export default { activeClass() { return this.state.active ? 'is-active' : '' }, - relativePath() { - return this.$file?.relativePath ?? '/' - }, }, methods: { /** @@ -140,10 +144,6 @@ export default { * Triggered by the "link file" button */ linkFile() { - if (this.startPath === null) { - this.startPath = this.relativePath.split('/').slice(0, -1).join('/') - } - const filePicker = buildFilePicker(this.startPath) filePicker diff --git a/src/components/Menu/AssistantAction.vue b/src/components/Menu/AssistantAction.vue index d8e6b4fc87f..f5141a6cfb6 100644 --- a/src/components/Menu/AssistantAction.vue +++ b/src/components/Menu/AssistantAction.vue @@ -176,9 +176,9 @@ import TextShort from 'vue-material-design-icons/TextShort.vue' import TranslateVariant from 'vue-material-design-icons/Translate.vue' import DeleteOutlineIcon from 'vue-material-design-icons/TrashCanOutline.vue' import { useEditor } from '../../composables/useEditor.ts' +import { useFileProps } from '../../composables/useFileProps.ts' import markdownit from '../../markdownit/index.js' import shouldInterpretAsMarkdown from '../../markdownit/shouldInterpretAsMarkdown.js' -import { useFileMixin } from '../Editor.provider.ts' import { BaseActionEntry } from './BaseActionEntry.js' import { useMenuIDMixin } from './MenuBar.provider.js' @@ -212,10 +212,11 @@ export default { NcModal, }, extends: BaseActionEntry, - mixins: [useFileMixin, useMenuIDMixin], + mixins: [useMenuIDMixin], setup() { const { editor } = useEditor() - return { editor } + const { fileId } = useFileProps() + return { editor, fileId } }, data() { return { @@ -238,7 +239,7 @@ export default { }, computed: { identifier() { - return 'text-file:' + this.$file.fileId + return 'text-file:' + this.fileId }, badgeStateIcon() { if ( diff --git a/src/components/SuggestionsBar.vue b/src/components/SuggestionsBar.vue index b85852423c1..50137b6ccb2 100644 --- a/src/components/SuggestionsBar.vue +++ b/src/components/SuggestionsBar.vue @@ -61,13 +61,14 @@ import { t } from '@nextcloud/l10n' import { generateUrl } from '@nextcloud/router' import NcButton from '@nextcloud/vue/components/NcButton' import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js' +import { ref } from 'vue' import { Document, Shape, Table as TableIcon, Upload } from '../components/icons.js' import { useConnection } from '../composables/useConnection.ts' import { useEditor } from '../composables/useEditor.ts' +import { useFileProps } from '../composables/useFileProps.ts' import { useNetworkState } from '../composables/useNetworkState.ts' import { buildFilePicker } from '../helpers/filePicker.js' import { isMobileDevice } from '../helpers/isMobileDevice.js' -import { useFileMixin } from './Editor.provider.ts' import { useActionChooseLocalAttachmentMixin } from './Editor/MediaHandler.provider.js' export default { @@ -80,23 +81,26 @@ export default { Upload, }, - mixins: [useActionChooseLocalAttachmentMixin, useFileMixin], + mixins: [useActionChooseLocalAttachmentMixin], setup() { const { editor } = useEditor() const { openData } = useConnection() const { networkOnline } = useNetworkState() + const { relativePath } = useFileProps() + const parentPath = (relativePath ?? '/').split('/').slice(0, -1).join('/') + const startPath = ref(parentPath) return { editor, isMobileDevice, networkOnline, openData, + startPath, } }, data: () => { return { - startPath: null, isEmptyContent: false, } }, @@ -164,10 +168,6 @@ export default { * Triggered by the "link to file or folder" button */ linkFile() { - if (this.startPath === null) { - this.startPath = this.relativePath.split('/').slice(0, -1).join('/') - } - const filePicker = buildFilePicker(this.startPath) filePicker diff --git a/src/composables/useFileProps.ts b/src/composables/useFileProps.ts new file mode 100644 index 00000000000..99e3d615271 --- /dev/null +++ b/src/composables/useFileProps.ts @@ -0,0 +1,24 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { inject, type InjectionKey, provide } from 'vue' + +interface FileProps { + fileId?: number + relativePath?: string +} + +export const filePropsKey = Symbol('tiptap:file:props') as InjectionKey + +export const provideFileProps = (props: FileProps) => { + provide(filePropsKey, { + fileId: props.fileId, + relativePath: props.relativePath, + }) +} + +export const useFileProps = () => { + return inject(filePropsKey) || {} +}