From 94576c157dd68b007db072b96f8c02f0f6186f1e Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 11 Jul 2017 08:47:48 +0200
Subject: [PATCH] OO-2865: show the full answers if we cannot extract a summary
 of it

---
 .../qti21/ui/components/FlowComponent.java    | 101 ++++++++++++++++++
 .../ui/components/FlowComponentRenderer.java  |  56 ++++++++++
 .../ims/qti21/ui/components/FlowFormItem.java |  68 ++++++++++++
 .../AssessmentItemEditorController.java       |  10 +-
 .../interactions/ChoiceScoreController.java   |  42 +++++++-
 .../interactions/MatchScoreController.java    |  30 +++++-
 .../interactions/_content/choices_score.html  |   6 +-
 .../interactions/_content/match_score.html    |   2 +-
 8 files changed, 301 insertions(+), 14 deletions(-)
 create mode 100644 src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java
 create mode 100644 src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java
 create mode 100644 src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java

diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java
new file mode 100644
index 00000000000..7559eae7154
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponent.java
@@ -0,0 +1,101 @@
+package org.olat.ims.qti21.ui.components;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.List;
+
+import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.InlineStatic;
+import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest;
+import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
+
+/**
+ * 
+ * Initial date: 10 juil. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FlowComponent extends AssessmentObjectComponent {
+	
+	private final static FlowComponentRenderer RENDERER = new FlowComponentRenderer();
+	
+	private ResolvedAssessmentTest resolvedAssessmentTest;
+	private final File assessmentItemFile;
+	
+	private final FlowFormItem qtiItem;
+	private List<FlowStatic> flowStatics;
+	private List<InlineStatic> inlineStatics;
+	
+	public FlowComponent(String name, File assessmentItemFile, FlowFormItem qtiItem) {
+		super(name);
+		this.qtiItem = qtiItem;
+		this.assessmentItemFile = assessmentItemFile;
+		setDomReplacementWrapperRequired(false);
+	}
+	
+	public List<FlowStatic> getFlowStatics() {
+		return flowStatics;
+	}
+
+	public void setFlowStatics(List<FlowStatic> flowStatics) {
+		this.flowStatics = flowStatics;
+	}
+
+	public List<InlineStatic> getInlineStatics() {
+		return inlineStatics;
+	}
+
+	public void setInlineStatics(List<InlineStatic> inlineStatics) {
+		this.inlineStatics = inlineStatics;
+	}
+
+	public ResolvedAssessmentTest getResolvedAssessmentTest() {
+		return resolvedAssessmentTest;
+	}
+
+	public void setResolvedAssessmentTest(ResolvedAssessmentTest resolvedAssessmentTest) {
+		this.resolvedAssessmentTest = resolvedAssessmentTest;
+	}
+
+	@Override
+	public FlowFormItem getQtiItem() {
+		return qtiItem;
+	}
+
+	@Override
+	public String getResponseUniqueIdentifier(ItemSessionState itemSessionState, Interaction interaction) {
+		return null;
+	}
+
+	@Override
+	public Interaction getInteractionOfResponseUniqueIdentifier(String responseUniqueId) {
+		return null;
+	}
+
+	@Override
+	public String relativePathTo(ResolvedAssessmentItem rAssessmentItem) {
+
+		String relativePathString = "";
+		if(resolvedAssessmentTest != null) {
+			URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId();
+			File testFile = new File(testUri);
+			Path relativePath = testFile.toPath().getParent().relativize(assessmentItemFile.toPath().getParent());
+			relativePathString = relativePath.toString();
+		}
+		
+		if(relativePathString.isEmpty()) {
+			return relativePathString;
+		} else if(relativePathString.endsWith("/")) {
+			return relativePathString;
+		}
+		return relativePathString.concat("/");
+	}
+
+	@Override
+	public FlowComponentRenderer getHTMLRendererSingleton() {
+		return RENDERER;
+	}
+}
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java
new file mode 100644
index 00000000000..c7faaa0dd26
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowComponentRenderer.java
@@ -0,0 +1,56 @@
+package org.olat.ims.qti21.ui.components;
+
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+
+import uk.ac.ed.ph.jqtiplus.node.content.variable.PrintedVariable;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
+import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
+
+/**
+ * 
+ * Initial date: 10 juil. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FlowComponentRenderer extends AssessmentObjectComponentRenderer {
+	
+	private static final OLog log = Tracing.createLoggerFor(FlowComponentRenderer.class);
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Component source, URLBuilder ubu, Translator translator,
+			RenderResult renderResult, String[] args) {
+		FlowComponent avc = (FlowComponent)source;
+		AssessmentRenderer aRenderer = new AssessmentRenderer(renderer);
+		if(avc.getFlowStatics() != null) {
+			try {
+				avc.getFlowStatics().forEach((flow)
+					-> avc.getHTMLRendererSingleton().renderFlow(aRenderer, target, avc, (ResolvedAssessmentItem)null, (ItemSessionState)null, flow, ubu, translator));
+			} catch (Exception e) {
+				log.error("", e);
+			}
+		}
+		if(avc.getInlineStatics() != null) {
+			try {
+				avc.getInlineStatics().forEach((inline)
+						-> avc.getHTMLRendererSingleton().renderInline(aRenderer, target, avc, (ResolvedAssessmentItem)null, (ItemSessionState)null, inline, ubu, translator));
+			} catch (Exception e) {
+				log.error("", e);
+			}
+		}
+	}
+
+	@Override
+	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb,
+			AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem,
+			ItemSessionState itemSessionState, PrintedVariable printedVar) {
+		//do nothing
+	}
+	
+}
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java b/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java
new file mode 100644
index 00000000000..74c376b280a
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/components/FlowFormItem.java
@@ -0,0 +1,68 @@
+package org.olat.ims.qti21.ui.components;
+
+import java.io.File;
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+
+import uk.ac.ed.ph.jqtiplus.node.content.basic.FlowStatic;
+import uk.ac.ed.ph.jqtiplus.node.content.basic.InlineStatic;
+
+/**
+ * 
+ * Initial date: 10 juil. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FlowFormItem extends AssessmentObjectFormItem {
+	
+	private final FlowComponent component;
+
+	public FlowFormItem(String name, File assessmentItemFile) {
+		super(name, null);
+		component = new FlowComponent(name, assessmentItemFile, this);
+	}
+	
+	public List<FlowStatic> getFlowStatics() {
+		return component.getFlowStatics();
+	}
+
+	public void setFlowStatics(List<FlowStatic> flowStatics) {
+		component.setFlowStatics(flowStatics);
+	}
+	
+	public List<InlineStatic> getInlineStatics() {
+		return component.getInlineStatics();
+	}
+
+	public void setInlineStatics(List<InlineStatic> inlineStatics) {
+		component.setInlineStatics(inlineStatics);
+	}
+
+	@Override
+	public FlowComponent getComponent() {
+		return component;
+	}
+
+	@Override
+	protected FlowComponent getFormItemComponent() {
+		return component;
+	}
+
+	@Override
+	protected void rootFormAvailable() {
+		// 
+	}
+
+	@Override
+	public void evalFormRequest(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	public void reset() {
+		//
+	}
+	
+	
+}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
index 05d5eae1279..a028278f3f7 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
@@ -235,7 +235,7 @@ public class AssessmentItemEditorController extends BasicController {
 		itemEditor = new SingleChoiceEditorController(ureq, getWindowControl(), scItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
 		listenTo(itemEditor);
-		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), scItemBuilder, itemRef, restrictedEdit,
+		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), scItemBuilder, itemRef, itemFile, restrictedEdit,
 				"Test editor QTI 2.1 in detail#details_testeditor_score");
 		listenTo(scoreEditor);
 		feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), scItemBuilder,
@@ -253,7 +253,7 @@ public class AssessmentItemEditorController extends BasicController {
 		itemEditor = new MultipleChoiceEditorController(ureq, getWindowControl(), mcItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
 		listenTo(itemEditor);
-		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), mcItemBuilder, itemRef, restrictedEdit,
+		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), mcItemBuilder, itemRef, itemFile, restrictedEdit,
 				"Test editor QTI 2.1 in detail#details_testeditor_score");
 		listenTo(scoreEditor);
 		feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), mcItemBuilder,
@@ -289,7 +289,7 @@ public class AssessmentItemEditorController extends BasicController {
 		itemEditor = new MatchEditorController(ureq, getWindowControl(), matchItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
 		listenTo(itemEditor);
-		scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, restrictedEdit);
+		scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, itemFile, restrictedEdit);
 		listenTo(scoreEditor);
 		feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), matchItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
@@ -306,7 +306,7 @@ public class AssessmentItemEditorController extends BasicController {
 		itemEditor = new MatchEditorController(ureq, getWindowControl(), matchItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
 		listenTo(itemEditor);
-		scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, restrictedEdit);
+		scoreEditor = new MatchScoreController(ureq, getWindowControl(), matchItemBuilder, itemRef, itemFile, restrictedEdit);
 		listenTo(scoreEditor);
 		feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), matchItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
@@ -411,7 +411,7 @@ public class AssessmentItemEditorController extends BasicController {
 		itemEditor = new HottextEditorController(ureq, getWindowControl(), hottextItemBuilder,
 				rootDirectory, rootContainer, itemFile, restrictedEdit);
 		listenTo(itemEditor);
-		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), hottextItemBuilder, itemRef, restrictedEdit,
+		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), hottextItemBuilder, itemRef, itemFile, restrictedEdit,
 				"Test editor QTI 2.1 in detail#details_testeditor_score");
 		listenTo(scoreEditor);
 		feedbackEditor = new FeedbackEditorController(ureq, getWindowControl(), hottextItemBuilder,
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java
index ac1f8b799c9..00f33d343ed 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/ChoiceScoreController.java
@@ -19,6 +19,8 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -32,7 +34,9 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.CodeHelper;
 import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.filter.FilterFactory;
 import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder;
@@ -40,6 +44,8 @@ import org.olat.ims.qti21.model.xml.AssessmentItemBuilder;
 import org.olat.ims.qti21.model.xml.ScoreBuilder;
 import org.olat.ims.qti21.model.xml.interactions.ChoiceAssessmentItemBuilder;
 import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation;
+import org.olat.ims.qti21.ui.ResourcesMapper;
+import org.olat.ims.qti21.ui.components.FlowFormItem;
 import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController;
 import org.olat.ims.qti21.ui.editor.SyncAssessmentItem;
 import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent;
@@ -68,18 +74,27 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp
 	private FormLayoutContainer scoreCont;
 	private final List<ChoiceWrapper> wrappers = new ArrayList<>();
 	
+	private int count = 0;
+	private final File itemFileRef;
+	private final String mapperUri;
 	private final ChoiceAssessmentItemBuilder itemBuilder;
 	
 	private int counter = 0;
 	private final String contextHelpUrl;
 	
 	public ChoiceScoreController(UserRequest ureq, WindowControl wControl,
-			ChoiceAssessmentItemBuilder itemBuilder, AssessmentItemRef itemRef, boolean restrictedEdit,
-			String contextHelpUrl) {
+			ChoiceAssessmentItemBuilder itemBuilder, AssessmentItemRef itemRef, File itemFileRef,
+			boolean restrictedEdit, String contextHelpUrl) {
 		super(ureq, wControl, itemRef, restrictedEdit);
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
+		this.itemFileRef = itemFileRef;
 		this.contextHelpUrl = contextHelpUrl;
+		
+		URI assessmentObjectUri = itemFileRef.toURI();
+		mapperUri = registerCacheableMapper(null, "ChoiceScoreController::" + CodeHelper.getRAMUniqueID(),
+				new ResourcesMapper(assessmentObjectUri));
+		
 		initForm(ureq);
 	}
 
@@ -233,6 +248,7 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp
 		private String summary;
 		private Choice choice;
 		private final TextElement pointsEl;
+		private FlowFormItem summaryEl;
 		
 		public ChoiceWrapper(Choice choice, TextElement pointsEl) {
 			setChoice(choice);
@@ -248,6 +264,10 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp
 			return summary;
 		}
 		
+		public FlowFormItem getSummaryEl() {
+			return summaryEl;
+		}
+		
 		public TextElement getPointsEl() {
 			return pointsEl;
 		}
@@ -259,15 +279,29 @@ public class ChoiceScoreController extends AssessmentItemRefEditorController imp
 		public void setChoice(Choice choice) {
 			this.choice = choice;
 			if(choice instanceof SimpleChoice) {
-				String answer = new AssessmentHtmlBuilder().flowStaticString(((SimpleChoice)choice).getFlowStatics());
+				SimpleChoice simpleChoice = (SimpleChoice)choice;
+				String answer = new AssessmentHtmlBuilder().flowStaticString(simpleChoice.getFlowStatics());
 				answer = FilterFactory.getHtmlTagAndDescapingFilter().filter(answer);
 				answer = answer.trim();
 				summary = Formatter.truncate(answer, 128);
+				if(!StringHelper.containsNonWhitespace(summary)) {
+					summaryEl = new FlowFormItem("summary" + count++, itemFileRef);
+					summaryEl.setFlowStatics(simpleChoice.getFlowStatics());
+					summaryEl.setMapperUri(mapperUri);
+					scoreCont.add(summaryEl);
+				}
 			} else if(choice instanceof Hottext) {
-				String answer = new AssessmentHtmlBuilder().inlineStaticString(((Hottext)choice).getInlineStatics());
+				Hottext hottext = (Hottext)choice;
+				String answer = new AssessmentHtmlBuilder().inlineStaticString(hottext.getInlineStatics());
 				answer = FilterFactory.getHtmlTagAndDescapingFilter().filter(answer);
 				answer = answer.trim();
 				summary = Formatter.truncate(answer, 128);
+				if(!StringHelper.containsNonWhitespace(summary)) {
+					summaryEl = new FlowFormItem("summary" + count++, itemFileRef);
+					summaryEl.setInlineStatics(hottext.getInlineStatics());
+					summaryEl.setMapperUri(mapperUri);
+					scoreCont.add(summaryEl);
+				}
 			} else {
 				summary = "";
 			}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java
index 41645f6dc62..260799f1655 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MatchScoreController.java
@@ -19,6 +19,8 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -34,6 +36,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.CodeHelper;
 import org.olat.core.util.Util;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder;
@@ -41,6 +44,8 @@ import org.olat.ims.qti21.model.xml.AssessmentItemBuilder;
 import org.olat.ims.qti21.model.xml.ScoreBuilder;
 import org.olat.ims.qti21.model.xml.interactions.MatchAssessmentItemBuilder;
 import org.olat.ims.qti21.model.xml.interactions.SimpleChoiceAssessmentItemBuilder.ScoreEvaluation;
+import org.olat.ims.qti21.ui.ResourcesMapper;
+import org.olat.ims.qti21.ui.components.FlowFormItem;
 import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController;
 import org.olat.ims.qti21.ui.editor.SyncAssessmentItem;
 import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent;
@@ -70,15 +75,24 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl
 	
 	private MatchAssessmentItemBuilder itemBuilder;
 	
+	private int count = 0;
+	private final String mapperUri;
+	private final File itemFileRef;
 	private List<MatchWrapper> sourceWrappers = new ArrayList<>();
 	private List<MatchWrapper> targetWrappers = new ArrayList<>();
 	private Map<DirectedPairValue, MatchScoreWrapper> scoreWrappers = new HashMap<>();
 	
 	public MatchScoreController(UserRequest ureq, WindowControl wControl, MatchAssessmentItemBuilder itemBuilder,
-			AssessmentItemRef itemRef, boolean restrictedEdit) {
+			AssessmentItemRef itemRef, File itemFileRef, boolean restrictedEdit) {
 		super(ureq, wControl, itemRef, restrictedEdit);
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
+		this.itemFileRef = itemFileRef;
+		
+		URI assessmentObjectUri = itemFileRef.toURI();
+		mapperUri = registerCacheableMapper(null, "MatchScoreController::" + CodeHelper.getRAMUniqueID(),
+				new ResourcesMapper(assessmentObjectUri));
+		
 		initForm(ureq);
 	}
 
@@ -250,22 +264,32 @@ public class MatchScoreController extends AssessmentItemRefEditorController impl
 	}
 	
 	private MatchWrapper createMatchWrapper(SimpleAssociableChoice choice) {
-		return new MatchWrapper(choice.getIdentifier(), choice);
+		FlowFormItem summaryEl = new FlowFormItem("summary_" + count++, itemFileRef);
+		summaryEl.setFlowStatics(choice.getFlowStatics());
+		summaryEl.setMapperUri(mapperUri);
+		scoreCont.add(summaryEl);
+		return new MatchWrapper(choice.getIdentifier(), choice, summaryEl);
 	}
 	
 	public static class MatchWrapper {
 
 		private final Identifier choiceIdentifier;
 		private SimpleAssociableChoice choice;
+		private final FlowFormItem summaryEl;
 		
-		public MatchWrapper(Identifier choiceIdentifier, SimpleAssociableChoice choice) {
+		public MatchWrapper(Identifier choiceIdentifier, SimpleAssociableChoice choice, FlowFormItem summaryEl) {
 			this.choiceIdentifier = choiceIdentifier;
 			this.choice = choice;
+			this.summaryEl = summaryEl;
 		}
 		
 		public String getSummary() {
 			return new AssessmentHtmlBuilder().flowStaticString(choice.getFlowStatics());
 		}
+		
+		public FlowFormItem getSummaryEl() {
+			return summaryEl;
+		}
 
 		public Identifier getChoiceIdentifier() {
 			return choiceIdentifier;
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html
index ecf08603563..8adeebdc235 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/choices_score.html
@@ -8,7 +8,11 @@
 	#foreach($choice in $choices)
 	<tr>
 		<td>#if(${choice.isCorrect()}) <i class="o_icon o_icon-lg o_icon_check_on"> </i> #end</td>
-		<td>$choice.summary</td>
+		<td>#if($r.isNotNull($choice.summaryEl))
+			$r.render($choice.summaryEl)
+		#else
+			$choice.summary
+		#end</td>
 		<td>$r.render($choice.getPointsEl().getComponent().getComponentName())
 		#if($f.hasError($choice.getPointsEl().getComponent().getComponentName()))
 			<div>$r.render("${choice.getPointsEl().getComponent().getComponentName()}_ERROR")</div>
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html
index 03cbbdb6b0d..060ff2ad87f 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/_content/match_score.html
@@ -3,7 +3,7 @@
 		<tr>
 			<th></th>
 			#foreach($targetChoice in $targetChoices)
-				<th>${targetChoice.getSummary()}
+				<th>${r.render($targetChoice.getSummaryEl())}
 			#end
 		</tr>
 	</thead>
-- 
GitLab