diff --git a/src/editor/core/cursor/CursorAgent.ts b/src/editor/core/cursor/CursorAgent.ts index 93eeeab..0c76478 100644 --- a/src/editor/core/cursor/CursorAgent.ts +++ b/src/editor/core/cursor/CursorAgent.ts @@ -1,5 +1,5 @@ import { debounce } from '../../utils' -import { getElementListByClipboardHTML } from '../../utils/clipboard' +import { getElementListByHTML } from '../../utils/clipboard' import { Draw } from '../draw/Draw' import { CanvasEvent } from '../event/CanvasEvent' @@ -67,7 +67,7 @@ export class CursorAgent { } if (item.type === 'text/html' && isHTML) { item.getAsString(htmlText => { - const elementList = getElementListByClipboardHTML(htmlText) + const elementList = getElementListByHTML(htmlText) this.draw.insertElementList(elementList) }) } diff --git a/src/editor/core/event/CanvasEvent.ts b/src/editor/core/event/CanvasEvent.ts index 032283b..e27e378 100644 --- a/src/editor/core/event/CanvasEvent.ts +++ b/src/editor/core/event/CanvasEvent.ts @@ -6,7 +6,7 @@ import { MouseEventButton } from '../../dataset/enum/Event' import { KeyMap } from '../../dataset/enum/Keymap' import { IElement } from '../../interface/Element' import { ICurrentPosition } from '../../interface/Position' -import { writeTextByElementList } from '../../utils/clipboard' +import { writeElementList } from '../../utils/clipboard' import { Cursor } from '../cursor/Cursor' import { Draw } from '../draw/Draw' import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle' @@ -571,7 +571,7 @@ export class CanvasEvent { const { startIndex, endIndex } = this.range.getRange() const elementList = this.draw.getElementList() if (startIndex !== endIndex) { - writeTextByElementList(elementList.slice(startIndex + 1, endIndex + 1)) + writeElementList(elementList.slice(startIndex + 1, endIndex + 1)) let curIndex: number if (activeControl) { curIndex = this.control.cut() @@ -588,7 +588,7 @@ export class CanvasEvent { const { startIndex, endIndex } = this.range.getRange() const elementList = this.draw.getElementList() if (startIndex !== endIndex) { - writeTextByElementList(elementList.slice(startIndex + 1, endIndex + 1)) + writeElementList(elementList.slice(startIndex + 1, endIndex + 1)) } } diff --git a/src/editor/utils/clipboard.ts b/src/editor/utils/clipboard.ts index 856ac3f..687ee4b 100644 --- a/src/editor/utils/clipboard.ts +++ b/src/editor/utils/clipboard.ts @@ -1,48 +1,84 @@ import { IElement } from '..' -import { HORIZON_TAB, WRAP, ZERO } from '../dataset/constant/Common' +import { ZERO } from '../dataset/constant/Common' import { TEXTLIKE_ELEMENT_TYPE } from '../dataset/constant/Element' import { ElementType } from '../dataset/enum/Element' +import { zipElementList } from './element' -export function writeText(text: string) { - if (!text) return - window.navigator.clipboard.writeText(text.replaceAll(ZERO, `\n`)) +export function writeClipboardItem(text: string, html: string) { + if (!text || !html) return + const plainText = new Blob([text], { type: 'text/plain' }) + const htmlText = new Blob([html], { type: 'text/html' }) + // @ts-ignore + const item = new ClipboardItem({ + [plainText.type]: plainText, + [htmlText.type]: htmlText + }) + window.navigator.clipboard.write([item]) } -export function writeTextByElementList(elementList: IElement[]) { - let text = `` - function pickTextFromElement(payload: IElement[]) { +export function writeElementList(elementList: IElement[]) { + const clipboardDom: HTMLDivElement = document.createElement('div') + function buildDomFromElementList(payload: IElement[]) { for (let e = 0; e < payload.length; e++) { const element = payload[e] + // 构造表格 if (element.type === ElementType.TABLE) { - if (e !== 0) { - text += WRAP - } + const tableDom: HTMLTableElement = document.createElement('table') const trList = element.trList! for (let t = 0; t < trList.length; t++) { + const trDom = document.createElement('tr') const tr = trList[t] for (let d = 0; d < tr.tdList.length; d++) { + const tdDom = document.createElement('td') const td = tr.tdList[d] - // 排除td首个元素 - pickTextFromElement(td.value.slice(1, td.value.length)) - if (d !== tr.tdList.length - 1) { - // td之间加水平制表符 - text += HORIZON_TAB - } + tdDom.innerText = td.value[0].value + trDom.append(tdDom) } - // tr后加换行符 - text += WRAP + tableDom.append(trDom) } + clipboardDom.append(tableDom) + } else if (element.type === ElementType.HYPERLINK) { + const a = document.createElement('a') + a.innerText = element.valueList![0].value + if (element.url) { + a.href = element.url + } + clipboardDom.append(a) } else if (!element.type || TEXTLIKE_ELEMENT_TYPE.includes(element.type)) { - text += element.value + const span = document.createElement('span') + let text = '' + if (element.type === ElementType.CONTROL) { + text = element.control!.value?.[0]?.value || '' + } else { + text = element.value + } + if (!text) continue + span.innerText = text.replace(new RegExp(`${ZERO}`, 'g'), '\n') + if (element.color) { + span.style.color = element.color + } + if (element.bold) { + span.style.fontWeight = '600' + } + if (element.italic) { + span.style.fontStyle = 'italic' + } + if (element.size) { + span.style.fontSize = `${element.size}px` + } + clipboardDom.append(span) } } } - pickTextFromElement(elementList) - if (!text) return - writeText(text.replace(new RegExp(`^${ZERO}`), '')) + buildDomFromElementList(zipElementList(elementList)) + // 写入剪贴板 + const text = clipboardDom.innerText + const html = clipboardDom.innerHTML + if (!text || !html) return + writeClipboardItem(text, html) } -export function getElementListByClipboardHTML(htmlText: string): IElement[] { +export function getElementListByHTML(htmlText: string): IElement[] { const elementList: IElement[] = [] function findTextNode(dom: Element | Node) { if (dom.nodeType === 3) { @@ -61,14 +97,20 @@ export function getElementListByClipboardHTML(htmlText: string): IElement[] { const childNodes = dom.childNodes for (let n = 0; n < childNodes.length; n++) { const node = childNodes[n] - findTextNode(node) - // block - if (node.nodeType === 1 && n !== childNodes.length - 1) { - const display = window.getComputedStyle(node as Element).display - if (display === 'block') { - elementList.push({ - value: `\n` - }) + // br元素与display:block元素需换行 + if (node.nodeName === 'BR') { + elementList.push({ + value: '\n' + }) + } else { + findTextNode(node) + if (node.nodeType === 1 && n !== childNodes.length - 1) { + const display = window.getComputedStyle(node as Element).display + if (display === 'block') { + elementList.push({ + value: '\n' + }) + } } } }