From 86569f51d3a32a7c148dbd6f06b5734a98836e68 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Mon, 24 Apr 2023 14:23:12 +0800 Subject: [PATCH] fix: paste and format element boundary error --- src/editor/core/cursor/CursorAgent.ts | 5 +- src/editor/core/range/RangeManager.ts | 6 + src/editor/utils/clipboard.ts | 2 +- src/editor/utils/element.ts | 207 +++++++++++++------------- 4 files changed, 114 insertions(+), 106 deletions(-) diff --git a/src/editor/core/cursor/CursorAgent.ts b/src/editor/core/cursor/CursorAgent.ts index d55cee9..7944ef5 100644 --- a/src/editor/core/cursor/CursorAgent.ts +++ b/src/editor/core/cursor/CursorAgent.ts @@ -76,8 +76,9 @@ export class CursorAgent { const pasteElementList = getElementListByHTML(htmlText, { innerWidth: this.draw.getOriginalInnerWidth() }) - if (~startIndex) { - // 如果是复制到虚拟元素里,则粘贴列表的虚拟元素需扁平化处理 + // 全选粘贴无需格式化上下文 + if (~startIndex && !rangeManager.getIsSelectAll()) { + // 如果是复制到虚拟元素里,则粘贴列表的虚拟元素需扁平化处理,避免产生新的虚拟元素 const anchorElement = elementList[startIndex] if (anchorElement?.titleId || anchorElement?.listId) { let start = 0 diff --git a/src/editor/core/range/RangeManager.ts b/src/editor/core/range/RangeManager.ts index b857333..932b9ea 100644 --- a/src/editor/core/range/RangeManager.ts +++ b/src/editor/core/range/RangeManager.ts @@ -154,6 +154,12 @@ export class RangeManager { return rangeElementList } + public getIsSelectAll() { + const elementList = this.draw.getElementList() + const { startIndex, endIndex } = this.range + return startIndex === 0 && elementList.length - 1 === endIndex + } + public getIsPointInRange(x: number, y: number): boolean { const { startIndex, endIndex } = this.range const positionList = this.position.getPositionList() diff --git a/src/editor/utils/clipboard.ts b/src/editor/utils/clipboard.ts index f999667..f03d907 100644 --- a/src/editor/utils/clipboard.ts +++ b/src/editor/utils/clipboard.ts @@ -353,7 +353,7 @@ export function getElementListByHTML(htmlText: string, options: IGetElementListB document.body.appendChild(clipboardDom) const deleteNodes: ChildNode[] = [] clipboardDom.childNodes.forEach(child => { - if (child.nodeType !== 1) { + if (child.nodeType !== 1 && !child.textContent?.trim()) { deleteNodes.push(child) } }) diff --git a/src/editor/utils/element.ts b/src/editor/utils/element.ts index f8b462a..de84f7a 100644 --- a/src/editor/utils/element.ts +++ b/src/editor/utils/element.ts @@ -40,7 +40,60 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme let i = 0 while (i < elementList.length) { let el = elementList[i] - if (el.type === ElementType.TABLE) { + // 优先处理虚拟元素 + if (el.type === ElementType.TITLE) { + // 移除父节点 + elementList.splice(i, 1) + // 格式化元素 + const valueList = el.valueList || [] + formatElementList(valueList, { + ...options, + isHandleFirstElement: false + }) + // 追加节点 + if (valueList.length) { + const titleId = getUUID() + const titleOptions = editorOptions.title + for (let v = 0; v < valueList.length; v++) { + const value = valueList[v] + value.titleId = titleId + value.level = el.level + // 文本型元素设置字体及加粗 + if (isTextLikeElement(value)) { + if (!value.size) { + value.size = titleOptions[titleSizeMapping[value.level!]] + } + if (value.bold === undefined) { + value.bold = true + } + } + elementList.splice(i, 0, value) + i++ + } + } + i-- + } else if (el.type === ElementType.LIST) { + // 移除父节点 + elementList.splice(i, 1) + // 格式化元素 + const valueList = el.valueList || [] + formatElementList(valueList, { + ...options + }) + // 追加节点 + if (valueList.length) { + const listId = getUUID() + for (let v = 0; v < valueList.length; v++) { + const value = valueList[v] + value.listId = listId + value.listType = el.listType + value.listStyle = el.listStyle + elementList.splice(i, 0, value) + i++ + } + } + i-- + } else if (el.type === ElementType.TABLE) { const tableId = getUUID() el.id = tableId if (el.trList) { @@ -107,58 +160,6 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme } } i-- - } else if (el.type === ElementType.TITLE) { - // 移除父节点 - elementList.splice(i, 1) - // 格式化元素 - const valueList = el.valueList || [] - formatElementList(valueList, { - ...options, - isHandleFirstElement: false - }) - // 追加节点 - if (valueList.length) { - const titleId = getUUID() - const titleOptions = editorOptions.title - for (let v = 0; v < valueList.length; v++) { - const value = valueList[v] - value.titleId = titleId - value.level = el.level - // 文本型元素设置字体及加粗 - if (isTextLikeElement(value)) { - if (!value.size) { - value.size = titleOptions[titleSizeMapping[value.level!]] - } - if (value.bold === undefined) { - value.bold = true - } - } - elementList.splice(i, 0, value) - i++ - } - } - i-- - } else if (el.type === ElementType.LIST) { - // 移除父节点 - elementList.splice(i, 1) - // 格式化元素 - const valueList = el.valueList || [] - formatElementList(valueList, { - ...options - }) - // 追加节点 - if (valueList.length) { - const listId = getUUID() - for (let v = 0; v < valueList.length; v++) { - const value = valueList[v] - value.listId = listId - value.listType = el.listType - value.listStyle = el.listStyle - elementList.splice(i, 0, value) - i++ - } - } - i-- } else if (el.type === ElementType.CONTROL) { const { prefix, postfix, value, placeholder, code, type, valueSets } = el.control! const controlId = getUUID() @@ -359,8 +360,56 @@ export function zipElementList(payload: IElement[]): IElement[] { e++ continue } - // 表格、超链接、日期、控件特殊处理 - if (element.type === ElementType.TABLE) { + // 优先处理虚拟元素,后表格、超链接、日期、控件特殊处理 + if (element.titleId && element.level) { + // 标题处理 + const titleId = element.titleId + const level = element.level + const titleElement: IElement = { + type: ElementType.TITLE, + value: '', + level + } + const valueList: IElement[] = [] + while (e < elementList.length) { + const titleE = elementList[e] + if (titleId !== titleE.titleId) { + e-- + break + } + delete titleE.level + valueList.push(titleE) + e++ + } + titleElement.valueList = zipElementList(valueList) + element = titleElement + } else if (element.listId && element.listType) { + // 列表处理 + const listId = element.listId + const listType = element.listType + const listStyle = element.listStyle + const listElement: IElement = { + type: ElementType.LIST, + value: '', + listId, + listType, + listStyle + } + const valueList: IElement[] = [] + while (e < elementList.length) { + const listE = elementList[e] + if (listId !== listE.listId) { + e-- + break + } + delete listE.listType + delete listE.listStyle + valueList.push(listE) + e++ + } + listElement.valueList = zipElementList(valueList) + element = listElement + } else if (element.type === ElementType.TABLE) { if (element.trList) { for (let t = 0; t < element.trList.length; t++) { const tr = element.trList[t] @@ -422,54 +471,6 @@ export function zipElementList(payload: IElement[]): IElement[] { } dateElement.valueList = zipElementList(valueList) element = dateElement - } else if (element.titleId && element.level) { - // 标题处理 - const titleId = element.titleId - const level = element.level - const titleElement: IElement = { - type: ElementType.TITLE, - value: '', - level - } - const valueList: IElement[] = [] - while (e < elementList.length) { - const titleE = elementList[e] - if (titleId !== titleE.titleId) { - e-- - break - } - delete titleE.level - valueList.push(titleE) - e++ - } - titleElement.valueList = zipElementList(valueList) - element = titleElement - } else if (element.listId && element.listType) { - // 列表处理 - const listId = element.listId - const listType = element.listType - const listStyle = element.listStyle - const listElement: IElement = { - type: ElementType.LIST, - value: '', - listId, - listType, - listStyle - } - const valueList: IElement[] = [] - while (e < elementList.length) { - const listE = elementList[e] - if (listId !== listE.listId) { - e-- - break - } - delete listE.listType - delete listE.listStyle - valueList.push(listE) - e++ - } - listElement.valueList = zipElementList(valueList) - element = listElement } else if (element.type === ElementType.CONTROL) { // 控件处理 const controlId = element.controlId