diff --git a/src/components/card/AttachmentList.vue b/src/components/card/AttachmentList.vue index 914aa3dc1..36b2a8dce 100644 --- a/src/components/card/AttachmentList.vue +++ b/src/components/card/AttachmentList.vue @@ -46,9 +46,9 @@ .{{ attachmentExtension(attachment) }}
- {{ formattedFileSize(attachment.extendedData.filesize) }} + {{ formattedFileSize(attachment.extendedData?.filesize) }} {{ relativeDate(attachment.createdAt*1000) }} - {{ attachment.extendedData.attachmentCreator.displayName }} + {{ attachment.extendedData?.attachmentCreator?.displayName }}
{{ t('deck', 'Pending share') }} @@ -158,7 +158,7 @@ export default { if (!attachment) { return {} } - const url = attachment.extendedData.hasPreview ? this.attachmentPreview(attachment) : OC.MimeType.getIconUrl(attachment.extendedData.mimetype) + const url = attachment?.extendedData?.hasPreview ? this.attachmentPreview(attachment) : OC.MimeType.getIconUrl(attachment?.extendedData?.mimetype) const styles = { 'background-image': `url("${url}")`, } @@ -166,16 +166,16 @@ export default { } }, attachmentPreview() { - return (attachment) => (attachment.extendedData.fileid ? generateUrl(`/core/preview?fileId=${attachment.extendedData.fileid}&x=64&y=64`) : null) + return (attachment) => (attachment?.extendedData?.fileid ? generateUrl(`/core/preview?fileId=${attachment.extendedData.fileid}&x=64&y=64`) : null) }, attachmentUrl() { - return (attachment) => generateUrl(`/apps/deck/cards/${attachment.cardId}/attachment/${attachment.id}`) + return (attachment) => (attachment?.cardId && attachment?.id ? generateUrl(`/apps/deck/cards/${attachment.cardId}/attachment/${attachment.id}`) : '#') }, internalLink() { - return (attachment) => generateUrl('/f/' + attachment.extendedData.fileid) + return (attachment) => (attachment?.extendedData?.fileid ? generateUrl('/f/' + attachment.extendedData.fileid) : '#') }, downloadLink() { - return (attachment) => generateRemoteUrl(`dav/files/${getCurrentUser().uid}/${attachment.extendedData.path}`) + return (attachment) => (attachment?.extendedData?.path ? generateRemoteUrl(`dav/files/${getCurrentUser().uid}/${attachment.extendedData.path}`) : '#') }, formattedFileSize() { return (filesize) => formatFileSize(filesize) @@ -196,11 +196,11 @@ export default { }, attachmentBasename() { return (attachment) => attachment?.extendedData?.info?.filename - ?? (attachment?.name ?? attachment.data).replace(/\.[^/.]+$/, '') + ?? (attachment?.name ?? attachment?.data ?? '').replace(/\.[^/.]+$/, '') }, attachmentExtension() { return (attachment) => attachment?.extendedData?.info?.extension - ?? (attachment?.name ?? attachment.data).split('.').pop() + ?? (attachment?.name ?? attachment?.data ?? '').split('.').pop() }, cardDetailsInModal() { return useSettingsStore().configByKey('cardDetailsInModal') diff --git a/src/components/card/Description.vue b/src/components/card/Description.vue index 8da0a6019..083619a11 100644 --- a/src/components/card/Description.vue +++ b/src/components/card/Description.vue @@ -182,8 +182,12 @@ export default { this.descriptionOld = newCard.description this.description = newCard.description - if (this.editor) { - this.editor.setContent(this.description) + if (this.editor && typeof this.editor.setContent === 'function') { + try { + this.editor.setContent(this.description) + } catch (e) { + console.debug('Failed to set editor content', e) + } } showWarning(t('deck', 'The description has been changed by another user.'), { timeout: 3000 }) } @@ -205,25 +209,42 @@ export default { this.descriptionLastEdit = 0 this.descriptionOld = this.card.description this.description = this.card.description - this.editor = await window.OCA.Text.createEditor({ - el: this.$refs.editor, - content: this.card.description, - readOnly: !this.canEdit, - onLoaded: () => { - this.descriptionLastEdit = 0 - }, - onUpdate: ({ markdown }) => { - if (this.description === markdown) { - return + if (!window.OCA?.Text?.createEditor || !this.$refs.editor) { + return + } + try { + const editor = await window.OCA.Text.createEditor({ + el: this.$refs.editor, + content: this.card.description, + readOnly: !this.canEdit, + onLoaded: () => { + this.descriptionLastEdit = 0 + }, + onUpdate: ({ markdown }) => { + if (this.description === markdown) { + return + } + this.description = markdown + this.updateDescription() + }, + onFileInsert: () => { + this.showAttachmentModal() + }, + }) + if (this._isBeingDestroyed || this._isDestroyed) { + if (editor && typeof editor.destroy === 'function') { + try { + await editor.destroy() + } catch (e) { + // Ignore teardown error on already destroyed component + } } - this.description = markdown - this.updateDescription() - }, - onFileInsert: () => { - this.showAttachmentModal() - }, - }) - + return + } + this.editor = editor + } catch (e) { + console.warn('Failed to initialize text editor', e) + } }, async destroyEditor() { await this.saveDescription() @@ -273,7 +294,9 @@ export default { const asImage = (attachment.type === 'file' && attachment.extendedData.hasPreview) || attachment.extendedData.mimetype.includes('image') // We need to strip those as text does not support rtl yet, so we cannot insert them separately const stripRTLO = (text) => text.replaceAll('\u202e', '') - const fileName = stripRTLO(attachment.extendedData.info.filename) + '.' + stripRTLO(attachment.extendedData.info.extension) + const base = attachment?.extendedData?.info?.filename ?? attachment?.data ?? '' + const ext = attachment?.extendedData?.info?.extension + const fileName = stripRTLO(base) + (ext ? '.' + stripRTLO(ext) : '') if (this.editor) { this.editor.insertAtCursor( asImage