From 5b18dda6b2be97c646285c4947147ff27f2d793e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Sun, 1 May 2022 20:23:08 +0800 Subject: [PATCH] feat:paste with style --- src/editor/core/command/CommandAdapt.ts | 31 +-------------- src/editor/core/cursor/CursorAgent.ts | 34 ++++++++++++++-- src/editor/core/draw/Draw.ts | 36 +++++++++++++++++ src/editor/utils/clipboard.ts | 52 ++++++++++++++++++++++++- 4 files changed, 119 insertions(+), 34 deletions(-) diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index 03dc0b3..ff877b7 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -1270,36 +1270,7 @@ export class CommandAdapt { if (!payload.length) return const isReadonly = this.draw.isReadonly() if (isReadonly) return - const activeControl = this.control.getActiveControl() - if (activeControl) return - const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside() - if (isPartRangeInControlOutside) return - const { startIndex, endIndex } = this.range.getRange() - if (!~startIndex && !~endIndex) return - // 格式化element - formatElementList(payload, { - isHandleFirstElement: false, - editorOptions: this.options - }) - const elementList = this.draw.getElementList() - const isCollapsed = startIndex === endIndex - const start = startIndex + 1 - if (!isCollapsed) { - elementList.splice(start, endIndex - startIndex) - } - const positionContext = this.position.getPositionContext() - for (let i = 0; i < payload.length; i++) { - const element = payload[i] - if (positionContext.isTable) { - element.tdId = positionContext.tdId - element.trId = positionContext.trId - element.tableId = positionContext.tableId - } - elementList.splice(start + i, 0, element) - } - const curIndex = startIndex + payload.length - this.range.setRange(curIndex, curIndex) - this.draw.render({ curIndex }) + this.draw.insertElementList(payload) } } \ No newline at end of file diff --git a/src/editor/core/cursor/CursorAgent.ts b/src/editor/core/cursor/CursorAgent.ts index aacf472..93eeeab 100644 --- a/src/editor/core/cursor/CursorAgent.ts +++ b/src/editor/core/cursor/CursorAgent.ts @@ -1,14 +1,17 @@ import { debounce } from '../../utils' +import { getElementListByClipboardHTML } from '../../utils/clipboard' import { Draw } from '../draw/Draw' import { CanvasEvent } from '../event/CanvasEvent' export class CursorAgent { + private draw: Draw private container: HTMLDivElement private agentCursorDom: HTMLTextAreaElement private canvasEvent: CanvasEvent constructor(draw: Draw, canvasEvent: CanvasEvent) { + this.draw = draw this.container = draw.getContainer() this.canvasEvent = canvasEvent // 代理光标绘制 @@ -40,9 +43,34 @@ export class CursorAgent { } private _paste(evt: ClipboardEvent) { - const text = evt.clipboardData?.getData('text') - if (text) { - this.canvasEvent.input(text) + const clipboardData = evt.clipboardData + if (!clipboardData) return + // 从粘贴板提取数据 + let isHTML = false + for (let i = 0; i < clipboardData.items.length; i++) { + const item = clipboardData.items[i] + if (item.type === 'text/html') { + isHTML = true + break + } + } + for (let i = 0; i < clipboardData.items.length; i++) { + const item = clipboardData.items[i] + if (item.kind !== 'string') continue + if (item.type === 'text/plain' && !isHTML) { + item.getAsString(plainText => { + const elementList = plainText.split('').map(value => ({ + value + })) + this.draw.insertElementList(elementList) + }) + } + if (item.type === 'text/html' && isHTML) { + item.getAsString(htmlText => { + const elementList = getElementListByClipboardHTML(htmlText) + this.draw.insertElementList(elementList) + }) + } } evt.preventDefault() } diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 099595a..746f439 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -40,6 +40,7 @@ import { zipElementList } from '../../utils/element' import { CheckboxParticle } from './particle/CheckboxParticle' import { DeepRequired } from '../../interface/Common' import { ControlComponent } from '../../dataset/enum/Control' +import { formatElementList } from '../../utils/element' export class Draw { @@ -285,6 +286,41 @@ export class Draw { return this.elementList } + public insertElementList(payload: IElement[]) { + if (!payload.length) return + const activeControl = this.control.getActiveControl() + if (activeControl) return + const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside() + if (isPartRangeInControlOutside) return + const { startIndex, endIndex } = this.range.getRange() + if (!~startIndex && !~endIndex) return + formatElementList(payload, { + isHandleFirstElement: false, + editorOptions: this.options + }) + const elementList = this.getElementList() + const isCollapsed = startIndex === endIndex + const start = startIndex + 1 + if (!isCollapsed) { + elementList.splice(start, endIndex - startIndex) + } + const positionContext = this.position.getPositionContext() + for (let i = 0; i < payload.length; i++) { + const element = payload[i] + if (positionContext.isTable) { + element.tdId = positionContext.tdId + element.trId = positionContext.trId + element.tableId = positionContext.tableId + } + elementList.splice(start + i, 0, element) + } + const curIndex = startIndex + payload.length + this.range.setRange(curIndex, curIndex) + this.render({ + curIndex + }) + } + public getOriginalElementList() { return this.elementList } diff --git a/src/editor/utils/clipboard.ts b/src/editor/utils/clipboard.ts index 9b4b815..856ac3f 100644 --- a/src/editor/utils/clipboard.ts +++ b/src/editor/utils/clipboard.ts @@ -40,4 +40,54 @@ export function writeTextByElementList(elementList: IElement[]) { pickTextFromElement(elementList) if (!text) return writeText(text.replace(new RegExp(`^${ZERO}`), '')) -} \ No newline at end of file +} + +export function getElementListByClipboardHTML(htmlText: string): IElement[] { + const elementList: IElement[] = [] + function findTextNode(dom: Element | Node) { + if (dom.nodeType === 3) { + const style = window.getComputedStyle(dom.parentNode as Element) + const value = dom.textContent + if (value) { + elementList.push({ + value, + color: style.color, + bold: Number(style.fontWeight) > 500, + italic: style.fontStyle.includes('italic'), + size: Math.floor(Number(style.fontSize.replace('px', ''))) + }) + } + } else if (dom.nodeType === 1) { + 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` + }) + } + } + } + } + } + // 追加dom + const clipboardDom = document.createElement('div') + clipboardDom.innerHTML = htmlText + document.body.appendChild(clipboardDom) + const deleteNodes: ChildNode[] = [] + clipboardDom.childNodes.forEach(child => { + if (child.nodeType !== 1) { + deleteNodes.push(child) + } + }) + deleteNodes.forEach(node => node.remove()) + // 搜索文本节点 + findTextNode(clipboardDom) + // 移除dom + clipboardDom.remove() + return elementList +}