From a53806e24ac54e681b67bc5b812df92a263fa7b8 Mon Sep 17 00:00:00 2001 From: Hikaru Y Date: Mon, 23 Oct 2023 08:12:56 +0900 Subject: [PATCH] Indicate current occlusion type in pop-up menu (#2760) * Simplify handling of occlusion types in editor code - Unify updateIONoteInEditMode(), setOcclusionFieldInner() and setOcclusionField() into updateOcclusionsField() - Don't use `includeInactive` property of Shape class in editor code - Drop `isEditMode` + Update the occlusions field every time a mask or text is updated, not only in editing mode but also in adding mode, so that IO cards can be previewed correctly in the card layout screen * Indicate current occlusion type in pop-up menu https://forums.ankiweb.net/t/anki-23-10-beta-5-6/35677/46 * Fix a11y warnings in Toolbar.svelte * Drop `occludeInactive` parameter from `MaskEditorAPI.getShapes()` --- qt/aqt/addcards.py | 2 +- qt/aqt/editor.py | 1 - ts/editor/NoteEditor.svelte | 35 +---------- ts/image-occlusion/Toolbar.svelte | 83 +++++++++++---------------- ts/image-occlusion/shapes/base.ts | 8 +-- ts/image-occlusion/shapes/to-cloze.ts | 16 +++--- ts/image-occlusion/tools/api.ts | 4 +- 7 files changed, 51 insertions(+), 98 deletions(-) diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index 3ccc71731..5c97697f7 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -373,7 +373,7 @@ class AddCards(QMainWindow): self.ifCanClose(doClose) def add_io_note(self) -> None: - self.editor.web.eval("setOcclusionFieldInner()") + self.editor.web.eval("updateOcclusionsField();") self.add_current_note() self.editor.web.eval("resetIOImageLoaded()") diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index b706c324c..6711a822f 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -586,7 +586,6 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too setCloseHTMLTags({json.dumps(self.mw.col.get_config("closeHTMLTags", True))}); triggerChanges(); setIsImageOcclusion({json.dumps(self.current_notetype_is_image_occlusion())}); - setIsEditMode({json.dumps(self.editorMode != EditorMode.ADD_CARDS)}); """ if self.addMode: diff --git a/ts/editor/NoteEditor.svelte b/ts/editor/NoteEditor.svelte index da9e1938f..54eb0a268 100644 --- a/ts/editor/NoteEditor.svelte +++ b/ts/editor/NoteEditor.svelte @@ -245,11 +245,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html $ioMaskEditorVisible = val; } - let isEditMode = false; - function setIsEditMode(val: boolean) { - isEditMode = val; - } - let cols: ("dupe" | "")[] = []; export function setBackgrounds(cls: ("dupe" | "")[]): void { cols = cls; @@ -450,26 +445,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } globalThis.setImageField = setImageField; - // update cloze deletions and set occlusion fields, it call in saveNow to update cloze deletions - function updateIONoteInEditMode() { - if (isEditMode) { - const clozeNote = get(fieldStores[ioFields.occlusions]); - if (clozeNote.includes("oi=1")) { - setOcclusionField(true); - } else { - setOcclusionField(false); - } - } - } - - function setOcclusionFieldInner() { + function updateOcclusionsField(): void { if (isImageOcclusion) { const occlusionsData = exportShapesToClozeDeletions($hideAllGuessOne); fieldStores[ioFields.occlusions].set(occlusionsData.clozes); } } - // global for calling this method in desktop note editor - globalThis.setOcclusionFieldInner = setOcclusionFieldInner; // reset for new occlusion in add mode function resetIOImageLoaded() { @@ -482,14 +463,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } globalThis.resetIOImageLoaded = resetIOImageLoaded; - function setOcclusionField(occludeInactive: boolean) { - // set fields data for occlusion and image fields for io notes type - if (isImageOcclusion) { - const occlusionsData = exportShapesToClozeDeletions(occludeInactive); - fieldStores[ioFields.occlusions].set(occlusionsData.clozes); - } - } - /** hide occlusions and image */ function hideFieldInOcclusionType( index: number, @@ -583,10 +556,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html setCloseHTMLTags, triggerChanges, setIsImageOcclusion, - setIsEditMode, setupMaskEditor, - setOcclusionField, - setOcclusionFieldInner, + updateOcclusionsField, ...oldEditorAdapter, }); @@ -651,7 +622,7 @@ the AddCards dialog) should be implemented in the user of this component.
diff --git a/ts/image-occlusion/Toolbar.svelte b/ts/image-occlusion/Toolbar.svelte index 78aa93d09..8081e328b 100644 --- a/ts/image-occlusion/Toolbar.svelte +++ b/ts/image-occlusion/Toolbar.svelte @@ -2,7 +2,7 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> -
@@ -100,46 +95,36 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-
(showFloating = !showFloating)}> - (showFloating = false)} + (showFloating = false)} + > + (showFloating = !showFloating)} > - - {#if $hideAllGuessOne} - {@html mdiViewDashboard} - {:else} - {@html mdiSquare} - {/if} - + {@html $hideAllGuessOne ? mdiViewDashboard : mdiSquare} + - - { - $hideAllGuessOne = true; - setOcclusionFieldForDesktop(); - }} - > - {tr.notetypesHideAllGuessOne()} - - { - $hideAllGuessOne = false; - setOcclusionFieldForDesktop(); - }} - > - {tr.notetypesHideOneGuessOne()} - - - -
+ + changeOcclusionType("all")} + > + {tr.notetypesHideAllGuessOne()} + + changeOcclusionType("one")} + > + {tr.notetypesHideOneGuessOne()} + + +
diff --git a/ts/image-occlusion/shapes/base.ts b/ts/image-occlusion/shapes/base.ts index e93aacb46..92806a923 100644 --- a/ts/image-occlusion/shapes/base.ts +++ b/ts/image-occlusion/shapes/base.ts @@ -20,15 +20,14 @@ export class Shape { top: number; fill: string = SHAPE_MASK_COLOR; /** Whether occlusions from other cloze numbers should be shown on the - * question side. + * question side. Used only in reviewer code. */ - occludeInactive = false; + occludeInactive?: boolean; /* Cloze ordinal */ ordinal = 0; constructor( - { left = 0, top = 0, fill = SHAPE_MASK_COLOR, occludeInactive = false, ordinal = 0 }: ConstructorParams = - {}, + { left = 0, top = 0, fill = SHAPE_MASK_COLOR, occludeInactive, ordinal = 0 }: ConstructorParams = {}, ) { this.left = left; this.top = top; @@ -45,7 +44,6 @@ export class Shape { left: floatToDisplay(this.left), top: floatToDisplay(this.top), ...(this.fill === SHAPE_MASK_COLOR ? {} : { fill: this.fill }), - ...(this.occludeInactive ? { oi: "1" } : {}), }; } diff --git a/ts/image-occlusion/shapes/to-cloze.ts b/ts/image-occlusion/shapes/to-cloze.ts index 82c66986e..c2378021a 100644 --- a/ts/image-occlusion/shapes/to-cloze.ts +++ b/ts/image-occlusion/shapes/to-cloze.ts @@ -17,12 +17,12 @@ export function exportShapesToClozeDeletions(occludeInactive: boolean): { clozes: string; noteCount: number; } { - const shapes = baseShapesFromFabric(occludeInactive); + const shapes = baseShapesFromFabric(); let clozes = ""; let index = 0; shapes.forEach((shapeOrShapes) => { - clozes += shapeOrShapesToCloze(shapeOrShapes, index); + clozes += shapeOrShapesToCloze(shapeOrShapes, index, occludeInactive); if (!(shapeOrShapes instanceof Text)) { index++; } @@ -34,7 +34,7 @@ export function exportShapesToClozeDeletions(occludeInactive: boolean): { /** Gather all Fabric shapes, and convert them into BaseShapes or * BaseShape[]s. */ -export function baseShapesFromFabric(occludeInactive: boolean): ShapeOrShapes[] { +export function baseShapesFromFabric(): ShapeOrShapes[] { const canvas = globalThis.canvas as Canvas; makeMaskTransparent(canvas, false); const activeObject = canvas.getActiveObject(); @@ -53,7 +53,6 @@ export function baseShapesFromFabric(occludeInactive: boolean): ShapeOrShapes[] return fabricObjectToBaseShapeOrShapes( canvas, object, - occludeInactive, parent, ); }) @@ -64,7 +63,6 @@ export function baseShapesFromFabric(occludeInactive: boolean): ShapeOrShapes[] function fabricObjectToBaseShapeOrShapes( size: Size, object: FabricObject, - occludeInactive: boolean, parentObject?: FabricObject, ): ShapeOrShapes | null { let shape: Shape; @@ -91,14 +89,12 @@ function fabricObjectToBaseShapeOrShapes( return fabricObjectToBaseShapeOrShapes( size, child, - occludeInactive, object, ); }); default: return null; } - shape.occludeInactive = occludeInactive; if (parentObject) { const newPosition = fabric.util.transformPoint( { x: shape.left, y: shape.top }, @@ -117,6 +113,7 @@ function fabricObjectToBaseShapeOrShapes( function shapeOrShapesToCloze( shapeOrShapes: ShapeOrShapes, index: number, + occludeInactive: boolean, ): string { let text = ""; function addKeyValue(key: string, value: string) { @@ -127,7 +124,7 @@ function shapeOrShapesToCloze( let type: string; if (Array.isArray(shapeOrShapes)) { return shapeOrShapes - .map((shape) => shapeOrShapesToCloze(shape, index)) + .map((shape) => shapeOrShapesToCloze(shape, index, occludeInactive)) .join(""); } else if (shapeOrShapes instanceof Rectangle) { type = "rect"; @@ -144,6 +141,9 @@ function shapeOrShapesToCloze( for (const [key, value] of Object.entries(shapeOrShapes.toDataForCloze())) { addKeyValue(key, value); } + if (occludeInactive) { + addKeyValue("oi", "1"); + } let ordinal: number; if (type === "text") { diff --git a/ts/image-occlusion/tools/api.ts b/ts/image-occlusion/tools/api.ts index bc4905e48..737895f76 100644 --- a/ts/image-occlusion/tools/api.ts +++ b/ts/image-occlusion/tools/api.ts @@ -40,8 +40,8 @@ export class MaskEditorAPI { return { clozes, cardCount }; } - getShapes(occludeInactive: boolean): ShapeOrShapes[] { - return baseShapesFromFabric(occludeInactive); + getShapes(): ShapeOrShapes[] { + return baseShapesFromFabric(); } redraw(): void {