UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

74 lines 2.67 kB
import { Fragment } from '@atlaskit/editor-prosemirror/model'; /** * Narrows a full-list replacement to the minimal changed range. * * Compares the old root list node with the new replacement fragment * from both ends to find the first and last positions where they differ, * then returns only the changed subrange. * * This reduces the scope of `tr.replaceWith()` so that remote cursors * on unchanged items are preserved during collaborative editing. */ export function narrowReplacementRange(doc, rootListStart, rootListEnd, fragment, contentStartOffsets) { const oldNode = doc.nodeAt(rootListStart); const newNode = fragment.childCount === 1 ? fragment.firstChild : null; if (!oldNode || !newNode || newNode.type !== oldNode.type) { return { start: rootListStart, end: rootListEnd, fragment, adjustedContentStartOffsets: contentStartOffsets }; } const minChildCount = Math.min(oldNode.childCount, newNode.childCount); let commonPrefixChildren = 0; let prefixSize = 0; for (let i = 0; i < minChildCount; i++) { const oldChild = oldNode.child(i); const newChild = newNode.child(i); if (oldChild.eq(newChild)) { commonPrefixChildren++; prefixSize += oldChild.nodeSize; } else { break; } } let commonSuffixChildren = 0; let suffixSize = 0; for (let i = 0; i < minChildCount - commonPrefixChildren; i++) { const oldChild = oldNode.child(oldNode.childCount - 1 - i); const newChild = newNode.child(newNode.childCount - 1 - i); if (oldChild.eq(newChild)) { commonSuffixChildren++; suffixSize += oldChild.nodeSize; } else { break; } } const totalCommon = commonPrefixChildren + commonSuffixChildren; if (totalCommon >= oldNode.childCount && totalCommon >= newNode.childCount) { return { start: rootListStart, end: rootListStart, fragment: Fragment.empty, adjustedContentStartOffsets: contentStartOffsets }; } const narrowedStart = rootListStart + 1 + prefixSize; const narrowedEnd = rootListEnd - 1 - suffixSize; const changedChildStart = commonPrefixChildren; const changedChildEnd = newNode.childCount - commonSuffixChildren; const changedNodes = []; for (let i = changedChildStart; i < changedChildEnd; i++) { changedNodes.push(newNode.child(i)); } const narrowedFragment = Fragment.from(changedNodes); const prefixOffset = 1 + prefixSize; const adjustedContentStartOffsets = contentStartOffsets.map(offset => offset - prefixOffset); return { start: narrowedStart, end: narrowedEnd, fragment: narrowedFragment, adjustedContentStartOffsets }; }