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

Commit 62a6adc

Browse files
committed
✨ Allow adding blocks from ReST
1 parent 0bdd7d2 commit 62a6adc

File tree

5 files changed

+65
-81
lines changed

5 files changed

+65
-81
lines changed

runestone/hparsons/css/hparsons.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@
1010
max-width: 500pt;
1111
margin-left: auto;
1212
margin-right: auto;
13-
}
13+
}
14+
15+
.hp_question {
16+
padding-left: 10px;
17+
padding-top: 10px;
18+
margin: 5px;
19+
}

runestone/hparsons/hparsons.py

Lines changed: 35 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
# You should have received a copy of the GNU General Public License
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#
19-
from __future__ import print_function
20-
2119
__author__ = "bmiller"
2220

2321
from docutils import nodes
@@ -34,31 +32,26 @@
3432
RunestoneIdNode,
3533
)
3634

37-
try:
38-
from html import escape # py3
39-
except ImportError:
40-
from cgi import escape # py2
41-
42-
4335
def setup(app):
4436
app.add_directive("hparsons", HParsonsDirective)
45-
app.add_node(HParsonsNode, html=(visit_ac_node, depart_ac_node))
37+
app.add_node(HParsonsNode, html=(visit_hp_node, depart_hp_node))
4638

4739

4840
TEMPLATE_START = """
4941
<div>
50-
<div data-component="hparsons" id=%(divid)s data-question_label="%(question_label)s">
51-
<div id=%(divid)s_question class="ac_question col-md-12">
42+
<div data-component="hparsons" id=%(divid)s data-question_label="%(question_label)s" class="alert alert-warning hparsons_section">
43+
<div class="hp_question col-md-12">
5244
"""
5345

