🐛 Resolved a selection conflict issue during IME input method combination input

This commit is contained in:
2025-12-23 00:37:10 +08:00
parent c47f7de5b8
commit 1c14092068
3 changed files with 49 additions and 1 deletions

View File

@@ -6,6 +6,9 @@ import i18n from './i18n';
import router from './router';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import { registerDirectives } from './directives';
import {EditorView} from "@codemirror/view";
(EditorView as any).EDIT_CONTEXT = false;
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

View File

@@ -15,7 +15,7 @@ export function createCursorPositionExtension(documentId: number) {
constructor(private view: EditorView) {
const {debouncedFn, flush} = createDebounce(
() => this.saveCursorPosition(),
{delay: 400}
{delay: 1000}
);
this.debouncedSave = {fn: debouncedFn, flush};

View File

@@ -7,6 +7,14 @@ import { StateField, RangeSetBuilder, EditorState, Transaction } from "@codemirr
import { blockState } from "./state";
import { codeBlockEvent, USER_EVENTS } from "./annotation";
/**
* IME 输入状态追踪
*
* 注意CodeMirror 有 view.composing 和 view.compositionStarted 内置状态,
* 但 transactionFilter 中访问不到 view所以需要用全局变量追踪
*/
let isComposing = false;
/**
* 块开始装饰组件
*/
@@ -223,8 +231,16 @@ const preventFirstBlockFromBeingDeleted = EditorState.changeFilter.of((tr: any)
/**
* 防止选择在第一个块之前
* 使用 transactionFilter 来确保选择不会在第一个块之前
*
* IME在输入法组合输入期间compositionstart ~ compositionend
* 暂时禁用选区矫正,避免与 IME 选区管理冲突导致光标跳转
*/
const preventSelectionBeforeFirstBlock = EditorState.transactionFilter.of((tr: any) => {
// IME 组合输入期间不矫正选区
if (isComposing) {
return tr;
}
if (tr.annotation(codeBlockEvent)) {
return tr;
}
@@ -256,6 +272,34 @@ const preventSelectionBeforeFirstBlock = EditorState.transactionFilter.of((tr: a
return tr;
});
/**
* IME 输入监听器
* 监听 composition 事件更新 isComposing 状态,供 transactionFilter 使用
*/
const imeListener = ViewPlugin.fromClass(
class {
constructor(view: EditorView) {
view.dom.addEventListener('compositionstart', this.handleCompositionStart);
view.dom.addEventListener('compositionend', this.handleCompositionEnd);
}
handleCompositionStart = () => {
isComposing = true;
};
handleCompositionEnd = () => {
// 延迟重置状态,确保所有相关事务都已处理完毕
setTimeout(() => {
isComposing = false;
}, 0);
};
destroy() {
}
}
);
/**
* 获取块装饰扩展 - 简化选项
*/
@@ -271,6 +315,7 @@ export function getBlockDecorationExtensions(options: {
atomicNoteBlock,
preventFirstBlockFromBeingDeleted,
preventSelectionBeforeFirstBlock,
imeListener, // IME 状态监听器
];
if (showBackground) {