feat:paste with style
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -41,3 +41,53 @@ export function writeTextByElementList(elementList: IElement[]) {
|
||||
if (!text) return
|
||||
writeText(text.replace(new RegExp(`^${ZERO}`), ''))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user