From afcc1745dfe2f7b20a1d99ddfa3ef68ca4f21d1f Mon Sep 17 00:00:00 2001 From: Erza Bytyci Date: Wed, 13 May 2026 07:58:56 +0000 Subject: [PATCH] Fix Click function and add rich editor, improve Gap edit functionality, fix the editor --- ...043_add_source_html_to_click_exercises.sql | 2 + gradesa/data/schema.sql | 3 +- gradesa/schema.sql | 3 +- .../app/admin/create-exercise/click/click.css | 34 ++- .../app/admin/create-exercise/click/page.js | 56 +++- .../fillinthegap/fillinthegap.css | 18 +- .../create-exercise/fillinthegap/page.js | 160 +++++++++-- .../admin/exercises/click/[click_id]/route.js | 25 +- .../app/api/admin/exercises/click/route.js | 17 +- .../api/admin/exercises/click/route.test.js | 49 ++++ gradesa/src/app/globals.css | 32 ++- .../exercises/click/[click_id]/page.js | 1 + .../src/app/pages/[type]/[slug]/chapters.css | 74 ++--- gradesa/src/app/talkback/page.js | 2 +- gradesa/src/app/talkback/talkback.css | 167 ++++++------ .../components/ui/button/button.module.css | 8 + gradesa/src/components/ui/click/click.css | 86 +++++- gradesa/src/components/ui/click/click.js | 257 +++++++++++++++--- .../src/components/ui/editor/ClientEditor.js | 185 +++++++++++++ gradesa/src/components/ui/sidebar/sidebar.js | 2 +- 20 files changed, 951 insertions(+), 230 deletions(-) create mode 100644 gradesa/data/migrations/00043_add_source_html_to_click_exercises.sql diff --git a/gradesa/data/migrations/00043_add_source_html_to_click_exercises.sql b/gradesa/data/migrations/00043_add_source_html_to_click_exercises.sql new file mode 100644 index 0000000..e8416db --- /dev/null +++ b/gradesa/data/migrations/00043_add_source_html_to_click_exercises.sql @@ -0,0 +1,2 @@ +ALTER TABLE public.click_exercises +ADD COLUMN IF NOT EXISTS source_html text; diff --git a/gradesa/data/schema.sql b/gradesa/data/schema.sql index 45b350d..76d4ef6 100644 --- a/gradesa/data/schema.sql +++ b/gradesa/data/schema.sql @@ -85,7 +85,8 @@ CREATE TABLE public.click_exercises ( title text NOT NULL, category text NOT NULL, target_words text[] NOT NULL, - all_words text[] NOT NULL + all_words text[] NOT NULL, + source_html text ); ALTER TABLE public.click_exercises diff --git a/gradesa/schema.sql b/gradesa/schema.sql index a13892d..081ed2a 100644 --- a/gradesa/schema.sql +++ b/gradesa/schema.sql @@ -50,7 +50,8 @@ CREATE TABLE public.click_exercises ( title text NOT NULL, category text NOT NULL, target_words text[] NOT NULL, - all_words text[] NOT NULL + all_words text[] NOT NULL, + source_html text ); ALTER TABLE public.click_exercises diff --git a/gradesa/src/app/admin/create-exercise/click/click.css b/gradesa/src/app/admin/create-exercise/click/click.css index 0a65ac6..f611c5b 100644 --- a/gradesa/src/app/admin/create-exercise/click/click.css +++ b/gradesa/src/app/admin/create-exercise/click/click.css @@ -1,10 +1,38 @@ +.click-admin-page { + max-width: 960px; +} + +.click-form { + display: grid; + gap: var(--u-md); +} + .exercise-click { - display: flex; - justify-content: space-between; + display: block; +} + +.click-block { + padding: var(--u-md); + border: 1px solid var(--bg3); + border-radius: var(--u-sm); + background: var(--bg2); +} + +.click-block label { + display: block; + margin-bottom: var(--u-xs); + color: var(--fg2); + font-weight: 600; } .click-input { - width: 60%; + width: 100%; + font: inherit; +} + +.click-form-actions { + display: flex; + justify-content: flex-start; } .error-message { diff --git a/gradesa/src/app/admin/create-exercise/click/page.js b/gradesa/src/app/admin/create-exercise/click/page.js index a3cd954..dcdc1a1 100644 --- a/gradesa/src/app/admin/create-exercise/click/page.js +++ b/gradesa/src/app/admin/create-exercise/click/page.js @@ -8,6 +8,17 @@ import { Button } from "@/components/ui/button"; import useQuery from "@/shared/hooks/useQuery"; import "./click.css"; import WordSelectionExercise from "@/components/ui/click/click.js"; +import Editor from "@/components/ui/editor"; +import { htmlToPlainText } from "@/shared/utils/normalizeEditorText"; + +function escapeHtml(value) { + return String(value || "") + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/\"/g, """) + .replace(/'/g, "'"); +} export default function CreateExercise() { const router = useRouter(); @@ -18,6 +29,7 @@ export default function CreateExercise() { const [error, setError] = useState(null); const [title, setTitle] = useState(""); const [targetCategory, setTargetCategory] = useState(""); + const [allWordsHtml, setAllWordsHtml] = useState(""); const [allWordsText, setAllWordsText] = useState(""); const [selectedWords, setSelectedWords] = useState([]); const [previewMode, setPreviewMode] = useState(false); @@ -45,15 +57,27 @@ export default function CreateExercise() { const text = hasExplicitSpacing ? storedWords.join("") : storedWords.join(" "); + const sourceHtml = + typeof exerciseData.source_html === "string" + ? exerciseData.source_html + : text + ? `

${escapeHtml(text)}

` + : ""; setTitle(exerciseData.title || ""); setTargetCategory(exerciseData.category || ""); + setAllWordsHtml(sourceHtml); setAllWordsText(text); setSelectedWords( Array.isArray(exerciseData.target_words) ? exerciseData.target_words : [] ); }, [exerciseData, isEditMode]); + const handleEditorContentChange = (html) => { + setAllWordsHtml(html); + setAllWordsText(htmlToPlainText(html)); + }; + // Preserve user-entered spacing and line breaks so preview and saved exercise match. const allWords = allWordsText.replace(/\r\n/g, "\n").match(/[^\S\n]+|\n|[^\s]+/g) ?? []; @@ -74,6 +98,7 @@ export default function CreateExercise() { targetCategory, targetWords: selectedWords, allWords, + sourceHtml: allWordsHtml, }), }); @@ -87,6 +112,7 @@ export default function CreateExercise() { targetCategory, targetWords: selectedWords, allWords, + sourceHtml: allWordsHtml, }); setSubmitted(true); @@ -139,7 +165,7 @@ export default function CreateExercise() { } return ( -
+

{isEditMode ? "Wortauswahl-Übung bearbeiten" @@ -148,9 +174,9 @@ export default function CreateExercise() { {submitted ? ( successMessage() // Show only the success message if submitted ) : !previewMode ? ( -
+ - + - + - + -