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
This commit is contained in:
Hikaru Y 2023-06-14 08:38:06 +09:00 committed by GitHub
parent f6fdf64c5d
commit 7164723a7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 20 deletions

View file

@ -511,6 +511,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
collapsed = [fld["collapsed"] for fld in flds] collapsed = [fld["collapsed"] for fld in flds]
plain_texts = [fld.get("plainText", False) for fld in flds] plain_texts = [fld.get("plainText", False) for fld in flds]
descriptions = [fld.get("description", "") 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() self.widget.show()
@ -533,7 +534,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
js = f""" js = f"""
saveSession(); saveSession();
setFields({json.dumps(data)}); setFields({json.dumps(data)});
setNotetypeId({json.dumps(self.note.mid)}); setNotetypeMeta({json.dumps(notetype_meta)});
setCollapsed({json.dumps(collapsed)}); setCollapsed({json.dumps(collapsed)});
setPlainTexts({json.dumps(plain_texts)}); setPlainTexts({json.dumps(plain_texts)});
setDescriptions({json.dumps(descriptions)}); setDescriptions({json.dumps(descriptions)});

View file

@ -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 RichTextInput, { editingInputIsRichText } from "./rich-text-input";
import RichTextBadge from "./RichTextBadge.svelte"; import RichTextBadge from "./RichTextBadge.svelte";
import SymbolsOverlay from "./symbols-overlay"; import SymbolsOverlay from "./symbols-overlay";
import type { SessionOptions } from "./types"; import type { NotetypeIdAndModTime, SessionOptions } from "./types";
function quoteFontFamily(fontFamily: string): string { function quoteFontFamily(fontFamily: string): string {
// generic families (e.g. sans-serif) must not be quoted // 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 = {}; const sessionOptions: SessionOptions = {};
export function saveSession(): void { export function saveSession(): void {
if (notetypeId) { if (notetypeMeta) {
sessionOptions[notetypeId] = { sessionOptions[notetypeMeta.id] = {
fieldsCollapsed, fieldsCollapsed,
fieldStates: { fieldStates: {
richTextsHidden, richTextsHidden,
plainTextsHidden, plainTextsHidden,
plainTextDefaults, 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[] = []; let fieldsCollapsed: boolean[] = [];
export function setCollapsed(defaultCollapsed: boolean[]): void { export function setCollapsed(defaultCollapsed: boolean[]): void {
fieldsCollapsed = fieldsCollapsed =
sessionOptions[notetypeId!]?.fieldsCollapsed ?? defaultCollapsed; sessionOptions[notetypeMeta?.id]?.fieldsCollapsed ?? defaultCollapsed;
} }
let richTextsHidden: boolean[] = []; let richTextsHidden: boolean[] = [];
@ -140,7 +141,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let plainTextDefaults: boolean[] = []; let plainTextDefaults: boolean[] = [];
export function setPlainTexts(defaultPlainTexts: boolean[]): void { export function setPlainTexts(defaultPlainTexts: boolean[]): void {
const states = sessionOptions[notetypeId!]?.fieldStates; const states = sessionOptions[notetypeMeta?.id]?.fieldStates;
if (states) { if (states) {
richTextsHidden = states.richTextsHidden; richTextsHidden = states.richTextsHidden;
plainTextsHidden = states.plainTextsHidden; plainTextsHidden = states.plainTextsHidden;
@ -223,9 +224,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
noteId = ntid; noteId = ntid;
} }
let notetypeId: number | null = null; let notetypeMeta: NotetypeIdAndModTime;
export function setNotetypeId(mid: number): void { function setNotetypeMeta({ id, modTime }: NotetypeIdAndModTime): void {
notetypeId = mid; 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; let insertSymbols = false;
@ -405,7 +410,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
focusIfField, focusIfField,
getNoteId, getNoteId,
setNoteId, setNoteId,
setNotetypeId, setNotetypeMeta,
wrap, wrap,
setMathjaxEnabled, setMathjaxEnabled,
setInsertSymbolsEnabled, setInsertSymbolsEnabled,

View file

@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import * as tr from "@tslib/ftl"; import * as tr from "@tslib/ftl";
import { getPlatformString, registerShortcut } from "@tslib/shortcuts"; import { getPlatformString, registerShortcut } from "@tslib/shortcuts";
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onDestroy } from "svelte";
import Badge from "../components/Badge.svelte"; import Badge from "../components/Badge.svelte";
import { context as editorFieldContext } from "./EditorField.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"); dispatch("toggle");
} }
function shortcut(target: HTMLElement): () => void { let unregister: ReturnType<typeof registerShortcut> | undefined;
return registerShortcut(toggle, keyCombination, { target });
}
onMount(() => editorField.element.then(shortcut)); editorField.element.then((target) => {
unregister = registerShortcut(toggle, keyCombination, { target });
});
onDestroy(() => unregister?.());
</script> </script>
<span <span

View file

@ -5,7 +5,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import * as tr from "@tslib/ftl"; import * as tr from "@tslib/ftl";
import { getPlatformString, registerShortcut } from "@tslib/shortcuts"; import { getPlatformString, registerShortcut } from "@tslib/shortcuts";
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onDestroy } from "svelte";
import Badge from "../components/Badge.svelte"; import Badge from "../components/Badge.svelte";
import { context as editorFieldContext } from "./EditorField.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"); dispatch("toggle");
} }
function shortcut(target: HTMLElement): () => void { let unregister: ReturnType<typeof registerShortcut> | undefined;
return registerShortcut(toggle, keyCombination, { target });
}
onMount(() => editorField.element.then(shortcut)); editorField.element.then((target) => {
unregister = registerShortcut(toggle, keyCombination, { target });
});
onDestroy(() => unregister?.());
</script> </script>
<span <span

View file

@ -8,8 +8,14 @@ export type EditorOptions = {
plainTextsHidden: boolean[]; plainTextsHidden: boolean[];
plainTextDefaults: boolean[]; plainTextDefaults: boolean[];
}; };
modTimeOfNotetype: number;
}; };
export type SessionOptions = { export type SessionOptions = {
[key: number]: EditorOptions; [key: number]: EditorOptions;
}; };
export type NotetypeIdAndModTime = {
id: number;
modTime: number;
};