Skip to content

Commit b4aa23e

Browse files
committed
implement text cloze and show toast after cloze generation
1 parent 9dc7587 commit b4aa23e

File tree

6 files changed

+114
-5
lines changed

6 files changed

+114
-5
lines changed

ftl/core/editing.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ editing-hide-all-guess-one = Hide All, Guess One
7878
editing-hide-one-guess-one = Hide One, Guess One
7979
editing-question-mask-color = Question Mask Color
8080
editing-answer-mask-color = Answer Mask Color
81+
editing-error-generating-cloze = Error occurred in generating image cloze
8182
8283
## Image Occlusion notes editing
8384

rslib/src/image_occlusion/io_back_template.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@
2727

2828
if (cloze.children.length) {
2929
if (cloze.children[0].className.includes("cloze-inactive")) {
30-
draw(shape, qColor);
30+
draw(shape, qColor, aColor);
31+
}
32+
if (shape == "i-text" && cloze.children[0].className == "cloze") {
33+
draw(shape, aColor, aColor);
3134
}
3235
}
3336
}
3437
}
3538

36-
function draw(shape, color) {
39+
function draw(shape, color, aColor) {
3740
ctx.fillStyle = color;
3841

3942
switch (shape) {
@@ -83,6 +86,15 @@
8386
ctx.closePath();
8487
ctx.fill();
8588
break;
89+
90+
case "i-text":
91+
ctx.font = `${cloze.dataset.fontSize}px ${cloze.dataset.fontFamily}`;
92+
if (aColor === color) {
93+
ctx.fillText(cloze.dataset.text, cloze.dataset.left, cloze.dataset.top);
94+
} else {
95+
ctx.fillText("[...]", cloze.dataset.left, cloze.dataset.top);
96+
}
97+
break;
8698
}
8799
}
88100
</script>

rslib/src/image_occlusion/io_front_template.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@
8383
ctx.closePath();
8484
ctx.fill();
8585
break;
86+
87+
case "i-text":
88+
ctx.font = `${cloze.dataset.fontSize}px ${cloze.dataset.fontFamily}`;
89+
ctx.fillText("[...]", cloze.dataset.left, cloze.dataset.top);
90+
break;
8691
}
8792
}
8893
</script>

ts/image-occlusion/Toast.svelte

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script lang="ts">
2+
import IconButton from "../components/IconButton.svelte";
3+
import { mdiClose } from "./icons";
4+
5+
export let type: "success" | "error" = "success";
6+
export let message;
7+
export let showToast = false;
8+
9+
const closeToast = () => {
10+
showToast = false;
11+
};
12+
</script>
13+
14+
{#if showToast}
15+
<div class="toast-container">
16+
<div class="toast {type === 'success' ? 'success' : 'error'}">
17+
{message}
18+
<IconButton iconSize={96} on:click={closeToast} class="toast-icon">
19+
{@html mdiClose}</IconButton
20+
>
21+
</div>
22+
</div>
23+
{/if}
24+
25+
<style>
26+
.toast-container {
27+
position: fixed;
28+
bottom: 3rem;
29+
z-index: 100;
30+
width: 100%;
31+
text-align: center;
32+
display: flex;
33+
justify-content: center;
34+
}
35+
36+
.toast {
37+
display: flex;
38+
align-items: center;
39+
padding: 1rem;
40+
background-color: #fff;
41+
border-radius: 0.5rem;
42+
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1);
43+
width: 60%;
44+
justify-content: space-between;
45+
}
46+
47+
.success {
48+
background: #66bb6a;
49+
color: white;
50+
}
51+
52+
.error {
53+
background: #ef5350;
54+
color: white;
55+
}
56+
57+
:global(.toast-icon) {
58+
background: unset !important;
59+
color: white !important;
60+
border: none !important;
61+
}
62+
</style>

ts/image-occlusion/generate.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@ import { addImageOcclusionNotes } from "./lib";
22
import { getAnswerMaskColor } from "./tools/lib";
33
import { noteFieldsData, tagsWritable } from "./store";
44
import { get } from "svelte/store";
5+
import Toast from "./Toast.svelte";
6+
import * as tr from "@tslib/ftl";
57

6-
let divData = ["type", "left", "top", "width", "height", "fill", "stroke", "strokeWidth", "angle", "radius", "startAngle", "endAngle", "rx", "ry", "points"];
8+
let divData = ["type", "left", "top", "width", "height", "fill", "stroke", "strokeWidth", "angle", "radius", "startAngle", "endAngle", "rx", "ry", "points", "text", "fontSize", "fontFamily"];
79

810
export function generate(imagePath: string, generateTye: string, deckId: number): void {
911
let canvas = globalThis.canvas;
1012
let canvasObjects = canvas.getObjects();
13+
if (canvasObjects.length < 1) {
14+
return;
15+
}
1116

1217
let occlusionNotes = `<div id='io_cloze' data-answer-mask-color='${getAnswerMaskColor()}'>`;
1318
let clozeDiv = "";
19+
let count = 0;
1420

1521
canvasObjects.forEach((object, index) => {
22+
count++;
1623
let obJson = object.toJSON();
1724
if (obJson.type === "group") {
1825
clozeDiv += getGroupCloze(object, index, generateTye);
@@ -24,7 +31,7 @@ export function generate(imagePath: string, generateTye: string, deckId: number)
2431
occlusionNotes += clozeDiv + "</div>";
2532
console.log(occlusionNotes);
2633

27-
saveImageNotes(imagePath, occlusionNotes, deckId);
34+
saveImageNotes(imagePath, occlusionNotes, deckId, count);
2835
}
2936

3037
const getCloze = (object, index, generateTye, relativePos) => {
@@ -74,6 +81,7 @@ const saveImageNotes = async function (
7481
imagePath: string,
7582
occlusions: string,
7683
deckId: number,
84+
count: number,
7785
) {
7886
const fieldsData = get(noteFieldsData);
7987
const tags = get(tagsWritable);
@@ -90,5 +98,25 @@ const saveImageNotes = async function (
9098
notes = textArea.value;;
9199
}
92100

93-
await addImageOcclusionNotes(imagePath, deckId, occlusions, header, notes, tags);
101+
let result = await addImageOcclusionNotes(imagePath, deckId, occlusions, header, notes, tags);
102+
showResult(result, count);
94103
};
104+
105+
// show toast message
106+
const showResult = (result, count) => {
107+
const toastComponent = new Toast({
108+
target: document.body,
109+
props: {
110+
message: "",
111+
type: "error",
112+
}
113+
});
114+
115+
if (result.note) {
116+
let msg = tr.importingNoteAdded({ count: count });
117+
toastComponent.$set({ message: msg, type: "success", showToast: true });
118+
} else {
119+
let msg = tr.editingErrorGeneratingCloze();
120+
toastComponent.$set({ message: msg, showToast: true });
121+
}
122+
}

ts/image-occlusion/icons.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ export { default as mdiFormatHeaderPound } from "@mdi/svg/svg/format-header-poun
4747
export { default as mdiFormatParagraph } from "@mdi/svg/svg/format-paragraph.svg";
4848
export { default as mdiCodeTags } from "@mdi/svg/svg/code-tags.svg";
4949
export { default as mdiMinus } from "@mdi/svg/svg/minus.svg";
50+
export { default as mdiClose } from "@mdi/svg/svg/close.svg";

0 commit comments

Comments
 (0)