1919from docutils import nodes
2020from docutils .parsers .rst import directives
2121from docutils .parsers .rst import Directive
22+ from .textfield import *
2223
24+ try :
25+ from html import escape # py3
26+ except ImportError :
27+ from cgi import escape # py2
2328
2429def setup (app ):
2530 app .add_directive ('activecode' , ActiveCode )
2631 app .add_directive ('actex' , ActiveExercise )
32+ app .add_role ('textfield' ,textfield_role )
2733 app .add_stylesheet ('codemirror.css' )
2834 app .add_stylesheet ('activecode.css' )
2935
@@ -38,152 +44,20 @@ def setup(app):
3844 app .add_javascript ('activecode.js' )
3945 app .add_javascript ('skulpt.min.js' )
4046 app .add_javascript ('skulpt-stdlib.js' )
47+ app .add_javascript ('clike.js' )
4148
4249 app .add_node (ActivcodeNode , html = (visit_ac_node , depart_ac_node ))
4350
4451 app .connect ('doctree-resolved' , process_activcode_nodes )
4552 app .connect ('env-purge-doc' , purge_activecodes )
4653
4754
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- '''
5255
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">
56+ TEMPLATE = """
57+ <pre data-component="activecode" id=%(divid)s data-lang="%(language)s" %(autorun)s %(hidecode)s %(include)s %(timelimit)s %(coach)s %(codelens)s data-audio='%(ctext)s' %(sourcefile)s %(datafile)s %(stdin)s %(gradebutton)s %(caption)s>
5858%(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-
59+ </pre>
60+ """
18761
18862class ActivcodeNode (nodes .General , nodes .Element ):
18963 def __init__ (self , content ):
@@ -202,50 +76,11 @@ def __init__(self, content):
20276# The node that is passed as a parameter is an instance of our node class.
20377def visit_ac_node (self , node ):
20478 # 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
210- 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
79+ res = TEMPLATE
80+ #todo: handle above in node.ac_components
81+ #todo handle 'hidecode' not in node.ac_components:
82+ # todo: handle if 'gradebutton' in node.ac_components: res += GRADES
83+
24984 res = res % node .ac_components
25085 res = res .replace ("u'" , "'" ) # hack: there must be a better way to include the list and avoid unicode strings
25186
@@ -288,7 +123,10 @@ class ActiveCode(Directive):
288123 'tour_5' : directives .unchanged ,
289124 'nocodelens' : directives .flag ,
290125 'coach' : directives .flag ,
291- 'timelimit' : directives .unchanged
126+ 'timelimit' : directives .unchanged ,
127+ 'stdin' : directives .unchanged ,
128+ 'datafile' : directives .unchanged ,
129+ 'sourcefile' : directives .unchanged
292130 }
293131
294132 def run (self ):
@@ -301,19 +139,11 @@ def run(self):
301139 self .options ['divid' ] = self .arguments [0 ]
302140
303141 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 "
142+ source = "\n " .join (self .content )
311143 else :
312144 source = '\n '
313- suffix = '\n '
314145
315146 self .options ['initialcode' ] = source
316- self .options ['suffix' ] = suffix
317147 str = source .replace ("\n " , "*nline*" )
318148 str0 = str .replace ("\" " , "*doubleq*" )
319149 str1 = str0 .replace ("(" , "*open*" )
@@ -336,29 +166,66 @@ def run(self):
336166
337167 if 'caption' not in self .options :
338168 self .options ['caption' ] = ''
169+ else :
170+ self .options ['caption' ] = "data-caption='%s'" % self .options ['caption' ]
339171
340172 if 'include' not in self .options :
341- self .options ['include' ] = 'undefined '
173+ self .options ['include' ] = ''
342174 else :
343175 lst = self .options ['include' ].split (',' )
344176 lst = [x .strip () for x in lst ]
345- self .options ['include' ] = lst
177+ self .options ['include' ] = 'data-include=' + " " . join ( lst )
346178
347179 if 'hidecode' in self .options :
348- self .options ['hidecode' ] = 'none '
180+ self .options ['hidecode' ] = 'data-hidecode="true" '
349181 else :
350- self .options ['hidecode' ] = 'block '
182+ self .options ['hidecode' ] = ''
351183
352184 if 'language' not in self .options :
353185 self .options ['language' ] = 'python'
354186
187+ if self .options ['language' ] == 'html' :
188+ self .options ['language' ] = 'htmlmixed'
189+ self .options ['initialcode' ] = escape (self .options ['initialcode' ])
190+
355191 if 'nocodelens' in self .options or self .options ['language' ] != 'python' :
356- self .options ['codelens' ] = False
192+ self .options ['codelens' ] = ''
357193 else :
358- self .options ['codelens' ] = True
194+ self .options ['codelens' ] = 'data-codelens="true"'
359195
360196 if 'timelimit' not in self .options :
361- self .options ['timelimit' ] = ''
197+ self .options ['timelimit' ] = 'data-timelimit=25000'
198+ else :
199+ self .options ['timelimit' ] = 'data-timelimit=%d' % self .options ['timelimit' ]
200+
201+ if 'autorun' not in self .options :
202+ self .options ['autorun' ] = ''
203+ else :
204+ self .options ['autorun' ] = 'data-autorun="true"'
205+
206+ if 'coach' in self .options :
207+ self .options ['coach' ] = 'data-coach="true"'
208+ else :
209+ self .options ['coach' ] = ''
210+
211+ # livecode options
212+ if 'stdin' in self .options :
213+ self .options ['stdin' ] = "data-stdin='%s'" % self .options ['stdin' ]
214+ else :
215+ self .options ['stdin' ] = ""
216+
217+ if 'datafile' not in self .options :
218+ self .options ['datafile' ] = ""
219+ else :
220+ self .options ['datafile' ] = "data-datafile='%s'" % self .options ['datafile' ]
221+
222+ if 'sourcefile' not in self .options :
223+ self .options ['sourcefile' ] = ""
224+ else :
225+ self .options ['sourcefile' ] = "data-sourcefile='%s'" % self .options ['sourcefile' ]
226+
227+ if 'gradebutton' not in self .options :
228+ self .options ['gradebutton' ] = ''
362229
363230 return [ActivcodeNode (self .options )]
364231
@@ -369,9 +236,9 @@ class ActiveExercise(ActiveCode):
369236 has_content = True
370237
371238 def run (self ):
372- self .options ['hidecode' ] = True
373- self .options ['gradebutton' ] = True
374- self .options ['coach' ] = True
239+ self .options ['hidecode' ] = "data-hidecode=true"
240+ self .options ['gradebutton' ] = "data-gradebutton=true"
241+ self .options ['coach' ] = "data-coach=true"
375242 return super (ActiveExercise , self ).run ()
376243
377244
0 commit comments