fix(editor): show editor if there is no content initially

This commit is contained in:
kolaente 2023-12-11 21:55:27 +01:00
parent 3cb1e7dede
commit af13d68c48
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
3 changed files with 31 additions and 63 deletions

View File

@ -118,7 +118,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed, nextTick, onBeforeUnmount, onMounted, ref, watch} from 'vue' import {computed, nextTick, onBeforeUnmount, onMounted, ref, watch} from 'vue'
import {refDebounced} from '@vueuse/core'
import EditorToolbar from './EditorToolbar.vue' import EditorToolbar from './EditorToolbar.vue'
@ -173,6 +172,7 @@ import {Placeholder} from '@tiptap/extension-placeholder'
import {eventToHotkeyString} from '@github/hotkey' import {eventToHotkeyString} from '@github/hotkey'
import {mergeAttributes} from '@tiptap/core' import {mergeAttributes} from '@tiptap/core'
import {createRandomID} from '@/helpers/randomId' import {createRandomID} from '@/helpers/randomId'
import {isEditorContentEmpty} from '@/helpers/editorContentEmpty'
const tiptapInstanceRef = ref<HTMLInputElement | null>(null) const tiptapInstanceRef = ref<HTMLInputElement | null>(null)
@ -272,7 +272,6 @@ const {
showSave = false, showSave = false,
placeholder = '', placeholder = '',
editShortcut = '', editShortcut = '',
// initialMode = 'edit',
} = defineProps<{ } = defineProps<{
modelValue: string, modelValue: string,
uploadCallback?: UploadCallback, uploadCallback?: UploadCallback,
@ -281,29 +280,12 @@ const {
showSave?: boolean, showSave?: boolean,
placeholder?: string, placeholder?: string,
editShortcut?: string, editShortcut?: string,
// initialMode?: Mode,
}>() }>()
const emit = defineEmits(['update:modelValue', 'save']) const emit = defineEmits(['update:modelValue', 'save'])
const inputHTML = ref('')
const internalMode = ref<Mode>('edit') const internalMode = ref<Mode>('edit')
const isEditing = computed(() => { const isEditing = computed(() => internalMode.value === 'edit' && isEditEnabled)
console.log('isEditing', {
// initialMode,
internal: internalMode.value,
result: internalMode.value === 'edit' && isEditEnabled,
})
return internalMode.value === 'edit' && isEditEnabled
})
// watch(
// () => initialMode,
// () => {
// console.log('watch', initialMode)
// internalMode.value === initialMode
// },
// )
const editor = useEditor({ const editor = useEditor({
content: modelValue, content: modelValue,
@ -391,15 +373,17 @@ const editor = useEditor({
BubbleMenu, BubbleMenu,
], ],
onUpdate: () => { onUpdate: () => {
// inputHTML.value = editor.value!.getHTML()
console.log('onUpdate')
bubbleNow() bubbleNow()
}, },
}) })
// Grundidee: Den Edit Mode intern entscheiden ohne Möglichkeit von außen watch(
// Problem: Der editor setzt den content irgendwie aus Gründen immer wieder auf leer, so dass der edit mode dann wieder enabled wird obwohl content da ist () => isEditing.value,
// --> Heißt eigentlich, dass der Content im Editor und der content in der Komponente nicht der gleiche ist, das ist schonmal ein grundsätzliches Problem () => {
editor.value?.setEditable(isEditing.value)
},
{immediate: true},
)
watch( watch(
() => modelValue, () => modelValue,
@ -410,19 +394,16 @@ watch(
return return
} }
console.log('content', value)
editor.value.commands.setContent(value, false) editor.value.commands.setContent(value, false)
// inputHTML.value = value
}, },
{immediate: true} {immediate: true},
) )
// const debouncedInputHTML = refDebounced(inputHTML, 1000)
// watch(debouncedInputHTML, () => bubbleNow())
function bubbleNow() { function bubbleNow() {
console.log('bubbleNow') if (editor.value?.getHTML() === modelValue) {
return
}
emit('update:modelValue', editor.value?.getHTML()) emit('update:modelValue', editor.value?.getHTML())
} }
@ -436,23 +417,11 @@ function bubbleSave() {
function setEdit(focus: boolean = true) { function setEdit(focus: boolean = true) {
internalMode.value = 'edit' internalMode.value = 'edit'
editor.value?.setEditable(isEditing.value)
if (focus) { if (focus) {
editor.value?.commands.focus() editor.value?.commands.focus()
} }
} }
watch(
() => isEditing.value,
() => {
nextTick(() => {
// console.log('wathcer is edit', isEditing.value)
setEdit(false)
})
},
{immediate: true},
)
onBeforeUnmount(() => editor.value?.destroy()) onBeforeUnmount(() => editor.value?.destroy())
const uploadInputRef = ref<HTMLInputElement | null>(null) const uploadInputRef = ref<HTMLInputElement | null>(null)
@ -522,15 +491,18 @@ function setLink() {
.run() .run()
} }
onMounted(() => { onMounted(async () => {
// internalMode.value = initialMode
nextTick(() => {
const input = tiptapInstanceRef.value?.querySelectorAll('.tiptap__editor')[0]?.children[0]
input?.addEventListener('paste', handleImagePaste)
})
if (editShortcut !== '') { if (editShortcut !== '') {
document.addEventListener('keydown', setFocusToEditor) document.addEventListener('keydown', setFocusToEditor)
} }
await nextTick()
const input = tiptapInstanceRef.value?.querySelectorAll('.tiptap__editor')[0]?.children[0]
input?.addEventListener('paste', handleImagePaste)
internalMode.value = isEditorContentEmpty(modelValue) ? 'edit' : 'preview'
editor.value?.commands.setContent(modelValue, false)
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
@ -568,9 +540,9 @@ function setFocusToEditor(event) {
} }
event.preventDefault() event.preventDefault()
// if (initialMode === 'preview' && isEditEnabled && !isEditing.value) { if (!isEditing.value && isEditEnabled) {
// internalMode.value = 'edit' internalMode.value = 'edit'
// } }
editor.value?.commands.focus() editor.value?.commands.focus()
} }

View File

@ -31,14 +31,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, computed, watch, nextTick} from 'vue' import {ref, computed, watch} from 'vue'
import CustomTransition from '@/components/misc/CustomTransition.vue' import CustomTransition from '@/components/misc/CustomTransition.vue'
import Editor from '@/components/input/AsyncEditor' import Editor from '@/components/input/AsyncEditor'
import type {ITask} from '@/modelTypes/ITask' import type {ITask} from '@/modelTypes/ITask'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
import {isEditorContentEmpty} from '@/helpers/editorContentEmpty'
type AttachmentUploadFunction = (file: File, onSuccess: (attachmentUrl: string) => void) => Promise<string> type AttachmentUploadFunction = (file: File, onSuccess: (attachmentUrl: string) => void) => Promise<string>
@ -63,15 +62,10 @@ const saving = ref(false)
const taskStore = useTaskStore() const taskStore = useTaskStore()
const loading = computed(() => taskStore.isLoading) const loading = computed(() => taskStore.isLoading)
const editorMode = ref('preview')
watch( watch(
() => modelValue.description, () => modelValue.description,
value => { value => {
description.value = value description.value = value
nextTick(() => {
editorMode.value = isEditorContentEmpty(value) ? 'edit' : 'preview'
})
}, },
{immediate: true}, {immediate: true},
) )

View File

@ -6,7 +6,8 @@
'is-modal': isModal, 'is-modal': isModal,
}" }"
> >
<div class="task-view"> <!-- Removing everything until the task is loaded to prevent empty initialization of other components -->
<div class="task-view" v-if="visible">
<Heading <Heading
:task="task" :task="task"
@update:task="Object.assign(task, $event)" @update:task="Object.assign(task, $event)"
@ -605,7 +606,8 @@ watch(
} }
try { try {
Object.assign(task.value, await taskService.get({id})) const loaded = await taskService.get({id})
Object.assign(task.value, loaded)
attachmentStore.set(task.value.attachments) attachmentStore.set(task.value.attachments)
taskColor.value = task.value.hexColor taskColor.value = task.value.hexColor
setActiveFields() setActiveFields()