From 7164723a7afd464c500d25419e7c60c4b793bf2c Mon Sep 17 00:00:00 2001 From: Hikaru Y Date: Wed, 14 Jun 2023 08:38:06 +0900 Subject: [PATCH] Fix two issues that can cause editor fields to behave incorrectly (#2540) * Fix shortcut not being unregistered when Plain/RichTextBadge is detroyed This fixes an issue where, if the "Show HTML by default" option of fields located at the same position in two notetypes have different values, switching between those notetypes during an editor session would cause the keyboard shortcut (Ctrl+Shift+X) to no longer function correctly thereafter. * Don't restore fields' state if notetype has been modified This fixes an issue where editor fields behave incorrectly after opening the 'Fields' dialog and customizing the notetype. An example of incorrect behavior is that after adding a new field and closing the dialog, the added field would display both richtext input and plaintext input, regardless of the options. * Rename type, variable and function - Apply suggestions from code review - Also use optional chaining instead of non-null assertion --- qt/aqt/editor.py | 3 ++- ts/editor/NoteEditor.svelte | 23 ++++++++++++++--------- ts/editor/PlainTextBadge.svelte | 12 +++++++----- ts/editor/RichTextBadge.svelte | 12 +++++++----- ts/editor/types.ts | 6 ++++++ 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index c2d80e8af..3eed03c64 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -511,6 +511,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too collapsed = [fld["collapsed"] for fld in flds] plain_texts = [fld.get("plainText", False) for fld in flds] descriptions = [fld.get("description", "") for fld in flds] + notetype_meta = {"id": self.note.mid, "modTime": self.note.note_type()["mod"]} self.widget.show() @@ -533,7 +534,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too js = f""" saveSession(); setFields({json.dumps(data)}); - setNotetypeId({json.dumps(self.note.mid)}); + setNotetypeMeta({json.dumps(notetype_meta)}); setCollapsed({json.dumps(collapsed)}); setPlainTexts({json.dumps(plain_texts)}); setDescriptions({json.dumps(descriptions)}); diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index bcfc20928..2fdf9f069 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -67,7 +67,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import RichTextInput, { editingInputIsRichText } from "./rich-text-input"; import RichTextBadge from "./RichTextBadge.svelte"; import SymbolsOverlay from "./symbols-overlay"; - import type { SessionOptions } from "./types"; + import type { NotetypeIdAndModTime, SessionOptions } from "./types"; function quoteFontFamily(fontFamily: string): string { // generic families (e.g. sans-serif) must not be quoted @@ -82,14 +82,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html const sessionOptions: SessionOptions = {}; export function saveSession(): void { - if (notetypeId) { - sessionOptions[notetypeId] = { + if (notetypeMeta) { + sessionOptions[notetypeMeta.id] = { fieldsCollapsed, fieldStates: { richTextsHidden, plainTextsHidden, plainTextDefaults, }, + modTimeOfNotetype: notetypeMeta.modTime, }; } } @@ -132,7 +133,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html let fieldsCollapsed: boolean[] = []; export function setCollapsed(defaultCollapsed: boolean[]): void { fieldsCollapsed = - sessionOptions[notetypeId!]?.fieldsCollapsed ?? defaultCollapsed; + sessionOptions[notetypeMeta?.id]?.fieldsCollapsed ?? defaultCollapsed; } let richTextsHidden: boolean[] = []; @@ -140,7 +141,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html let plainTextDefaults: boolean[] = []; export function setPlainTexts(defaultPlainTexts: boolean[]): void { - const states = sessionOptions[notetypeId!]?.fieldStates; + const states = sessionOptions[notetypeMeta?.id]?.fieldStates; if (states) { richTextsHidden = states.richTextsHidden; plainTextsHidden = states.plainTextsHidden; @@ -223,9 +224,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html noteId = ntid; } - let notetypeId: number | null = null; - export function setNotetypeId(mid: number): void { - notetypeId = mid; + let notetypeMeta: NotetypeIdAndModTime; + function setNotetypeMeta({ id, modTime }: NotetypeIdAndModTime): void { + notetypeMeta = { id, modTime }; + // Discard the saved state of the fields if the notetype has been modified. + if (sessionOptions[id]?.modTimeOfNotetype !== modTime) { + delete sessionOptions[id]; + } } let insertSymbols = false; @@ -405,7 +410,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html focusIfField, getNoteId, setNoteId, - setNotetypeId, + setNotetypeMeta, wrap, setMathjaxEnabled, setInsertSymbolsEnabled, diff --git a/ts/editor/PlainTextBadge.svelte b/ts/editor/PlainTextBadge.svelte index 51b46aa50..5310a5b02 100644 --- a/ts/editor/PlainTextBadge.svelte +++ b/ts/editor/PlainTextBadge.svelte @@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import * as tr from "@tslib/ftl"; import { getPlatformString, registerShortcut } from "@tslib/shortcuts"; - import { createEventDispatcher, onMount } from "svelte"; + import { createEventDispatcher, onDestroy } from "svelte"; import Badge from "../components/Badge.svelte"; import { context as editorFieldContext } from "./EditorField.svelte"; @@ -24,11 +24,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html dispatch("toggle"); } - function shortcut(target: HTMLElement): () => void { - return registerShortcut(toggle, keyCombination, { target }); - } + let unregister: ReturnType | undefined; - onMount(() => editorField.element.then(shortcut)); + editorField.element.then((target) => { + unregister = registerShortcut(toggle, keyCombination, { target }); + }); + + onDestroy(() => unregister?.());