mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
fix double saving of undo states
This commit is contained in:
parent
84de8aec3e
commit
becac6ade8
2 changed files with 35 additions and 10 deletions
|
@ -40,7 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
const key = Symbol("richText");
|
||||
const [context, setContextProperty] = contextProperty<RichTextInputAPI>(key);
|
||||
const [globalInputHandler, setupGlobalInputHandler] = useInputHandler();
|
||||
const [globalInputHandler, setupGlobalInputHandler] = useInputHandler( { handleUndo: false });
|
||||
const [lifecycle, instances, setupLifecycleHooks] =
|
||||
lifecycleHooks<RichTextInputAPI>();
|
||||
const apiStore = writable<SurroundedAPI | null>(null);
|
||||
|
@ -97,7 +97,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
const nodes = getNormalizingNodeStore();
|
||||
const [richTextPromise, resolve] = useRichTextResolve();
|
||||
const { mirror, preventResubscription } = useDOMMirror();
|
||||
const [inputHandler, setupInputHandler] = useInputHandler();
|
||||
const [inputHandler, setupInputHandler] = useInputHandler({ handleUndo: true });
|
||||
const [customStyles, stylesResolve] = promiseWithResolver<Record<string, any>>();
|
||||
|
||||
export function attachShadow(element: Element): void {
|
||||
|
|
|
@ -96,23 +96,37 @@ function getCaretPosition(element: Element) {
|
|||
* Prevents that too many event listeners are attached and allows for some
|
||||
* coordination between them.
|
||||
*/
|
||||
function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
||||
interface InputHandlerOptions {
|
||||
handleUndo: boolean;
|
||||
}
|
||||
function useInputHandler(
|
||||
options: InputHandlerOptions,
|
||||
): [InputHandlerAPI, SetupInputHandlerAction] {
|
||||
const beforeInput = new HandlerList<InputEventParams>();
|
||||
const insertText = new HandlerList<InsertTextParams>();
|
||||
const afterInput = new HandlerList<EventParams>();
|
||||
|
||||
const undoManager = new UndoManager();
|
||||
let hasSetupObserver = false;
|
||||
const config = {
|
||||
let undoManager: UndoManager | null = null;
|
||||
let isUndoing = false;
|
||||
|
||||
let observer: MutationObserver | null = null;
|
||||
const observerConfig = {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
};
|
||||
const observer = new MutationObserver(onMutation);
|
||||
let hasSetupObserver = false;
|
||||
|
||||
if (options.handleUndo){
|
||||
undoManager = new UndoManager();
|
||||
observer = new MutationObserver(onMutation);
|
||||
}
|
||||
|
||||
function onMutation(mutationsList: MutationRecord[]) {
|
||||
if(isUndoing) return;
|
||||
|
||||
const element = <Element> mutationsList[0].target;
|
||||
undoManager.register(element.innerHTML, getMaxOffset(element));
|
||||
undoManager!.register(element.innerHTML, getMaxOffset(element));
|
||||
}
|
||||
|
||||
async function onBeforeInput(this: Element, event: InputEvent): Promise<void> {
|
||||
|
@ -149,14 +163,17 @@ function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
|||
}
|
||||
|
||||
async function onInput(this: Element, event: Event): Promise<void> {
|
||||
await afterInput.dispatch({ event });
|
||||
|
||||
if (!undoManager) { return; }
|
||||
if (!hasSetupObserver) {
|
||||
observer.observe(this, config);
|
||||
observer!.observe(this, observerConfig);
|
||||
hasSetupObserver = true;
|
||||
}
|
||||
|
||||
const position = getCaretPosition(this);
|
||||
undoManager.register(this.innerHTML, position - 1);
|
||||
undoManager.clearRedoStack();
|
||||
await afterInput.dispatch({ event });
|
||||
}
|
||||
|
||||
const pointerDown = new HandlerList<{ event: PointerEvent }>();
|
||||
|
@ -186,11 +203,19 @@ function useInputHandler(): [InputHandlerAPI, SetupInputHandlerAction] {
|
|||
} else if (event.code === "Tab") {
|
||||
specialKey.dispatch({ event, action: "tab" });
|
||||
} else if ((event.ctrlKey || event.metaKey) && event.key == "z") {
|
||||
if (!undoManager) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
isUndoing = true;
|
||||
undoManager.undo(this);
|
||||
setTimeout(() => { isUndoing = false }); //reset the flag when the current execution stack is cleared
|
||||
} else if ((event.ctrlKey || event.metaKey) && event.key == "y") {
|
||||
if (!undoManager) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
isUndoing = true;
|
||||
undoManager.redo(this);
|
||||
setTimeout(() => { isUndoing = false }); //reset the flag when the current execution stack is cleared
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue