@@ -3,42 +3,40 @@ import { VIRTUAL_ELEMENT_TYPE } from '../../../dataset/constant/Element'
|
|||||||
import { ElementType } from '../../../dataset/enum/Element'
|
import { ElementType } from '../../../dataset/enum/Element'
|
||||||
import { IElement } from '../../../interface/Element'
|
import { IElement } from '../../../interface/Element'
|
||||||
import { IPasteOption } from '../../../interface/Event'
|
import { IPasteOption } from '../../../interface/Event'
|
||||||
|
import { getClipboardData, removeClipboardData } from '../../../utils/clipboard'
|
||||||
import {
|
import {
|
||||||
formatElementContext,
|
formatElementContext,
|
||||||
getElementListByHTML
|
getElementListByHTML
|
||||||
} from '../../../utils/element'
|
} from '../../../utils/element'
|
||||||
import { CanvasEvent } from '../CanvasEvent'
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
export function pastHTML(host: CanvasEvent, htmlText: string) {
|
export function pasteElement(host: CanvasEvent, elementList: IElement[]) {
|
||||||
const draw = host.getDraw()
|
const draw = host.getDraw()
|
||||||
const isReadonly = draw.isReadonly()
|
const isReadonly = draw.isReadonly()
|
||||||
if (isReadonly) return
|
if (isReadonly) return
|
||||||
const rangeManager = draw.getRange()
|
const rangeManager = draw.getRange()
|
||||||
const { startIndex } = rangeManager.getRange()
|
const { startIndex } = rangeManager.getRange()
|
||||||
const elementList = draw.getElementList()
|
const originalElementList = draw.getElementList()
|
||||||
const pasteElementList = getElementListByHTML(htmlText, {
|
|
||||||
innerWidth: draw.getOriginalInnerWidth()
|
|
||||||
})
|
|
||||||
// 全选粘贴无需格式化上下文
|
// 全选粘贴无需格式化上下文
|
||||||
if (~startIndex && !rangeManager.getIsSelectAll()) {
|
if (~startIndex && !rangeManager.getIsSelectAll()) {
|
||||||
// 如果是复制到虚拟元素里,则粘贴列表的虚拟元素需扁平化处理,避免产生新的虚拟元素
|
// 如果是复制到虚拟元素里,则粘贴列表的虚拟元素需扁平化处理,避免产生新的虚拟元素
|
||||||
const anchorElement = elementList[startIndex]
|
const anchorElement = originalElementList[startIndex]
|
||||||
if (anchorElement?.titleId || anchorElement?.listId) {
|
if (anchorElement?.titleId || anchorElement?.listId) {
|
||||||
let start = 0
|
let start = 0
|
||||||
while (start < pasteElementList.length) {
|
while (start < elementList.length) {
|
||||||
const pasteElement = pasteElementList[start]
|
const pasteElement = elementList[start]
|
||||||
if (anchorElement.titleId && /^\n/.test(pasteElement.value)) {
|
if (anchorElement.titleId && /^\n/.test(pasteElement.value)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (VIRTUAL_ELEMENT_TYPE.includes(pasteElement.type!)) {
|
if (VIRTUAL_ELEMENT_TYPE.includes(pasteElement.type!)) {
|
||||||
pasteElementList.splice(start, 1)
|
elementList.splice(start, 1)
|
||||||
if (pasteElement.valueList) {
|
if (pasteElement.valueList) {
|
||||||
for (let v = 0; v < pasteElement.valueList.length; v++) {
|
for (let v = 0; v < pasteElement.valueList.length; v++) {
|
||||||
const element = pasteElement.valueList[v]
|
const element = pasteElement.valueList[v]
|
||||||
if (element.value === ZERO || element.value === '\n') {
|
if (element.value === ZERO || element.value === '\n') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pasteElementList.splice(start, 0, element)
|
elementList.splice(start, 0, element)
|
||||||
start++
|
start++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,11 +45,21 @@ export function pastHTML(host: CanvasEvent, htmlText: string) {
|
|||||||
start++
|
start++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
formatElementContext(elementList, pasteElementList, startIndex, {
|
formatElementContext(originalElementList, elementList, startIndex, {
|
||||||
isBreakWhenWrap: true
|
isBreakWhenWrap: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
draw.insertElementList(pasteElementList)
|
draw.insertElementList(elementList)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pasteHTML(host: CanvasEvent, htmlText: string) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
if (isReadonly) return
|
||||||
|
const elementList = getElementListByHTML(htmlText, {
|
||||||
|
innerWidth: draw.getOriginalInnerWidth()
|
||||||
|
})
|
||||||
|
pasteElement(host, elementList)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pasteImage(host: CanvasEvent, file: File | Blob) {
|
export function pasteImage(host: CanvasEvent, file: File | Blob) {
|
||||||
@@ -96,6 +104,14 @@ export function pasteByEvent(host: CanvasEvent, evt: ClipboardEvent) {
|
|||||||
paste(evt)
|
paste(evt)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 优先读取编辑器内部粘贴板数据
|
||||||
|
const clipboardText = clipboardData.getData('text')
|
||||||
|
const editorClipboardData = getClipboardData()
|
||||||
|
if (clipboardText === editorClipboardData?.text) {
|
||||||
|
pasteElement(host, editorClipboardData.elementList)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
removeClipboardData()
|
||||||
// 从粘贴板提取数据
|
// 从粘贴板提取数据
|
||||||
let isHTML = false
|
let isHTML = false
|
||||||
for (let i = 0; i < clipboardData.items.length; i++) {
|
for (let i = 0; i < clipboardData.items.length; i++) {
|
||||||
@@ -116,7 +132,7 @@ export function pasteByEvent(host: CanvasEvent, evt: ClipboardEvent) {
|
|||||||
}
|
}
|
||||||
if (item.type === 'text/html' && isHTML) {
|
if (item.type === 'text/html' && isHTML) {
|
||||||
item.getAsString(htmlText => {
|
item.getAsString(htmlText => {
|
||||||
pastHTML(host, htmlText)
|
pasteHTML(host, htmlText)
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -166,7 +182,7 @@ export async function pasteByApi(host: CanvasEvent, options?: IPasteOption) {
|
|||||||
const htmlTextBlob = await item.getType('text/html')
|
const htmlTextBlob = await item.getType('text/html')
|
||||||
const htmlText = await htmlTextBlob.text()
|
const htmlText = await htmlTextBlob.text()
|
||||||
if (htmlText) {
|
if (htmlText) {
|
||||||
pastHTML(host, htmlText)
|
pasteHTML(host, htmlText)
|
||||||
}
|
}
|
||||||
} else if (item.types.some(type => type.startsWith('image/'))) {
|
} else if (item.types.some(type => type.startsWith('image/'))) {
|
||||||
const type = item.types.find(type => type.startsWith('image/'))!
|
const type = item.types.find(type => type.startsWith('image/'))!
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export const EDITOR_COMPONENT = 'editor-component'
|
export const EDITOR_COMPONENT = 'editor-component'
|
||||||
export const EDITOR_PREFIX = 'ce'
|
export const EDITOR_PREFIX = 'ce'
|
||||||
|
export const EDITOR_CLIPBOARD = `${EDITOR_PREFIX}-clipboard`
|
||||||
|
|||||||
@@ -1,9 +1,38 @@
|
|||||||
import { IEditorOption, IElement } from '..'
|
import { IEditorOption, IElement } from '..'
|
||||||
|
import { EDITOR_CLIPBOARD } from '../dataset/constant/Editor'
|
||||||
import { DeepRequired } from '../interface/Common'
|
import { DeepRequired } from '../interface/Common'
|
||||||
import { createDomFromElementList } from './element'
|
import { createDomFromElementList, zipElementList } from './element'
|
||||||
|
|
||||||
export function writeClipboardItem(text: string, html: string) {
|
export interface IClipboardData {
|
||||||
if (!text || !html) return
|
text: string
|
||||||
|
elementList: IElement[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setClipboardData(data: IClipboardData) {
|
||||||
|
localStorage.setItem(
|
||||||
|
EDITOR_CLIPBOARD,
|
||||||
|
JSON.stringify({
|
||||||
|
text: data.text,
|
||||||
|
elementList: data.elementList
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClipboardData(): IClipboardData | null {
|
||||||
|
const clipboardText = localStorage.getItem(EDITOR_CLIPBOARD)
|
||||||
|
return clipboardText ? JSON.parse(clipboardText) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeClipboardData() {
|
||||||
|
localStorage.removeItem(EDITOR_CLIPBOARD)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function writeClipboardItem(
|
||||||
|
text: string,
|
||||||
|
html: string,
|
||||||
|
elementList: IElement[]
|
||||||
|
) {
|
||||||
|
if (!text && !html && !elementList.length) return
|
||||||
const plainText = new Blob([text], { type: 'text/plain' })
|
const plainText = new Blob([text], { type: 'text/plain' })
|
||||||
const htmlText = new Blob([html], { type: 'text/html' })
|
const htmlText = new Blob([html], { type: 'text/html' })
|
||||||
if (window.ClipboardItem) {
|
if (window.ClipboardItem) {
|
||||||
@@ -27,6 +56,8 @@ export function writeClipboardItem(text: string, html: string) {
|
|||||||
document.execCommand('copy')
|
document.execCommand('copy')
|
||||||
fakeElement.remove()
|
fakeElement.remove()
|
||||||
}
|
}
|
||||||
|
// 编辑器结构化数据
|
||||||
|
setClipboardData({ text, elementList })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writeElementList(
|
export function writeElementList(
|
||||||
@@ -40,6 +71,6 @@ export function writeElementList(
|
|||||||
// 先追加后移除,否则innerText无法解析换行符
|
// 先追加后移除,否则innerText无法解析换行符
|
||||||
clipboardDom.remove()
|
clipboardDom.remove()
|
||||||
const html = clipboardDom.innerHTML
|
const html = clipboardDom.innerHTML
|
||||||
if (!text || !html) return
|
if (!text && !html && !elementList.length) return
|
||||||
writeClipboardItem(text, html)
|
writeClipboardItem(text, html, zipElementList(elementList))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user