diff options
Diffstat (limited to 'src/components/EditorWrapper.vue')
-rw-r--r-- | src/components/EditorWrapper.vue | 114 |
1 files changed, 66 insertions, 48 deletions
diff --git a/src/components/EditorWrapper.vue b/src/components/EditorWrapper.vue index 782a91434..913528229 100644 --- a/src/components/EditorWrapper.vue +++ b/src/components/EditorWrapper.vue @@ -37,7 +37,7 @@ </p> </div> <div v-if="displayed" id="editor-wrapper" :class="{'has-conflicts': hasSyncCollission, 'icon-loading': !contentLoaded && !hasConnectionIssue, 'richEditor': isRichEditor, 'show-color-annotations': showAuthorAnnotations}"> - <div v-if="tiptap" + <div v-if="$editor" id="editor" :class="{ draggedOver }" @image-paste="onPaste" @@ -46,8 +46,6 @@ @image-drop="onEditorDrop"> <MenuBar v-if="renderMenus" ref="menubar" - :editor="tiptap" - :sync-service="syncService" :file-path="relativePath" :file-id="fileId" :is-rich-editor="isRichEditor" @@ -63,7 +61,7 @@ {{ lastSavedStatus }} </div> <SessionList :sessions="filteredSessions"> - <GuestNameDialog v-if="isPublic && currentSession.guestName" :sync-service="syncService" /> + <GuestNameDialog v-if="isPublic && currentSession.guestName" /> </SessionList> </div> <slot name="header" /> @@ -71,12 +69,11 @@ <div v-if="!menubarLoaded" class="menubar placeholder" /> <div ref="contentWrapper" class="content-wrapper"> <MenuBubble v-if="renderMenus" - :editor="tiptap" :content-wrapper="contentWrapper" :file-path="relativePath" /> <EditorContent v-show="contentLoaded" class="editor__content" - :editor="tiptap" /> + :editor="$editor" /> </div> </div> <ReadOnlyEditor v-if="hasSyncCollission" @@ -95,6 +92,8 @@ import escapeHtml from 'escape-html' import moment from '@nextcloud/moment' import { showError } from '@nextcloud/dialogs' +import { EDITOR, SYNC_SERVICE } from './EditorWrapper.provider' + import { SyncService, ERROR_TYPE, IDLE_TIMEOUT } from './../services/SyncService' import { endpointUrl, getRandomGuestName } from './../helpers' import { extensionHighlight } from '../helpers/mappings' @@ -144,6 +143,27 @@ export default { isMobile, store, ], + provide() { + const val = {} + + // providers aren't naturally reactive + // and $editor will start as null + // using getters we can always provide the + // actual $editor without being reactive + Object.defineProperty(val, EDITOR, { + get: () => { + return this.$editor + }, + }) + + Object.defineProperty(val, SYNC_SERVICE, { + get: () => { + return this.$syncService + }, + }) + + return val + }, props: { initialSession: { type: Object, @@ -186,10 +206,6 @@ export default { return { IDLE_TIMEOUT, - tiptap: null, - /** @type {SyncService} */ - syncService: null, - document: null, sessions: [], currentSession: null, @@ -297,6 +313,8 @@ export default { this.$parent.$emit('update:loaded', true) }, created() { + this.$editor = null + this.$syncService = null this.saveStatusPolling = setInterval(() => { this.updateLastSavedStatus() }, 2000) @@ -307,11 +325,11 @@ export default { methods: { async close() { clearInterval(this.saveStatusPolling) - if (this.currentSession && this.syncService) { + if (this.currentSession && this.$syncService) { try { - await this.syncService.close() + await this.$syncService.close() this.currentSession = null - this.syncService = null + this.$syncService = null } catch (e) { // Ignore issues closing the session since those might happen due to network issues } @@ -329,16 +347,16 @@ export default { return } const guestName = localStorage.getItem('nick') ? localStorage.getItem('nick') : getRandomGuestName() - this.syncService = new SyncService({ + this.$syncService = new SyncService({ shareToken: this.shareToken, filePath: this.relativePath, guestName, forceRecreate: this.forceRecreate, serialize: (document) => { if (this.isRichEditor) { - return (createMarkdownSerializer(this.tiptap.schema)).serialize(document) + return (createMarkdownSerializer(this.$editor.schema)).serialize(document) } - return serializePlainText(this.tiptap) + return serializePlainText(this.$editor) }, }) @@ -346,7 +364,7 @@ export default { this.currentSession = session this.document = document this.readOnly = document.readOnly - this.lock = this.syncService.lock + this.lock = this.$syncService.lock localStorage.setItem('nick', this.currentSession.guestName) this.$store.dispatch('setCurrentSession', this.currentSession) }) @@ -359,7 +377,7 @@ export default { this.document = document this.syncError = null - this.tiptap.setOptions({ editable: !this.readOnly }) + this.$editor.setOptions({ editable: !this.readOnly }) }) .on('loaded', ({ documentSource }) => { this.hasConnectionIssue = false @@ -368,14 +386,14 @@ export default { : '<pre>' + escapeHtml(documentSource) + '</pre>' const language = extensionHighlight[this.fileExtension] || this.fileExtension loadSyntaxHighlight(language).then(() => { - this.tiptap = createEditor({ + this.$editor = createEditor({ content, onCreate: ({ editor }) => { - this.syncService.state = editor.state - this.syncService.startSync() + this.$syncService.state = editor.state + this.$syncService.startSync() }, onUpdate: ({ editor }) => { - this.syncService.state = editor.state + this.$syncService.state = editor.state }, extensions: [ Collaboration.configure({ @@ -386,8 +404,8 @@ export default { // debounce changes so we can save some bandwidth debounce: EDITOR_PUSH_DEBOUNCE, onSendable: ({ sendable }) => { - if (this.syncService) { - this.syncService.sendSteps() + if (this.$syncService) { + this.$syncService.sendSteps() } }, update: ({ steps, version, editor }) => { @@ -406,7 +424,7 @@ export default { }), Keymap.configure({ 'Mod-s': () => { - this.syncService.save() + this.$syncService.save() return true }, }), @@ -425,25 +443,25 @@ export default { enableRichEditing: this.isRichEditor, currentDirectory: this.currentDirectory, }) - this.tiptap.on('focus', () => { + this.$editor.on('focus', () => { this.$emit('focus') }) - this.tiptap.on('blur', () => { + this.$editor.on('blur', () => { this.$emit('blur') }) - this.syncService.state = this.tiptap.state + this.$syncService.state = this.$editor.state }) }) .on('sync', ({ steps, document }) => { this.hasConnectionIssue = false try { - const collaboration = this.tiptap.extensionManager.extensions.find(e => e.name === 'collaboration') + const collaboration = this.$editor.extensionManager.extensions.find(e => e.name === 'collaboration') collaboration.options.update({ version: document.currentVersion, steps, - editor: this.tiptap, + editor: this.$editor, }) - this.syncService.state = this.tiptap.state + this.$syncService.state = this.$editor.state this.updateLastSavedStatus() } catch (e) { console.error('Failed to update steps in collaboration plugin', e) @@ -452,7 +470,7 @@ export default { this.document = document }) .on('error', (error, data) => { - this.tiptap.setOptions({ editable: false }) + this.$editor.setOptions({ editable: false }) if (error === ERROR_TYPE.SAVE_COLLISSION && (!this.syncError || this.syncError.type !== ERROR_TYPE.SAVE_COLLISSION)) { this.contentLoaded = true this.syncError = { @@ -477,7 +495,7 @@ export default { if (state.initialLoading && !this.contentLoaded) { this.contentLoaded = true if (this.autofocus && !this.readOnly) { - this.tiptap.commands.focus() + this.$editor.commands.focus() } this.$emit('ready') this.$parent.$emit('ready', true) @@ -487,12 +505,12 @@ export default { } }) .on('idle', () => { - this.syncService.close() + this.$syncService.close() this.idle = true this.readOnly = true - this.tiptap.setOptions({ editable: !this.readOnly }) + this.$editor.setOptions({ editable: !this.readOnly }) }) - this.syncService.open({ + this.$syncService.open({ fileId: this.fileId, filePath: this.relativePath, initialSession: this.initialSession, @@ -503,8 +521,8 @@ export default { }, resolveUseThisVersion() { - this.syncService.forceSave() - this.tiptap.setOptions({ editable: !this.readOnly }) + this.$syncService.forceSave() + this.$editor.setOptions({ editable: !this.readOnly }) }, resolveUseServerVersion() { @@ -515,17 +533,17 @@ export default { reconnect() { this.contentLoaded = false this.hasConnectionIssue = false - if (this.syncService) { - this.syncService.close().then(() => { - this.syncService = null - this.tiptap.destroy() + if (this.$syncService) { + this.$syncService.close().then(() => { + this.$syncService = null + this.$editor.destroy() this.initSession() }).catch((e) => { // Ignore issues closing the session since those might happen due to network issues }) } else { - this.syncService = null - this.tiptap.destroy() + this.$syncService = null + this.$editor.destroy() this.initSession() } this.idle = false @@ -597,7 +615,7 @@ export default { return } - return this.syncService.uploadImage(file).then((response) => { + return this.$syncService.uploadImage(file).then((response) => { this.insertAttachmentImage(response.data?.name, response.data?.id, position) }).catch((error) => { console.error(error) @@ -606,7 +624,7 @@ export default { }, insertImagePath(imagePath) { this.uploadingImages = true - this.syncService.insertImageFile(imagePath).then((response) => { + this.$syncService.insertImageFile(imagePath).then((response) => { this.insertAttachmentImage(response.data?.name, response.data?.id) }).catch((error) => { console.error(error) @@ -621,9 +639,9 @@ export default { // as it does not need to be unique and matching the real file name const alt = name.replaceAll(/[[\]]/g, '') if (position) { - this.tiptap.chain().focus(position).setImage({ src, alt }).focus().run() + this.$editor.chain().focus(position).setImage({ src, alt }).focus().run() } else { - this.tiptap.chain().setImage({ src, alt }).focus().run() + this.$editor.chain().setImage({ src, alt }).focus().run() } }, }, |