From 53ff56edc0396dd03a6047ecd1141da5a0436b76 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 10 Nov 2025 10:00:42 +0000 Subject: [PATCH] Add clean method to QuestionForm to unwrap single

tags from TinyMCE HTML fields --- sbas/forms.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sbas/forms.py b/sbas/forms.py index 9ef3a2ea..40302d46 100755 --- a/sbas/forms.py +++ b/sbas/forms.py @@ -22,6 +22,7 @@ from django.contrib.admin.widgets import FilteredSelectMultiple from django.forms.widgets import RadioSelect, TextInput, Textarea from tinymce.widgets import TinyMCE +import re from dal import autocomplete from crispy_forms.helper import FormHelper @@ -160,6 +161,45 @@ class QuestionForm(ModelForm): return instance + def clean(self): + """Strip a single wrapping

...

from TinyMCE-provided HTML fields. + + This handles the common TinyMCE behaviour where the editor wraps + inline content in a root

. We only unwrap when the entire value + is a single

element (so multi-paragraph content is preserved). + """ + cleaned = super(QuestionForm, self).clean() + + def _unwrap_single_p(html: str) -> str: + if not html or not isinstance(html, str): + return html + # Match a single

...

that spans the whole string + m = re.fullmatch(r"\s*]*>(.*)

\s*", html, flags=re.DOTALL | re.IGNORECASE) + if m: + return m.group(1) + return html + + fields_to_unwrap = [ + "stem", + "feedback", + "a_answer", + "a_feedback", + "b_answer", + "b_feedback", + "c_answer", + "c_feedback", + "d_answer", + "d_feedback", + "e_answer", + "e_feedback", + ] + + for fname in fields_to_unwrap: + if fname in cleaned: + cleaned[fname] = _unwrap_single_p(cleaned.get(fname)) + + return cleaned + class Meta: model = Question