fix: resolve issues with vue-easymde (#2629)

Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Reviewed-on: vikunja/frontend#2629
Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:
Dominik Pschenitschni 2022-11-03 14:37:24 +00:00 committed by konrad
parent 8b7b4d61a3
commit eb59ca5836
3 changed files with 39 additions and 36 deletions

View File

@ -70,6 +70,7 @@
"@cypress/vue": "4.2.2", "@cypress/vue": "4.2.2",
"@faker-js/faker": "7.6.0", "@faker-js/faker": "7.6.0",
"@rushstack/eslint-patch": "1.2.0", "@rushstack/eslint-patch": "1.2.0",
"@types/codemirror": "^5.60.5",
"@types/dompurify": "2.3.4", "@types/dompurify": "2.3.4",
"@types/flexsearch": "0.7.3", "@types/flexsearch": "0.7.3",
"@types/lodash.debounce": "4.0.7", "@types/lodash.debounce": "4.0.7",

View File

@ -15,6 +15,7 @@ specifiers:
'@rushstack/eslint-patch': 1.2.0 '@rushstack/eslint-patch': 1.2.0
'@sentry/tracing': 7.17.4 '@sentry/tracing': 7.17.4
'@sentry/vue': 7.17.4 '@sentry/vue': 7.17.4
'@types/codemirror': ^5.60.5
'@types/dompurify': 2.3.4 '@types/dompurify': 2.3.4
'@types/flexsearch': 0.7.3 '@types/flexsearch': 0.7.3
'@types/is-touch-device': 1.0.0 '@types/is-touch-device': 1.0.0
@ -142,6 +143,7 @@ devDependencies:
'@cypress/vue': 4.2.2_cypress@10.11.0+vue@3.2.41 '@cypress/vue': 4.2.2_cypress@10.11.0+vue@3.2.41
'@faker-js/faker': 7.6.0 '@faker-js/faker': 7.6.0
'@rushstack/eslint-patch': 1.2.0 '@rushstack/eslint-patch': 1.2.0
'@types/codemirror': 5.60.5
'@types/dompurify': 2.3.4 '@types/dompurify': 2.3.4
'@types/flexsearch': 0.7.3 '@types/flexsearch': 0.7.3
'@types/lodash.debounce': 4.0.7 '@types/lodash.debounce': 4.0.7
@ -2911,7 +2913,6 @@ packages:
resolution: {integrity: sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==} resolution: {integrity: sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==}
dependencies: dependencies:
'@types/tern': 0.23.4 '@types/tern': 0.23.4
dev: false
/@types/concat-stream/1.6.1: /@types/concat-stream/1.6.1:
resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==}
@ -2945,7 +2946,6 @@ packages:
/@types/estree/0.0.51: /@types/estree/0.0.51:
resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==}
dev: false
/@types/flexsearch/0.7.3: /@types/flexsearch/0.7.3:
resolution: {integrity: sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==} resolution: {integrity: sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==}
@ -3117,7 +3117,6 @@ packages:
resolution: {integrity: sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==} resolution: {integrity: sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==}
dependencies: dependencies:
'@types/estree': 0.0.51 '@types/estree': 0.0.51
dev: false
/@types/trusted-types/2.0.2: /@types/trusted-types/2.0.2:
resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==} resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==}

View File

