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

« back to all changes in this revision

Viewing changes to www/media/common/util.js

  • Committer: mattgiuca
  • Date: 2008-02-15 07:14:52 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:478
scripts/usrmgr-server: Renamed actions from dashes to underscores.
    (Consistency).
    accept_user returns a dict instead of None.

apps.py: Turned off auth for userservice (otherwise requests can't come thru
    from a user who is not activated; dispatch blocks such requests).
    Userservice does its own auth from now on.

userservice: Now makes the call to usrmgt-server for accept_me.
    Does authentication (since we can't do it at dispatch level).

tos.js: Clicking Accept now makes an Ajax call to userservice to get the
    account activated.

WHAT WORKS: Clicking the button now gets the account activated. There are some
    rough edges and errors won't be handled well.
WHAT DOESN'T: After clicking, the user is left thinking that nothing happened.
    They have to log out and back in again to enable themselves.
    (This is noted in the bug tracker).

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: JavaScript Utilities
 
19
 * Author: Matt Giuca
 
20
 * Date: 11/1/2008
 
21
 *
 
22
 * Defines some generic JavaScript utility functions.
 
23
 */
 
24
 
 
25
/* Expects the following variables to have been declared by JavaScript in
 
26
 * the HTML generated by the server:
 
27
 * - root_dir
 
28
 * - username
 
29
 */
 
30
 
 
31
/** Removes all children of a given DOM element
 
32
 * \param elem A DOM Element. Will be modified.
 
33
 */
 
34
function dom_removechildren(elem)
 
35
{
 
36
    while (elem.lastChild != null)
 
37
        elem.removeChild(elem.lastChild);
 
38
}
 
39
 
 
40
/** Creates a DOM element with simple text inside it.
 
41
 * \param tagname String. Name of the element's tag (eg. "p").
 
42
 * \param text String. Text to be placed inside the element.
 
43
 * \param title String, optional. Tooltip for the text.
 
44
 *  (Note, title creates a span element around the text).
 
45
 * \return DOM Element object.
 
46
 */
 
47
function dom_make_text_elem(tagname, text, title)
 
48
{
 
49
    if (text == null) text = "";
 
50
    var elem = document.createElement(tagname);
 
51
    var textnode;
 
52
    if (title == null)
 
53
        textnode = document.createTextNode(text);
 
54
    else
 
55
    {
 
56
        textnode = document.createElement("span");
 
57
        textnode.setAttribute("title", title);
 
58
        textnode.appendChild(document.createTextNode(text));
 
59
    }
 
60
    elem.appendChild(textnode);
 
61
    return elem;
 
62
}
 
63
 
 
64
/** Creates a DOM element with hyperlinked text inside it.
 
65
 * \param tagname String. Name of the element's tag (eg. "p").
 
66
 * \param text String. Text to be placed inside the element.
 
67
 * \param title String, optional. Sets a tooltip for the link.
 
68
 * \param href String. URL the text will link to. This is a raw string,
 
69
 *  it will automatically be URL-encoded.
 
70
 * \param onclick Optional string. Will be set as the "onclick" attribute
 
71
 *  of the "a" element.
 
72
 * \param dontencode Optional boolean. If true, will not encode the href.
 
73
 *  if including query strings, you must set this to true and use build_url
 
74
 *  to escape the URI correctly.
 
75
 * \return DOM Element object.
 
76
 */
 
77
function dom_make_link_elem(tagname, text, title, href, onclick, dontencode)
 
78
{
 
79
    if (text == null) text = "";
 
80
    if (href == null) href = "";
 
81
    var elem = document.createElement(tagname);
 
82
    var link = document.createElement("a");
 
83
    if (dontencode != true)
 
84
        href = urlencode_path(href);
 
85
    link.setAttribute("href", href);
 
86
    if (title != null)
 
87
        link.setAttribute("title", title);
 
88
    if (onclick != null)
 
89
        link.setAttribute("onclick", onclick);
 
90
    link.appendChild(document.createTextNode(text));
 
91
    elem.appendChild(link);
 
92
    return elem;
 
93
}
 
94
 
 
95
/** Creates a DOM img element. All parameters are optional except src.
 
96
 * If alt (compulsory in HTML) is omitted, will be set to "".
 
97
 */
 
98
function dom_make_img(src, width, height, title, alt)
 
99
{
 
100
    var img = document.createElement("img");
 
101
    img.setAttribute("src", urlencode_path(src));
 
102
    if (width != null)
 
103
        img.setAttribute("width", width);
 
104
    if (height != null)
 
105
        img.setAttribute("height", height);
 
106
    if (title != null)
 
107
        img.setAttribute("title", title);
 
108
    if (alt == null) alt = "";
 
109
    img.setAttribute("alt", alt);
 
110
    return img;
 
111
}
 
112
 
 
113
/** Given a number of bytes, returns a string representing the file size in a
 
114
 * human-readable format.
 
115
 * eg. nice_filesize(6) -> "6 bytes"
 
116
 *     nice_filesize(81275) -> "79.4 kB"
 
117
 *     nice_filesize(13498346) -> "12.9 MB"
 
118
 * \param bytes Number of bytes. Must be an integer.
 
119
 * \return String.
 
120
 */
 
121
function nice_filesize(bytes)
 
122
{
 
123
    if (bytes == null) return "";
 
124
    var size;
 
125
    if (bytes < 1024)
 
126
        return bytes.toString() + " B";
 
127
    size = bytes / 1024;
 
128
    if (size < 1024)
 
129
        return size.toFixed(1) + " kB";
 
130
    size = size / 1024;
 
131
    if (size < 1024)
 
132
        return size.toFixed(1) + " MB";
 
133
    size = size / 1024;
 
134
    return size.toFixed(1) + " GB";
 
135
}
 
136
 
 
137
/** Given a URL, returns an object containing a number of attributes
 
138
 * describing the components of the URL, similar to CGI request variables.
 
139
 * The object has the following attributes:
 
140
 * - scheme
 
141
 * - server_name
 
142
 * - server_port
 
143
 * - path
 
144
 * - query_string
 
145
 * - args
 
146
 * The first five of these are strings, which comprise the URL as follows:
 
147
 * <scheme> "://" <server_name> ":" <server_port> <path> "?" <query_string>
 
148
 * Any of these strings may be set to null if not found.
 
149
 *
 
150
 * "args" is an object whose attributes are the query_string arguments broken
 
151
 * up.
 
152
 * Args values are strings for single values, arrays of strings for values
 
153
 * whose names appear multiple times.
 
154
 * args is never null, though it may be empty.
 
155
 *
 
156
 * All strings are decoded/unescaped. Reserved characters
 
157
 * (; , / ? : @ & = + * $) are not decoded except in args and path.
 
158
 *
 
159
 * \param url String. A URL. To read from the current browser window, use
 
160
 *  window.location.href.
 
161
 * \return The above described object.
 
162
 */
 
163
function parse_url(url)
 
164
{
 
165
    var obj = {};
 
166
    var index;
 
167
    var serverpart;
 
168
    var args;
 
169
 
 
170
    /* Split scheme from rest */
 
171
    index = url.indexOf("://");
 
172
    if (index < 0)
 
173
        obj.scheme = null;
 
174
    else
 
175
    {
 
176
        obj.scheme = url.substr(0, index);
 
177
        url = url.substr(index+3);
 
178
    }
 
179
 
 
180
    /* Split server name/port from rest */
 
181
    index = url.indexOf("/");
 
182
    if (index < 0)
 
183
    {
 
184
        serverpart = url;
 
185
        url = null;
 
186
    }
 
187
    else
 
188
    {
 
189
        serverpart = url.substr(0, index);
 
190
        url = url.substr(index);
 
191
    }
 
192
 
 
193
    /* Split server name from port */
 
194
    index = serverpart.indexOf(":");
 
195
    if (index < 0)
 
196
    {
 
197
        obj.server_name = serverpart;
 
198
        obj.server_port = null;
 
199
    }
 
200
    else
 
201
    {
 
202
        obj.server_name = serverpart.substr(0, index);
 
203
        obj.server_port = serverpart.substr(index+1);
 
204
    }
 
205
 
 
206
    /* Split path from query string */
 
207
    if (url == null)
 
208
    {
 
209
        obj.path = null;
 
210
        obj.query_string = null;
 
211
    }
 
212
    else
 
213
    {
 
214
        index = url.indexOf("?");
 
215
        if (index < 0)
 
216
        {
 
217
            obj.path = url;
 
218
            obj.query_string = null;
 
219
        }
 
220
        else
 
221
        {
 
222
            obj.path = url.substr(0, index);
 
223
            obj.query_string = url.substr(index+1);
 
224
        }
 
225
    }
 
226
    obj.path = decodeURIComponent(obj.path);
 
227
 
 
228
    /* Split query string into arguments */
 
229
    args = {};
 
230
    if (obj.query_string != null)
 
231
    {
 
232
        var args_strs = obj.query_string.split("&");
 
233
        var arg_str;
 
234
        var arg_key, arg_val;
 
235
        for (var i=0; i<args_strs.length; i++)
 
236
        {
 
237
            arg_str = args_strs[i];
 
238
            index = arg_str.indexOf("=");
 
239
            /* Ignore malformed args */
 
240
            if (index >= 0)
 
241
            {
 
242
                arg_key = decodeURIComponent(arg_str.substr(0, index));
 
243
                arg_val = decodeURIComponent(arg_str.substr(index+1));
 
244
                if (arg_key in args)
 
245
                {
 
246
                    /* Collision - make an array */
 
247
                    if (args[arg_key] instanceof Array)
 
248
                        args[arg_key][args[arg_key].length] = arg_val;
 
249
                    else
 
250
                        args[arg_key] = [args[arg_key], arg_val];
 
251
                }
 
252
                else
 
253
                    args[arg_key] = arg_val;
 
254
            }
 
255
        }
 
256
    }
 
257
    obj.args = args;
 
258
 
 
259
    return obj;
 
260
}
 
261
 
 
262
/** Builds a query_string from an args object. Encodes the arguments.
 
263
 * \param args Args object as described in parse_url.
 
264
 * \return Query string portion of a URL.
 
265
 */
 
266
function make_query_string(args)
 
267
{
 
268
    var query_string = "";
 
269
    var arg_val;
 
270
    for (var arg_key in args)
 
271
    {
 
272
        arg_val = args[arg_key];
 
273
        if (arg_val instanceof Array)
 
274
            for (var i=0; i<arg_val.length; i++)
 
275
                query_string += "&" + encodeURIComponent(arg_key) + "=" +
 
276
                    encodeURIComponent(arg_val[i]);
 
277
        else
 
278
            query_string += "&" + encodeURIComponent(arg_key) + "=" +
 
279
                encodeURIComponent(arg_val);
 
280
    }
 
281
    if (query_string != "")
 
282
        /* Drop the first "&" */
 
283
        query_string = query_string.substr(1);
 
284
 
 
285
    return query_string;
 
286
}
 
287
 
 
288
/** Given an object exactly of the form described for the output of parseurl,
 
289
 * returns a URL string built from those parameters. The URL is properly
 
290
 * encoded.
 
291
 * parseurl and buildurl are strict inverses of each other.
 
292
 * Note that either query_string or args may be supplied. If both are
 
293
 * supplied, query_string is preferred (because it keeps the argument order).
 
294
 * If you take a url from parseurl, modify args, and pass to buildurl,
 
295
 * you need to set query_string to null to use the new args.
 
296
 * \param obj Object as returned by parseurl.
 
297
 * \return String, a URL.
 
298
 */
 
299
function build_url(obj)
 
300
{
 
301
    var url = "";
 
302
    var query_string = null;
 
303
 
 
304
    if (("scheme" in obj) && obj.scheme != null)
 
305
        url = obj.scheme.toString() + "://";
 
306
    if (("server_name" in obj) && obj.server_name != null)
 
307
        url += obj.server_name.toString();
 
308
    if (("server_port" in obj) && obj.server_port != null)
 
309
        url += ":" + obj.server_port.toString();
 
310
    if (("path" in obj) && obj.path != null)
 
311
    {
 
312
        var path = urlencode_path(obj.path.toString());
 
313
        if (url.length > 0 && path.length > 0 && path[0] != "/")
 
314
            path = "/" + path;
 
315
        url += path;
 
316
    }
 
317
    if (("query_string" in obj) && obj.query_string != null)
 
318
        query_string = encodeURI(obj.query_string.toString());
 
319
    else if (("args" in obj) && obj.args != null)
 
320
        query_string = make_query_string(obj.args);
 
321
 
 
322
    if (query_string != "" && query_string != null)
 
323
        url += "?" + query_string;
 
324
 
 
325
    return url;
 
326
}
 
327
 
 
328
/** URL-encodes a path. This is a special case of URL encoding as all
 
329
 * characters *except* the slash must be encoded.
 
330
 */
 
331
function urlencode_path(path)
 
332
{
 
333
    /* Split up the path, URLEncode each segment with encodeURIComponent,
 
334
     * and rejoin.
 
335
     */
 
336
    var split = path.split('/');
 
337
    for (var i=0; i<split.length; i++)
 
338
        split[i] = encodeURIComponent(split[i]);
 
339
    path = path_join.apply(null, split);
 
340
    if (split[0] == "" && split.length > 1) path = "/" + path;
 
341
    return path;
 
342
}
 
343
 
 
344
/** Given an argument map, as output in the args parameter of the return of
 
345
 * parseurl, gets the first occurence of an argument in the URL string.
 
346
 * If the argument was not found, returns null.
 
347
 * If there was a single argument, returns the argument.
 
348
 * If there were multiple arguments, returns the first.
 
349
 * \param args Object mapping arguments to strings or arrays of strings.
 
350
 * \param arg String. Argument name.
 
351
 * \return String.
 
352
 */
 
353
function arg_getfirst(args, arg)
 
354
{
 
355
    if (!(arg in args))
 
356
        return null;
 
357
    var r = args[arg];
 
358
    if (r instanceof Array)
 
359
        return r[0];
 
360
    else
 
361
        return r;
 
362
}
 
363
 
 
364
/** Given an argument map, as output in the args parameter of the return of
 
365
 * parseurl, gets all occurences of an argument in the URL string, as an
 
366
 * array.
 
367
 * If the argument was not found, returns [].
 
368
 * Otherwise, returns all occurences as an array, even if there was only one.
 
369
 * \param args Object mapping arguments to strings or arrays of strings.
 
370
 * \param arg String. Argument name.
 
371
 * \return Array of strings.
 
372
 */
 
373
function arg_getlist(args, arg)
 
374
{
 
375
    if (!(arg in args))
 
376
        return [];
 
377
    var r = args[arg];
 
378
    if (r instanceof Array)
 
379
        return r;
 
380
    else
 
381
        return [r];
 
382
}
 
383
 
 
384
/** Joins one or more paths together. Accepts 1 or more arguments.
 
385
 */
 
386
function path_join(path1 /*, path2, ... */)
 
387
{
 
388
    var arg;
 
389
    var path = "";
 
390
    for (var i=0; i<arguments.length; i++)
 
391
    {
 
392
        arg = arguments[i];
 
393
        if (arg.length == 0) continue;
 
394
        if (arg[0] == '/')
 
395
            path = arg;
 
396
        else
 
397
        {
 
398
            if (path.length > 0 && path[path.length-1] != '/')
 
399
                path += '/';
 
400
            path += arg;
 
401
        }
 
402
    }
 
403
    return path;
 
404
}
 
405
 
 
406
 
 
407
/** Builds a multipart_formdata string from an args object. Similar to
 
408
 * make_query_string, but it returns data of type "multipart/form-data"
 
409
 * instead of "application/x-www-form-urlencoded". This is good for
 
410
 * encoding large strings such as text objects from the editor.
 
411
 * Should be written with a Content-Type of
 
412
 * "multipart/form-data, boundary=<boundary>".
 
413
 * All fields are sent with a Content-Type of text/plain.
 
414
 * \param args Args object as described in parse_url.
 
415
 * \param boundary Random "magic" string which DOES NOT appear in any of
 
416
 *  the argument values. This should match the "boundary=" value written to
 
417
 *  the Content-Type header.
 
418
 * \return String in multipart/form-data format.
 
419
 */
 
420
function make_multipart_formdata(args, boundary)
 
421
{
 
422
    var data = "";
 
423
    var arg_val;
 
424
    /* Mutates data */
 
425
    var extend_data = function(arg_key, arg_val)
 
426
    {
 
427
        /* FIXME: Encoding not supported here (should not matter if we
 
428
         * only use ASCII names */
 
429
        data += "--" + boundary + "\r\n"
 
430
            + "Content-Disposition: form-data; name=\"" + arg_key
 
431
            + "\"\r\n\r\n"
 
432
            + arg_val + "\r\n";
 
433
    }
 
434
 
 
435
    for (var arg_key in args)
 
436
    {
 
437
        arg_val = args[arg_key];
 
438
        if (arg_val instanceof Array)
 
439
            for (var i=0; i<arg_val.length; i++)
 
440
            {
 
441
                extend_data(arg_key, arg_val[i]);
 
442
            }
 
443
        else
 
444
            extend_data(arg_key, arg_val);
 
445
    }
 
446
    /* End boundary */
 
447
    data += "--" + boundary + "--\r\n";
 
448
 
 
449
    return data;
 
450
}
 
451
 
 
452
/** Converts a list of directories into a path name, with a slash at the end.
 
453
 * \param pathlist List of strings.
 
454
 * \return String.
 
455
 */
 
456
function pathlist_to_path(pathlist)
 
457
{
 
458
    ret = path_join.apply(null, pathlist);
 
459
    if (ret[ret.length-1] != '/')
 
460
        ret += '/';
 
461
    return ret;
 
462
}
 
463
 
 
464
/** Given a path relative to the IVLE root, gives a path relative to
 
465
 * the site root.
 
466
 */
 
467
function make_path(path)
 
468
{
 
469
    return path_join(root_dir, path);
 
470
}
 
471
 
 
472
/** Shorthand for make_path(path_join(app, ...))
 
473
 * Creates an absolute path for a given path within a given app.
 
474
 */
 
475
function app_path(app /*,...*/)
 
476
{
 
477
    return make_path(path_join.apply(null, arguments));
 
478
}
 
479
 
 
480
/** Given a path, gets the "basename" (the last path segment).
 
481
 */
 
482
function path_basename(path)
 
483
{
 
484
    segments = path.split("/");
 
485
    if (segments[segments.length-1].length == 0)
 
486
        return segments[segments.length-2];
 
487
    else
 
488
        return segments[segments.length-1];
 
489
}
 
490
 
 
491
/** Given a string str, determines whether it ends with substr */
 
492
function endswith(str, substring)
 
493
{
 
494
    if (str.length < substring.length) return false;
 
495
    return str.substr(str.length - substring.length) == substring;
 
496
}
 
497
 
 
498
/** Equivalent to Python's repr.
 
499
 * Gets the JavaScript string representation.
 
500
 * Actually just calls JSON.stringify.
 
501
 */
 
502
function repr(str)
 
503
{
 
504
    return JSON.stringify(str);
 
505
}
 
506
 
 
507
/** Removes all occurences of a value from an array.
 
508
 */
 
509
Array.prototype.removeall = function(val)
 
510
{
 
511
    var i, j;
 
512
    var arr = this;
 
513
    j = 0;
 
514
    for (i=0; i<arr.length; i++)
 
515
    {
 
516
        arr[j] = arr[i];
 
517
        if (arr[i] != val) j++;
 
518
    }
 
519
    arr.splice(j, i-j);
 
520
}
 
521
 
 
522
/** Makes an XMLHttpRequest call to the server. Waits (synchronously) for a
 
523
 * response, and returns an XMLHttpRequest object containing the completed
 
524
 * response.
 
525
 *
 
526
 * \param app IVLE app to call (such as "fileservice").
 
527
 * \param path URL path to make the request to, within the application.
 
528
 * \param args Argument object, as described in parse_url and friends.
 
529
 * \param method String; "GET" or "POST"
 
530
 * \param content_type String, optional. Only applies if method is "POST".
 
531
 *      May be "application/x-www-form-urlencoded" or "multipart/form-data".
 
532
 *      Defaults to "application/x-www-form-urlencoded".
 
533
 * \return An XMLHttpRequest object containing the completed response.
 
534
 */
 
535
function ajax_call(app, path, args, method, content_type)
 
536
{
 
537
    if (content_type != "multipart/form-data")
 
538
        content_type = "application/x-www-form-urlencoded";
 
539
    path = app_path(app, path);
 
540
    var url;
 
541
    /* A random string, for multipart/form-data
 
542
     * (This is not checked against anywhere else, it is solely defined and
 
543
     * used within this function) */
 
544
    var boundary = "48234n334nu7n4n2ynonjn234t683jyh80j";
 
545
    var xhr = new XMLHttpRequest();
 
546
    if (method == "GET")
 
547
    {
 
548
        /* GET sends the args in the URL */
 
549
        url = build_url({"path": path, "args": args});
 
550
        /* open's 3rd argument = false -> SYNCHRONOUS (wait for response)
 
551
         * (No need for a callback function) */
 
552
        xhr.open(method, url, false);
 
553
        xhr.send(null);
 
554
    }
 
555
    else
 
556
    {
 
557
        /* POST sends the args in application/x-www-form-urlencoded */
 
558
        url = encodeURI(path);
 
559
        xhr.open(method, url, false);
 
560
        var message;
 
561
        if (content_type == "multipart/form-data")
 
562
        {
 
563
            xhr.setRequestHeader("Content-Type",
 
564
                "multipart/form-data, boundary=" + boundary);
 
565
            message = make_multipart_formdata(args, boundary);
 
566
        }
 
567
        else
 
568
        {
 
569
            xhr.setRequestHeader("Content-Type", content_type);
 
570
            message = make_query_string(args);
 
571
        }
 
572
        xhr.setRequestHeader("Content-Length", message.length);
 
573
        xhr.send(message);
 
574
    }
 
575
    return xhr;
 
576
}
 
577