|
@@ -1,6 +1,7 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div
|
|
<div
|
|
|
class="editable-element-text"
|
|
class="editable-element-text"
|
|
|
|
|
+ ref="elementRef"
|
|
|
:class="{ 'lock': elementInfo.lock }"
|
|
:class="{ 'lock': elementInfo.lock }"
|
|
|
:style="{
|
|
:style="{
|
|
|
top: elementInfo.top + 'px',
|
|
top: elementInfo.top + 'px',
|
|
@@ -10,7 +11,8 @@
|
|
|
}"
|
|
}"
|
|
|
@mousedown="$event => handleSelectElement($event)"
|
|
@mousedown="$event => handleSelectElement($event)"
|
|
|
>
|
|
>
|
|
|
- <div class="element-content"
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="element-content"
|
|
|
:style="{
|
|
:style="{
|
|
|
backgroundColor: elementInfo.fill,
|
|
backgroundColor: elementInfo.fill,
|
|
|
opacity: elementInfo.opacity,
|
|
opacity: elementInfo.opacity,
|
|
@@ -23,9 +25,9 @@
|
|
|
:height="elementInfo.height"
|
|
:height="elementInfo.height"
|
|
|
:outline="elementInfo.outline"
|
|
:outline="elementInfo.outline"
|
|
|
/>
|
|
/>
|
|
|
- <div class="text"
|
|
|
|
|
- v-html="elementInfo.content"
|
|
|
|
|
- :contenteditable="!elementInfo.lock"
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="text"
|
|
|
|
|
+ ref="editorViewRef"
|
|
|
@mousedown="$event => handleSelectElement($event, false)"
|
|
@mousedown="$event => handleSelectElement($event, false)"
|
|
|
></div>
|
|
></div>
|
|
|
</div>
|
|
</div>
|
|
@@ -33,10 +35,16 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
<script lang="ts">
|
|
|
-import { computed, defineComponent, PropType } from 'vue'
|
|
|
|
|
|
|
+import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
|
|
|
|
|
+import debounce from 'lodash/debounce'
|
|
|
|
|
+import { useStore } from 'vuex'
|
|
|
|
|
+import { MutationTypes, State } from '@/store'
|
|
|
|
|
+import { EditorView } from 'prosemirror-view'
|
|
|
import { PPTTextElement } from '@/types/slides'
|
|
import { PPTTextElement } from '@/types/slides'
|
|
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
|
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
|
|
|
|
+import { initProsemirrorEditor, createDocument } from '@/prosemirror/'
|
|
|
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
|
|
import useElementShadow from '@/views/components/element/hooks/useElementShadow'
|
|
|
|
|
+import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
|
|
|
|
|
|
|
import ElementOutline from '@/views/components/element/ElementOutline.vue'
|
|
import ElementOutline from '@/views/components/element/ElementOutline.vue'
|
|
|
|
|
|
|
@@ -59,6 +67,72 @@ export default defineComponent({
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
setup(props) {
|
|
setup(props) {
|
|
|
|
|
+ const store = useStore<State>()
|
|
|
|
|
+ const { addHistorySnapshot } = useHistorySnapshot()
|
|
|
|
|
+
|
|
|
|
|
+ const elementRef = ref<HTMLElement | null>(null)
|
|
|
|
|
+
|
|
|
|
|
+ const debounceUpdateTextElementHeight = debounce(function(realHeight) {
|
|
|
|
|
+ store.commit(MutationTypes.UPDATE_ELEMENT, {
|
|
|
|
|
+ id: props.elementInfo.id,
|
|
|
|
|
+ props: { height: realHeight },
|
|
|
|
|
+ })
|
|
|
|
|
+ }, 500, { trailing: true })
|
|
|
|
|
+
|
|
|
|
|
+ const updateTextElementHeight = () => {
|
|
|
|
|
+ if(!elementRef.value) return
|
|
|
|
|
+
|
|
|
|
|
+ const realHeight = elementRef.value.clientHeight
|
|
|
|
|
+ if(props.elementInfo.height !== realHeight) {
|
|
|
|
|
+ debounceUpdateTextElementHeight(realHeight)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ const resizeObserver = new ResizeObserver(updateTextElementHeight)
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ if(elementRef.value) resizeObserver.observe(elementRef.value)
|
|
|
|
|
+ })
|
|
|
|
|
+ onUnmounted(() => {
|
|
|
|
|
+ if(elementRef.value) resizeObserver.unobserve(elementRef.value)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const editorViewRef = ref<Element | null>(null)
|
|
|
|
|
+ let editorView: EditorView
|
|
|
|
|
+
|
|
|
|
|
+ const handleFocus = () => {
|
|
|
|
|
+ store.commit(MutationTypes.SET_DISABLE_HOTKEYS_STATE, true)
|
|
|
|
|
+ }
|
|
|
|
|
+ const handleBlur = () => {
|
|
|
|
|
+ store.commit(MutationTypes.SET_DISABLE_HOTKEYS_STATE, false)
|
|
|
|
|
+ }
|
|
|
|
|
+ const handleInput = debounce(function() {
|
|
|
|
|
+ store.commit(MutationTypes.UPDATE_ELEMENT, {
|
|
|
|
|
+ id: props.elementInfo.id,
|
|
|
|
|
+ props: { content: editorView.dom.innerHTML },
|
|
|
|
|
+ })
|
|
|
|
|
+ addHistorySnapshot()
|
|
|
|
|
+ }, 500, { trailing: true })
|
|
|
|
|
+
|
|
|
|
|
+ const textContent = computed(() => props.elementInfo.content)
|
|
|
|
|
+ watch(textContent, () => {
|
|
|
|
|
+ if(!editorView) return
|
|
|
|
|
+ if(editorView.hasFocus()) return
|
|
|
|
|
+ editorView.dom.innerHTML = textContent.value
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ editorView = initProsemirrorEditor((editorViewRef.value as Element), textContent.value, {
|
|
|
|
|
+ handleDOMEvents: {
|
|
|
|
|
+ focus: handleFocus,
|
|
|
|
|
+ blur: handleBlur,
|
|
|
|
|
+ keydown: handleInput,
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ onUnmounted(() => {
|
|
|
|
|
+ editorView && editorView.destroy()
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
const handleSelectElement = (e: MouseEvent, canMove = true) => {
|
|
const handleSelectElement = (e: MouseEvent, canMove = true) => {
|
|
|
if(props.elementInfo.lock) return
|
|
if(props.elementInfo.lock) return
|
|
|
e.stopPropagation()
|
|
e.stopPropagation()
|
|
@@ -70,6 +144,8 @@ export default defineComponent({
|
|
|
const { shadowStyle } = useElementShadow(shadow)
|
|
const { shadowStyle } = useElementShadow(shadow)
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
|
|
+ elementRef,
|
|
|
|
|
+ editorViewRef,
|
|
|
handleSelectElement,
|
|
handleSelectElement,
|
|
|
shadowStyle,
|
|
shadowStyle,
|
|
|
}
|
|
}
|
|
@@ -97,15 +173,4 @@ export default defineComponent({
|
|
|
cursor: text;
|
|
cursor: text;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-::v-deep(.text) {
|
|
|
|
|
- word-break: break-word;
|
|
|
|
|
- font-family: '微软雅黑';
|
|
|
|
|
- outline: 0;
|
|
|
|
|
-
|
|
|
|
|
- ::selection {
|
|
|
|
|
- background-color: rgba(27, 110, 232, 0.3);
|
|
|
|
|
- color: inherit;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
</style>
|
|
</style>
|