Skip to content

Commit

Permalink
"show cell answer state" option for MCQ; only show highlight when not…
Browse files Browse the repository at this point in the history
… dirty

Question authors can choose not to show the correct/incorrect state on
individual choice inputs for MCQ parts. This is appropriate when the
marking is based on the entire choice matrix, as opposed to the default
where each choice adds or subtracts marks when ticked.

This also fixes #581, removing the feedback styling when a part is dirty
  • Loading branch information
christianp committed Nov 5, 2018
1 parent 75a24d5 commit 8cf5789
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 19 deletions.
7 changes: 5 additions & 2 deletions bin/exam.py
Expand Up @@ -984,6 +984,7 @@ class MultipleChoicePart(Part):
warningType = 'none'
layoutType = 'all'
layoutExpression = ''
showCellAnswerState = True

def __init__(self,marks=0,prompt=''):
Part.__init__(self,marks,prompt)
Expand All @@ -1004,7 +1005,7 @@ def loadDATA(self, builder, data):
}

self.displayType = displayTypes[self.kind]
tryLoad(data,['minMarks','maxMarks','minAnswers','maxAnswers','shuffleChoices','shuffleAnswers','displayType','displayColumns','warningType'],self)
tryLoad(data,['minMarks','maxMarks','minAnswers','maxAnswers','shuffleChoices','shuffleAnswers','displayType','displayColumns','warningType','showCellAnswerState'],self)

if haskey(data,'minmarks'):
self.minMarksEnabled = True
Expand Down Expand Up @@ -1041,13 +1042,15 @@ def toxml(self):
part = super(MultipleChoicePart,self).toxml()
appendMany(part,['choices','answers','layout',['marking','matrix','maxmarks','minmarks','distractors','warning']])

part.attrib['showcellanswerstate'] = strcons_fix(self.showCellAnswerState)

choices = part.find('choices')
choices.attrib = {
'minimumexpected': strcons_fix(self.minAnswers),
'maximumexpected': strcons_fix(self.maxAnswers),
'displaycolumns': strcons_fix(self.displayColumns),
'shuffle': strcons_fix(self.shuffleChoices),
'displaytype': strcons(self.displayType)
'displaytype': strcons(self.displayType),
}

if isinstance(self.choices,str):
Expand Down
1 change: 1 addition & 0 deletions runtime/scripts/parts/multipleresponse.js
Expand Up @@ -49,6 +49,7 @@ MultipleResponsePart.prototype = /** @lends Numbas.parts.MultipleResponsePart.pr
this.flipped = false;
}
//work out marks available
tryGetAttribute(settings,xml,'.','showCellAnswerState');
tryGetAttribute(settings,xml,'marking/maxmarks','enabled','maxMarksEnabled');
if(this.type=='1_n_2') {
settings.maxMarksEnabled = false;
Expand Down
20 changes: 10 additions & 10 deletions themes/default/files/resources/exam.css
Expand Up @@ -288,41 +288,41 @@ input.jme {
border-bottom-color: #34444f;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.student-answer.answered input {
.part:not(.dirty) > .student-answer.answered input {
border: 1px solid;
border-color: hsl(204,72%,50%);
background: hsl(204,72%,95%);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.student-answer.answered[feedback-state='correct'] input {
.part:not(.dirty) > .student-answer.answered[feedback-state='correct'] input {
border-color: hsl(120, 50%, 50%);
background: hsl(120, 50%, 95%);
}
.student-answer.answered[feedback-state='wrong'] input {
.part:not(.dirty) > .student-answer.answered[feedback-state='wrong'] input {
border-color: hsl(0, 50%, 50%);
background: hsl(0, 50%, 95%);
}
.student-answer.answered[feedback-state='partial'] input {
.part:not(.dirty) > .student-answer.answered[feedback-state='partial'] input {
background: white;
}

.student-answer.answered .multiplechoice .checked label {
.part:not(.dirty) > .student-answer.answered .multiplechoice.show-cell-answer-state .checked label {
border-bottom: 1px solid hsl(204,72%,50%);
}
.student-answer.answered:not([feedback-state='none']) .multiplechoice .checked.correct label {
..part:not(.dirty) > student-answer.answered:not([feedback-state='none']) .multiplechoice.show-cell-answer-state .checked.correct label {
border-bottom-color: hsl(120,50%,50%);
}
.student-answer.answered:not([feedback-state='none']) .multiplechoice .checked:not(.correct) label {
..part:not(.dirty) > student-answer.answered:not([feedback-state='none']) .multiplechoice.show-cell-answer-state .checked:not(.correct) label {
border-bottom-color: hsl(0,50%,50%);
}

#everything .student-answer.answered .choices-grid td.checked {
#everything .part:not(.dirty) > .student-answer.answered .choices-grid.show-cell-answer-state td.checked {
background: hsl(204,72%,95%);
}
#everything .student-answer.answered:not([feedback-state='none']) .choices-grid td.checked.correct {
#everything .part:not(.dirty) > .student-answer.answered:not([feedback-state='none']) .choices-grid.show-cell-answer-state td.checked.correct {
background: hsl(120,50%,95%);
}
#everything .student-answer.answered:not([feedback-state='none']) .choices-grid td.checked:not(.correct) {
#everything .part:not(.dirty) > .student-answer.answered:not([feedback-state='none']) .choices-grid.show-cell-answer-state td.checked:not(.correct) {
background: hsl(0,50%,95%);
}

Expand Down
Expand Up @@ -38,6 +38,7 @@ Numbas.queueScript('display/parts/multipleresponse',['display-base','part-displa
return obs;
}
this.layout = util.copyarray(p.layout);
this.showCellAnswerState = ko.observable(p.settings.showCellAnswerState);
switch(p.type) {
case '1_n_2':
/** Index of student's current answer choice (not necessarily submitted)
Expand Down Expand Up @@ -197,4 +198,4 @@ Numbas.queueScript('display/parts/multipleresponse',['display-base','part-displa
}
};
display.MultipleResponsePartDisplay = extend(display.PartDisplay,display.MultipleResponsePartDisplay,true);
});
});
8 changes: 4 additions & 4 deletions themes/default/templates/xslt/parts/choices.xslt
Expand Up @@ -4,17 +4,17 @@
<span localise-data-jme-context-description="part.mcq.choices">
<xsl:choose>
<xsl:when test="@displaytype='radiogroup'">
<ul class="multiplechoice clearfix" data-bind="reorder_list: {{order: part.shuffleAnswers}}">
<ul class="multiplechoice clearfix" data-bind="reorder_list: {{order: part.shuffleAnswers}}, css: {{'show-cell-answer-state': showCellAnswerState}}">
<xsl:apply-templates select="choice" mode="radiogroup"/>
</ul>
</xsl:when>
<xsl:when test="@displaytype='checkbox'">
<ul class="multiplechoice clearfix" data-bind="reorder_list: {{order: part.shuffleAnswers}}">
<ul class="multiplechoice clearfix" data-bind="reorder_list: {{order: part.shuffleAnswers}}, css: {{'show-cell-answer-state': showCellAnswerState}}">
<xsl:apply-templates select="choice" mode="checkbox"/>
</ul>
</xsl:when>
<xsl:when test="@displaytype='dropdownlist'">
<select class="multiplechoice" data-bind="value: studentAnswer, disable: revealed, reorder_list: {{order: part.shuffleAnswers, leaders: 1}}">
<select class="multiplechoice" data-bind="value: studentAnswer, disable: revealed, reorder_list: {{order: part.shuffleAnswers, leaders: 1}}, css: {{'show-cell-answer-state': showCellAnswerState}}">
<option value=""></option>
<xsl:apply-templates select="choice" mode="dropdownlist"/>
</select>
Expand Down Expand Up @@ -128,4 +128,4 @@
<xsl:template match="distractor">
<span><xsl:apply-templates /></span>
</xsl:template>
{% endraw %}
{% endraw %}
4 changes: 2 additions & 2 deletions themes/default/templates/xslt/parts/m_n_x.xslt
Expand Up @@ -2,7 +2,7 @@
<xsl:template match="part[@type='m_n_x']" mode="typespecific">
<xsl:variable name="displaytype" select="choices/@displaytype"/>
<form autocomplete="nope">
<table class="choices-grid" data-bind="reorder_table: {{rows: part.shuffleChoices, columns: part.shuffleAnswers, leaders: 1}}">
<table class="choices-grid" data-bind="reorder_table: {{rows: part.shuffleChoices, columns: part.shuffleAnswers, leaders: 1}}, css: {{'show-cell-answer-state': showCellAnswerState}}">
<thead localise-data-jme-context-description="part.mcq.answers">
<td/>
<xsl:for-each select="answers/answer">
Expand Down Expand Up @@ -93,4 +93,4 @@
</xsl:for-each>
</tr>
</xsl:template>
{% endraw %}
{% endraw %}

0 comments on commit 8cf5789

Please sign in to comment.