|
14 | 14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | 15 | # |
16 | 16 |
|
17 | | -__author__ = 'bmiller' |
| 17 | +__author__ = 'isaiahmayerchak' |
18 | 18 |
|
19 | 19 | from docutils import nodes |
20 | 20 | from docutils.parsers.rst import directives |
21 | 21 | from docutils.parsers.rst import Directive |
| 22 | +from .textfield import * |
22 | 23 |
|
23 | 24 |
|
24 | 25 | def setup(app): |
25 | 26 | app.add_directive('activecode', ActiveCode) |
26 | | - app.add_directive('actex', ActiveExercise) |
27 | | - app.add_stylesheet('codemirror.css') |
28 | 27 | app.add_stylesheet('activecode.css') |
29 | 28 |
|
30 | | - app.add_javascript('jquery.highlight.js') |
31 | | - app.add_javascript('bookfuncs.js') |
| 29 | + app.add_javascript('skulpt.min.js') |
| 30 | + app.add_javascript('skulpt-stdlib.js') |
32 | 31 | app.add_javascript('codemirror.js') |
33 | | - app.add_javascript('xml.js') |
34 | | - app.add_javascript('css.js') |
35 | | - app.add_javascript('htmlmixed.js') |
36 | 32 | app.add_javascript('python.js') |
37 | | - app.add_javascript('javascript.js') |
38 | 33 | app.add_javascript('activecode.js') |
39 | | - app.add_javascript('skulpt.min.js') |
40 | | - app.add_javascript('skulpt-stdlib.js') |
| 34 | + |
| 35 | + app.add_role('textfield', textfield_role) |
41 | 36 |
|
42 | 37 | app.add_node(ActivcodeNode, html=(visit_ac_node, depart_ac_node)) |
43 | 38 |
|
44 | 39 | app.connect('doctree-resolved', process_activcode_nodes) |
45 | 40 | app.connect('env-purge-doc', purge_activecodes) |
46 | 41 |
|
47 | 42 |
|
48 | | -START = ''' |
49 | | -<div id="cont"></div> |
50 | | -<div id="%(divid)s" lang="%(language)s" time="%(timelimit)s" class="ac_section alert alert-warning" > |
51 | | -''' |
52 | | - |
53 | | -EDIT1 = ''' |
54 | | -</div> |
55 | | -<br/> |
56 | | -<div id="%(divid)s_code_div" style="display: %(hidecode)s" class="ac_code_div"> |
57 | | -<textarea cols="50" rows="12" id="%(divid)s_code" class="active_code" prefixcode="%(include)s" lang="%(language)s"> |
58 | | -%(initialcode)s |
59 | | -</textarea> |
60 | | -</div> |
61 | | -''' |
62 | | - |
63 | | -CAPTION = ''' |
64 | | -<div class="clearfix"></div> |
65 | | -<p class="ac_caption"><span class="ac_caption_text">%(caption)s (%(divid)s)</span> </p> |
66 | | -''' |
67 | | - |
68 | | -UNHIDE = ''' |
69 | | -<span class="ac_sep"></span> |
70 | | -<button class='btn btn-default' id="%(divid)s_showb" onclick="$('#%(divid)s_code_div').toggle();cm_editors['%(divid)s_code'].refresh();$('#%(divid)s_saveb').toggle();$('#%(divid)s_loadb').toggle()">Show/Hide Code</button> |
71 | | -''' |
72 | | - |
73 | | -GRADES = ''' |
74 | | -<span class="ac_sep"></span> |
75 | | -<input type="button" class='btn btn-default ' id="gradeb" name="Show Feedback" value="Show Feedback" onclick="createGradeSummary('%(divid)s')"/> |
76 | | -''' |
77 | | - |
78 | | -AUDIO = ''' |
79 | | -<span class="ac_sep"></span> |
80 | | -<input type="button" class='btn btn-default ' id="audiob" name="Play Audio" value="Start Audio Tour" onclick="createAudioTourHTML('%(divid)s','%(argu)s','%(no_of_buttons)s','%(ctext)s')"/> |
81 | | -''' |
82 | | - |
83 | | -EDIT2 = ''' |
84 | | -<div class="ac_actions"> |
85 | | -<button class='btn btn-success' id="%(divid)s_runb">Run</button> |
86 | | -<button class="ac_opt btn btn-default" style="display: inline-block" id="%(divid)s_saveb" onclick="saveEditor('%(divid)s');">Save</button> |
87 | | -<button class="ac_opt btn btn-default" style="display: inline-block" id="%(divid)s_loadb" onclick="requestCode('%(divid)s');">Load</button> |
88 | | -''' |
89 | | - |
90 | | -VIZB = '''<button class='btn btn-default' id="%(divid)s_vizb" onclick="injectCodelens(this,'%(divid)s');">Show in Codelens</button> |
91 | | -''' |
92 | | - |
93 | | -COACHB = '''<button class='ac_opt btn btn-default' id="%(divid)s_coach_b" onclick="injectCodeCoach('%(divid)s');">Code Coach</button> |
94 | | -''' |
95 | | - |
96 | | -SCRIPT = ''' |
97 | | -<script> |
98 | | -if ('%(hidecode)s' == 'none') { |
99 | | - // a hack to preserve the inline-block display style. Toggle() will use display: block |
100 | | - // (instead of inline-block) if the previous display style was 'none' |
101 | | - $('#%(divid)s_saveb').toggle(); |
102 | | - $('#%(divid)s_loadb').toggle(); |
103 | | -} |
104 | | -if ($("#%(divid)s").attr("lang") !== "html" && $("#%(divid)s_code_div").parents(".admonition").length == 0 && $("#%(divid)s_code_div").parents("#exercises").length == 0){ |
105 | | - if ($(window).width() > 975){ |
106 | | - $("#%(divid)s_code_div").offset({ |
107 | | - left: $("#%(divid)s .clearfix").offset().left |
108 | | - }); |
109 | | - } |
110 | | - $("#%(divid)s_runb").one("click", function(){ |
111 | | - $({}) |
112 | | - .queue(function (next) { |
113 | | - if ($(window).width() > 975){ |
114 | | - $("#%(divid)s_code_div").animate({ |
115 | | - left: 40 |
116 | | - }, 500, next); |
117 | | - if (! Sk.TurtleGraphics ) { |
118 | | - Sk.TurtleGraphics = {}; |
119 | | - } |
120 | | - Sk.TurtleGraphics.height = 320; |
121 | | - Sk.TurtleGraphics.width = 320; |
122 | | - } |
123 | | - else{ |
124 | | - next(); |
125 | | - } |
126 | | - }) |
127 | | - .queue(function (next) { |
128 | | - $("#%(divid)s_runb").parent().siblings(".ac_output").show(); |
129 | | - runit('%(divid)s',this, %(include)s); |
130 | | - $("#%(divid)s_runb").on("click", function(){ |
131 | | - runit('%(divid)s',this, %(include)s); |
132 | | - }); |
133 | | - }) |
134 | | -
|
135 | | - }); |
136 | | -} |
137 | | -else{ |
138 | | - $("#%(divid)s_code_div").css({float : "none", marginLeft : "auto", marginRight : "auto"}); |
139 | | - $("#%(divid)s_runb").parent().siblings(".ac_output").show().css({float : "none", right : "0px"}); |
140 | | - $("#%(divid)s_runb").on("click", function(){ |
141 | | - runit('%(divid)s',this, %(include)s); |
142 | | - }); |
143 | | -} |
144 | | -</script> |
145 | | -''' |
146 | | -OUTPUT_START = ''' |
147 | | -<div class="ac_output">''' |
148 | | - |
149 | | -CANVAS = ''' |
150 | | -<div style="text-align: center"> |
151 | | -<div id="%(divid)s_canvas" class="ac-canvas" style="border-style: solid; text-align: center"></div> |
152 | | -</div> |
153 | | -''' |
154 | | - |
155 | | -SUFF = '''<pre id="%(divid)s_suffix" style="display:none">%(suffix)s</pre>''' |
156 | | - |
157 | | -PRE = '''<pre id="%(divid)s_pre" class="active_out"></pre> |
158 | | -''' |
159 | | -OUTPUT_END = ''' |
160 | | -</div> <!-- end output -->''' |
161 | | - |
162 | | -VIZ = '''<div id="%(divid)s_codelens_div" style="display:none"></div>''' |
163 | | - |
164 | | -# <iframe id="%(divid)s_codelens" width="800" height="500" style="display:block"src="#"> |
165 | | -# </iframe> |
166 | | - |
167 | | -COACH = '''<div id="%(divid)s_coach_div" style="display:none;"></div>''' |
168 | | - |
169 | | -HTMLOUT = '''<div id="%(divid)s_htmlout" style="display:none;" class="ac_htmlout"></div>''' |
170 | | - |
171 | | -END = ''' |
172 | | -</div> |
173 | | -
|
174 | | -''' |
175 | | - |
176 | | -AUTO = ''' |
177 | | -<script type="text/javascript"> |
178 | | -$(document).ready(function() { |
179 | | - $(window).load(function() { |
180 | | - var runb = document.getElementById("%(divid)s_runb"); |
181 | | - runit('%(divid)s',runb, %(include)s); |
182 | | - }); |
183 | | -}); |
184 | | -</script> |
185 | | -''' |
186 | | - |
| 43 | +TEMPLATE = """ |
| 44 | + <pre data-component="activecode" id=%(divid)s data-lang="%(language)s" %(autorun)s %(hidecode)s %(include)s %(timelimit)s %(coach)s %(codelens)s> |
| 45 | + %(initialcode)s |
| 46 | + </pre> |
| 47 | + """ |
187 | 48 |
|
188 | 49 | class ActivcodeNode(nodes.General, nodes.Element): |
189 | 50 | def __init__(self, content): |
190 | 51 | """ |
191 | | -
|
192 | 52 | Arguments: |
193 | 53 | - `self`: |
194 | 54 | - `content`: |
195 | 55 | """ |
196 | 56 | super(ActivcodeNode, self).__init__() |
197 | | - self.ac_components = content |
| 57 | + self.ac_options = content |
198 | 58 |
|
199 | | - |
200 | | -# self for these functions is an instance of the writer class. For example |
201 | | -# in html, self is sphinx.writers.html.SmartyPantsHTMLTranslator |
202 | | -# The node that is passed as a parameter is an instance of our node class. |
203 | 59 | def visit_ac_node(self, node): |
204 | 60 | # print self.settings.env.activecodecounter |
205 | | - res = START |
206 | | - if 'above' in node.ac_components: |
207 | | - res += CANVAS |
208 | | - if 'tour_1' not in node.ac_components: |
209 | | - res += EDIT2 |
| 61 | + res = "" |
| 62 | + |
| 63 | + if 'language' not in node.ac_options: |
| 64 | + node.ac_options['language'] = 'python' |
| 65 | + |
| 66 | + if 'autorun' in node.ac_options: |
| 67 | + node.ac_options['autorun'] = 'data-autorun' |
| 68 | + else: |
| 69 | + node.ac_options['autorun'] = '' |
| 70 | + |
| 71 | + if 'hidecode' in node.ac_options: |
| 72 | + node.ac_options['hidecode'] = 'data-hidecode' |
| 73 | + else: |
| 74 | + node.ac_options['hidecode'] = '' |
| 75 | + |
| 76 | + if 'include' in node.ac_options: |
| 77 | + node.ac_options['include'] = 'data-include=' + str(node.ac_options['include']) |
210 | 78 | else: |
211 | | - res += EDIT2 + AUDIO |
212 | | - if node.ac_components['codelens']: |
213 | | - res += VIZB |
214 | | - |
215 | | - if 'coach' in node.ac_components: |
216 | | - res += COACHB |
217 | | - |
218 | | - if 'hidecode' not in node.ac_components: |
219 | | - node.ac_components['hidecode'] = 'block' |
220 | | - if node.ac_components['hidecode'] == 'none': |
221 | | - res += UNHIDE |
222 | | - if 'gradebutton' in node.ac_components: |
223 | | - res += GRADES |
224 | | - res += EDIT1 |
225 | | - res += OUTPUT_START |
226 | | - if 'above' not in node.ac_components: |
227 | | - if 'nocanvas' not in node.ac_components: |
228 | | - res += CANVAS |
229 | | - if 'suffix' in node.ac_components: |
230 | | - res += SUFF |
231 | | - if 'nopre' not in node.ac_components: |
232 | | - res += PRE |
233 | | - if 'autorun' in node.ac_components: |
234 | | - res += AUTO |
235 | | - res += OUTPUT_END |
236 | | - res += CAPTION |
237 | | - |
238 | | - if node.ac_components['codelens']: |
239 | | - res += VIZ |
240 | | - |
241 | | - if 'coach' in node.ac_components: |
242 | | - res += COACH |
243 | | - |
244 | | - if node.ac_components['language'] == 'html': |
245 | | - res += HTMLOUT |
246 | | - |
247 | | - res += SCRIPT |
248 | | - res += END |
249 | | - res = res % node.ac_components |
| 79 | + node.ac_options['include'] = '' |
| 80 | + |
| 81 | + if 'timelimit' in node.ac_options: |
| 82 | + node.ac_options['timelimit'] = 'data-timelimit=' + str(node.ac_options['timelimit']) |
| 83 | + else: |
| 84 | + node.ac_options['timelimit'] = '' |
| 85 | + |
| 86 | + if 'coach' in node.ac_options: |
| 87 | + node.ac_options['coach'] = 'data-coach' |
| 88 | + else: |
| 89 | + node.ac_options['coach'] = '' |
| 90 | + |
| 91 | + if 'codelens' in node.ac_options: |
| 92 | + node.ac_options['codelens'] = 'data-codelens' |
| 93 | + else: |
| 94 | + node.ac_options['codelens'] = '' |
| 95 | + |
| 96 | + res += TEMPLATE % node.ac_options |
| 97 | + |
250 | 98 | res = res.replace("u'", "'") # hack: there must be a better way to include the list and avoid unicode strings |
251 | 99 |
|
252 | 100 | self.body.append(res) |
@@ -300,80 +148,11 @@ def run(self): |
300 | 148 |
|
301 | 149 | self.options['divid'] = self.arguments[0] |
302 | 150 |
|
303 | | - if self.content: |
304 | | - if '====' in self.content: |
305 | | - idx = self.content.index('====') |
306 | | - source = "\n".join(self.content[:idx]) |
307 | | - suffix = "\n".join(self.content[idx + 1:]) |
308 | | - else: |
309 | | - source = "\n".join(self.content) |
310 | | - suffix = "\n" |
311 | | - else: |
312 | | - source = '\n' |
313 | | - suffix = '\n' |
314 | | - |
| 151 | + source = "\n".join(self.content) |
315 | 152 | self.options['initialcode'] = source |
316 | | - self.options['suffix'] = suffix |
317 | | - str = source.replace("\n", "*nline*") |
318 | | - str0 = str.replace("\"", "*doubleq*") |
319 | | - str1 = str0.replace("(", "*open*") |
320 | | - str2 = str1.replace(")", "*close*") |
321 | | - str3 = str2.replace("'", "*singleq*") |
322 | | - self.options['argu'] = str3 |
323 | | - |
324 | | - complete = "" |
325 | | - no_of_buttons = 0 |
326 | | - okeys = list(self.options.keys()) |
327 | | - for k in okeys: |
328 | | - if '_' in k: |
329 | | - x, label = k.split('_') |
330 | | - no_of_buttons = no_of_buttons + 1 |
331 | | - complete = complete + self.options[k] + "*atype*" |
332 | | - |
333 | | - newcomplete = complete.replace("\"", "*doubleq*") |
334 | | - self.options['ctext'] = newcomplete |
335 | | - self.options['no_of_buttons'] = no_of_buttons |
336 | | - |
337 | | - if 'caption' not in self.options: |
338 | | - self.options['caption'] = '' |
339 | | - |
340 | | - if 'include' not in self.options: |
341 | | - self.options['include'] = 'undefined' |
342 | | - else: |
343 | | - lst = self.options['include'].split(',') |
344 | | - lst = [x.strip() for x in lst] |
345 | | - self.options['include'] = lst |
346 | | - |
347 | | - if 'hidecode' in self.options: |
348 | | - self.options['hidecode'] = 'none' |
349 | | - else: |
350 | | - self.options['hidecode'] = 'block' |
351 | | - |
352 | | - if 'language' not in self.options: |
353 | | - self.options['language'] = 'python' |
354 | | - |
355 | | - if 'nocodelens' in self.options or self.options['language'] != 'python': |
356 | | - self.options['codelens'] = False |
357 | | - else: |
358 | | - self.options['codelens'] = True |
359 | | - |
360 | | - if 'timelimit' not in self.options: |
361 | | - self.options['timelimit'] = '' |
362 | 153 |
|
363 | 154 | return [ActivcodeNode(self.options)] |
364 | 155 |
|
365 | 156 |
|
366 | | -class ActiveExercise(ActiveCode): |
367 | | - required_arguments = 1 |
368 | | - optional_arguments = 0 |
369 | | - has_content = True |
370 | | - |
371 | | - def run(self): |
372 | | - self.options['hidecode'] = True |
373 | | - self.options['gradebutton'] = True |
374 | | - self.options['coach'] = True |
375 | | - return super(ActiveExercise, self).run() |
376 | | - |
377 | | - |
378 | 157 | if __name__ == '__main__': |
379 | 158 | a = ActiveCode() |
0 commit comments