const adjustSteps:()

in packages/roosterjs-editor-dom/lib/edit/adjustInsertPosition.ts [22:96]


const adjustSteps: ((
    root: HTMLElement,
    nodeToInsert: Node,
    position: NodePosition,
    range: Range
) => NodePosition)[] = [
    adjustInsertPositionForHyperLink,
    adjustInsertPositionForStructuredNode,
    adjustInsertPositionForParagraph,
    adjustInsertPositionForVoidElement,
    adjustInsertPositionForMoveCursorOutOfALink,
];

/**
 * Adjust position for A tag don't be nested inside another A tag.
 */
function adjustInsertPositionForHyperLink(
    root: HTMLElement,
    nodeToInsert: Node,
    position: NodePosition,
    range: Range
): NodePosition {
    let blockElement = getBlockElementAtNode(root, position.node);

    if (blockElement) {
        // Find the first <A> tag within current block which covers current selection
        // If there are more than one nested, let's handle the first one only since that is not a common scenario.
        let anchor = queryElements(
            root,
            'a[href]',
            null /*forEachCallback*/,
            QueryScope.OnSelection,
            createRange(position)
        ).filter((a: HTMLElement) => blockElement.contains(a))[0];

        // If this is about to insert node to an empty A tag, clear the A tag and reset position
        if (anchor && isNodeEmpty(anchor)) {
            position = new Position(anchor, PositionType.Before);
            safeRemove(anchor);
            anchor = null;
        }

        // If this is about to insert nodes which contains A tag into another A tag, need to break current A tag
        // otherwise we will have nested A tags which is a wrong HTML structure
        if (
            anchor &&
            (<ParentNode>(nodeToInsert as HTMLElement))?.querySelector &&
            (<ParentNode>(nodeToInsert as HTMLElement))?.querySelector('a[href]')
        ) {
            let normalizedPosition = position.normalize();
            let parentNode = normalizedPosition.node.parentNode;
            let nextNode =
                normalizedPosition.node.nodeType == NodeType.Text
                    ? splitTextNode(
                          <Text>normalizedPosition.node,
                          normalizedPosition.offset,
                          false /*returnFirstPart*/
                      )
                    : normalizedPosition.isAtEnd
                    ? normalizedPosition.node.nextSibling
                    : normalizedPosition.node;
            let splitter: Node = root.ownerDocument.createTextNode('');
            parentNode.insertBefore(splitter, nextNode);

            while (contains(anchor, splitter)) {
                splitter = splitBalancedNodeRange(splitter);
            }

            position = new Position(splitter, PositionType.Before);
            safeRemove(splitter);
        }
    }

    return position;
}