Anki/ts/routes/image-occlusion/add-or-update-note.svelte.ts
jariji 33d1057a46 Add "hide all but one" occlusion mode.
This PR adds the "hide all but one" occlusion mode. An example use case
is a note containing a collection of pairs of selection, where each
selection is the prompt for the other in its pair.

For example, given a table like

| small | big |
|-------+-----|
|   a   |  A  |
|   b   |  B  |
|   c   |  C  |

in each card, five letters are occluded, and one is shown. The user is
prompted to state the occluded symbol that is adjacent to the shown symbol.
2025-11-04 01:03:09 +00:00

77 lines
2.6 KiB
TypeScript

// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { OpChanges } from "@generated/anki/collection_pb";
import { addImageOcclusionNote, updateImageOcclusionNote } from "@generated/backend";
import * as tr from "@generated/ftl";
import { get } from "svelte/store";
import { mount } from "svelte";
import type { IOAddingMode, IOMode } from "./lib";
import { exportShapesToClozeDeletions } from "./shapes/to-cloze";
import { notesDataStore, OcclusionMode, tagsWritable } from "./store";
import Toast from "./Toast.svelte";
export const addOrUpdateNote = async function(
mode: IOMode,
occlusionMode: OcclusionMode,
): Promise<void> {
const { clozes: occlusionCloze, noteCount } = exportShapesToClozeDeletions(occlusionMode);
if (noteCount === 0) {
return;
}
const fieldsData: { id: string; title: string; divValue: string; textareaValue: string }[] = get(notesDataStore);
const tags = get(tagsWritable);
let header = fieldsData[0].textareaValue;
let backExtra = fieldsData[1].textareaValue;
header = header ? `<div>${header}</div>` : "";
backExtra = backExtra ? `<div>${backExtra}</div>` : "";
if (mode.kind == "edit") {
const result = await updateImageOcclusionNote({
noteId: BigInt(mode.noteId),
occlusions: occlusionCloze,
header,
backExtra,
tags,
});
showResult(mode.noteId, result, noteCount);
} else {
const result = await addImageOcclusionNote({
// IOCloningMode is not used on mobile
notetypeId: BigInt((<IOAddingMode> mode).notetypeId),
imagePath: (<IOAddingMode> mode).imagePath,
occlusions: occlusionCloze,
header,
backExtra,
tags,
});
showResult(null, result, noteCount);
}
};
// show toast message
const showResult = (noteId: number | null, result: OpChanges, count: number) => {
const props = $state({
message: "",
type: "error" as "error" | "success",
showToast: true,
});
mount(Toast, {
target: document.body,
props,
});
if (result.note) {
const msg = noteId ? tr.browsingCardsUpdated({ count: count }) : tr.importingCardsAdded({ count: count });
props.message = msg;
props.type = "success";
props.showToast = true;
} else {
const msg = tr.notetypesErrorGeneratingCloze();
props.message = msg;
props.showToast = true;
}
};