~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to www/media/console/console.js

  • Committer: mattgiuca
  • Date: 2008-02-05 01:41:15 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:409
Moved www/conf and www/common to a new directory lib. This separates the "web"
part of IVLE from what is becoming less web oriented (at least from Apache's
standpoint).
Modified setup.py to install this lib directory correctly and write conf in
the right place. Also adds the lib directory to ivle.pth.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
1
23
digest_constant = "hello";
2
24
 
3
 
/* Starts the console server.
4
 
 * Returns an object with fields "host", "port", "magic" describing the
5
 
 * server.
 
25
var server_host;
 
26
var server_port;
 
27
var server_magic;
 
28
 
 
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
 
 
34
/* Console DOM objects */
 
35
console_body = null;
 
36
console_filler = null;
 
37
 
 
38
windowpane_mode = false;
 
39
server_started = false;
 
40
 
 
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.
6
47
 */
7
48
function start_server()
8
49
{
9
 
    var xhr = ajax_call("consoleservice", "", "", "POST");
 
50
    if (server_started) return;
 
51
    var xhr = ajax_call("consoleservice", "start", {}, "POST");
10
52
    var json_text = xhr.responseText;
11
 
    return JSON.parse(json_text);
12
 
}
13
 
 
14
 
function onload()
15
 
{
16
 
    var consolebody = document.getElementById("consolebody");
17
 
    var iframe = document.createElement("iframe");
18
 
    consolebody.appendChild(iframe);
19
 
    iframe.setAttribute("width", "100%");
20
 
    /* TODO: Height 100%, once CSS is working */
21
 
    iframe.setAttribute("height", "600px");
22
 
 
23
 
    /* Start the server */
24
 
    var server_info = start_server();
25
 
 
26
 
    var digest = hex_md5(digest_constant + server_info.magic);
27
 
 
28
 
    var url = "http://"
29
 
        + server_info.host.toString() + ":"
30
 
        + server_info.port.toString() + "?digest=" + digest;
31
 
 
32
 
    iframe.setAttribute("src", url);
 
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;
 
58
}
 
59
 
 
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
 */
 
67
function console_init(windowpane)
 
68
{
 
69
    /* Set up the console as a floating pane */
 
70
    console_body = document.getElementById("console_body");
 
71
    /* If there is no console body, don't worry.
 
72
     * (This lets us import console.js even on pages without a console box */
 
73
    if (console_body == null) return;
 
74
    console_filler = document.getElementById("console_filler");
 
75
    if (windowpane)
 
76
    {
 
77
        windowpane_mode = true;
 
78
        console_minimize();
 
79
    }
 
80
    /* TEMP: Start the server now.
 
81
     * Ultimately we want the server to start only when a line is typed, but
 
82
     * it currently does it asynchronously and doesn't start in time for the
 
83
     * first line. */
 
84
    start_server();
 
85
}
 
86
 
 
87
/** Hide the main console panel, so the console minimizes to just an input box
 
88
 *  at the page bottom. */
 
89
function console_minimize()
 
90
{
 
91
    if (!windowpane_mode) return;
 
92
    console_body.setAttribute("class", "windowpane minimal");
 
93
    console_filler.setAttribute("class", "windowpane minimal");
 
94
}
 
95
 
 
96
/** Show the main console panel, so it enlarges out to its full size.
 
97
 */
 
98
function console_maximize()
 
99
{
 
100
    if (!windowpane_mode) return;
 
101
    console_body.setAttribute("class", "windowpane maximal");
 
102
    console_filler.setAttribute("class", "windowpane maximal");
 
103
    /* Focus the input box by default */
 
104
    document.getElementById("console_inputText").focus()
 
105
}
 
106
 
 
107
/* current_text is the string currently on the command line.
 
108
 * If non-empty, it will be stored at the bottom of the history.
 
109
 */
 
110
function historyUp(current_text)
 
111
{
 
112
    /* Remember the changes made to this item */
 
113
    this.edited[this.cursor] = current_text;
 
114
    if (this.cursor > 0)
 
115
    {
 
116
        this.cursor--;
 
117
    }
 
118
    this.earliestCursor = this.cursor;
 
119
}
 
