Repository navigation
[QTI] Editing a question drops content the editor doesn't model #6309
Copy link
Copy link
Open
Labels
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Target branch: unstable
Observed behavior
Saving any edit to a QTI question rewrites parts the editor doesn't model. isEditableItem (validateItem.js#L45-L127) checks only the root's attributes and children, so none of these open read-only:
- Interaction attributes: the builders write only what they set (textEntry/parse.js#L308-L320, choice/parse.js#L139-L145). Every converted legacy input question loses
placeholder-text="Enter your answer here"; a choice losesclass="qti-labels-upper-alpha". - Prefixed MathML in the prompt:
adoptNoderecreates<m:math>with its prefix (xml.js#L99-L103), which TipTap doesn't read as math.solve <m:math>…</m:math>.saves as<p>solve x+1.</p>. data-catalog-idrefin the prompt: TipTap drops the span.Pick the <span data-catalog-idref="g1">vowel</span>.saves as<p>Pick the vowel.</p>. Since Show QTI questions read-only when an edit would drop item-level content #6306 an item that also holds the glossary<qti-catalog>opens read-only; one without it is still editable.- Text entry answers:
_extractAnswerscompares the trimmed<qti-value>with the untrimmed first map-key (textEntry/parse.js#L214-L224), so it reads answers by value. Map-keysParis,Paris(case-sensitive),Parisopen asParis,Paris.
Expected behavior
- An edit keeps everything it didn't touch.
User-facing consequences
- Learners see a question that differs from the uploaded one: no placeholder, no choice labels, no formula, no glossary term, or a dropped answer.
- The author isn't told.
Steps to reproduce
- Open a converted legacy input question (
input_question.xml), click Edit, change a hint, click Close:<qti-text-entry-interaction>has noplaceholder-text. - Open a single-choice item whose root declares
xmlns:m="http://www.w3.org/1998/Math/MathML"and whose prompt holds<m:math>…</m:math>, type at the end of the question text, click Close: the saved prompt has no<m:math>. - Open a single-choice item whose prompt is
Pick the <span data-catalog-idref="g1">vowel</span>.and holds no<qti-catalog>, add a hint, click Close: the saved prompt is<p>Pick the vowel.</p>. - Call
_extractAnswerson the declaration below: it returns[['Paris', false], [' Paris', false]].<qti-response-declaration identifier="RESPONSE" cardinality="single" base-type="string"> <qti-correct-response><qti-value> Paris</qti-value></qti-correct-response> <qti-mapping default-value="0"> <qti-map-entry map-key=" Paris" mapped-value="1" case-sensitive="false"/> <qti-map-entry map-key="Paris" mapped-value="1" case-sensitive="true"/> <qti-map-entry map-key="Paris" mapped-value="1" case-sensitive="false"/> </qti-mapping> </qti-response-declaration>
Acceptance Criteria
- Editing a converted text entry question keeps
placeholder-text; editing a choice question keepsclasson<qti-choice-interaction>. - Editing the prompt of an item with prefixed MathML saves the formula as MathML, and the item passes the XSD check.
- An item with
data-catalog-idrefin its prompt keeps it on save, or opens read-only. - The declaration above reads as
[[' Paris', false], ['Paris', true], ['Paris', false]], and opening that item emits noupdate:rawData. - Tests cover each case from opening the item to the emitted
raw_data.
Context
unstable at 98b560e.
AI usage
rtibbles chose which issues to merge; Claude Code reproduced each case on unstable with Jest and drafted this issue, which merges #6287, #6307 and #6308.
Reactions are currently unavailable

Activity
[-][QTI] Text entry answers are merged and reordered when the first answer has surrounding space[/-][+][QTI] Editing a question drops content the editor doesn't model[/+]