Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 411aef3

Browse files
committed
Pretext from clickable, codelens, and dnd
1 parent d18db7f commit 411aef3

File tree

3 files changed

+73
-16
lines changed

3 files changed

+73
-16
lines changed

runestone/clickableArea/clickable.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def setup(app):
3131
app.add_directive("clickablearea", ClickableArea)
3232

3333
app.add_node(ClickableAreaNode, html=(visit_ca_html, depart_ca_html),
34-
xml=(substitute_visitor, substitute_departure))
34+
xml=(visit_ca_xml, depart_ca_xml))
3535

3636
app.add_config_value("clickable_div_class", "", "html")
3737

@@ -46,6 +46,11 @@ def setup(app):
4646
</div>
4747
"""
4848

49+
XML_START = """
50+
<exercise xml:id="{divid}">
51+
<statement><p>{question}</p></statement>
52+
"""
53+
4954

5055
class ClickableAreaNode(nodes.General, nodes.Element, RunestoneIdNode):
5156
pass
@@ -97,6 +102,29 @@ def depart_ca_html(self, node):
97102
self.body.remove(node["delimiter"])
98103

99104

105+
def visit_ca_xml(self, node):
106+
res = XML_START.format(**node["runestone_options"])
107+
if node["runestone_options"]["feedback"]:
108+
res += "<feedback><p>{feedback}</p></feedback>\n".format(
109+
**node["runestone_options"])
110+
res += "<areas>\n"
111+
if "iscode" in node["runestone_options"]:
112+
# The case where iscode is not in options makes no sense and probably does not exist in
113+
# any runestone books
114+
for row in node["runestone_options"]["raw_source"]:
115+
row = row.replace("\n", "")
116+
row = row.replace(":click-correct:", "<area correct='yes'>")
117+
row = row.replace(":click-incorrect:", "<area>")
118+
row = row.replace(":endclick", "</area>")
119+
row = "<cline>" + row + "</cline>\n"
120+
res += row
121+
self.output.append(res)
122+
123+
124+
def depart_ca_xml(self, node):
125+
self.output.append("</areas></exercise>")
126+
127+
100128
class ClickableArea(RunestoneIdDirective):
101129
"""
102130
.. clickablearea:: identifier
@@ -159,6 +187,7 @@ def run(self):
159187
source = source.replace(":endclick:", "</span>")
160188
source = "<pre>" + source + "</pre>"
161189
self.options["clickcode"] = source
190+
self.options["raw_source"] = self.content
162191
else:
163192
self.options["clickcode"] = ""
164193
clickNode = ClickableAreaNode()

runestone/codelens/visualizer.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ def setup(app):
6161
</div>
6262
"""
6363

64+
PTX_TEMPLATE = """
65+
<program xml:id="{divid} interactive="codelens" language="{language}>
66+
<input>
67+
{source}
68+
</input>
69+
</program>
70+
"""
71+
6472

6573
class CodeLensNode(nodes.General, nodes.Element, RunestoneIdNode):
6674
pass
@@ -73,18 +81,8 @@ def visit_codelens_xml(self, node):
7381
if "tracedata" in node["runestone_options"]:
7482
node["runestone_options"]["tracedata"] = node["runestone_options"]["tracedata"].replace(
7583
"<", "&lt;").replace(">", "&gt;")
76-
html += DATA
77-
else:
78-
html += "</div>"
79-
html = html % node["runestone_options"]
8084

81-
self.output.append(
82-
"<exercise runestone='{divid}' />".format(**node["runestone_options"]))
83-
with open("rs-substitutes.xml", "a") as subfile:
84-
subfile.write("<substitute xml:id='{divid}'>".format(
85-
**node["runestone_options"]))
86-
subfile.write(html)
87-
subfile.write("</substitute>")
85+
res = PTX_TEMPLATE.format(**node["runestone_options"])
8886

8987

9088
def visit_codelens_html(self, node):
@@ -209,7 +207,7 @@ def js_var_finalizer(input_code, output_trace):
209207
source = "\n".join(self.content)
210208
else:
211209
source = "\n"
212-
210+
self.options["source"] = source.replace("<", "&lt;")
213211
CUMULATIVE_MODE = False
214212
self.JS_VARNAME = self.options["divid"] + "_trace"
215213
env = self.state.document.settings.env

runestone/dragndrop/dragndrop.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
def setup(app):
3434
app.add_directive("dragndrop", DragNDrop)
3535

36-
app.add_node(DragNDropNode, html=(visit_dnd_html, depart_dnd_html))
36+
app.add_node(DragNDropNode, html=(visit_dnd_html, depart_dnd_html),
37+
xml=(visit_dnd_xml, depart_dnd_xml))
3738

3839
app.add_config_value("dragndrop_div_class", "runestone", "html")
3940

@@ -51,6 +52,12 @@ def setup(app):
5152
"""
5253
TEMPLATE_END = """</ul></div>"""
5354

55+
XML_START = """
56+
<exercise xml:id="{divid}">
57+
<statement><p>{question}</p></statement>
58+
{feedback}
59+
"""
60+
5461

5562
class DragNDropNode(nodes.General, nodes.Element, RunestoneIdNode):
5663
pass
@@ -61,11 +68,34 @@ class DragNDropNode(nodes.General, nodes.Element, RunestoneIdNode):
6168

6269

6370
def visit_dnd_xml(self, node):
64-
write_substitute(self, node)
71+
res = XML_START
72+
73+
if "feedback" in node["runestone_options"]:
74+
node["runestone_options"]["feedback"] = (
75+
"<feedback><p>"
76+
+ node["runestone_options"]["feedback"]
77+
+ "</p></feedback>"
78+
)
79+
else:
80+
node["runestone_options"]["feedback"] = ""
81+
82+
res = res.format(**node["runestone_options"])
83+
self.output.append(res)
6584

6685

6786
def depart_dnd_xml(self, node):
68-
pass
87+
self.output.append("<matches>")
88+
okeys = list(node["runestone_options"].keys())
89+
okeys.sort()
90+
for k in okeys:
91+
if "match" in k:
92+
x, ix = k.split("_")
93+
dragE, dropE = node["runestone_options"][k].split("|||")
94+
self.output.append(f'<match order="{ix}">')
95+
self.output.append(f"<premise>{dragE}</premise>")
96+
self.output.append(f"<response>{dropE}</response>")
97+
self.output.append("</match>")
98+
self.output.append("</matches></exercise>")
6999

70100

71101
def visit_dnd_html(self, node):

0 commit comments

Comments
 (0)