120
 
 
121
function historyDown(current_text)
 
122
{
 
123
    /* Remember the changes made to this item */
 
124
    this.edited[this.cursor] = current_text;
 
125
    if (this.cursor < this.items.length - 1)
 
126
    {
 
127
        this.cursor++;
 
128
    }
 
129
}
 
130
 
 
131
function historyCurr()
 
132
{
 
133
    return this.edited[this.cursor];
 
134
}
 
135
 
 
136
function historySubmit(text)
 
137
{
 
138
    /* Copy the selected item's "edited" version over the permanent version of
 
139
     * the last item. */
 
140
    this.items[this.items.length-1] = text;
 
141
    /* Add a new blank item */
 
142
    this.items[this.items.length] = "";
 
143
    this.cursor = this.items.length-1;
 
144
    /* Blow away all the edited versions, replacing them with the existing
 
145
     * items set.
 
146
     * Not the whole history - just start from the earliest edited one.
 
147
     * (This avoids slowdown over extended usage time).
 
148
     */
 
149
    for (var i=this.earliestCursor; i<=this.cursor; i++)
 
150
        this.edited[i] = this.items[i];
 
151
    this.earliestCursor = this.cursor;
 
152
}
 
153
 
 
154
function historyShow()
 
155
{
 
156
    var res = "";
 
157
    for (var i = 0; i < this.items.length; i++)
 
158
    {
 
159
        if (i == this.cursor)
 
160
        {
 
161
            res += "["
 
162
        }
 
163
        res += this.items[i].toString();
 
164
        if (i == this.cursor)
 
165
        {
 
166
            res += "]"
 
167
        }
 
168
        res += " "
 
169
    }
 
170
    if (this.cursor == this.items.length)
 
171
    {
 
172
        res += "[]";
 
173
    }
 
174
    return res;
 
175
}
 
176
 
 
177
/* How history works
 
178
 * This is a fairly complex mechanism due to complications when editing
 
179
 * history items. We store two arrays. "items" is the permanent history of
 
180
 * each item. "edited" is a "volatile" version of items - the edits made to
 
181
 * the history between now and last time you hit "enter".
 
182
 * This is because the user can go back and edit any of the previous items,
 
183
 * and the edits are remembered until they hit enter.
 
184
 *
 
185
 * When hitting enter, the "edited" version of the currently selected item
 
186
 * replaces the "item" version of the last item in the list.
 
187
 * Then a new blank item is created, for the new line of input.
 
188
 * Lastly, all the "edited" versions are replaced with their stable versions.
 
189
 *
 
190
 * Cursor never points to an invalid location.
 
191
 */
 
192
function History()
 
193
{
 
194
    this.items = new Array("");
 
195
    this.edited = new Array("");
 
196
    this.cursor = 0;
 
197
    this.earliestCursor = 0;
 
198
    this.up = historyUp;
 
199
    this.down = historyDown;
 
200
    this.curr = historyCurr;
 
201
    this.submit = historySubmit;
 
202
    this.show = historyShow;
 
203
}
 
204
 
 
205
var hist = new History();
 
206
 
 
207
/** Send a line of text to the Python server, wait for its return, and react
 
208
 * to its response by writing to the output box.
 
209
 * Also maximize the console window if not already.
 
210
 */
 
211
function console_enter_line(inputline, which)
 
