307
by mattgiuca
tutorial: Now each problem div has an ID. Added submit buttons which call |
1 |
/* IVLE - Informatics Virtual Learning Environment
|
2 |
* Copyright (C) 2007-2008 The University of Melbourne
|
|
3 |
*
|
|
4 |
* This program is free software; you can redistribute it and/or modify
|
|
5 |
* it under the terms of the GNU General Public License as published by
|
|
6 |
* the Free Software Foundation; either version 2 of the License, or
|
|
7 |
* (at your option) any later version.
|
|
8 |
*
|
|
9 |
* This program is distributed in the hope that it will be useful,
|
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
* GNU General Public License for more details.
|
|
13 |
*
|
|
14 |
* You should have received a copy of the GNU General Public License
|
|
15 |
* along with this program; if not, write to the Free Software
|
|
16 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17 |
*
|
|
18 |
* Module: Tutorial system (client)
|
|
19 |
* Author: Matt Giuca
|
|
20 |
* Date: 25/1/2008
|
|
21 |
*/
|
|
22 |
||
331
by mattgiuca
Console: Configured console to display properly as a "floating" window in the |
23 |
/* Runs at startup. */
|
24 |
function onload() |
|
25 |
{
|
|
26 |
/* Set up the console plugin to display as a popup window */
|
|
27 |
console_init(true); |
|
28 |
}
|
|
29 |
||
325
by mattgiuca
tutorial: Added "run" button which submits the students code to the |
30 |
/** User clicks "Run" button. Do an Ajax call and print the test output.
|
31 |
*/
|
|
32 |
function runproblem(problemid, filename) |
|
33 |
{
|
|
34 |
/* Get the source code the student is submitting */
|
|
35 |
var problemdiv = document.getElementById(problemid); |
|
36 |
var problembox = problemdiv.getElementsByTagName("textarea")[0]; |
|
37 |
var code = problembox.value; |
|
38 |
||
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
39 |
/* Dump the entire file to the console */
|
40 |
/* FIXME: Multiple lines aren't received properly by the server */
|
|
41 |
console_enter_line(code); |
|
42 |
return; |
|
43 |
||
44 |
/* TEMP: Old code here */
|
|
325
by mattgiuca
tutorial: Added "run" button which submits the students code to the |
45 |
var args = {"code": code, "problem": filename, "action": "run"}; |
46 |
||
47 |
/* Send the form as multipart/form-data, since we are sending a whole lump
|
|
48 |
* of Python code, it should be treated like a file upload. */
|
|
49 |
var xhr = ajax_call("tutorialservice", "", args, "POST", |
|
50 |
"multipart/form-data"); |
|
51 |
var testresponse = JSON.parse(xhr.responseText); |
|
52 |
handle_runresponse(problemdiv, testresponse); |
|
53 |
}
|
|
54 |
||
55 |
/** Given a response object (JSON-parsed object), displays the result of the
|
|
56 |
* test to the user. This modifies the given problemdiv's children.
|
|
57 |
*/
|
|
58 |
function handle_runresponse(problemdiv, runresponse) |
|
59 |
{
|
|
60 |
var runoutput = problemdiv.getElementsByTagName("textarea")[1]; |
|
61 |
dom_removechildren(runoutput); |
|
62 |
runoutput.appendChild(document.createTextNode(runresponse.stdout)); |
|
63 |
}
|
|
64 |
||
307
by mattgiuca
tutorial: Now each problem div has an ID. Added submit buttons which call |
65 |
/** User clicks "Submit" button. Do an Ajax call and run the test.
|
66 |
* problemid: "id" of the problem's div element.
|
|
67 |
* filename: Filename of the problem's XML file (used to identify the problem
|
|
68 |
* when interacting with the server).
|
|
69 |
*/
|
|
70 |
function submitproblem(problemid, filename) |
|
71 |
{
|
|
72 |
/* Get the source code the student is submitting */
|
|
312
by mattgiuca
Full client-side testing - functional. |
73 |
var problemdiv = document.getElementById(problemid); |
74 |
var problembox = problemdiv.getElementsByTagName("textarea")[0]; |
|
75 |
var code = problembox.value; |
|
76 |
||
77 |
var args = {"code": code, "problem": filename, "action": "test"}; |
|
78 |
||
79 |
/* Send the form as multipart/form-data, since we are sending a whole lump
|
|
80 |
* of Python code, it should be treated like a file upload. */
|
|
81 |
var xhr = ajax_call("tutorialservice", "", args, "POST", |
|
82 |
"multipart/form-data"); |
|
83 |
var testresponse = JSON.parse(xhr.responseText); |
|
84 |
handle_testresponse(problemdiv, testresponse); |
|
85 |
}
|
|
86 |
||
87 |
/** Given a problem div, return the testoutput div which is its child.
|
|
88 |
* (The div which is its child whose class is "testoutput".
|
|
89 |
*/
|
|
90 |
function get_testoutput(problemdiv) |
|
91 |
{
|
|
92 |
var childs = problemdiv.childNodes; |
|
93 |
var i; |
|
94 |
var testoutput; |
|
95 |
for (i=0; i<childs.length; i++) |
|
96 |
if (childs[i].nodeType == problemdiv.ELEMENT_NODE && |
|
97 |
childs[i].getAttribute("class") == "testoutput") |
|
98 |
return childs[i]; |
|
99 |
return null; |
|
100 |
}
|
|
101 |
||
102 |
/** Given a response object (JSON-parsed object), displays the result of the
|
|
103 |
* test to the user. This modifies the given problemdiv's children.
|
|
104 |
*/
|
|
105 |
function handle_testresponse(problemdiv, testresponse) |
|
106 |
{
|
|
107 |
var testoutput = get_testoutput(problemdiv); |
|
108 |
var i, j; |
|
109 |
var ul; |
|
110 |
var case_ul; |
|
111 |
if (testoutput == null) return; /* should not happen */ |
|
112 |
dom_removechildren(testoutput); |
|
113 |
||
114 |
ul = document.createElement("ul"); |
|
115 |
testoutput.appendChild(ul); |
|
116 |
||
117 |
if ("critical_error" in testresponse) |
|
118 |
{
|
|
119 |
/* Only one error - and it's bad.
|
|
120 |
* Just print and stop */
|
|
121 |
ul.appendChild(create_response_item("critical", |
|
122 |
testresponse.critical_error.name, |
|
123 |
testresponse.critical_error.detail)); |
|
124 |
return; |
|
125 |
}
|
|
126 |
||
127 |
for (i=0; i<testresponse.cases.length; i++) |
|
128 |
{
|
|
129 |
var testcase = testresponse.cases[i]; |
|
130 |
if ("exception" in testcase) |
|
131 |
{
|
|
132 |
/* User's code threw an exception */
|
|
133 |
fail_li = create_response_item("fail", testcase.name); |
|
134 |
ul.appendChild(fail_li); |
|
135 |
/* Create a sub-ul to display the failing cases. */
|
|
136 |
case_ul = document.createElement("ul"); |
|
137 |
fail_li.appendChild(case_ul); |
|
138 |
case_ul.appendChild(create_response_item("exception", |
|
139 |
testcase.exception.name, testcase.exception.detail)); |
|
140 |
}
|
|
141 |
else if (testcase.passed) |
|
142 |
{
|
|
143 |
/* All parts of the test case passed. Just report the overall case
|
|
144 |
* passing. */
|
|
145 |
ul.appendChild(create_response_item("pass", testcase.name)); |
|
146 |
}
|
|
147 |
else
|
|
148 |
{
|
|
149 |
var fail_li = create_response_item("fail", testcase.name); |
|
150 |
ul.appendChild(fail_li); |
|
151 |
/* Create a sub-ul to display the failing cases. */
|
|
152 |
case_ul = document.createElement("ul"); |
|
153 |
fail_li.appendChild(case_ul); |
|
154 |
||
155 |
for (j=0; j<testcase.parts.length; j++) |
|
156 |
{
|
|
157 |
var part = testcase.parts[j]; |
|
158 |
if (part.passed) |
|
159 |
{
|
|
160 |
case_ul.appendChild(create_response_item("pass", |
|
161 |
part.description)); |
|
162 |
}
|
|
163 |
else
|
|
164 |
{
|
|
165 |
case_ul.appendChild(create_response_item("fail", |
|
166 |
part.description, part.error_message)); |
|
167 |
}
|
|
168 |
}
|
|
169 |
}
|
|
170 |
}
|
|
171 |
}
|
|
172 |
||
173 |
/* DOM creators for test case response elements */
|
|
174 |
||
175 |
/** Create a <li> element for the result of a test case.
|
|
176 |
* type: "pass", "fail", "exception" or "critical"
|
|
177 |
* detail should be null for passing cases.
|
|
178 |
* For exceptions and crits, "desc" is the exception name,
|
|
179 |
* detail is the message.
|
|
180 |
*/
|
|
181 |
function create_response_item(type, desc, detail) |
|
182 |
{
|
|
183 |
var crit = false; |
|
184 |
if (type == "critical") |
|
185 |
{
|
|
186 |
/* Crits look like exceptions, but are slightly different */
|
|
187 |
crit = true; |
|
188 |
type = "exception"; |
|
189 |
}
|
|
190 |
var li = document.createElement("li"); |
|
191 |
li.setAttribute("class", type); |
|
192 |
var b = document.createElement("b"); |
|
193 |
var text = type[0].toUpperCase() + type.substr(1) + ":"; |
|
194 |
b.appendChild(document.createTextNode(text)); |
|
195 |
li.appendChild(b); |
|
196 |
if (type == "pass") |
|
197 |
text = desc; |
|
198 |
else if (type == "fail") |
|
199 |
text = desc + (detail == null ? "" : ":"); |
|
200 |
else if (type == "exception") |
|
201 |
{
|
|
202 |
if (crit) |
|
203 |
text = "Your code could not be executed, " |
|
204 |
+ "due to the following error:"; |
|
205 |
else
|
|
206 |
text = "The following exception occured " |
|
207 |
+ "while running your code:"; |
|
208 |
}
|
|
209 |
li.appendChild(document.createTextNode(" " + text)); |
|
210 |
if (type == "pass" || (type == "fail" && detail == null)) |
|
211 |
return li; |
|
212 |
||
213 |
/* Non-passes, display the error message */
|
|
214 |
li.appendChild(document.createElement("br")); |
|
215 |
if (type == "exception") |
|
216 |
{
|
|
217 |
b = document.createElement("b"); |
|
218 |
b.appendChild(document.createTextNode(desc + ":")); |
|
219 |
li.appendChild(b); |
|
220 |
}
|
|
221 |
li.appendChild(document.createTextNode(detail)); |
|
222 |
return li; |
|
307
by mattgiuca
tutorial: Now each problem div has an ID. Added submit buttons which call |
223 |
}
|