| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- <template>
- <div
- class="editable-element"
- ref="elementRef"
- :id="`editable-element-${elementInfo.id}`"
- :style="{
- zIndex: elementIndex,
- }"
- >
- <component
- :is="currentElementComponent"
- :elementInfo="elementInfo"
- :selectElement="selectElement"
- :contextmenus="contextmenus"
- ></component>
- </div>
- </template>
- <script lang="ts" setup>
- import { computed, onMounted } from 'vue'
- import { storeToRefs } from 'pinia'
- import { ElementTypes, type PPTElement } from '@/types/slides'
- import type { ContextmenuItem } from '@/components/Contextmenu/types'
- import useLockElement from '@/hooks/useLockElement'
- import useDeleteElement from '@/hooks/useDeleteElement'
- import useCombineElement from '@/hooks/useCombineElement'
- import useOrderElement from '@/hooks/useOrderElement'
- import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas'
- import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
- import useSelectElement from '@/hooks/useSelectElement'
- import useHistorySnapshot from '@/hooks/useHistorySnapshot'
- import { useSlidesStore, useMainStore } from '@/store'
- import message from '@/utils/message'
- import { lang } from '@/main'
- import { ElementOrderCommands, ElementAlignCommands } from '@/types/edit'
- import ImageElement from '@/views/components/element/ImageElement/index.vue'
- import TextElement from '@/views/components/element/TextElement/index.vue'
- import ShapeElement from '@/views/components/element/ShapeElement/index.vue'
- import LineElement from '@/views/components/element/LineElement/index.vue'
- import ChartElement from '@/views/components/element/ChartElement/index.vue'
- import TableElement from '@/views/components/element/TableElement/index.vue'
- import LatexElement from '@/views/components/element/LatexElement/index.vue'
- import VideoElement from '@/views/components/element/VideoElement/index.vue'
- import AudioElement from '@/views/components/element/AudioElement/index.vue'
- import FrameElement from '@/views/components/element/FrameElement/index.vue'
- import { initClipboardFocus } from '@/utils/clipboard'
- const mainStore = useMainStore()
- onMounted(() => {
- console.log('ed,onMounted')
- initClipboardFocus()
- mainStore.setDisableHotkeysState(false)
- })
- const props = defineProps<{
- elementInfo: PPTElement
- elementIndex: number
- isMultiSelect: boolean
- selectElement: (e: MouseEvent | TouchEvent, element: PPTElement, canMove?: boolean) => void
- openLinkDialog: () => void
- openWebpageLinkEditDialog: (elementId: string, currentUrl: string) => void
- }>()
- const currentElementComponent = computed<unknown>(() => {
- const elementTypeMap = {
- [ElementTypes.IMAGE]: ImageElement,
- [ElementTypes.TEXT]: TextElement,
- [ElementTypes.SHAPE]: ShapeElement,
- [ElementTypes.LINE]: LineElement,
- [ElementTypes.CHART]: ChartElement,
- [ElementTypes.TABLE]: TableElement,
- [ElementTypes.LATEX]: LatexElement,
- [ElementTypes.VIDEO]: VideoElement,
- [ElementTypes.AUDIO]: AudioElement,
- [ElementTypes.FRAME]: FrameElement,
- }
- return elementTypeMap[props.elementInfo.type] || null
- })
- const { orderElement } = useOrderElement()
- const { alignElementToCanvas } = useAlignElementToCanvas()
- const { combineElements, uncombineElements } = useCombineElement()
- const { deleteElement } = useDeleteElement()
- const { lockElement, unlockElement } = useLockElement()
- const { copyElement, pasteElement, cutElement } = useCopyAndPasteElement()
- const { selectAllElements } = useSelectElement()
- const contextmenus = (): ContextmenuItem[] => {
- if (props.elementInfo.lock) {
- return [{
- text: lang.ssUnlock,
- handler: () => unlockElement(props.elementInfo),
- }]
- }
- const baseMenu = [
- {
- text: lang.ssCut,
- subText: 'Ctrl + X',
- handler: cutElement,
- },
- {
- text: lang.ssCopy,
- subText: 'Ctrl + C',
- handler: copyElement,
- },
- {
- text: lang.ssPaste,
- subText: 'Ctrl + V',
- handler: pasteElement,
- },
- { divider: true },
- {
- text: lang.ssAlignHCenter,
- handler: () => alignElementToCanvas(ElementAlignCommands.HORIZONTAL),
- children: [
- { text: lang.ssAlignHVCenter, handler: () => alignElementToCanvas(ElementAlignCommands.CENTER), },
- { text: lang.ssAlignHCenter, handler: () => alignElementToCanvas(ElementAlignCommands.HORIZONTAL) },
- { text: lang.ssAlignLeft, handler: () => alignElementToCanvas(ElementAlignCommands.LEFT) },
- { text: lang.ssAlignRight, handler: () => alignElementToCanvas(ElementAlignCommands.RIGHT) },
- ],
- },
- {
- text: lang.ssAlignVCenter,
- handler: () => alignElementToCanvas(ElementAlignCommands.VERTICAL),
- children: [
- { text: lang.ssAlignHVCenter, handler: () => alignElementToCanvas(ElementAlignCommands.CENTER) },
- { text: lang.ssAlignVCenter, handler: () => alignElementToCanvas(ElementAlignCommands.VERTICAL) },
- { text: lang.ssAlignTop, handler: () => alignElementToCanvas(ElementAlignCommands.TOP) },
- { text: lang.ssAlignBottom, handler: () => alignElementToCanvas(ElementAlignCommands.BOTTOM) },
- ],
- },
- { divider: true },
- {
- text: lang.ssBringFront,
- disable: props.isMultiSelect && !props.elementInfo.groupId,
- handler: () => orderElement(props.elementInfo, ElementOrderCommands.TOP),
- children: [
- { text: lang.ssBringFront, handler: () => orderElement(props.elementInfo, ElementOrderCommands.TOP) },
- { text: lang.ssBringForward, handler: () => orderElement(props.elementInfo, ElementOrderCommands.UP) },
- ],
- },
- {
- text: lang.ssSendBack,
- disable: props.isMultiSelect && !props.elementInfo.groupId,
- handler: () => orderElement(props.elementInfo, ElementOrderCommands.BOTTOM),
- children: [
- { text: lang.ssSendBack, handler: () => orderElement(props.elementInfo, ElementOrderCommands.BOTTOM) },
- { text: lang.ssSendBackward, handler: () => orderElement(props.elementInfo, ElementOrderCommands.DOWN) },
- ],
- },
- { divider: true },
- {
- text: lang.ssSetLink,
- handler: props.openLinkDialog,
- },
- {
- text: props.elementInfo.groupId ? lang.ssUngroupEl : lang.ssGroupEl,
- subText: 'Ctrl + G',
- handler: props.elementInfo.groupId ? uncombineElements : combineElements,
- hide: !props.isMultiSelect,
- },
- {
- text: lang.ssSelectAll,
- subText: 'Ctrl + A',
- handler: selectAllElements,
- },
- {
- text: lang.ssLock,
- subText: 'Ctrl + L',
- handler: lockElement,
- },
- {
- text: lang.ssDelete,
- subText: 'Delete',
- handler: deleteElement,
- },
- ]
- // 为网页元素添加特殊菜单项
- if (props.elementInfo.type === ElementTypes.FRAME) {
- const frameMenu = [
- {
- text: lang.ssOpenNewWin,
- handler: () => {
- const frameElement = props.elementInfo as any
- if (frameElement.url) {
- window.open(frameElement.url, '_blank')
- }
- },
- },
- {
- text: lang.ssCopyLink,
- handler: () => {
- const frameElement = props.elementInfo as any
- if (frameElement.url) {
- navigator.clipboard.writeText(frameElement.url)
- }
- },
- },
- { divider: true },
- ]
- // 为网页元素过滤掉"设置链接"功能
- const filteredBaseMenu = baseMenu.filter(item => item.text !== lang.ssSetLink)
- return [...frameMenu, ...filteredBaseMenu]
- }
- return baseMenu
- }
- </script>
|