From 489eadb352123bd220029b098e5f80fb72c4e9c8 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Tue, 11 Jan 2022 23:39:41 +0100 Subject: [PATCH] Fix IME input after tab (#1584) * Avoid initial call of mirror-dom * Disable updateFocus from OldEditorAdapter * fixes IME input duplication bug * Fix saving of latestLocation for ContentEditable * Fix IME after calling placeCaretAfterContent * Export other libraries from domlib/index.ts * Remove dead code + Uncomment code which was mistakenly left commmented --- ts/domlib/index.ts | 6 +- ts/editable/ContentEditable.svelte | 4 +- ts/editable/content-editable.ts | 50 ++++++++---- ts/editor/OldEditorAdapter.svelte | 11 +-- ts/editor/RichTextInput.svelte | 1 - .../mathjax-overlay/MathjaxHandle.svelte | 3 +- ts/sveltelib/mirror-dom.ts | 77 ++++++++++--------- ts/sveltelib/node-store.ts | 11 +-- ts/sveltelib/store-subscribe.ts | 4 +- 9 files changed, 90 insertions(+), 77 deletions(-) diff --git a/ts/domlib/index.ts b/ts/domlib/index.ts index b530593ab..4808c7ce5 100644 --- a/ts/domlib/index.ts +++ b/ts/domlib/index.ts @@ -1,5 +1,7 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -export * as location from "./location"; -export * as surround from "./surround"; +export * from "./location"; +export * from "./surround"; +export * from "./move-nodes"; +export * from "./place-caret"; diff --git a/ts/editable/ContentEditable.svelte b/ts/editable/ContentEditable.svelte index 3a4b39415..d1a6bb02b 100644 --- a/ts/editable/ContentEditable.svelte +++ b/ts/editable/ContentEditable.svelte @@ -12,7 +12,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import actionList from "../sveltelib/action-list"; import contentEditableAPI, { saveLocation, - prepareFocusHandling, + initialFocusHandling, preventBuiltinContentEditableShortcuts, } from "./content-editable"; import type { ContentEditableAPI } from "./content-editable"; @@ -40,7 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html contenteditable="true" use:resolve use:saveLocation - use:prepareFocusHandling + use:initialFocusHandling use:preventBuiltinContentEditableShortcuts use:mirrorAction={mirrorOptions} use:managerAction={{}} diff --git a/ts/editable/content-editable.ts b/ts/editable/content-editable.ts index 6c755aa9b..3f2582bb7 100644 --- a/ts/editable/content-editable.ts +++ b/ts/editable/content-editable.ts @@ -17,30 +17,42 @@ function flushLocation(): void { } } -let latestLocation: SelectionLocation | null = null; +function safePlaceCaretAfterContent(editable: HTMLElement): void { + /** + * Workaround: If you try to invoke an IME after calling + * `placeCaretAfterContent` on a cE element, the IME will immediately + * end and the input character will be duplicated + */ + placeCaretAfterContent(editable); + restoreSelection(editable, saveSelection(editable)!); +} -function onFocus(this: HTMLElement): void { - if (!latestLocation) { - placeCaretAfterContent(this); - return; - } +function onFocus(location: SelectionLocation | null): () => void { + return function (this: HTMLElement): void { + if (!location) { + safePlaceCaretAfterContent(this); + return; + } - try { - restoreSelection(this, latestLocation); - } catch { - placeCaretAfterContent(this); - } + try { + restoreSelection(this, location); + } catch { + safePlaceCaretAfterContent(this); + } + }; } function onBlur(this: HTMLElement): void { - prepareFocusHandling(this); - latestLocation = saveSelection(this); + prepareFocusHandling(this, saveSelection(this)); } -let removeOnFocus: () => void; - -export function prepareFocusHandling(editable: HTMLElement): void { - removeOnFocus = on(editable, "focus", onFocus, { once: true }); +function prepareFocusHandling( + editable: HTMLElement, + latestLocation: SelectionLocation | null = null, +): void { + const removeOnFocus = on(editable, "focus", onFocus(latestLocation), { + once: true, + }); locationEvents.push( removeOnFocus, @@ -48,6 +60,10 @@ export function prepareFocusHandling(editable: HTMLElement): void { ); } +export function initialFocusHandling(editable: HTMLElement): void { + prepareFocusHandling(editable); +} + /* Must execute before DOMMirror */ export function saveLocation(editable: HTMLElement): { destroy(): void } { const removeOnBlur = on(editable, "blur", onBlur); diff --git a/ts/editor/OldEditorAdapter.svelte b/ts/editor/OldEditorAdapter.svelte index fd88db316..dae07472e 100644 --- a/ts/editor/OldEditorAdapter.svelte +++ b/ts/editor/OldEditorAdapter.svelte @@ -8,7 +8,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import type { PlainTextInputAPI } from "./PlainTextInput.svelte"; import type { EditorToolbarAPI } from "./EditorToolbar.svelte"; - import { registerShortcut } from "../lib/shortcuts"; import contextProperty from "../sveltelib/context-property"; import { writable, get } from "svelte/store"; @@ -27,15 +26,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const activeInput = writable(null); const currentField = writable(null); - - function updateFocus() { - get(activeInput)?.moveCaretToEnd(); - } - - registerShortcut( - () => document.addEventListener("focusin", updateFocus, { once: true }), - "Shift?+Tab", - );