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

Commit b700d3c

Browse files
committed
revert parsons back to pre-RSE0001 implementation
1 parent 212aa0f commit b700d3c

File tree

7 files changed

+1163
-308
lines changed

7 files changed

+1163
-308
lines changed

runestone/parsons/README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Parsons Directive
2+
=================
3+
4+
The master repository for the parsons problems code is https://github.com/vkaravir/js-parsons.git
5+
6+
If you want to make customizations ONLY for runestone you should use the fork at https://github.com/bnmnetp/js-parsons.git
7+

runestone/parsons/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
12
from .parsons import *
3+

runestone/parsons/css/parsons.css

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ li.correctPosition, .testcase.pass {
7272
.testcase .msg { font-weight: bold; }
7373
.testcase .error { color: red;}
7474
.testcase .feedback { font-weight: bolder;}
75-
.testcase.fail .expected, .testcase.fail .actual {
76-
color: red;
75+
.testcase.fail .expected, .testcase.fail .actual {
76+
color: red;
7777
font-weight: bolder;
7878
}
79-
.testcase .output {
80-
display: block;
81-
white-space: pre;
79+
.testcase .output {
80+
display: block;
81+
white-space: pre;
8282
background-color: #555555;
8383
color: white;
8484
font-size: 12px;

runestone/parsons/js/lib/jquery-ui.min.js

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runestone/parsons/js/lib/jquery.min.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runestone/parsons/js/parsons.js

Lines changed: 957 additions & 257 deletions
Large diffs are not rendered by default.

runestone/parsons/parsons.py

Lines changed: 173 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# You should have received a copy of the GNU General Public License
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
#
16-
__author__ = 'isaiahmayerchak'
16+
__author__ = 'hewner'
1717

1818
import re
1919
from docutils import nodes
@@ -28,44 +28,17 @@ def setup(app):
2828
app.add_stylesheet('parsons.css')
2929
app.add_stylesheet('lib/prettify.css')
3030

31-
app.add_node(ParsonsNode, html=(visit_prs_node, depart_prs_node))
32-
3331
# includes parsons specific javascript headers
3432
# parsons-noconflict reverts underscore and
3533
# jquery to their original versions
34+
app.add_javascript('lib/jquery.min.js')
35+
app.add_javascript('lib/jquery-ui.min.js')
3636
app.add_javascript('lib/prettify.js')
3737
app.add_javascript('lib/underscore-min.js')
3838
app.add_javascript('lib/lis.js')
3939
app.add_javascript('parsons.js')
40-
app.add_javascript('parsonsaux.js')
41-
42-
43-
TEMPLATE = '''
44-
<pre data-component="parsons" id="%(divid)s">
45-
<span data-question>%(qnumber)s: %(instructions)s</span>%(code)s</pre>
46-
'''
47-
48-
class ParsonsNode(nodes.General, nodes.Element):
49-
def __init__(self,content):
50-
"""
51-
Arguments:
52-
- `self`:
53-
- `content`:
54-
"""
55-
super(ParsonsNode,self).__init__()
56-
self.prs_options = content
57-
58-
def visit_prs_node(self,node):
59-
res = TEMPLATE % node.prs_options
60-
61-
self.body.append(res)
40+
app.add_javascript('parsons-noconflict.js')
6241

63-
def depart_prs_node(self,node):
64-
''' This is called at the start of processing an datafile node. If parsons had recursive nodes
65-
etc and did not want to do all of the processing in visit_prs_node any finishing touches could be
66-
added here.
67-
'''
68-
pass
6942

7043
class ParsonsProblem(Assessment):
7144
required_arguments = 1
@@ -76,13 +49,18 @@ class ParsonsProblem(Assessment):
7649

7750
def run(self):
7851
"""
79-
Instructions for solving the problem should be written and then a line with -----
52+
53+
Instructions for solving the problem should be written and then a line with -----
8054
signals the beginning of the code. If you want more than one line in a single
8155
code block, seperate your code blocks with =====.
56+
8257
Both the instructions sections and code blocks are optional. If you don't include any
8358
=====, the code will assume you want each line to be its own code block.
59+
8460
Example:
61+
8562
.. parsonsprob:: unqiue_problem_id_here
63+
8664
Solve my really cool parsons problem...if you can.
8765
-----
8866
def findmax(alist):
@@ -98,24 +76,173 @@ def findmax(alist):
9876
curmax = item
9977
=====
10078
return curmax
79+
80+
10181
"""
102-
self.options['divid'] = self.arguments[0]
103-
self.options['qnumber'] = self.getNumber()
104-
self.options['instructions'] = ""
105-
self.options['code'] = self.content
82+
83+
template_values = {}
84+
template_values['qnumber'] = self.getNumber()
85+
template_values['unique_id'] = self.lineno
86+
template_values['instructions'] = ""
87+
code = self.content
88+
10689
if '-----' in self.content:
10790
index = self.content.index('-----')
108-
self.options['instructions'] = "\n".join(self.content[:index])
109-
self.options['code'] = self.content[index + 1:]
91+
template_values['instructions'] = "\n".join(self.content[:index])
92+
code = self.content[index + 1:]
11093

111-
if '=====' in self.options['code']:
112-
self.options['code'] = "\n".join(self.options['code'])
113-
114-
self.options['code'] = self.options['code'].replace('=====', '---')
94+
if '=====' in code:
95+
template_values['code'] = self.parse_multiline_parsons(code);
11596
else:
116-
self.options['code'] = "\n".join(self.options['code'])
117-
118-
self.options['divid'] = self.arguments[0]
97+
template_values['code'] = "\n".join(code)
98+
99+
template_values['divid'] = self.arguments[0]
100+
101+
TEMPLATE = '''
102+
<div class='parsons alert alert-warning' id="parsons-%(unique_id)s">
103+
<div class="parsons-text">%(qnumber)s: %(instructions)s<br /><br /></div>
104+
<div style="clear:left;"></div>
105+
<div id="parsons-orig-%(unique_id)s" style="display:none;">%(code)s</div>
106+
<div class="sortable-code-container">
107+
<div id="parsons-sortableTrash-%(unique_id)s" class="sortable-code"></div>
108+
<div id="parsons-sortableCode-%(unique_id)s" class="sortable-code"></div>
109+
<div style="clear:left;"></div>
110+
</div>
111+
<div class="parsons-controls">
112+
<input type="button" class='btn btn-success' id="checkMe%(unique_id)s" value="Check Me"/>
113+
<input type="button" class='btn btn-default' id="reset%(unique_id)s" value="Reset"/>
114+
<div id="parsons-message-%(unique_id)s"></div>
115+
</div>
116+
</div>
117+
118+
<script>
119+
$pjQ(document).ready(function(){
120+
var rb = new RunestoneBase();
121+
$("#parsons-%(unique_id)s").not(".sortable-code").not(".parsons-controls").on("click", function(){
122+
$('html, body').animate({
123+
scrollTop: ($("#parsons-%(unique_id)s").offset().top - 50)
124+
}, 700);
125+
}).find(".sortable-code, .parsons-controls").click(function(e) {
126+
return false;
127+
});
128+
var msgBox = $("#parsons-message-%(unique_id)s");
129+
msgBox.hide();
130+
var displayErrors = function (fb) {
131+
if(fb.errors.length > 0) {
132+
var hash = pp_%(unique_id)s.getHash("#ul-parsons-sortableCode-%(unique_id)s");
133+
msgBox.fadeIn(500);
134+
msgBox.attr('class','alert alert-danger');
135+
msgBox.html(fb.errors[0]);
136+
rb.logBookEvent({'event':'parsons', 'act':hash, 'div_id':'%(divid)s'});
137+
138+
} else {
139+
rb.logBookEvent({'event':'parsons', 'act':'yes', 'div_id':'%(divid)s'});
140+
msgBox.fadeIn(100);
141+
msgBox.attr('class','alert alert-success');
142+
msgBox.html("Perfect!")
143+
}
144+
145+
}
146+
147+
$(window).load(function() {
148+
// set min width and height
149+
var sortableul = $("#ul-parsons-sortableCode-%(unique_id)s");
150+
var trashul = $("#ul-parsons-sortableTrash-%(unique_id)s");
151+
var sortableHeight = sortableul.height();
152+
var sortableWidth = sortableul.width();
153+
var trashWidth = trashul.width();
154+
var trashHeight = trashul.height();
155+
var minHeight = Math.max(trashHeight,sortableHeight);
156+
var minWidth = Math.max(trashWidth, sortableWidth);
157+
trashul.css("min-height",minHeight + "px");
158+
sortableul.css("min-height",minHeight + "px");
159+
sortableul.height(minHeight);
160+
trashul.css("min-width",minWidth + "px");
161+
sortableul.css("min-width",minWidth + "px");
162+
});
163+
164+
165+
var pp_%(unique_id)s = new ParsonsWidget({
166+
'sortableId': 'parsons-sortableCode-%(unique_id)s',
167+
'trashId': 'parsons-sortableTrash-%(unique_id)s',
168+
'max_wrong_lines': 1,
169+
'solution_label': 'Drop blocks here',
170+
'feedback_cb' : displayErrors
171+
});
172+
pp_%(unique_id)s.init($pjQ("#parsons-orig-%(unique_id)s").text());
173+
pp_%(unique_id)s.shuffleLines();
174+
175+
if(localStorage.getItem('%(divid)s') && localStorage.getItem('%(divid)s-trash')) {
176+
try {
177+
var solution = localStorage.getItem('%(divid)s');
178+
var trash = localStorage.getItem('%(divid)s-trash');
179+
pp_%(unique_id)s.createHTMLFromHashes(solution,trash);
180+
pp_%(unique_id)s.getFeedback();
181+
} catch(err) {
182+
var text = "An error occured restoring old %(divid)s state. Error: ";
183+
console.log(text + err.message);
184+
}
185+
186+
}
187+
$pjQ("#reset%(unique_id)s").click(function(event){
188+
event.preventDefault();
189+
pp_%(unique_id)s.shuffleLines();
190+
191+
// set min width and height
192+
var sortableul = $("#ul-parsons-sortableCode-%(unique_id)s");
193+
var trashul = $("#ul-parsons-sortableTrash-%(unique_id)s");
194+
var sortableHeight = sortableul.height();
195+
var sortableWidth = sortableul.width();
196+
var trashWidth = trashul.width();
197+
var trashHeight = trashul.height();
198+
var minHeight = Math.max(trashHeight,sortableHeight);
199+
var minWidth = Math.max(trashWidth, sortableWidth);
200+
trashul.css("min-height",minHeight + "px");
201+
sortableul.css("min-height",minHeight + "px");
202+
trashul.css("min-width",minWidth + "px");
203+
sortableul.css("min-width",minWidth + "px");
204+
msgBox.hide();
205+
});
206+
207+
$pjQ("#checkMe%(unique_id)s").click(function(event){
208+
event.preventDefault();
209+
var hash = pp_%(unique_id)s.getHash("#ul-parsons-sortableCode-%(unique_id)s");
210+
localStorage.setItem('%(divid)s',hash);
211+
hash = pp_%(unique_id)s.getHash("#ul-parsons-sortableTrash-%(unique_id)s");
212+
localStorage.setItem('%(divid)s-trash',hash);
213+
214+
pp_%(unique_id)s.getFeedback();
215+
msgBox.fadeIn(100);
216+
217+
});
218+
219+
});
220+
221+
222+
</script>
223+
224+
'''
119225

120226
self.assert_has_content()
121-
return [ParsonsNode(self.options)]
227+
return [nodes.raw('', TEMPLATE % template_values, format='html')]
228+
229+
def parse_multiline_parsons(self, lines):
230+
current_block = []
231+
results = []
232+
for line in lines:
233+
if (line == '====='):
234+
results.append(self.convert_leading_whitespace_for_block(current_block))
235+
current_block = []
236+
else:
237+
current_block.append(line)
238+
results.append(self.convert_leading_whitespace_for_block(current_block))
239+
return "\n".join(results)
240+
241+
def convert_leading_whitespace_for_block(self, block):
242+
whitespaceMatcher = re.compile("^\s*")
243+
initialWhitespace = whitespaceMatcher.match(block[0]).end()
244+
result = block[0]
245+
for line in block[1:]:
246+
result += '\\n' # not a line break...the literal characters \n
247+
result += line[initialWhitespace:]
248+
return result

0 commit comments

Comments
 (0)