212
{
 
213
    /* Start the server if it hasn't already been started */
 
214
    start_server();
 
215
    var digest = hex_md5(inputline + server_magic);
 
216
    var args = {"host": server_host, "port": server_port,
 
217
                    "digest":digest, "text":inputline};
 
218
    var xmlhttp = ajax_call("consoleservice", which, args, "POST");
 
219
 
 
220
    var res = JSON.parse(xmlhttp.responseText);
 
221
    var output = document.getElementById("console_output");
 
222
    {
 
223
        var pre = document.createElement("pre");
 
224
        pre.setAttribute("class", "inputMsg");
 
225
        pre.appendChild(document.createTextNode(inputline + "\n"));
 
226
        output.appendChild(pre);
 
227
    }
 
228
    if (res.hasOwnProperty('okay'))
 
229
    {
 
230
        // Success!
 
231
        // print out the output (res.okay[0])
 
232
        var pre = document.createElement("pre");
 
233
        pre.setAttribute("class", "outputMsg");
 
234
        pre.appendChild(document.createTextNode(res.okay[0]));
 
235
        output.appendChild(pre);
 
236
        // print out the return value (res.okay[1])
 
237
        if (res.okay[1])
 
238
        {
 
239
            var pre = document.createElement("pre");
 
240
            pre.setAttribute("class", "outputMsg");
 
241
            pre.appendChild(document.createTextNode(res.okay[1] + "\n"));
 
242
            output.appendChild(pre);
 
243
        }
 
244
        // set the prompt to >>>
 
245
        var prompt = document.getElementById("console_prompt");
 
246
        prompt.replaceChild(document.createTextNode(">>> "), prompt.firstChild);
 
247
    }
 
248
    else if (res.hasOwnProperty('exc'))
 
249
    {
 
250
        // Failure!
 
251
        // print out any output that came before the error
 
252
        if (res.exc[0].length > 0)
 
253
        {
 
254
            var pre = document.createElement("pre");
 
255
            pre.setAttribute("class", "outputMsg");
 
256
            pre.appendChild(document.createTextNode(res.exc[0]));
 
257
            output.appendChild(pre);
 
258
        }
 
259
 
 
260
        // print out the error message (res.exc)
 
261
        var pre = document.createElement("pre");
 
262
        pre.setAttribute("class", "errorMsg");
 
263
        pre.appendChild(document.createTextNode(res.exc[1]));
 
264
        output.appendChild(pre);
 
265
    }
 
266
    else if (res.hasOwnProperty('more'))
 
267
    {
 
268
        // Need more input, so set the prompt to ...
 
269
        var prompt = document.getElementById("console_prompt");
 
270
        prompt.replaceChild(document.createTextNode("... "), prompt.firstChild);
 
271
    }
 
272
    else {
 
273
        // assert res.hasOwnProperty('input')
 
274
        var prompt = document.getElementById("console_prompt");
 
275
        prompt.replaceChild(document.createTextNode("+++ "), prompt.firstChild);
 
276
    }
 
277
    /* Open up the console so we can see the output */
 
278
    console_maximize();
 
279
}
 
280
 
 
281
function catch_input(key)
 
282
{
 
283
    var inp = document.getElementById('console_inputText');
 
284
    switch (key)
 
285
    {
 
286
    case 9:                 /* Tab key */
 
287
        var selstart = inp.selectionStart;
 
288
        var selend = inp.selectionEnd;
 
289
        if (selstart == selend)
 
290
        {
 
291
            /* No selection, just a carat. Insert a tab here. */
 
292
            inp.value = inp.value.substr(0, selstart)
 
293
                + TAB_STRING + inp.value.substr(selstart);
 
294
        }
 
295
        else
 
296
        {
 
297
            /* Text is selected. Just indent the whole line
 
298
             * by inserting a tab at the start */
 
299
            inp.value = TAB_STRING + inp.value;
 
300
        }
 
301
        /* Update the selection so the same characters as before are selected
 
302
         */
 
303
        inp.selectionStart = selstart + TAB_STRING.length;
 
304
        inp.selectionEnd = inp.selectionStart + (selend - selstart);
 
305
        /* Cancel the event, so the TAB key doesn't move focus away from this
 
306
         * box */
 
307
        return false;
 
308
        /* Note: If it happens that some browsers don't support event
 
309
         * cancelling properly, this hack might work instead:
 
310
        setTimeout(
 
311
            "document.getElementById('console_inputText').focus()",
 
312
            0);
 
313
         */
 
314
        break;
 
315
    case 13:                /* Enter key */
 
316
        /* Send the line of text to the server */
 
317
        console_enter_line(inp.value, "chat");
 
318
        hist.submit(inp.value);
 
319
        inp.value = hist.curr();
 
320
        break;
 
321
    case 38:                /* Up arrow */
 
322
        hist.up(inp.value);
 
323
        inp.value = hist.curr();
 
324
        break;
 
325
    case 40:                /* Down arrow */
 
326
        hist.down(inp.value);
 
327
        inp.value = hist.curr();
 
328
        break;
 
329
    }
33
330
}