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__ = 'hewner '
16+ __author__ = 'isaiahmayerchak '
1717
1818import re
1919from docutils import nodes
@@ -28,17 +28,44 @@ 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+
3133 # includes parsons specific javascript headers
3234 # parsons-noconflict reverts underscore and
3335 # 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 ('parsons-noconflict.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+ '''
4147
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 )
62+
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
4269
4370class ParsonsProblem (Assessment ):
4471 required_arguments = 1
@@ -49,18 +76,13 @@ class ParsonsProblem(Assessment):
4976
5077 def run (self ):
5178 """
52-
53- Instructions for solving the problem should be written and then a line with -----
79+ Instructions for solving the problem should be written and then a line with -----
5480 signals the beginning of the code. If you want more than one line in a single
5581 code block, seperate your code blocks with =====.
56-
5782 Both the instructions sections and code blocks are optional. If you don't include any
5883 =====, the code will assume you want each line to be its own code block.
59-
6084Example:
61-
6285.. parsonsprob:: unqiue_problem_id_here
63-
6486 Solve my really cool parsons problem...if you can.
6587 -----
6688 def findmax(alist):
@@ -76,173 +98,24 @@ def findmax(alist):
7698 curmax = item
7799 =====
78100 return curmax
79-
80-
81101 """
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
102+ self .options ['divid' ] = self .arguments [0 ]
103+ self .options ['qnumber' ] = self .getNumber ()
104+ self .options ['instructions' ] = ""
105+ self .options ['code' ] = self .content
88106
89107 if '-----' in self .content :
90108 index = self .content .index ('-----' )
91- template_values ['instructions' ] = "\n " .join (self .content [:index ])
92- code = self .content [index + 1 :]
109+ self . options ['instructions' ] = "\n " .join (self .content [:index ])
110+ self . options [ ' code' ] = self .content [index + 1 :]
93111
94- if '=====' in code :
95- template_values ['code' ] = self .parse_multiline_parsons ( code );
112+ if '=====' in self . options [ ' code' ] :
113+ self . options ['code' ] = self .options [ ' code' ]. replace ( '====' , '---' )
96114 else :
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-
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- logBookEvent({'event':'parsons', 'act':hash, 'div_id':'%(divid)s'});
137-
138- } else {
139- 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- '''
115+ self .options ['code' ] = "\n " .join (self .options ['code' ])
116+
117+ self .options ['divid' ] = self .arguments [0 ]
118+ print (self .options )
225119
226120 self .assert_has_content ()
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
121+ return [ParsonsNode (self .options )]
0 commit comments