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

Commit 1528542

Browse files
committed
Merge pull request #20 from RunestoneInteractive/master
Updating master
2 parents 5cb7e5f + 0ed8abb commit 1528542

File tree

8 files changed

+408
-150
lines changed

8 files changed

+408
-150
lines changed

runestone/assess/js/mchoice.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ MultipleChoice.prototype.createMCForm = function () {
148148

149149
MultipleChoice.prototype.renderMCContainer = function () {
150150
this.containerDiv = document.createElement("div");
151-
$(this.containerDiv).text(this.question);
151+
$(this.containerDiv).html(this.question);
152152
$(this.containerDiv).addClass("alert alert-warning");
153153
this.containerDiv.id = this.divid;
154154
};

runestone/assess/multiplechoice.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def run(self):
123123
...
124124
"""
125125
TEMPLATE_START = '''
126-
<ul data-component="multiplechoice" data-multipleanswers="%(multipleAnswers)s" %(random)s id="%(divid)s">%(bodytext)s
126+
<ul data-component="multiplechoice" data-multipleanswers="%(multipleAnswers)s" %(random)s id="%(divid)s">
127127
'''
128128

129129
OPTION = '''
@@ -146,7 +146,7 @@ def run(self):
146146
mcNode.template_option = OPTION
147147
mcNode.template_end = TEMPLATE_END
148148

149-
#self.state.nested_parse(self.content, self.content_offset, mcNode)
149+
self.state.nested_parse(self.content, self.content_offset, mcNode)
150150
return [mcNode]
151151

152152
#backwards compatibility

runestone/clickableArea/README.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
<h2>Clickable Area</h2>
22

33
```html
4-
<pre data-component="clickablearea" id="clickable1">
5-
<span data-question>Click on all variable assignment statements</span><span data-feedback>Remember, variable assignment statements usually involve the operator '='.</span>def main():
4+
<div data-component="clickablearea" id="clickable1">
5+
<span data-question>Click on all variable assignment statements</span><span data-feedback>Remember, variable assignment statements usually involve the operator '='.</span>
6+
<pre>
7+
def main():
68
<span data-incorrect>print("Hello world")</span>
79
<span data-correct>x = 4</span>
810
for i in range(5):
911
<span data-correct>y = i</span>
1012
print(y)
1113
<span data-incorrect>return 0</span>
1214
</pre>
15+
</div>
1316
```
14-
Here the <code>pre</code> tag represents the entire component to be rendered.
15-
Each area that the author would like to be clickable is wrapped in a <code>span</code> tag that has the <code>data-correct</code> or <code>data-incorrect</code> attribute.
16-
After specifying the data-component, question and feedback (optional), the author can start his/her block of code, indented as he/he would like, using <code>span</code> elements to identify the clickable parts of the code.
17+
```html
18+
<div data-component="clickablearea"><span data-question>This is the question.</span>
19+
<table border="1" style="width:100%">
20+
<tr id=test>
21+
<td data-correct>Table Cell 1</td>
22+
<td>Table Cell 2</td>
23+
<td><img data-incorrect src="http://images/example.jpg"></td>
24+
</tr>
25+
<tr data-correct>
26+
<td>Table Cell 4</td>
27+
<td>Table Cell 5</td>
28+
<td>Table Cell 6</td>
29+
</tr>
30+
</table>
31+
</div>
32+
```
33+
Here the <code>div</code> tag represents the entire component to be rendered.
34+
35+
Each element that the author would like to be clickable must have either the <code>data-correct</code> or <code>data-incorrect</code> attribute.
36+
After specifying the <code>data-component</code>, <code>data-question</code> and <code>data-feedback</code> (feedback is optional), the author can create any HTML elements he/she wants, and make any of them clickable with the <code>data-correct</code>/data-incorrect</code> tags. If the author would like to make a block of code with specific areas to be clickable, he/she can create a <code>pre</code> element and wrap the clickable parts of the code in <code>span</code> elements with the <code>data-correct</code>/<code>data-incorrect</code> attributes.
1737

1838
Option spec:
1939
<ul>
Lines changed: 1 addition & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1 @@
1-
# Copyright (C) 2011 Bradley N. Miller
2-
#
3-
# This program is free software: you can redistribute it and/or modify
4-
# it under the terms of the GNU General Public License as published by
5-
# the Free Software Foundation, either version 3 of the License, or
6-
# (at your option) any later version.
7-
#
8-
# This program is distributed in the hope that it will be useful,
9-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11-
# GNU General Public License for more details.
12-
#
13-
# You should have received a copy of the GNU General Public License
14-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15-
#
16-
17-
__author__ = 'isaiahmayerchak'
18-
19-
from docutils import nodes
20-
from docutils.parsers.rst import directives
21-
from docutils.parsers.rst import Directive
22-
23-
def setup(app):
24-
app.add_directive('clickablearea',ClickableArea)
25-
app.add_javascript('clickable.js')
26-
app.add_javascript('timedclickable.js')
27-
app.add_stylesheet('clickable.css')
28-
29-
app.add_node(ClickableAreaNode, html=(visit_ca_node, depart_ca_node))
30-
31-
32-
TEMPLATE = """
33-
<pre data-component="clickablearea" id="%(divid)s">
34-
<span data-question>%(question)s</span>%(feedback)s%(clickcode)s
35-
</pre>
36-
"""
37-
38-
39-
class ClickableAreaNode(nodes.General, nodes.Element):
40-
def __init__(self,content):
41-
"""
42-
Arguments:
43-
- `self`:
44-
- `content`:
45-
"""
46-
super(ClickableAreaNode,self).__init__()
47-
self.ca_options = content
48-
49-
# self for these functions is an instance of the writer class. For example
50-
# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator
51-
# The node that is passed as a parameter is an instance of our node class.
52-
def visit_ca_node(self,node):
53-
res = TEMPLATE
54-
55-
if "feedback" in node.ca_options:
56-
node.ca_options["feedback"] = "<span data-feedback>" + node.ca_options["feedback"] + "</span>"
57-
else:
58-
node.ca_options["feedback"] = ""
59-
60-
res = res % node.ca_options
61-
62-
self.body.append(res)
63-
64-
def depart_ca_node(self,node):
65-
pass
66-
67-
68-
class ClickableArea(Directive):
69-
required_arguments = 1
70-
optional_arguments = 0
71-
has_content = True
72-
option_spec = {"question":directives.unchanged,
73-
"feedback":directives.unchanged
74-
}
75-
76-
def run(self):
77-
"""
78-
process the multiplechoice directive and generate html for output.
79-
:param self:
80-
:return:
81-
.. clickablearea:: identifier
82-
:question: Question text
83-
84-
--Content--
85-
"""
86-
self.options['divid'] = self.arguments[0]
87-
88-
if self.content:
89-
source = "\n".join(self.content)
90-
else:
91-
source = '\n'
92-
source = source.replace(":click-correct:", "<span data-correct>")
93-
source = source.replace(":click-incorrect:", "<span data-incorrect>")
94-
source = source.replace(":endclick:", "</span>")
95-
self.options['clickcode'] = source
96-
97-
clickNode = ClickableAreaNode(self.options)
98-
clickNode.template_start = TEMPLATE
99-
100-
return [clickNode]
1+
from .clickable import *
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Copyright (C) 2011 Bradley N. Miller
2+
#
3+
# This program is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
#
16+
17+
__author__ = 'isaiahmayerchak'
18+
19+
from docutils import nodes
20+
from docutils.parsers.rst import directives
21+
from docutils.parsers.rst import Directive
22+
23+
def setup(app):
24+
app.add_directive('clickablearea',ClickableArea)
25+
app.add_javascript('clickable.js')
26+
app.add_javascript('timedclickable.js')
27+
app.add_stylesheet('clickable.css')
28+
29+
app.add_node(ClickableAreaNode, html=(visit_ca_node, depart_ca_node))
30+
31+
32+
TEMPLATE = """
33+
<div data-component="clickablearea" id="%(divid)s" %(table)s %(correct)s %(incorrect)s>
34+
<span data-question>%(question)s</span>%(feedback)s%(clickcode)s
35+
"""
36+
TEMPLATE_END = """
37+
</div>
38+
"""
39+
40+
class ClickableAreaNode(nodes.General, nodes.Element):
41+
def __init__(self,content):
42+
"""
43+
Arguments:
44+
- `self`:
45+
- `content`:
46+
"""
47+
super(ClickableAreaNode,self).__init__()
48+
self.ca_options = content
49+
50+
# self for these functions is an instance of the writer class. For example
51+
# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator
52+
# The node that is passed as a parameter is an instance of our node class.
53+
def visit_ca_node(self,node):
54+
res = TEMPLATE
55+
56+
if "feedback" in node.ca_options:
57+
node.ca_options["feedback"] = "<span data-feedback>" + node.ca_options["feedback"] + "</span>"
58+
else:
59+
node.ca_options["feedback"] = ""
60+
61+
if "iscode" not in node.ca_options:
62+
node.ca_options["correct"] = "data-cc=" + '"' + node.ca_options["correct"] + '"'
63+
node.ca_options["incorrect"] = "data-ci=" + '"' + node.ca_options["incorrect"] + '"'
64+
else:
65+
node.ca_options["correct"] = ""
66+
node.ca_options["incorrect"] = ""
67+
68+
res = res % node.ca_options
69+
70+
self.body.append(res)
71+
72+
def depart_ca_node(self,node):
73+
res = ""
74+
res = TEMPLATE_END % node.ca_options
75+
self.body.append(res)
76+
77+
78+
class ClickableArea(Directive):
79+
required_arguments = 1
80+
optional_arguments = 0
81+
has_content = True
82+
final_argument_whitespace = True
83+
option_spec = {"question":directives.unchanged,
84+
"feedback":directives.unchanged,
85+
"iscode":directives.flag,
86+
"correct":directives.unchanged,
87+
"incorrect":directives.unchanged,
88+
"table":directives.flag
89+
}
90+
91+
def run(self):
92+
"""
93+
process the clickablearea directive and generate html for output.
94+
:param self:
95+
:return:
96+
.. clickablearea:: identifier
97+
:question: Question text
98+
:feedback: Optional feedback for incorrect answer
99+
:iscode: Boolean that if present will put the content into a <pre>
100+
:table: Boolean that indicates that the content is a table.
101+
:correct: An array of the indices of the correct elements, separated by semicolons--if this is a table, each item in the array is a tuple
102+
with the first number being the row and the second number being the column--use a column number of 0 to make the whole row correct (ex: 1,2;3,0 makes the 2nd data cell in the first row correct as well as the entire 3rd row)
103+
:incorrect: An array of the indices of the incorrect elements--same format as the correct elements.
104+
--Content--
105+
"""
106+
self.assert_has_content()
107+
self.options['divid'] = self.arguments[0]
108+
if "iscode" in self.options:
109+
source = "\n".join(self.content)
110+
source = source.replace(":click-correct:", "<span data-correct>")
111+
source = source.replace(":click-incorrect:", "<span data-incorrect>")
112+
source = source.replace(":endclick:", "</span>")
113+
source = "<pre>" + source + "</pre>"
114+
self.options['clickcode'] = source
115+
else:
116+
self.options['clickcode'] = ''
117+
clickNode = ClickableAreaNode(self.options)
118+
clickNode.template_start = TEMPLATE
119+
120+
if "table" in self.options:
121+
self.options["table"] = "data-table"
122+
else:
123+
self.options["table"] = ""
124+
125+
if "iscode" not in self.options:
126+
self.state.nested_parse(self.content, self.content_offset, clickNode)
127+
128+
return [clickNode]

runestone/clickableArea/css/clickable.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,53 @@
33
}
44

55
.clickable-clicked {
6+
box-shadow: 0px 0px 2px 2px rgba(0,100,0,0.75);
7+
}
8+
9+
span.clickable-clicked {
610
background-color: yellow;
11+
box-shadow: initial;
12+
}
13+
14+
.clickable-clicked td {
15+
background-color: #dad6c1;
16+
box-shadow: initial;
17+
}
18+
19+
td.clickable-clicked{
20+
background-color: #dad6c1;
21+
box-shadow: initial;
22+
}
23+
24+
td img {
25+
margin: 5px;
26+
}
27+
28+
.clickable-clicked th {
29+
background-color: #dad6c1;
30+
box-shadow: initial;
31+
}
32+
33+
th.clickable-clicked{
34+
background-color: #dad6c1;
35+
box-shadow: initial;
36+
}
37+
38+
.clickable-incorrect {
39+
border: 1px solid red !important;
40+
background-color: #f2dede !important;
41+
}
42+
43+
.clickable-incorrect th {
44+
border: 1px solid red !important;
45+
background-color: #f2dede !important;
46+
}
47+
48+
.clickable-incorrect td {
49+
border: 1px solid red !important;
50+
background-color: #f2dede !important;
51+
}
52+
53+
img.clickable-incorrect {
54+
box-shadow: 0px 0px 2px 2px rgba(100,0,0,0.75);
755
}

0 commit comments

Comments
 (0)