@@ -40,10 +40,9 @@ class MChoiceNode(nodes.General, nodes.Element, RunestoneIdNode):
4040 <statement>
4141
4242"""
43-
43+ # TODO: detect old versus new style to include the choices or not
4444XML_START_END = """
4545 </statement>
46- <choices>
4746"""
4847
4948XML_OPTION = """
@@ -52,13 +51,12 @@ class MChoiceNode(nodes.General, nodes.Element, RunestoneIdNode):
5251 <p>{atext}</p>
5352 </statement>
5453 <feedback>
55- <p>Incorrect: green means "go!".</p>
54+ {feedtext}
5655 </feedback>
5756 </choice>
5857"""
5958
6059XML_END = """
61- </choices>
6260 </exercise>
6361"""
6462
@@ -101,6 +99,8 @@ def depart_mc_common(self, node):
10199 res = ""
102100 currFeedback = ""
103101 # Add all of the possible answers
102+ if node ["runestone_options" ]["is_new_style" ] == False and hasattr (self , "output" ):
103+ res += "<choices>\n "
104104 okeys = list (node ["runestone_options" ].keys ())
105105 okeys .sort ()
106106 for k in okeys :
@@ -113,11 +113,12 @@ def depart_mc_common(self, node):
113113 currFeedback , ""
114114 ) # node["runestone_options"][currFeedback]
115115 if label in node ["runestone_options" ]["correct" ]:
116- node ["runestone_options" ]["is_correct" ] = "data-correct"
116+ node ["runestone_options" ]["is_correct" ] = "data-correct='yes' "
117117 else :
118118 node ["runestone_options" ]["is_correct" ] = ""
119119 res += node ["template_option" ].format (** node ["runestone_options" ])
120-
120+ if node ["runestone_options" ]["is_new_style" ] == False and hasattr (self , "output" ):
121+ res += "</choices>\n "
121122 res += node ["template_end" ].format (** node ["runestone_options" ])
122123 return res
123124
@@ -126,8 +127,8 @@ def visit_mc_xml(self, node):
126127 node ["template_start" ] = XML_START
127128 node ["template_end" ] = XML_END
128129 node ["template_option" ] = XML_OPTION
129- pdb .set_trace ()
130130 res = visit_mc_common (self , node )
131+ res = res .replace ("data-correct" , "correct" )
131132 self .output .append (res )
132133
133134
@@ -290,13 +291,14 @@ def run(self):
290291 # ...and so on...
291292 #
292293 # See if the last item is a list. If so, and questions/answers weren't specified as options, assume it contains questions and answers.
294+ self .options ["is_new_style" ] = False
293295 answers_bullet_list = mcNode [- 1 ] if len (mcNode ) else None
294296 if isinstance (answers_bullet_list , nodes .bullet_list ) and (
295297 "answer_a" not in self .options and ("correct" not in self .options )
296298 ):
297299 # Accumulate the correct answers.
298300 correct_answers = []
299-
301+ self . options [ "is_new_style" ] = True
300302 # Walk it, processing each answer and its associated feedback.
301303 for answer_list_item in answers_bullet_list :
302304 assert isinstance (answer_list_item , nodes .list_item )
@@ -402,6 +404,15 @@ def depart_answers_bullet_html(self, node):
402404 self .compact_simple , self .compact_p = self .context .pop ()
403405
404406
407+ def visit_answers_bullet_xml (self , node ):
408+ self .output .append ("</statement>" )
409+ self .output .append ("<choices>" )
410+
411+
412+ def depart_answers_bullet_xml (self , node ):
413+ self .output .append ("</choice>" )
414+
415+
405416# Write out the special attributes needed by the ``<li>`` tag.
406417def visit_answer_list_item (self , node ):
407418 # See the structure_.
@@ -423,11 +434,36 @@ def visit_answer_list_item(self, node):
423434 )
424435
425436
437+ def visit_answer_list_item_xml (self , node ):
438+ # See the structure_.
439+ mc_node = node .parent .parent
440+
441+ # _`label`: Turn the index of this item in the answer_bullet_list (see structure_) into a letter.
442+ label = chr (node .parent .index (node ) + ord ("a" ))
443+ # Update dict for formatting the HTML.
444+ mc_node ["runestone_options" ]["alabel" ] = label
445+ if label in mc_node ["runestone_options" ]["correct" ]:
446+ mc_node ["runestone_options" ]["is_correct" ] = "data-correct"
447+ self .output .append ("<choice correct='yes'>" )
448+ else :
449+ mc_node ["runestone_options" ]["is_correct" ] = ""
450+ self .output .append ("<choice>" )
451+ # Format the HTML.
452+ self .output .append (
453+ '<statement id="{divid}_opt_{alabel}">' .format (
454+ ** mc_node ["runestone_options" ])
455+ )
456+
457+
426458# Although the feedback for an answer is given as a sublist, the HTML is just a list. So, let the feedback list item close this list.
427459def depart_answer_list_item (self , node ):
428460 pass
429461
430462
463+ def depart_answer_list_item_xml (self , node ):
464+ self .output .append ("</choice>" )
465+
466+
431467# Nothing to output, since feedback isn't nested under an answer in the HTML.
432468def visit_feedback_bullet_html (self , node ):
433469 pass
@@ -450,11 +486,29 @@ def visit_feedback_list_item(self, node):
450486 )
451487
452488
489+ def visit_feedback_list_item_xml (self , node ):
490+ # See label_ and structure_.
491+ answer_list_item = node .parent .parent
492+ mc_node = answer_list_item .parent .parent
493+ label = chr (answer_list_item .parent .index (answer_list_item ) + ord ("a" ))
494+ mc_node ["runestone_options" ]["alabel" ] = label
495+ self .output .append ("</statement>" )
496+ self .output .append (
497+ '<feedback id="{divid}_opt_{alabel}">\n ' .format (
498+ ** mc_node ["runestone_options" ])
499+ )
500+
501+
453502def depart_feedback_list_item (self , node ):
454503 self .body .append ("</li>" )
455504
456505
506+ def depart_feedback_list_item_xml (self , node ):
507+ self .output .append ("</feedback>" )
508+
457509# backwards compatibility
510+
511+
458512class MChoiceMF (MChoice ):
459513 def run (self ):
460514 raise self .error (
0 commit comments