Commit 47702f1b by Ahsan Ulhaq

Merge pull request #7918 from edx/ahsan/AC-103-fieldset-legend-solution-lost-when-editing-problem

Fieldset and legend solution is lost when edit Problem
parents 1ca4b3b9 c75526ea
......@@ -139,6 +139,7 @@ class LoncapaProblem(object):
self.do_reset()
self.problem_id = id
self.capa_system = capa_system
self.question_label = ""
state = state or {}
......@@ -732,6 +733,7 @@ class LoncapaProblem(object):
'status': status,
'id': input_id,
'input_state': self.input_state[input_id],
'question_label': self.question_label if self.question_label else None,
'answervariable': answervariable,
'feedback': {
'message': msg,
......@@ -762,8 +764,12 @@ class LoncapaProblem(object):
tree = etree.Element(problemtree.tag)
for item in problemtree:
item_xhtml = self._extract_html(item)
item_sibling = self.sibling_for_item(problemtree, item)
if item_xhtml is not None:
tree.append(item_xhtml)
if item_xhtml.tag == "legend" and item_sibling is not None and item_sibling in self.responders:
self.question_label = item_xhtml.text
else:
tree.append(item_xhtml)
if tree.tag in html_transforms:
tree.tag = html_transforms[problemtree.tag]['tag']
......@@ -834,3 +840,18 @@ class LoncapaProblem(object):
for solution in tree.findall('.//solution'):
solution.attrib['id'] = "%s_solution_%i" % (self.problem_id, solution_id)
solution_id += 1
def sibling_for_item(self, tree, node):
"""
Check if node exist in problem tree and return next sibling if exist
else return None
"""
problem_tree = tree.xpath('//problem/*')
if node in problem_tree:
node_index = problem_tree.index(node)
try:
return problem_tree[node_index + 1]
except IndexError:
return None
else:
return None
......@@ -214,6 +214,7 @@ class InputTypeBase(object):
self.hintmode = feedback.get('hintmode', None)
self.input_state = state.get('input_state', {})
self.answervariable = state.get("answervariable", None)
self.question_label = state.get("question_label", None)
# put hint above msg if it should be displayed
if self.hintmode == 'always':
......@@ -313,6 +314,7 @@ class InputTypeBase(object):
context.update(self._extra_context())
if self.answervariable:
context.update({'answervariable': self.answervariable})
context.update({'question_label': self.question_label if self.question_label is not None else ""})
return context
def _extra_context(self):
......
......@@ -17,8 +17,8 @@
% endif
</div>
<fieldset role="${input_type}group" aria-label="${label}">
<fieldset>
<legend>${question_label}</legend>
% for choice_id, choice_description in choices:
<label for="input_${id}_${choice_id}"
## If the student has selected this choice...
......
......@@ -175,6 +175,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
'label': '',
'value': '',
'preprocessor': None,
'question_label': '',
'msg': '',
'inline': False,
'hidden': False,
......
......@@ -126,6 +126,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.context = {'id': '1',
'choices': choices,
'status': Status('correct'),
'question_label': 'test',
'label': 'test',
'input_type': 'checkbox',
'name_array_suffix': '1',
......@@ -141,6 +142,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.context['status'] = Status('correct')
self.context['input_type'] = 'checkbox'
self.context['value'] = ['1', '2']
self.context['question_label'] = ['']
# Should mark the entire problem correct
xml = self.render_to_xml(self.context)
......@@ -222,8 +224,8 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
(not the entire problem) is marked correct.
"""
conditions = [
{'input_type': 'radio', 'value': '2'},
{'input_type': 'radio', 'value': ['2']}]
{'input_type': 'radio', 'question_label': '', 'value': '2'},
{'input_type': 'radio', 'question_label': '', 'value': ['2']}]
self.context['status'] = Status('correct')
......@@ -270,16 +272,16 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
"""
conditions = [
{'input_type': 'radio', 'status': Status('correct'), 'value': ''},
{'input_type': 'radio', 'status': Status('correct'), 'value': '2'},
{'input_type': 'radio', 'status': Status('correct'), 'value': ['2']},
{'input_type': 'radio', 'status': Status('incorrect'), 'value': '2'},
{'input_type': 'radio', 'status': Status('incorrect'), 'value': []},
{'input_type': 'radio', 'status': Status('incorrect'), 'value': ['2']},
{'input_type': 'checkbox', 'status': Status('correct'), 'value': []},
{'input_type': 'checkbox', 'status': Status('correct'), 'value': ['2']},
{'input_type': 'checkbox', 'status': Status('incorrect'), 'value': []},
{'input_type': 'checkbox', 'status': Status('incorrect'), 'value': ['2']}]
{'input_type': 'radio', 'status': Status('correct'), 'question_label': '', 'value': ''},
{'input_type': 'radio', 'status': Status('correct'), 'question_label': '', 'value': '2'},
{'input_type': 'radio', 'status': Status('correct'), 'question_label': '', 'value': ['2']},
{'input_type': 'radio', 'status': Status('incorrect'), 'question_label': '', 'value': '2'},
{'input_type': 'radio', 'status': Status('incorrect'), 'question_label': '', 'value': []},
{'input_type': 'radio', 'status': Status('incorrect'), 'question_label': '', 'value': ['2']},
{'input_type': 'checkbox', 'status': Status('correct'), 'question_label': '', 'value': []},
{'input_type': 'checkbox', 'status': Status('correct'), 'question_label': '', 'value': ['2']},
{'input_type': 'checkbox', 'status': Status('incorrect'), 'question_label': '', 'value': []},
{'input_type': 'checkbox', 'status': Status('incorrect'), 'question_label': '', 'value': ['2']}]
self.context['show_correctness'] = 'never'
self.context['submitted_message'] = 'Test message'
......@@ -315,9 +317,9 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
"""
conditions = [
{'input_type': 'radio', 'status': Status('unsubmitted'), 'value': ''},
{'input_type': 'radio', 'status': Status('unsubmitted'), 'value': []},
{'input_type': 'checkbox', 'status': Status('unsubmitted'), 'value': []},
{'input_type': 'radio', 'status': Status('unsubmitted'), 'question_label': '', 'value': ''},
{'input_type': 'radio', 'status': Status('unsubmitted'), 'question_label': '', 'value': []},
{'input_type': 'checkbox', 'status': Status('unsubmitted'), 'question_label': '', 'value': []},
# These tests expose bug #365
# When the bug is fixed, uncomment these cases.
......@@ -341,8 +343,8 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
def test_label(self):
xml = self.render_to_xml(self.context)
xpath = "//fieldset[@aria-label='%s']" % self.context['label']
self.assert_has_xpath(xml, xpath, self.context)
xpath = "//fieldset/legend"
self.assert_has_text(xml, xpath, self.context['question_label'])
class TextlineTemplateTest(TemplateTestCase):
......@@ -925,7 +927,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
(not the entire problem) is marked correct."""
conditions = [
{'input_type': 'radio', 'value': self.VALUE_DICT}]
{'input_type': 'radio', 'question_label': '', 'value': self.VALUE_DICT}]
self.context['status'] = 'correct'
......@@ -945,7 +947,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
(not the entire problem) is marked incorrect."""
conditions = [
{'input_type': 'radio', 'value': self.VALUE_DICT}]
{'input_type': 'radio', 'question_label': '', 'value': self.VALUE_DICT}]
self.context['status'] = 'incorrect'
......
......@@ -61,6 +61,7 @@ class OptionInputTest(unittest.TestCase):
'value': 'Down',
'options': [('Up', 'Up'), ('Down', 'Down'), ('Don\'t know', 'Don\'t know')],
'status': inputtypes.Status('answered'),
'question_label': '',
'label': '',
'msg': '',
'inline': False,
......@@ -121,6 +122,7 @@ class ChoiceGroupTest(unittest.TestCase):
'id': 'sky_input',
'value': 'foil3',
'status': inputtypes.Status('answered'),
'question_label': '',
'label': '',
'msg': '',
'input_type': expected_input_type,
......@@ -174,6 +176,7 @@ class JavascriptInputTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'prob_1_2',
'status': inputtypes.Status('unanswered'),
'question_label': '',
# 'label': '',
'msg': '',
'value': '3',
......@@ -207,6 +210,7 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'question_label': '',
'label': 'testing 123',
'size': size,
'msg': '',
......@@ -239,6 +243,7 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'question_label': '',
'label': '',
'size': size,
'msg': '',
......@@ -283,6 +288,7 @@ class TextLineTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'BumbleBee',
'status': inputtypes.Status('unanswered'),
'question_label': '',
'label': '',
'size': size,
'msg': '',
......@@ -324,6 +330,7 @@ class FileSubmissionTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'prob_1_2',
'status': inputtypes.Status('queued'),
'question_label': '',
'label': '',
'msg': the_input.submitted_msg,
'value': 'BumbleBee.py',
......@@ -374,6 +381,7 @@ class CodeInputTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
'question_label': '',
# 'label': '',
'msg': the_input.submitted_msg,
'mode': mode,
......@@ -429,6 +437,7 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
'question_label': '',
# 'label': '',
'msg': self.the_input.submitted_msg,
'mode': self.mode,
......@@ -460,6 +469,7 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
'question_label': '',
# 'label': '',
'msg': the_input.submitted_msg,
'mode': self.mode,
......@@ -491,6 +501,7 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status(status),
'question_label': '',
# 'label': '',
'msg': '',
'mode': self.mode,
......@@ -522,6 +533,7 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
'question_label': '',
# 'label': '',
'msg': the_input.submitted_msg,
'mode': self.mode,
......@@ -648,7 +660,14 @@ class MatlabTest(unittest.TestCase):
output = self.the_input.get_html()
self.assertEqual(
etree.tostring(output),
"""<div>{\'status\': Status(\'queued\'), \'button_enabled\': True, \'rows\': \'10\', \'queue_len\': \'3\', \'mode\': \'\', \'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\', \'linenumbers\': \'true\', \'queue_msg\': \'\', \'value\': \'print "good evening"\', \'msg\': u\'Submitted. As soon as a response is returned, this message will be replaced by that feedback.\', \'matlab_editor_js\': \'/dummy-static/js/vendor/CodeMirror/octave.js\', \'hidden\': \'\', \'id\': \'prob_1_2\', \'tabsize\': 4}</div>"""
" ".join(textwrap.dedent("""
<div>{\'status\': Status(\'queued\'), \'button_enabled\': True, \'rows\': \'10\', \'queue_len\': \'3\',
\'question_label\': \'\', \'mode\': \'\', \'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\',
\'linenumbers\': \'true\', \'queue_msg\': \'\', \'value\': \'print "good evening"\',
\'msg\': u\'Submitted. As soon as a response is returned, this message will be replaced by that feedback.\',
\'matlab_editor_js\': \'/dummy-static/js/vendor/CodeMirror/octave.js\', \'hidden\': \'\',
\'id\': \'prob_1_2\', \'tabsize\': 4}</div>
""").replace('\n', ' ').split())
)
# test html, that is correct HTML5 html, but is not parsable by XML parser.
......@@ -739,6 +758,7 @@ class MatlabTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'print "good evening"',
'status': inputtypes.Status('queued'),
'question_label': '',
'msg': self.the_input.submitted_msg,
'mode': self.mode,
'rows': self.rows,
......@@ -848,6 +868,7 @@ class SchematicTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'question_label': '',
'label': '',
'msg': '',
'initial_value': initial_value,
......@@ -892,6 +913,7 @@ class ImageInputTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'question_label': '',
'label': '',
'width': width,
'height': height,
......@@ -947,6 +969,7 @@ class CrystallographyTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'question_label': '',
# 'label': '',
'msg': '',
'width': width,
......@@ -989,6 +1012,7 @@ class VseprTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'question_label': '',
'msg': '',
'width': width,
'height': height,
......@@ -1022,6 +1046,7 @@ class ChemicalEquationTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'H2OYeah',
'status': inputtypes.Status('unanswered'),
'question_label': '',
'label': '',
'msg': '',
'size': self.size,
......@@ -1111,6 +1136,7 @@ class FormulaEquationTest(unittest.TestCase):
'id': 'prob_1_2',
'value': 'x^2+1/2',
'status': inputtypes.Status('unanswered'),
'question_label': '',
'label': '',
'msg': '',
'size': self.size,
......@@ -1240,6 +1266,7 @@ class DragAndDropTest(unittest.TestCase):
'id': 'prob_1_2',
'value': value,
'status': inputtypes.Status('unsubmitted'),
'question_label': '',
# 'label': '',
'msg': '',
'drag_and_drop_json': json.dumps(user_input)
......@@ -1292,6 +1319,7 @@ class AnnotationInputTest(unittest.TestCase):
'STATIC_URL': '/dummy-static/',
'id': 'annotation_input',
'status': inputtypes.Status('answered'),
'question_label': '',
# 'label': '',
'msg': '',
'title': 'foo',
......@@ -1368,6 +1396,7 @@ class TestChoiceText(unittest.TestCase):
expected = {
'STATIC_URL': '/dummy-static/',
'msg': '',
'question_label': '',
'label': '',
'input_type': expected_input_type,
'choices': choices,
......
......@@ -509,7 +509,7 @@ describe 'MarkdownEditingDescriptor', ->
[Explanation]
""")
expect(data).toEqual("""<problem>
<p>Who lead the civil right movement in the United States of America?</p>
<legend>Who lead the civil right movement in the United States of America?</legend>
<stringresponse answer="w*.?s*Luther Kings*.*" type="ci regexp" >
<textline label="Who lead the civil right movement in the United States of America?" size="20"/>
</stringresponse>
......@@ -541,14 +541,14 @@ describe 'MarkdownEditingDescriptor', ->
expect(data).toEqual("""<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of France?</p>
<legend>What is the capital of France?</legend>
<stringresponse answer="Paris" type="ci" >
<textline label="What is the capital of France?" size="20"/>
</stringresponse>
<p>Germany is a country in Europe, too.</p>
<p>What is the capital of Germany?</p>
<legend>What is the capital of Germany?</legend>
<multiplechoiceresponse>
<choicegroup label="What is the capital of Germany?" type="MultipleChoice">
<choice correct="false">Bonn</choice>
......@@ -574,11 +574,12 @@ describe 'MarkdownEditingDescriptor', ->
( ) Hamburg
(x) Berlin
( ) Donut
""")
expect(data).toEqual("""<problem>
<p>France is a country in Europe.</p>
<p>What is the capital of France?</p>
<legend>What is the capital of France?</legend>
<stringresponse answer="Paris" type="ci" >
<textline label="What is the capital of France?" size="20"/>
</stringresponse>
......@@ -594,8 +595,8 @@ describe 'MarkdownEditingDescriptor', ->
<choice correct="false">Donut</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>""")
it 'tests malformed labels', ->
data = MarkdownEditingDescriptor.markdownToXml("""
......@@ -604,7 +605,7 @@ describe 'MarkdownEditingDescriptor', ->
>>What is the capital of France?<
= Paris
blah>>What is the capital of <<Germany?<<
>>What is the capital of <<Germany?<<
( ) Bonn
( ) Hamburg
(x) Berlin
......@@ -618,7 +619,7 @@ describe 'MarkdownEditingDescriptor', ->
<textline size="20"/>
</stringresponse>
<p>blahWhat is the capital of Germany?</p>
<legend>What is the capital of Germany?</legend>
<multiplechoiceresponse>
<choicegroup label="What is the capital of &lt;&lt;Germany?" type="MultipleChoice">
<choice correct="false">Bonn</choice>
......@@ -636,7 +637,7 @@ describe 'MarkdownEditingDescriptor', ->
= 3.14159 +- .02
""")
expect(data).toEqual("""<problem>
<p>Enter the numerical value of Pi:</p>
<legend>Enter the numerical value of Pi:</legend>
<numericalresponse answer="3.14159">
<responseparam type="tolerance" default=".02" />
<formulaequationinput label="Enter the numerical value of Pi:" />
......@@ -650,7 +651,7 @@ describe 'MarkdownEditingDescriptor', ->
= Paris
""")
expect(data).toEqual("""<problem>
<p>What is the "capital" of France & the 'best' > place < to live"?</p>
<legend>What is the "capital" of France & the 'best' > place < to live"?</legend>
<stringresponse answer="Paris" type="ci" >
<textline label="What is the &quot;capital&quot; of France &amp; the &apos;best&apos; &gt; place &lt; to live&quot;?" size="20"/>
</stringresponse>
......
......@@ -371,7 +371,9 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
line = line.replace(/>>|<</g, '');
line = line.replace(/>>/g, '<legend>');
line = line.replace(/<+$/g, '</legend>');
line = line.replace(/<</g, '');
} else if (line.match(/<\w+response/) && didinput && curlabel == prevlabel) {
// reset label to prevent gobbling up previous one (if multiple questions)
curlabel = '';
......
......@@ -16,6 +16,7 @@ metadata:
[x] French
[ ] Hungarian
Note: Make sure you select all of the correct options—there may be more than one!
[explanation]
......@@ -28,18 +29,16 @@ data: |
<p>When you add the component, be sure to select <strong>Settings</strong>
to specify a <strong>Display Name</strong> and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<fieldset>
<legend>The following languages are in the Indo-European family:</legend>
<choiceresponse>
<checkboxgroup direction="vertical">
<choice correct="true" name="urdu">Urdu</choice>
<choice correct="false" name="finnish">Finnish</choice>
<choice correct="true" name="marathi">Marathi</choice>
<choice correct="true" name="french">French</choice>
<choice correct="false" name="hungarian">Hungarian</choice>
</checkboxgroup>
</choiceresponse>
</fieldset>
<legend>The following languages are in the Indo-European family:</legend>
<choiceresponse>
<checkboxgroup direction="vertical">
<choice correct="true" name="urdu">Urdu</choice>
<choice correct="false" name="finnish">Finnish</choice>
<choice correct="true" name="marathi">Marathi</choice>
<choice correct="true" name="french">French</choice>
<choice correct="false" name="hungarian">Hungarian</choice>
</checkboxgroup>
</choiceresponse>
<p><strong>Note</strong>: Make sure you select all of the correct options—there may be more than one!</p>
<solution>
<div class="detailed-solution">
......
......@@ -15,6 +15,7 @@ metadata:
(x) Indonesia
( ) Russia
[explanation]
According to September 2014 estimates:
The population of Indonesia is approximately 250 million.
......@@ -30,7 +31,6 @@ data: |
<p>When you add the problem, be sure to select <strong>Settings</strong>
to specify a <strong>Display Name</strong> and other values that apply.</p>
<p>You can use the following example problem as a model.</p>
<fieldset>
<legend>Which of the following countries has the largest population?</legend>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice">
......@@ -40,7 +40,6 @@ data: |
<choice correct="false" name="russia">Russia</choice>
</choicegroup>
</multiplechoiceresponse>
</fieldset>
<solution>
<div class="detailed-solution">
<p>Explanation</p>
......
......@@ -14,11 +14,12 @@ metadata:
>>How many miles away from Earth is the sun? Use scientific notation to answer.<<
= 9.3*10^6
or= 9.296*10^6
or= 9.296*10^6
>>The square of what number is -100?<<
= 10*i
= 10*i
[explanation]
The sun is 93,000,000, or 9.3*10^6, miles away from Earth.
......
......@@ -14,6 +14,7 @@ metadata:
[[(India), Spain, China, Bermuda]]
[explanation]
India became an independent nation on August 15, 1947.
[explanation]
......
......@@ -14,7 +14,7 @@ metadata:
= Nanjing Higher Normal Institute
or= National Central University
or= Nanjing University
[explanation]
Nanjing Higher Normal Institute first admitted female students in 1920.
[explanation]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment