201
201
% (cgi.escape(subject), cgi.escape(worksheetname)))
203
203
# Write each element
205
205
for node in worksheetdom.childNodes:
206
problemid = present_worksheet_node(req, node, problemid)
206
exerciseid = present_worksheet_node(req, node, exerciseid)
207
207
req.write("</div>\n") # tutorialbody
209
def present_worksheet_node(req, node, problemid):
209
def present_worksheet_node(req, node, exerciseid):
210
210
"""Given a node of a worksheet XML document, writes it out to the
211
request. This recursively searches for "problem" elements and handles
212
those specially (presenting their XML problem spec and input box), and
211
request. This recursively searches for "exercise" elements and handles
212
those specially (presenting their XML exercise spec and input box), and
213
213
just dumps the other elements as regular HTML.
215
problemid is the ID to use for the first problem.
216
Returns the new problemid after all the problems have been written
217
(since we need unique IDs for each problem).
215
exerciseid is the ID to use for the first exercise.
216
Returns the new exerciseid after all the exercises have been written
217
(since we need unique IDs for each exercise).
219
219
if node.nodeType == node.ELEMENT_NODE:
220
if node.tagName == "problem":
221
present_problem(req, node.getAttribute("src"), problemid)
220
if node.tagName == "exercise":
221
present_exercise(req, node.getAttribute("src"), exerciseid)
224
224
# Some other element. Write out its head and foot, and recurse.
225
225
req.write("<" + node.tagName)
259
259
return data.strip()
261
def present_problem(req, problemsrc, problemid):
262
"""Open a problem file, and write out the problem to the request in HTML.
263
problemsrc: "src" of the problem file. A path relative to the top-level
264
problems base directory, as configured in conf.
261
def present_exercise(req, exercisesrc, exerciseid):
262
"""Open a exercise file, and write out the exercise to the request in HTML.
263
exercisesrc: "src" of the exercise file. A path relative to the top-level
264
exercises base directory, as configured in conf.
266
req.write('<div class="tuteproblem" id="problem%d">\n'
266
req.write('<div class="exercise" id="exercise%d">\n'
268
268
# First normalise the path
269
problemsrc = os.path.normpath(problemsrc)
269
exercisesrc = os.path.normpath(exercisesrc)
270
270
# Now if it begins with ".." or separator, then it's illegal
271
if problemsrc.startswith("..") or problemsrc.startswith(os.sep):
271
if exercisesrc.startswith("..") or exercisesrc.startswith(os.sep):
274
problemfile = os.path.join(conf.problems_base, problemsrc)
274
exercisefile = os.path.join(conf.exercises_base, exercisesrc)
277
problemfile = open(problemfile)
278
except (TypeError, IOError): # TypeError if problemfile == None
277
exercisefile = open(exercisefile)
278
except (TypeError, IOError): # TypeError if exercisefile == None
279
279
req.write("<p><b>Server Error</b>: "
280
+ "Problem file could not be opened.</p>\n")
280
+ "Exercise file could not be opened.</p>\n")
281
281
req.write("</div>\n")
284
# Read problem file and present the problem
284
# Read exercise file and present the exercise
285
285
# Note: We do not use the testing framework because it does a lot more
286
# work than we need. We just need to get the problem name and a few other
286
# work than we need. We just need to get the exercise name and a few other
287
287
# fields from the XML.
289
problemdom = minidom.parse(problemfile)
291
problemdom = problemdom.documentElement
292
if problemdom.tagName != "problem":
289
exercisedom = minidom.parse(exercisefile)
291
exercisedom = exercisedom.documentElement
292
if exercisedom.tagName != "exercise":
293
293
# TODO: Nicer error message, to help authors
294
294
req.throw_error(req.HTTP_INTERNAL_SERVER_ERROR)
295
problemname = problemdom.getAttribute("name")
296
rows = problemdom.getAttribute("rows")
295
exercisename = exercisedom.getAttribute("name")
296
rows = exercisedom.getAttribute("rows")
299
299
# Look for some other fields we need, which are elements:
304
for elem in problemdom.childNodes:
304
for elem in exercisedom.childNodes:
305
305
if elem.nodeType == elem.ELEMENT_NODE:
306
306
if elem.tagName == "desc":
307
problemdesc = innerXML(elem).strip()
307
exercisedesc = innerXML(elem).strip()
308
308
if elem.tagName == "partial":
309
problempartial= getTextData(elem) + '\n'
309
exercisepartial= getTextData(elem) + '\n'
311
# Print this problem out to HTML
312
req.write("<p><b>Exercise:</b> %s</p>\n" % problemname)
313
if problemdesc is not None:
314
req.write("<div>%s</div>\n" % problemdesc)
315
req.write('<textarea class="problembox" cols="80" rows="%s">%s</textarea>'
316
% (rows, problempartial))
317
filename = cgi.escape(cjson.encode(problemsrc), quote=True)
318
req.write("""\n<div class="problembuttons">
311
# Print this exercise out to HTML
312
req.write("<p><b>Exercise:</b> %s</p>\n" % exercisename)
313
if exercisedesc is not None:
314
req.write("<div>%s</div>\n" % exercisedesc)
315
req.write('<textarea class="exercisebox" cols="80" rows="%s">%s</textarea>'
316
% (rows, exercisepartial))
317
filename = cgi.escape(cjson.encode(exercisesrc), quote=True)
318
req.write("""\n<div class="exercisebuttons">
319
319
<input type="button" value="Run"
320
onclick="runproblem("problem%d", %s)" />
320
onclick="runexercise("exercise%d", %s)" />
321
321
<input type="button" value="Submit"
322
onclick="submitproblem("problem%d", %s)" />
322
onclick="submitexercise("exercise%d", %s)" />
324
324
<div class="testoutput">
326
""" % (problemid, filename, problemid, filename))
326
""" % (exerciseid, filename, exerciseid, filename))
327
327
req.write("</div>\n")