5446
TEMPLATE_END = """
5547
</div>
5648
<div class='hparsons'></div>
57-
<textarea data-lang="%(language)s" id="%(divid)s_editor"
49+
<textarea data-lang="%(language)s"
5850
%(optional)s
5951
%(dburl)s
52+
%(textentry)s
6053
style="visibility: hidden;">
61-
%(initialcode)s
54+
%(initialsetting)s
6255
</textarea>
6356
</div>
6457
</div>
@@ -74,10 +67,7 @@ def __init__(self, options, **kwargs):
7467
# self for these functions is an instance of the writer class. For example
7568
# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator
7669
# The node that is passed as a parameter is an instance of our node class.
77-
def visit_ac_node(self, node):
78-
# print self.settings.env.activecodecounter
79-
80-
# todo: handle above in node.runestone_options
70+
def visit_hp_node(self, node):
8171

8272
node.delimiter = "_start__{}_".format(node.runestone_options["divid"])
8373

@@ -87,11 +77,7 @@ def visit_ac_node(self, node):
8777
self.body.append(res)
8878

8979

90-
def depart_ac_node(self, node):
91-
"""This is called at the start of processing an activecode node. If activecode had recursive nodes
92-
etc and did not want to do all of the processing in visit_ac_node any finishing touches could be
93-
added here.
94-
"""
80+
def depart_hp_node(self, node):
9581
res = TEMPLATE_END % node.runestone_options
9682
self.body.append(res)
9783

@@ -104,37 +90,28 @@ def depart_ac_node(self, node):
10490
self.body.remove(node.delimiter)
10591

10692

107-
def process_activcode_nodes(app, env, docname):
108-
pass
109-
110-
111-
def purge_activecodes(app, env, docname):
112-
pass
113-
114-
11593
class HParsonsDirective(RunestoneIdDirective):
11694
# only keep: language, autograde, dburl
11795
"""
118-
.. activecode:: uniqueid
119-
:autograde: unittest
120-
:language: python, html, javascript, java, python2, python3
121-
:dburl: url to load database for sql mode
122-
:showlastsql: -- Only show the last sql result in output
123-
124-
If this is a homework problem instead of an example in the text
125-
then the assignment text should go here. The assignment text ends with
126-
the line containing four tilde ~
127-
~~~~
128-
print("Hidden code before students code - good for scaffolding")
129-
^^^^
130-
print("hello world")
131-
====
132-
print("Hidden code, such as unit tests come after the four = signs")
96+
.. hparsons:: uniqueid
97+
:language: sql, regex
98+
:dburl: only for sql -- url to load database
13399
134-
config values (conf.py):
100+
:textentry: if you will use text entry instead of horizontal parsons
135101
136-
- activecode_div_class - custom CSS class of the component's outermost div
137-
- activecode_hide_load_history - if True, hide the load history button
102+
Here is the problem description. It must ends with the tildes.
103+
Make sure you use the correct delimitier for each section below.
104+
~~~~
105+
--blocks--
106+
block 1
107+
block 2
108+
--explanations--
109+
explanations for block 1
110+
explanations for block 2
111+
--unittest--
112+
assert 1,1 == world
113+
assert 0,1 == hello
114+
assert 2,1 == 42
138115
"""
139116

140117
required_arguments = 1
@@ -143,22 +120,21 @@ class HParsonsDirective(RunestoneIdDirective):
143120
option_spec = RunestoneIdDirective.option_spec.copy()
144121
option_spec.update(
145122
{
146-
"language": directives.unchanged,
147123
"dburl": directives.unchanged,
148-
"showlastsql": directives.flag,
124+
"language": directives.unchanged,
125+
"textentry": directives.flag,
149126
}
150127
)
151128

152129
def run(self):
153130
super(HParsonsDirective, self).run()
154131

155132
env = self.state.document.settings.env
156-
# keep track of how many activecodes we have....
157-
# could be used to automatically make a unique id for them.
158-
if not hasattr(env, "activecodecounter"):
159-
env.activecodecounter = 0
160-
env.activecodecounter += 1
161-
self.options["name"] = self.arguments[0].strip()
133+
134+
if "textentry" in self.options:
135+
self.options['textentry'] = ' data-textentry="true"'
136+
else:
137+
self.options['textentry'] = ''
162138

163139
explain_text = None
164140
if self.content:
@@ -173,14 +149,9 @@ def run(self):
173149
self.explain_text = explain_text or ["Not an Exercise"]
174150
addQuestionToDB(self)
175151

176-
self.options["initialcode"] = source
177-
str = source.replace("\n", "*nline*")
178-
str0 = str.replace('"', "*doubleq*")
179-
str1 = str0.replace("(", "*open*")
180-
str2 = str1.replace(")", "*close*")
181-
str3 = str2.replace("'", "*singleq*")
182-
self.options["argu"] = str3
152+
self.options["initialsetting"] = source
183153

154+
# TODO: change this
184155
if "language" not in self.options:
185156
self.options["language"] = "python"
186157

@@ -234,6 +205,7 @@ def run(self):
234205

235206
maybeAddToAssignment(self)
236207
if explain_text:
208+
self.updateContent()
237209
self.state.nested_parse(explain_text, self.content_offset, acnode)
238210

239211
return [acnode]

runestone/hparsons/js/horizontal-parsons.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15723,12 +15723,12 @@ class HParsonsElement extends HTMLElement {
1572315723
sheet.innerHTML += '.hparsons-tip { font-style: italic; }\n';
1572415724
sheet.innerHTML += '.parsons-block {display: inline-block; font-family: monospace; border-color:gray; margin: 0 1px; position: relative; border-radius: 10px; background-color: #efefef; border: 1px solid #d3d3d3; padding: 5px 10px; margin-top: 5px;}\n';
1572515725
sheet.innerHTML += '.parsons-block:hover, .parsons-block:focus { border-color: black;}\n';
15726-
sheet.innerHTML += '.drop-area { background-color: #ffa; padding: 0 5px; height: 42px; }\n';
15726+
sheet.innerHTML += '.drop-area { background-color: #ffa; padding: 0 5px; height: 42px; margin: 2px 0;}\n';
1572715727
// TODO:(UI) move the tooltip to the top of the line
1572815728
sheet.innerHTML += '.parsons-block .tooltip { visibility: hidden; width: 200px; background-color: black; color: #fff; text-align: center; padding: 5px 0; border-radius: 6px; position: absolute; z-index: 1; margin: 0 10px; bottom: 120%; margin-left: -100px;}\n';
1572915729
sheet.innerHTML += '.parsons-block .tooltip::after {content: " ";position: absolute; top: 100%;left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: black transparent transparent transparent;}\n';
1573015730
sheet.innerHTML += '.drag-area .parsons-block:hover .tooltip { visibility: visible;}\n';
15731-
sheet.innerHTML += '.drag-area { background-color: #efefff; padding: 0 5px; height: 42px; }\n';
15731+
sheet.innerHTML += '.drag-area { background-color: #efefff; padding: 0 5px; height: 42px; margin: 2px 0; }\n';
1573215732
// unittest
1573315733
this.root.appendChild(sheet);
1573415734
const global_sheet = document.createElement('style');

runestone/hparsons/js/hparsons-sql.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Handsontable from "handsontable";
22
// import 'handsontable/dist/handsontable.full.css';
33
import initSqlJs from "sql.js/dist/sql-wasm.js";
44
import RunestoneBase from "../../common/js/runestonebase.js";
5+
import "../css/hparsons.css";
56

67
var allDburls = {};
78

@@ -24,7 +25,6 @@ export default class SQLHParons extends RunestoneBase {
2425
this.origElem = orig;
2526
this.origText = this.origElem.textContent;
2627
this.code = $(orig).text() || "\n\n\n\n\n";
27-
this.question = $(opts.orig).find(`#${this.divid}_question`)[0];
2828
this.dburl = $(orig).data("dburl");
2929
this.runButton = null;
3030
this.saveButton = null;
@@ -38,7 +38,7 @@ export default class SQLHParons extends RunestoneBase {
3838
this.prefix = this.code.substring(0, prefixEnd);
3939
this.code = this.code.substring(prefixEnd + 5);
4040
}
41-
suffStart = this.code.indexOf("====");
41+
suffStart = this.code.indexOf("--unittest--");
4242
if (suffStart > -1) {
4343
this.suffix = this.code.substring(suffStart + 5);
4444
this.code = this.code.substring(0, suffStart);
@@ -139,11 +139,19 @@ export default class SQLHParons extends RunestoneBase {
139139
// copied from activecode, already modified to add parsons
140140
createEditor() {
141141
this.outerDiv = document.createElement("div");
142-
$(this.outerDiv).addClass("hparsons_section alert alert-warning");
143142
$(this.origElem).replaceWith(this.outerDiv);
144143
this.outerDiv.innerHTML = `<horizontal-parsons input-type='parsons' id='${this.divid}-hparsons'>`;
144+
console.log(this.code);
145+
let blocks = [];
146+
let blockIndex = this.code.indexOf('--blocks--');
147+
if (blockIndex > -1) {
148+
let blocksString = this.code.substring(blockIndex + 10);
149+
let endIndex = blocksString.indexOf('\n--');
150+
blocksString = endIndex > -1 ? blocksString.substring(0, endIndex) : blocksString;
151+
blocks = blocksString.split('\n');
152+
}
145153
this.hparsons = $(this.outerDiv).find("horizontal-parsons")[0];
146-
this.hparsons.parsonsData = ['select', '*', 'from', 'test', ';'];
154+
this.hparsons.parsonsData = blocks.slice(1, -1);
147155
}
148156

149157
// copied from activecode
@@ -184,13 +192,6 @@ export default class SQLHParons extends RunestoneBase {
184192

185193
// TODO: maybe remove the question part
186194
$(this.outerDiv).prepend(ctrlDiv);
187-
if (this.question) {
188-
if ($(this.question).html().match(/^\s+$/)) {
189-
$(this.question).remove();
190-
} else {
191-
$(this.outerDiv).prepend(this.question);
192-
}
193-
}
194195
this.controlDiv = ctrlDiv;
195196
}
196197

runestone/hparsons/test/_sources/index.rst

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ Horizontal Parsons Test
44

55
.. Testing horizontal Parsons problems.
66
7-
Horizontal Parsons + SQL aaa
7+
Horizontal Parsons + SQL
88
--------------------------------------
99
.. hparsons:: test_activecode_6
1010
:language: sql
11-
:autograde: unittest
1211
:dburl: /_static/test.db
1312

14-
select * from test;
1513

16-
=====
14+
this is a cute horizontal parsons problem!
15+
~~~~
16+
--blocks--
17+
select
18+
*
19+
from
20+
test
21+
--unittest--
1722
assert 1,1 == world
1823
assert 0,1 == hello
1924
assert 2,1 == 42

0 commit comments

Comments
 (0)