Skip to content
Snippets Groups Projects
Commit 8288a25a authored by srosse's avatar srosse
Browse files

OO-4622: render rubric's images in test results and correction flow

parent 0633c330
No related branches found
No related tags found
No related merge requests found
Showing
with 81 additions and 51 deletions
......@@ -64,10 +64,10 @@ import org.olat.ims.qti21.QTI21AssessmentResultsOptions;
import org.olat.ims.qti21.QTI21Constants;
import org.olat.ims.qti21.QTI21Service;
import org.olat.ims.qti21.model.QTI21QuestionType;
import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder;
import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
import org.olat.ims.qti21.ui.assessment.TerminatedStaticCandidateSessionContext;
import org.olat.ims.qti21.ui.components.FeedbackResultFormItem;
import org.olat.ims.qti21.ui.components.FlowFormItem;
import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem;
import org.olat.repository.RepositoryEntry;
import org.olat.user.UserManager;
......@@ -128,11 +128,11 @@ public class AssessmentResultController extends FormBasicController {
private final File fUnzippedDirRoot;
private final URI assessmentObjectUri;
private final File assessmentTestFile;
private final ResourceLocator inputResourceLocator;
private final ResolvedAssessmentTest resolvedAssessmentTest;
private UserShortDescription assessedIdentityInfosCtrl;
private final Map<String,AssessmentItemSession> identifierToItemSession = new HashMap<>();
private final AssessmentHtmlBuilder htmlBuilder;
private int count = 0;
......@@ -167,7 +167,6 @@ public class AssessmentResultController extends FormBasicController {
this.candidateSession = candidateSession;
this.fUnzippedDirRoot = fUnzippedDirRoot;
this.submissionMapperUri = submissionMapperUri;
htmlBuilder = new AssessmentHtmlBuilder();
ResourceLocator fileResourceLocator = new PathResourceLocator(fUnzippedDirRoot.toPath());
inputResourceLocator =
......@@ -181,6 +180,8 @@ public class AssessmentResultController extends FormBasicController {
}
resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(fUnzippedDirRoot, false, false);
URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId();
assessmentTestFile = new File(testUri);
File signature = qtiService.getAssessmentResultSignature(candidateSession);
if (signature != null) {
......@@ -313,7 +314,7 @@ public class AssessmentResultController extends FormBasicController {
TestPlanNodeKey testPlanNodeKey = node.getKey();
TestNodeType testNodeType = node.getTestNodeType();
if(testNodeType == TestNodeType.ASSESSMENT_SECTION) {
String rubrics = getSectionRubric(node);
List<FlowFormItem> rubrics = getSectionRubric(layoutCont, node);
Results r = new Results(true, node.getSectionPartTitle(), rubrics, "o_mi_qtisection", options.isSectionSummary());
AssessmentSectionSessionState sectionState = testSessionState.getAssessmentSectionSessionStates().get(testPlanNodeKey);
if(sectionState != null) {
......@@ -345,22 +346,31 @@ public class AssessmentResultController extends FormBasicController {
}
}
private String getSectionRubric(TestPlanNode node) {
private List<FlowFormItem> getSectionRubric(FormLayoutContainer layoutCont, TestPlanNode node) {
AssessmentTest assessmentTest = resolvedAssessmentTest.getRootNodeLookup().extractIfSuccessful();
StringBuilder sb = new StringBuilder(128);
List<FlowFormItem> rubricsEls = new ArrayList<>();
AbstractPart part = assessmentTest.lookupFirstDescendant(node.getIdentifier());
if(part instanceof AssessmentSection) {
AssessmentSection section = (AssessmentSection)part;
for(RubricBlock rubricBlock:section.getRubricBlocks()) {
String content = htmlBuilder.blocksString(rubricBlock.getBlocks());
if(StringHelper.containsNonWhitespace(content)) {
sb.append("<div class='rubric'>").append(content).append("</div>");
String rubricElId = "section_rubric_" + (count++);
FlowFormItem formItem = new FlowFormItem(rubricElId, assessmentTestFile);
formItem.setBlocks(rubricBlock.getBlocks());
formItem.setCandidateSessionContext(candidateSessionContext);
formItem.setResourceLocator(inputResourceLocator);
formItem.setAssessmentObjectUri(assessmentObjectUri);
formItem.setMapperUri(mapperUri);
if(submissionMapperUri != null) {
formItem.setSubmissionMapperUri(submissionMapperUri);
}
rubricsEls.add(formItem);
layoutCont.add(rubricElId, formItem);
}
}
return sb.toString();
return rubricsEls;
}
private Results initFormItemResult(FormLayoutContainer layoutCont, TestPlanNode node,
......@@ -634,7 +644,6 @@ public class AssessmentResultController extends FormBasicController {
private String itemIdentifier;
private final String title;
private final String rubrics;
private final String cssClass;
private final boolean section;
private final boolean metadataVisible;
......@@ -649,6 +658,7 @@ public class AssessmentResultController extends FormBasicController {
private FormItem questionItem;
private FormItem correctSolutionItem;
private final List<FlowFormItem> rubrics;
private InteractionResults interactionResults;
private final List<Results> subResults = new ArrayList<>();
......@@ -669,7 +679,7 @@ public class AssessmentResultController extends FormBasicController {
this.rubrics = null;
}
public Results(boolean section, String title, String rubrics, String cssClass, boolean metadataVisible) {
public Results(boolean section, String title, List<FlowFormItem> rubrics, String cssClass, boolean metadataVisible) {
this.section = section;
this.title = title;
this.rubrics = rubrics;
......@@ -677,7 +687,6 @@ public class AssessmentResultController extends FormBasicController {
this.metadataVisible = metadataVisible;
}
public void setItemIdentifier(String itemIdentifier) {
this.itemIdentifier = itemIdentifier;
}
......@@ -721,7 +730,7 @@ public class AssessmentResultController extends FormBasicController {
return title;
}
public String getRubrics() {
public List<FlowFormItem> getRubrics() {
return rubrics;
}
......
......@@ -39,7 +39,7 @@
<tbody>
#if($contextTitle)
<tr class="o_qti_coursename">
<th>$r.translate("results.contextinfo.context")</th>
<th scope="row">$r.translate("results.contextinfo.context")</th>
<td>
<strong>$r.escapeHtml($contextTitle)</strong>
<small class="hidden-xs text-muted small">
......@@ -52,7 +52,7 @@
</tr>
#end
<tr class="o_qti_testname">
<th>$r.translate("results.contextinfo.test")</th>
<th scope="row">$r.translate("results.contextinfo.test")</th>
<td><strong>$testTitle</strong>
<small class="hidden-xs text-muted small">
#if($testExternalRef) ${testExternalRef} #end
......@@ -92,7 +92,7 @@
<div class="o_sel_results_details o_block_large">
<table class="table table-condensed"><tbody>
<tr class="o_qti_run_durationinfo">
<th>$r.translate("results.duration")</th>
<th scope="row">$r.translate("results.duration")</th>
<td class="o_sel_assessmenttest_duration">
$r.formatDurationInMillis($testResults.duration)
<span class="hidden-xs hidden-sm text-muted small o_block_inline_left">
......@@ -101,7 +101,7 @@
</td>
</tr>
<tr class="o_qti_run_questioninfo">
<th>$r.translate("question.progress.answered")</th>
<th scope="row">$r.translate("question.progress.answered")</th>
<td>
<div>
<span title="$r.translateInAttribute("question.progress.answered")">$testResults.numberOfAnsweredQuestions</span>
......@@ -112,7 +112,7 @@
</tr>
#if(${testResults.hasScore()})
<tr class="o_qti_scoreinfo o_sel_assessmenttest_scores">
<th>$r.translate("results.score.yourscore")</th>
<th scope="row">$r.translate("results.score.yourscore")</th>
<td>
<div>
#if ($testResults.hasMaxScore())
......@@ -131,7 +131,7 @@
#end
#if ($testResults.cutValue)
<tr class="o_qti_cutinfo">
<th>$r.translate("score.cut")</th>
<th scope="row">$r.translate("score.cut")</th>
<td>
$testResults.cutValue
</td>
......@@ -139,7 +139,7 @@
#end
#if(${testResults.hasPass()})
<tr class="o_qti_stateinfo #if(${testResults.getCalculatedPassed().booleanValue()}) o_passed #elseif(!${testResults.getCalculatedPassed().booleanValue()}) o_failed #else o_unknown #end">
<th>$r.translate("passed.yourpassed")</th>
<th scope="row">$r.translate("passed.yourpassed")</th>
<td>
#if(${testResults.getCalculatedPassed().booleanValue()})
<i class="o_icon o_icon_passed"></i>
......@@ -155,7 +155,7 @@
#end
#if($r.isNotNull($signatureUrl))
<tr class="o_qti_signature">
<th>$r.translate("digital.signature.download")</th>
<th scope="row">$r.translate("digital.signature.download")</th>
<td><a href="$signatureUrl" target="_blank"><i class="o_icon o_icon-fw o_icon_download"> </i> $r.translate("digital.signature.download.link")</a></td>
</tr>
#end
......@@ -164,7 +164,7 @@
#set($itemResult = $itemResults.get(0))
#if($r.isNotEmpty($itemResult.getSubResults()))
<tr class="o_qti_signature">
<th>$r.translate("results.questions.overview")</th>
<th scope="row">$r.translate("results.questions.overview")</th>
<td>
<div class="o_qti_section_sublisting">
#foreach($subResults in $itemResult.getSubResults())
......@@ -387,7 +387,11 @@
#end
</h3>
#if($r.isNotEmpty($itemResult.rubrics))
<div class="o_info o_assessmentsection_rubrics">$r.xssScan($itemResult.rubrics)</div>
<div class="o_info o_assessmentsection_rubrics">
#foreach($rubric in $itemResult.rubrics)
<div class='rubric clearfix'>$r.render($rubric)</div>
#end
</div>
#end
#end
#else
......@@ -409,11 +413,11 @@
#if($itemResult.metadataVisible)
<table class="table"><tbody>
<tr class="o_qti_item_id">
<th>ID</th>
<th scope="row">ID</th>
<td>$itemResult.itemIdentifier</td>
</tr>
<tr class="o_sel_assessmentitem_status">
<th>$r.translate("results.session.status")</th>
<th scope="row">$r.translate("results.session.status")</th>
<td>
#if(${itemResult.hasPass()})
#if(${itemResult.getPass().booleanValue()})
......@@ -427,7 +431,7 @@
</tr>
#if(${itemResult.hasScore()})
<tr class="o_sel_assessmentitem_score">
<th>$r.translate("results.score.yourscore")</th>
<th scope="row">$r.translate("results.score.yourscore")</th>
<td>
<div class="col-xs-3 col-md-2" style='padding-left:0;'>
<span title="$r.translateInAttribute("results.score.yourscore")" class="o_sel_assessmentitem_score">$itemResult.score</span>
......@@ -449,13 +453,13 @@
</tr>
#elseif(${itemResult.hasMaxScore()})
<tr>
<th>$r.translate("score.max")</th>
<th scope="row">$r.translate("score.max")</th>
<td><span class="o_sel_assessmentitem_maxscore">$itemResult.maxScore</span></td>
</tr>
#end
#if(${itemResult.hasPass()})
<tr class="o_state #if(${testResults.getPass().booleanValue()}) o_passed #elseif(!${testResults.getPass().booleanValue()}) o_failed #else o_unknown #end">
<th>$r.translate("passed.yourpassed")</th>
<th scope="row">$r.translate("passed.yourpassed")</th>
<td>
#if(${itemResult.getPass().booleanValue()})
<i class="o_icon o_icon_passed"></i>
......
......@@ -58,12 +58,12 @@ import org.olat.ims.qti21.AssessmentItemSession;
import org.olat.ims.qti21.AssessmentTestSession;
import org.olat.ims.qti21.QTI21Constants;
import org.olat.ims.qti21.QTI21Service;
import org.olat.ims.qti21.model.xml.AssessmentHtmlBuilder;
import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
import org.olat.ims.qti21.ui.assessment.model.AssessmentItemCorrection;
import org.olat.ims.qti21.ui.assessment.model.SectionRubrics;
import org.olat.ims.qti21.ui.components.FeedbackResultFormItem;
import org.olat.ims.qti21.ui.components.FlowFormItem;
import org.olat.ims.qti21.ui.components.InteractionResultFormItem;
import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem;
import org.olat.repository.RepositoryEntry;
......@@ -123,7 +123,8 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
private final String mapperUri;
private final URI assessmentObjectUri;
private final ResourceLocator inputResourceLocator;
private final File assessmentTestFile;
private final AssessmentItem assessmentItem;
private final List<Interaction> interactions;
private final AssessmentItemCorrection correction;
......@@ -133,7 +134,6 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
private BigDecimal overrideAutoScore;
private boolean manualScore = false;
private final AssessmentHtmlBuilder htmlBuilder;
private int count = 0;
private final long id = CodeHelper.getRAMUniqueID();
......@@ -153,11 +153,12 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
this.mapperUri = mapperUri;
this.correction = correction;
this.resolvedAssessmentTest = resolvedAssessmentTest;
URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId();
assessmentTestFile = new File(testUri);
resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(correction.getItemRef());
assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
interactions = assessmentItem.getItemBody().findInteractions();
this.submissionDirectoryMaps = submissionDirectoryMaps;
htmlBuilder = new AssessmentHtmlBuilder();
FileResourceManager frm = FileResourceManager.getInstance();
File fUnzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
......@@ -288,12 +289,12 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
layoutCont.contextPut("interactionWrapper", wrapper);
layoutCont.contextPut("autoSaved", Boolean.valueOf(isAutoSaved(testPlanNodeKey, testSessionState)));
List<SectionRubrics> sectionRubrics = initSectionsRubrics();
List<SectionRubrics> sectionRubrics = initSectionsRubrics(layoutCont);
layoutCont.contextPut("sectionRubrics", sectionRubrics);
}
}
private List<SectionRubrics> initSectionsRubrics() {
private List<SectionRubrics> initSectionsRubrics(FormItemContainer layoutCont) {
List<SectionRubrics> sectionParentLine = new ArrayList<>();
try {
......@@ -311,7 +312,7 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
}
if(writeRubrics) {
String rubrics = getSectionRubrics(section);
List<FlowFormItem> rubrics = getSectionRubrics(section, layoutCont);
String openLabel;
if(StringHelper.containsNonWhitespace(section.getTitle())) {
openLabel = translate("show.rubric.with.title", new String[]{ section.getTitle() });
......@@ -334,15 +335,21 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
return sectionParentLine;
}
private String getSectionRubrics(AssessmentSection section) {
StringBuilder sb = new StringBuilder(1024);
private List<FlowFormItem> getSectionRubrics(AssessmentSection section, FormItemContainer layoutCont) {
List<FlowFormItem> rubricsEls = new ArrayList<>();
for(RubricBlock rubricBlock:section.getRubricBlocks()) {
String content = htmlBuilder.blocksString(rubricBlock.getBlocks());
if(StringHelper.containsNonWhitespace(content)) {
sb.append("<div class='rubric'>").append(content).append("</div>");
}
String rubricElId = "section_rubric_" + (count++);
FlowFormItem formItem = new FlowFormItem(rubricElId, assessmentTestFile);
formItem.setBlocks(rubricBlock.getBlocks());
formItem.setResourceLocator(inputResourceLocator);
formItem.setAssessmentObjectUri(assessmentObjectUri);
formItem.setMapperUri(mapperUri);
rubricsEls.add(formItem);
layoutCont.add(rubricElId, formItem);
}
return sb.toString();
return rubricsEls;
}
private ItemBodyResultFormItem initFormInteraction(TestPlanNodeKey testPlanNodeKey,
......
......@@ -13,7 +13,9 @@
#if($r.isNotEmpty($sectionRubric.title))
<h4>$sectionRubric.title</h4>
#end
<div class='rubric'>$sectionRubric.rubrics</div>
#foreach($rubric in $sectionRubric.rubrics)
<div class='rubric clearfix'>$r.render($rubric)</div>
#end
<a id='h${sectionRubric.identifier}' href='javascript:;' class='o_toogle_rubrics o_hide'><span>$r.translate("hide.rubric.short")</span></a>
</div>
<script>
......
......@@ -19,6 +19,10 @@
*/
package org.olat.ims.qti21.ui.assessment.model;
import java.util.List;
import org.olat.ims.qti21.ui.components.FlowFormItem;
/**
*
* Initial date: 4 Oct 2018<br>
......@@ -28,11 +32,11 @@ package org.olat.ims.qti21.ui.assessment.model;
public class SectionRubrics {
private final String title;
private final String rubrics;
private final List<FlowFormItem> rubrics;
private final String identifier;
private final String openLabel;
public SectionRubrics(String identifier, String title, String rubrics, String openLabel) {
public SectionRubrics(String identifier, String title, List<FlowFormItem> rubrics, String openLabel) {
this.identifier = identifier;
this.rubrics = rubrics;
this.title = title;
......@@ -43,7 +47,7 @@ public class SectionRubrics {
return title;
}
public String getRubrics() {
public List<FlowFormItem> getRubrics() {
return rubrics;
}
......
......@@ -389,6 +389,10 @@ span.o_qti_gaptext_score_alternative {
}
}
.o_assessment_test_results .o_info.o_assessmentsection_rubrics {
margin: $o-box-margin 0;
}
.o_assessmentitem{
h1 {
margin-bottom: 0;
......
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment