executeHandleInsertCharacter function
Implementation
void executeHandleInsertCharacter(String character, FluentDocument document) {
final node = getNodeAtCursor(document.eventHandler);
bool inserted = false;
bool needsForward = true;
if (node is Root) {
final newParagraph = Paragraph(
text: character,
textAlign: document.pendingTextAlign,
indent: document.pendingIndent,
styleName: document.pendingStyle.name,
);
// Apply style properties to fragments
final style = document.pendingStyle;
final firstFrag = newParagraph.fragments.first as Fragment;
firstFrag.fontFamily = style.fontFamily ?? document.pendingFontFamily;
firstFrag.fontSize = style.fontSize ?? document.pendingFontSize;
firstFrag.styles = List.from(style.styles ?? document.pendingStyles);
firstFrag.color = style.color ?? document.pendingColor;
firstFrag.highlightColor = style.highlightColor ?? document.pendingHighlightColor;
node.nodes.add(newParagraph);
document.cursor.moveTo(firstFrag.id, character.length);
inserted = true;
needsForward = false;
}
// HorizontalRule: behaves like block-level FluentImage. The character
// is inserted in a Paragraph before or after the HR.
if (node is HorizontalRule) {
final parent = findParent(document.content, node);
if (parent != null) {
final newFrag = FragmentOperations.createFragmentWithPendingStyles(document, character);
final offset = document.cursor.anchorOffset;
final wrapper = Paragraph(
textAlign: document.pendingTextAlign,
indent: document.pendingIndent,
styleName: document.pendingStyle.name,
)..fragments.add(newFrag);
final style = document.pendingStyle;
newFrag.fontFamily = style.fontFamily ?? document.pendingFontFamily;
newFrag.fontSize = style.fontSize ?? document.pendingFontSize;
newFrag.styles = List.from(style.styles ?? document.pendingStyles);
if (offset == 0) {
insertBefore(parent, node, wrapper);
} else {
insertAfter(parent, node, wrapper);
}
document.cursor.moveTo(newFrag.id, character.length);
document.updateContent();
return;
}
}
// Image: insert a new fragment before or after the image.
// If the image is inline (parent Paragraph/Link), insert a naked Fragment.
// If it's block-level (parent Root/ListItem/FluentCell/etc.), wrap the
// fragment in a Paragraph otherwise it won't be renderable.
if (node is FluentImage) {
final parent = findParent(document.content, node);
if (parent != null) {
final newFrag = FragmentOperations.createFragmentWithPendingStyles(document, character);
final offset = document.cursor.anchorOffset;
// Inline context: Paragraph or Link accept naked fragments
final isInlineContext = parent is Paragraph &&
parent is! FluentList && parent is! FluentTable && parent is! FluentRow;
if (isInlineContext) {
if (offset == 0) {
insertBefore(parent, node, newFrag);
document.updateContent();
return;
} else {
insertAfter(parent, node, newFrag);
}
} else {
// Block context: wrap in Paragraph
final wrapper = Paragraph(
textAlign: document.pendingTextAlign,
indent: document.pendingIndent,
styleName: document.pendingStyle.name,
)..fragments.add(newFrag);
// Apply style properties to the fragment
final style = document.pendingStyle;
newFrag.fontFamily = style.fontFamily ?? document.pendingFontFamily;
newFrag.fontSize = style.fontSize ?? document.pendingFontSize;
newFrag.styles = List.from(style.styles ?? document.pendingStyles);
if (offset == 0) {
insertBefore(parent, node, wrapper);
} else {
insertAfter(parent, node, wrapper);
}
}
document.cursor.moveTo(newFrag.id, character.length);
inserted = true;
needsForward = false; // cursor already positioned correctly
}
}
if (node is InlineContainerNode && node is! FluentImage) {
final result = getFragmentAtCursor(document.eventHandler);
if (result != null) {
final frag = result.fragment as Fragment;
final offset = result.offset;
if (_shouldApplyPendingFont(document, frag)) {
_insertWithPendingFont(document, character, frag, offset);
return;
}
inserted = insertCharacterInFragment(
character,
frag,
offset,
);
}
}
if (node is Fragment && node is! FluentImage && node is! HorizontalRule) {
final frag = node;
final offset = document.cursor.anchorOffset;
if (_shouldApplyPendingFont(document, frag)) {
_insertWithPendingFont(document, character, frag, offset);
return;
}
inserted = insertCharacterInFragment(
character,
frag,
offset,
);
}
if (inserted) {
if (needsForward) document.cursor.forward();
document.updateContent();
// Notify comment system of the text mutation.
final fragId = document.cursor.anchorId;
final frag = document.nodeById(fragId);
final parent = frag != null ? findParent(document.content, frag) : null;
if (parent is Paragraph) {
final globalOffset = document.getGlobalOffsetInParagraph(
parent.id,
fragId,
document.cursor.anchorOffset - character.length,
);
if (globalOffset != null) {
document.notifyTextMutation(parent.id, globalOffset, character.length);
}
}
}
}