diff --git a/packages/engine/src/change/paste.ts b/packages/engine/src/change/paste.ts index d4e40fa9..0dc15408 100644 --- a/packages/engine/src/change/paste.ts +++ b/packages/engine/src/change/paste.ts @@ -44,7 +44,6 @@ export default class Paste { const defaultStyle = this.getDefaultStyle(); const { inline } = this.engine; const nodeApi = this.engine.node; - // 第一轮预处理,主要处理 span 节点 $(fragment).traverse((node) => { // 跳过Card if (node.isCard() || fragment === node.fragment) { @@ -97,9 +96,32 @@ export default class Paste { if (nodeApi.isBlock(node, this.schema)) { this.engine.block.brToBlock(node); } + } else { + let text = node.text(); + if (/\s/.test(text)) { + text = text.replace(/\s/g, ' '); + node.text(text); + } + if (/\u200b/.test(text)) { + let isRemove = true; + const next = node.next(); + const prev = node.prev(); + const parent = node.parent(); + if (parent && nodeApi.isMark(parent, this.schema)) + isRemove = false; + else if (parent && nodeApi.isInline(parent, this.schema)) + isRemove = false; + else if (next && nodeApi.isInline(next, this.schema)) + isRemove = false; + else if (prev && nodeApi.isInline(prev, this.schema)) + isRemove = false; + if (isRemove) { + text = text.replace(/\u200b/g, ''); + node.text(text); + } + } } }); - // 第二轮处理 $(fragment).traverse((node) => { let parent = node.parent(); // 跳过已被删除的节点 @@ -228,7 +250,25 @@ export default class Paste { // 处理嵌套 let nodeParent = parent; + const handleBlock = (node: NodeInterface) => { + if ( + nodeParent && + !nodeParent.fragment && + nodeApi.isBlock(node, this.schema) && + nodeApi.isBlock(nodeParent, this.schema) && + !this.schema.isAllowIn(nodeParent.name, node.name) + ) { + const children = node.children(); + nodeApi.unwrap(node); + children.each((_, index) => { + handleBlock(children.eq(index)!); + }); + } + }; + handleBlock(node); + while ( + node.length > 0 && nodeParent && !nodeParent.fragment && nodeApi.isBlock(node, this.schema) && @@ -244,6 +284,7 @@ export default class Paste { // mark 相同的嵌套 nodeParent = parent; while ( + node.length > 0 && nodeParent && nodeApi.isMark(nodeParent, this.schema) && nodeApi.isMark(node, this.schema) diff --git a/packages/engine/src/node/index.ts b/packages/engine/src/node/index.ts index 413c6028..6c4e188e 100644 --- a/packages/engine/src/node/index.ts +++ b/packages/engine/src/node/index.ts @@ -854,6 +854,15 @@ class NodeModel implements NodeModelInterface { ) { childNode.append($('
')); } + if ( + this.editor.node.isBlock(childNode) && + childNode.children().length === 1 && + childNode.first()?.isText() && + this.isEmptyWithTrim(childNode) + ) { + childNode.html('
'); + } + this.removeSide(childNode); childNode = nextNode; } diff --git a/packages/engine/src/ot/producer.ts b/packages/engine/src/ot/producer.ts index 7da59e5a..20f61e05 100644 --- a/packages/engine/src/ot/producer.ts +++ b/packages/engine/src/ot/producer.ts @@ -207,7 +207,11 @@ class Producer extends EventEmitter2 { const oldPath = path.slice(); ops.forEach((op) => { - for (let p = 0; p < path!.length; p++) { + for ( + let p = 0; + p < path!.length && op.p.length < path!.length; + p++ + ) { if (('li' in op || 'ld' in op) && op.p.length === p + 1) { if (op.p[p] <= path![p]) { if ('li' in op) oldPath[p] = oldPath[p] - 1; diff --git a/packages/engine/src/ot/utils.ts b/packages/engine/src/ot/utils.ts index 1f73f482..26859412 100644 --- a/packages/engine/src/ot/utils.ts +++ b/packages/engine/src/ot/utils.ts @@ -143,12 +143,7 @@ export const isReverseOp = (op: Op, next: Op) => { // 节点增加和删除 if (insertOp.li && deleteNext.ld) { - return ( - isEqual(insertOp.li, deleteNext.ld) && - (isEqual(op.p, next.p) || - isReversePath(op.p, next.p) || - isReversePath(next.p, op.p)) - ); + return isEqual(insertOp.li, deleteNext.ld) && isEqual(op.p, next.p); } if (deleteOp.ld && insertNext.li) { @@ -202,6 +197,8 @@ export const updateIndex = ( export const opsSort = (ops: Op[]) => { ops.sort((op1, op2) => { let diff = 0; + if (isCursorOp(op1)) return 1; + if (isCursorOp(op2)) return -1; for (let p = 0; p < op1.p.length; p++) { const v1 = op1.p[p]; // od oi 最后一个参数是属性名称 @@ -234,8 +231,12 @@ export const opsSort = (ops: Op[]) => { return -1; } // 如果删除节点比增加的节点索引小,排在加入节点前面 - if (diff < 1 && 'ld' in op1 && 'li' in op2) return -1; - + if ('ld' in op1 && 'li' in op2) return -1; + if ('li' in op1 && 'ld' in op2) return 1; + if (diff < 1 && 'ld' in op1 && 'si' in op2) return 1; + if (diff > 0 && 'ld' in op1 && 'si' in op2) return -1; + if (diff < 1 && 'si' in op1 && 'ld' in op2) return 1; + if (diff > 0 && 'si' in op1 && 'ld' in op2) return -1; const isLi = 'li' in op1 && 'li' in op2; const isLd = 'ld' in op1 && 'ld' in op2; // 都是新增节点,越小排越前面 diff --git a/packages/engine/src/parser/index.ts b/packages/engine/src/parser/index.ts index 3ade3d08..6bb2e93b 100644 --- a/packages/engine/src/parser/index.ts +++ b/packages/engine/src/parser/index.ts @@ -126,6 +126,7 @@ class Parser implements ParserInterface { const { rule } = value; oldRules.push(rule); const { name, attributes, style } = value.node; + delete attributes['data-id']; const newNode = $(`<${name} />`); nodeApi.setAttributes(newNode, { ...attributes, @@ -285,7 +286,8 @@ class Parser implements ParserInterface { if ( parent && nodeApi.isBlock(parent, schema) && - parent.children().length === 1 + parent.children().length === 1 && + child.children().length === 0 ) { const newChild = $('
'); child.before(newChild);