@ -4,22 +4,28 @@
class="vue-simplemde-textarea" class="vue-simplemde-textarea"
:name="name" :name="name"
:value="modelValue" :value="modelValue"
@input="handleInput($event.target.value)" @input="handleInput(($event.target as HTMLTextAreaElement).value)"
/> />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, watch, onMounted, onDeactivated, onBeforeUnmount, nextTick, shallowReactive} from 'vue' import {ref, watch, onMounted, onDeactivated, onBeforeUnmount, nextTick, shallowReactive, type ShallowReactive, type PropType} from 'vue'
import type { ShallowReactive } from 'vue' import EasyMDE, {toggleFullScreen} from 'easymde'
import EasyMDE from 'easymde'
import {marked} from 'marked' import {marked} from 'marked'
import type CodeMirror from 'codemirror'
const props = defineProps({ const props = defineProps({
modelValue: String, modelValue: {
name: String, type: String,
previewClass: String, default: '',
},
name: {
type: String,
},
previewClass: {
type: String,
},
autoinit: { autoinit: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -37,7 +43,7 @@ const props = defineProps({
default: () => ({}), default: () => ({}),
}, },
previewRender: { previewRender: {
type: Function, type: Function as PropType<EasyMDE.Options['previewRender']>,
}, },
}) })
@ -51,9 +57,9 @@ onMounted(() => {
}) })
onDeactivated(() => { onDeactivated(() => {
if (!easymde) return if (easymde === undefined) return
const isFullScreen = easymde.codemirror.getOption('fullScreen') if (easymde.isFullscreenActive()) toggleFullScreen(easymde)
if (isFullScreen) easymde.toggleFullScreen() easymde.toTextArea
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
@ -67,8 +73,8 @@ onBeforeUnmount(() => {
const easymdeRef = ref<HTMLElement | null>(null) const easymdeRef = ref<HTMLElement | null>(null)
function initialize() { function initialize() {
const configs = Object.assign({ const configs: EasyMDE.Options = Object.assign({
element: easymdeRef.value?.firstElementChild, element: easymdeRef.value?.firstElementChild as HTMLElement,
initialValue: props.modelValue, initialValue: props.modelValue,
previewRender: props.previewRender, previewRender: props.previewRender,
renderingConfig: {}, renderingConfig: {},
@ -81,7 +87,7 @@ function initialize() {
// Determine whether to enable code highlighting // Determine whether to enable code highlighting
if (props.highlight) { if (props.highlight) {
configs.renderingConfig.codeSyntaxHighlighting = true configs.renderingConfig!.codeSyntaxHighlighting = true
} }
// Set whether to render the input html // Set whether to render the input html
@ -92,15 +98,16 @@ function initialize() {
// Add a custom previewClass // Add a custom previewClass
const className = props.previewClass || '' const className = props.previewClass || ''
addPreviewClass(className) addPreviewClass(easymde, className)
// Binding event // Binding event
bindingEvents() easymde.codemirror.on('change', handleCodemirrorInput)
easymde.codemirror.on('blur', handleCodemirrorBlur)
nextTick(() => emit('initialized', easymde)) nextTick(() => emit('initialized', easymde))
} }
function addPreviewClass(className: string) { function addPreviewClass(easymde: EasyMDE, className: string) {
const wrapper = easymde.codemirror.getWrapperElement() const wrapper = easymde.codemirror.getWrapperElement()
const preview = document.createElement('div') const preview = document.createElement('div')
wrapper.nextSibling.className += ` ${className}` wrapper.nextSibling.className += ` ${className}`
@ -108,28 +115,24 @@ function addPreviewClass(className: string) {
wrapper.appendChild(preview) wrapper.appendChild(preview)
} }
function bindingEvents() { function handleInput(val: string) {
easymde.codemirror.on('change', handleCodemirrorInput) isValueUpdateFromInner.value = true
easymde.codemirror.on('blur', handleCodemirrorBlur) emit('update:modelValue', val)
} }
function handleCodemirrorInput(instance, changeObj) { function handleCodemirrorInput(instance: CodeMirror.Editor, changeObj: CodeMirror.EditorChange) {
if (changeObj.origin === 'setValue') { if (changeObj.origin === 'setValue' || easymde === undefined) {
return return
} }
const val = easymde.value() handleInput(easymde.value())
handleInput(val)
} }
function handleCodemirrorBlur() { function handleCodemirrorBlur() {
const val = easymde.value() if (easymde === undefined) {
return
}
isValueUpdateFromInner.value = true isValueUpdateFromInner.value = true
emit('blur', val) emit('blur', easymde.value())
}
function handleInput(val) {
isValueUpdateFromInner.value = true
emit('update:modelValue', val)
} }
watch( watch(
@ -138,7 +141,7 @@ watch(
if (isValueUpdateFromInner.value) { if (isValueUpdateFromInner.value) {
isValueUpdateFromInner.value = false isValueUpdateFromInner.value = false
} else { } else {
easymde.value(val) easymde?.value(val)
} }
}, },
) )