Skip invisible caret anchors during navigation

This commit is contained in:
NineKey
2026-09-13 21:30:35 +08:00
parent 109445cf18
commit c823ae5693
+41 -21
View File
@@ -310,26 +310,13 @@ app.registerExtension({
} else if (container === composer) {
sibling = composer.childNodes[selection.focusOffset + (direction < 0 ? -1 : 0)];
}
while (sibling?.nodeType === Node.TEXT_NODE && !withoutCaretAnchors(sibling.nodeValue)) {
sibling = direction < 0 ? sibling.previousSibling : sibling.nextSibling;
}
if (sibling?.nodeType !== Node.ELEMENT_NODE) return null;
return sibling.classList.contains("dynamic-tag-chip") ? sibling : null;
};
const moveAcrossAdjacentChip = (direction) => {
const selected = node.inlineComposerSelectedChip;
const chip = selected || adjacentChip(direction);
if (!chip) return false;
const range = document.createRange();
if (direction < 0) range.setStartBefore(chip);
else range.setStartAfter(chip);
range.collapse(true);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
selected?.classList.remove("selected");
node.inlineComposerSelectedChip = null;
return true;
};
const caretTextFrom = root => {
let text = "";
const walk = parent => {
@@ -388,13 +375,46 @@ app.registerExtension({
return range;
};
const moveCaretVertically = direction => {
const selection = window.getSelection();
if (!selection?.rangeCount || !selection.isCollapsed || !composer.contains(selection.anchorNode)) return false;
const currentCaretOffset = selection => {
const before = selection.getRangeAt(0).cloneRange();
before.selectNodeContents(composer);
before.setEnd(selection.anchorNode, selection.anchorOffset);
const offset = caretTextFrom(before.cloneContents()).length;
return caretTextFrom(before.cloneContents()).length;
};
const moveCaretHorizontally = direction => {
const selection = window.getSelection();
if (!selection?.rangeCount || !selection.isCollapsed || !composer.contains(selection.anchorNode)) return false;
const focus = selection.anchorNode;
const isAnchor = current => current?.nodeType === Node.TEXT_NODE
&& current.nodeValue.includes(CARET_ANCHOR);
let nearChip = Boolean(node.inlineComposerSelectedChip) || isAnchor(focus);
if (focus === composer) {
nearChip ||= [focus.childNodes[selection.anchorOffset - 1], focus.childNodes[selection.anchorOffset]]
.some(current => isAnchor(current) || current?.classList?.contains("dynamic-tag-chip"));
} else if (focus?.nodeType === Node.TEXT_NODE) {
if (selection.anchorOffset === 0) nearChip ||= isAnchor(focus.previousSibling)
|| focus.previousSibling?.classList?.contains("dynamic-tag-chip");
if (selection.anchorOffset === focus.nodeValue.length) nearChip ||= isAnchor(focus.nextSibling)
|| focus.nextSibling?.classList?.contains("dynamic-tag-chip");
}
if (!nearChip) return false;
const offset = currentCaretOffset(selection);
const target = offset + direction;
const length = caretTextFrom(composer).length;
if (target < 0 || target > length) return false;
const range = rangeAtCaretOffset(target);
selection.removeAllRanges();
selection.addRange(range);
node.inlineComposerSelectedChip?.classList.remove("selected");
node.inlineComposerSelectedChip = null;
return true;
};
const moveCaretVertically = direction => {
const selection = window.getSelection();
if (!selection?.rangeCount || !selection.isCollapsed || !composer.contains(selection.anchorNode)) return false;
const offset = currentCaretOffset(selection);
const lines = caretTextFrom(composer).split("\n");
let line = 0;
let lineStart = 0;
@@ -755,7 +775,7 @@ app.registerExtension({
}
if (!event.shiftKey && !event.ctrlKey && !event.metaKey && !event.altKey
&& (event.key === "ArrowLeft" || event.key === "ArrowRight")
&& moveAcrossAdjacentChip(event.key === "ArrowLeft" ? -1 : 1)) {
&& moveCaretHorizontally(event.key === "ArrowLeft" ? -1 : 1)) {
event.preventDefault();
return;
}