Add clean method to QuestionForm to unwrap single <p> tags from TinyMCE HTML fields

This commit is contained in:
Ross
2025-11-10 10:00:42 +00:00
parent e078b5a98f
commit 53ff56edc0
+40
View File
@@ -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 <p>...</p> from TinyMCE-provided HTML fields.
This handles the common TinyMCE behaviour where the editor wraps
inline content in a root <p>. We only unwrap when the entire value
is a single <p> 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 <p ...>...</p> that spans the whole string
m = re.fullmatch(r"\s*<p\b[^>]*>(.*)</p>\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