332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
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: Console (Client-side JavaScript)
|
|
19 |
* Author: Tom Conway, Matt Giuca
|
|
20 |
* Date: 30/1/2008
|
|
21 |
*/
|
|
22 |
||
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
23 |
digest_constant = "hello"; |
24 |
||
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
25 |
var server_host; |
26 |
var server_port; |
|
27 |
var server_magic; |
|
28 |
||
339
by mattgiuca
console: |
29 |
/* Begin religious debate (tabs vs spaces) here: */
|
30 |
/* (This string will be inserted in the console when the user presses the Tab
|
|
31 |
* key) */
|
|
32 |
TAB_STRING = " "; |
|
33 |
||
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
34 |
/* Console DOM objects */
|
35 |
console_body = null; |
|
36 |
console_filler = null; |
|
37 |
||
339
by mattgiuca
console: |
38 |
windowpane_mode = false; |
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
39 |
server_started = false; |
339
by mattgiuca
console: |
40 |
|
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
41 |
/* Starts the console server, if it isn't already.
|
42 |
* This can be called any number of times - it only starts the one server.
|
|
43 |
* This is a separate step from console_init, as the server is only to be
|
|
44 |
* started once the first command is entered.
|
|
45 |
* Does not return a value. Writes to global variables
|
|
46 |
* server_host, server_port, server_magic.
|
|
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
47 |
*/
|
48 |
function start_server() |
|
49 |
{
|
|
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
50 |
if (server_started) return; |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
51 |
var xhr = ajax_call("consoleservice", "start", {}, "POST"); |
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
52 |
var json_text = xhr.responseText; |
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
53 |
var server_info = JSON.parse(json_text); |
54 |
server_host = server_info.host; |
|
55 |
server_port = server_info.port; |
|
56 |
server_magic = server_info.magic; |
|
57 |
server_started = true; |
|
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
58 |
}
|
59 |
||
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
60 |
/** Initialises the console. All apps which import console are required to
|
61 |
* call this function.
|
|
62 |
* Optional "windowpane" (bool), if true, will cause the console to go into
|
|
63 |
* "window pane" mode which will allow it to be opened and closed, and float
|
|
64 |
* over the page.
|
|
65 |
* (Defaults to closed).
|
|
66 |
*/
|
|
331
by mattgiuca
Console: Configured console to display properly as a "floating" window in the |
67 |
function console_init(windowpane) |
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
68 |
{
|
331
by mattgiuca
Console: Configured console to display properly as a "floating" window in the |
69 |
/* Set up the console as a floating pane */
|
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
70 |
console_body = document.getElementById("console_body"); |
71 |
console_filler = document.getElementById("console_filler"); |
|
331
by mattgiuca
Console: Configured console to display properly as a "floating" window in the |
72 |
if (windowpane) |
339
by mattgiuca
console: |
73 |
{
|
74 |
windowpane_mode = true; |
|
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
75 |
console_minimize(); |
339
by mattgiuca
console: |
76 |
}
|
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
77 |
/* TEMP: Start the server now.
|
78 |
* Ultimately we want the server to start only when a line is typed, but
|
|
79 |
* it currently does it asynchronously and doesn't start in time for the
|
|
80 |
* first line. */
|
|
81 |
start_server(); |
|
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
82 |
}
|
83 |
||
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
84 |
/** Hide the main console panel, so the console minimizes to just an input box
|
85 |
* at the page bottom. */
|
|
86 |
function console_minimize() |
|
87 |
{
|
|
339
by mattgiuca
console: |
88 |
if (!windowpane_mode) return; |
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
89 |
console_body.setAttribute("class", "windowpane minimal"); |
90 |
console_filler.setAttribute("class", "windowpane minimal"); |
|
91 |
}
|
|
92 |
||
93 |
/** Show the main console panel, so it enlarges out to its full size.
|
|
94 |
*/
|
|
95 |
function console_maximize() |
|
96 |
{
|
|
339
by mattgiuca
console: |
97 |
if (!windowpane_mode) return; |
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
98 |
console_body.setAttribute("class", "windowpane maximal"); |
99 |
console_filler.setAttribute("class", "windowpane maximal"); |
|
100 |
}
|
|
101 |
||
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
102 |
/* Below here imported from trunk/console/console.js
|
103 |
* (Tom Conway)
|
|
104 |
*/
|
|
105 |
||
106 |
var magic = 'xyzzy'; |
|
107 |
||
108 |
function historyUp() |
|
109 |
{
|
|
110 |
if (this.cursor >= 0) |
|
111 |
{
|
|
112 |
this.cursor--; |
|
113 |
}
|
|
114 |
}
|
|
115 |
||
116 |
function historyDown() |
|
117 |
{
|
|
118 |
if (this.cursor < this.items.length) |
|
119 |
{
|
|
120 |
this.cursor++; |
|
121 |
}
|
|
122 |
}
|
|
123 |
||
124 |
function historyCurr() |
|
125 |
{
|
|
126 |
if (this.cursor < 0 || this.cursor >= this.items.length) |
|
127 |
{
|
|
128 |
return ""; |
|
129 |
}
|
|
130 |
return this.items[this.cursor]; |
|
131 |
}
|
|
132 |
||
133 |
function historyAdd(text) |
|
134 |
{
|
|
135 |
this.items[this.items.length] = text; |
|
136 |
this.cursor = this.items.length; |
|
137 |
}
|
|
138 |
||
139 |
function historyShow() |
|
140 |
{
|
|
141 |
var res = ""; |
|
142 |
if (this.cursor == -1) |
|
143 |
{
|
|
144 |
res += "[]"; |
|
145 |
}
|
|
146 |
for (var i = 0; i < this.items.length; i++) |
|
147 |
{
|
|
148 |
if (i == this.cursor) |
|
149 |
{
|
|
150 |
res += "[" |
|
151 |
}
|
|
152 |
res += this.items[i].toString(); |
|
153 |
if (i == this.cursor) |
|
154 |
{
|
|
155 |
res += "]" |
|
156 |
}
|
|
157 |
res += " " |
|
158 |
}
|
|
159 |
if (this.cursor == this.items.length) |
|
160 |
{
|
|
161 |
res += "[]"; |
|
162 |
}
|
|
163 |
return res; |
|
164 |
}
|
|
165 |
||
166 |
function History() |
|
167 |
{
|
|
168 |
this.items = new Array(); |
|
169 |
this.cursor = -1; |
|
170 |
this.up = historyUp; |
|
171 |
this.down = historyDown; |
|
172 |
this.curr = historyCurr; |
|
173 |
this.add = historyAdd; |
|
174 |
this.show = historyShow; |
|
175 |
}
|
|
176 |
||
177 |
var hist = new History(); |
|
178 |
||
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
179 |
/** Send a line of text to the Python server, wait for its return, and react
|
180 |
* to its response by writing to the output box.
|
|
181 |
* Also maximize the console window if not already.
|
|
182 |
*/
|
|
183 |
function console_enter_line(inputline) |
|
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
184 |
{
|
343
by mattgiuca
console: Small refactoring of how server starts up. Currently does not affect |
185 |
/* Start the server if it hasn't already been started */
|
186 |
start_server(); |
|
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
187 |
var digest = hex_md5(inputline + magic); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
188 |
var args = {"host": server_host, "port": server_port, |
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
189 |
"digest":digest, "text":inputline}; |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
190 |
var xmlhttp = ajax_call("consoleservice", "chat", args, "POST"); |
191 |
||
192 |
var res = JSON.parse(xmlhttp.responseText); |
|
328
by mattgiuca
console: Renamed HTML element IDs to prefix "console_". |
193 |
var output = document.getElementById("console_output"); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
194 |
{
|
195 |
var pre = document.createElement("pre"); |
|
196 |
pre.setAttribute("class", "inputMsg"); |
|
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
197 |
pre.appendChild(document.createTextNode(inputline + "\n")); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
198 |
output.appendChild(pre); |
199 |
}
|
|
200 |
if (res.hasOwnProperty('okay')) |
|
201 |
{
|
|
202 |
// Success!
|
|
203 |
// print out the output (res.okay[0])
|
|
204 |
var pre = document.createElement("pre"); |
|
205 |
pre.setAttribute("class", "outputMsg"); |
|
206 |
pre.appendChild(document.createTextNode(res.okay[0])); |
|
207 |
output.appendChild(pre); |
|
208 |
// print out the return value (res.okay[1])
|
|
209 |
if (res.okay[1]) |
|
210 |
{
|
|
211 |
var pre = document.createElement("pre"); |
|
212 |
pre.setAttribute("class", "outputMsg"); |
|
213 |
pre.appendChild(document.createTextNode(res.okay[1] + "\n")); |
|
214 |
output.appendChild(pre); |
|
215 |
}
|
|
216 |
// set the prompt to >>>
|
|
328
by mattgiuca
console: Renamed HTML element IDs to prefix "console_". |
217 |
var prompt = document.getElementById("console_prompt"); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
218 |
prompt.replaceChild(document.createTextNode(">>> "), prompt.firstChild); |
219 |
}
|
|
220 |
else if (res.hasOwnProperty('exc')) |
|
221 |
{
|
|
222 |
// Failure!
|
|
341
by mattgiuca
www/media/console/console.js: Merged in Tom's changes from console/console.js. |
223 |
// print out any output that came before the error
|
224 |
if (res.exc[0].length > 0) |
|
225 |
{
|
|
226 |
var pre = document.createElement("pre"); |
|
227 |
pre.setAttribute("class", "outputMsg"); |
|
228 |
pre.appendChild(document.createTextNode(res.exc[0])); |
|
229 |
output.appendChild(pre); |
|
230 |
}
|
|
231 |
||
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
232 |
// print out the error message (res.exc)
|
233 |
var pre = document.createElement("pre"); |
|
234 |
pre.setAttribute("class", "errorMsg"); |
|
341
by mattgiuca
www/media/console/console.js: Merged in Tom's changes from console/console.js. |
235 |
pre.appendChild(document.createTextNode(res.exc[1])); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
236 |
output.appendChild(pre); |
237 |
}
|
|
238 |
else if (res.hasOwnProperty('more')) |
|
239 |
{
|
|
240 |
// Need more input, so set the prompt to ...
|
|
328
by mattgiuca
console: Renamed HTML element IDs to prefix "console_". |
241 |
var prompt = document.getElementById("console_prompt"); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
242 |
prompt.replaceChild(document.createTextNode("... "), prompt.firstChild); |
243 |
}
|
|
244 |
else { |
|
245 |
// assert res.hasOwnProperty('input')
|
|
328
by mattgiuca
console: Renamed HTML element IDs to prefix "console_". |
246 |
var prompt = document.getElementById("console_prompt"); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
247 |
prompt.replaceChild(document.createTextNode("+++ "), prompt.firstChild); |
248 |
}
|
|
332
by mattgiuca
console plugin: Now presents minimize/maximize buttons, allowing itself to be |
249 |
/* Open up the console so we can see the output */
|
250 |
console_maximize(); |
|
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
251 |
}
|
252 |
||
253 |
function catch_input(key) |
|
254 |
{
|
|
328
by mattgiuca
console: Renamed HTML element IDs to prefix "console_". |
255 |
var inp = document.getElementById('console_inputText'); |
339
by mattgiuca
console: |
256 |
switch (key) |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
257 |
{
|
339
by mattgiuca
console: |
258 |
case 9: /* Tab key */ |
259 |
var selstart = inp.selectionStart; |
|
260 |
var selend = inp.selectionEnd; |
|
261 |
if (selstart == selend) |
|
262 |
{
|
|
263 |
/* No selection, just a carat. Insert a tab here. */
|
|
264 |
inp.value = inp.value.substr(0, selstart) |
|
265 |
+ TAB_STRING + inp.value.substr(selstart); |
|
266 |
}
|
|
267 |
else
|
|
268 |
{
|
|
269 |
/* Text is selected. Just indent the whole line
|
|
270 |
* by inserting a tab at the start */
|
|
271 |
inp.value = TAB_STRING + inp.value; |
|
272 |
}
|
|
273 |
/* Update the selection so the same characters as before are selected
|
|
274 |
*/
|
|
275 |
inp.selectionStart = selstart + TAB_STRING.length; |
|
276 |
inp.selectionEnd = inp.selectionStart + (selend - selstart); |
|
277 |
/* Cancel the event, so the TAB key doesn't move focus away from this
|
|
278 |
* box */
|
|
279 |
return false; |
|
280 |
/* Note: If it happens that some browsers don't support event
|
|
281 |
* cancelling properly, this hack might work instead:
|
|
282 |
setTimeout(
|
|
283 |
"document.getElementById('console_inputText').focus()",
|
|
284 |
0);
|
|
285 |
*/
|
|
286 |
break; |
|
287 |
case 13: /* Enter key */ |
|
288 |
/* Send the line of text to the server */
|
|
333
by mattgiuca
console.js: enter_line now accepts the line as an argument instead of reading |
289 |
console_enter_line(inp.value); |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
290 |
hist.add(inp.value); |
291 |
inp.value = hist.curr(); |
|
339
by mattgiuca
console: |
292 |
break; |
293 |
case 38: /* Up arrow */ |
|
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
294 |
hist.up(); |
295 |
inp.value = hist.curr(); |
|
339
by mattgiuca
console: |
296 |
break; |
297 |
case 40: /* Down arrow */ |
|
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
298 |
hist.down(); |
299 |
inp.value = hist.curr(); |
|
339
by mattgiuca
console: |
300 |
break; |
276
by mattgiuca
Console now runs inside IVLE (without requiring an IFRAME). The separate |
301 |
}
|
217
by mattgiuca
Console: Python code generates a minimal document with a DIV and links to |
302 |
}
|