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

« back to all changes in this revision

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

Created a new help system.

The new help system allows plugins to register their help paths, using
a dict of dicts and helpfile paths. This system allows multiple plugins
to use the same heading for their help files (ie. 'admin').

It also allows XHTMLViews to have a 'help' property, which makes the
context-sensitive help link point to their help path.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
/* Expects the following variables to have been declared by JavaScript in
26
26
 * the HTML generated by the server:
27
27
 * - root_dir
 
28
 * - public_host
28
29
 * - username
29
30
 */
30
31
 
278
279
            query_string += "&" + encodeURIComponent(arg_key) + "=" +
279
280
                encodeURIComponent(arg_val);
280
281
    }
281
 
    if (query_string == "")
282
 
        query_string = null;
283
 
    else
 
282
    if (query_string != "")
284
283
        /* Drop the first "&" */
285
284
        query_string = query_string.substr(1);
286
285
 
312
311
    if (("path" in obj) && obj.path != null)
313
312
    {
314
313
        var path = urlencode_path(obj.path.toString());
315
 
        if (url.length > 0 && path.length > 0 && path[0] != "/")
 
314
        if (url.length > 0 && path.length > 0 && path.charAt(0) != "/")
316
315
            path = "/" + path;
317
316
        url += path;
318
317
    }
321
320
    else if (("args" in obj) && obj.args != null)
322
321
        query_string = make_query_string(obj.args);
323
322
 
324
 
    if (query_string != null)
 
323
    if (query_string != "" && query_string != null)
325
324
        url += "?" + query_string;
326
325
 
327
326
    return url;
343
342
    return path;
344
343
}
345
344
 
 
345
/** Writes a JSONable object to the cookie under a particular key
 
346
 * (JSON encoded and URL encoded).
 
347
 */
 
348
function write_cookie(key, value)
 
349
{
 
350
    var sendstr = encodeURIComponent(key) + "="
 
351
        + encodeURIComponent(JSON.stringify(value))
 
352
        + "; path=" + urlencode_path(root_dir);
 
353
    /* This actually just assigns to the key, not replacing the whole cookie
 
354
     * as it appears to. */
 
355
    document.cookie = sendstr;
 
356
}
 
357
/** Reads a cookie which has a JSONable object encoded as its value.
 
358
 * Returns the object, parsed from JSON.
 
359
 */
 
360
function read_cookie(key)
 
361
{
 
362
    var cookies = document.cookie.split(";");
 
363
    var checkstart = encodeURIComponent(key) + "=";
 
364
    var checklen = checkstart.length;
 
365
    for (var i=0; i<cookies.length; i++)
 
366
    {
 
367
        var cookie = cookies[i];
 
368
        while (cookie[0] == ' ')
 
369
            cookie = cookie.substr(1);
 
370
        if (cookie.substr(0, checklen) == checkstart)
 
371
        {
 
372
            var valstr = cookie.substr(checklen);
 
373
            valstr = decodeURIComponent(valstr);
 
374
            return JSON.parse(valstr);
 
375
        }
 
376
    }
 
377
}
 
378
 
346
379
/** Given an argument map, as output in the args parameter of the return of
347
380
 * parseurl, gets the first occurence of an argument in the URL string.
348
381
 * If the argument was not found, returns null.
393
426
    {
394
427
        arg = arguments[i];
395
428
        if (arg.length == 0) continue;
396
 
        if (arg[0] == '/')
 
429
        if (arg.charAt(0) == '/')
397
430
            path = arg;
398
431
        else
399
432
        {
400
 
            if (path.length > 0 && path[path.length-1] != '/')
 
433
            if (path.length > 0 && path.charAt(path.length-1) != '/')
401
434
                path += '/';
402
435
            path += arg;
403
436
        }
428
461
    {
429
462
        /* FIXME: Encoding not supported here (should not matter if we
430
463
         * only use ASCII names */
431
 
        data += "--" + boundary + "\n"
 
464
        data += "--" + boundary + "\r\n"
432
465
            + "Content-Disposition: form-data; name=\"" + arg_key
433
 
            + "\"\n\n"
434
 
            + arg_val + "\n";
 
466
            + "\"\r\n\r\n"
 
467
            + arg_val + "\r\n";
435
468
    }
436
469
 
437
470
    for (var arg_key in args)
446
479
            extend_data(arg_key, arg_val);
447
480
    }
448
481
    /* End boundary */
449
 
    data += "--" + boundary + "--\n";
 
482
    data += "--" + boundary + "--\r\n";
450
483
 
451
484
    return data;
452
485
}
458
491
function pathlist_to_path(pathlist)
459
492
{
460
493
    ret = path_join.apply(null, pathlist);
461
 
    if (ret[ret.length-1] != '/')
 
494
    if (ret.charAt(ret.length-1) != '/')
462
495
        ret += '/';
463
496
    return ret;
464
497
}
479
512
    return make_path(path_join.apply(null, arguments));
480
513
}
481
514
 
 
515
/** Generates an absolute URL to a public application
 
516
 */
 
517
function public_app_path(app /*,...*/)
 
518
{
 
519
    return location.protocol + "//" + public_host
 
520
        + make_path(path_join.apply(null, arguments));
 
521
}
 
522
 
482
523
/** Given a path, gets the "basename" (the last path segment).
483
524
 */
484
525
function path_basename(path)
497
538
    return str.substr(str.length - substring.length) == substring;
498
539
}
499
540
 
500
 
/** Equivalent to Python's repr.
501
 
 * Gets the JavaScript string representation.
502
 
 * Actually just calls JSON.stringify.
503
 
 */
504
 
function repr(str)
505
 
{
506
 
    return JSON.stringify(str);
507
 
}
508
 
 
509
541
/** Removes all occurences of a value from an array.
510
542
 */
511
543
Array.prototype.removeall = function(val)
521
553
    arr.splice(j, i-j);
522
554
}
523
555
 
524
 
/** Makes an XMLHttpRequest call to the server. Waits (synchronously) for a
525
 
 * response, and returns an XMLHttpRequest object containing the completed
526
 
 * response.
 
556
/** Shallow-clones an object */
 
557
function shallow_clone_object(obj)
 
558
{
 
559
    o = {};
 
560
    for (k in obj)
 
561
        o[k] = obj[k];
 
562
    return o;
 
563
}
 
564
 
 
565
/** Returns a new XMLHttpRequest object, in a somewhat browser-agnostic
 
566
 * fashion.
 
567
 */
 
568
function new_xmlhttprequest()
 
569
{
 
570
    try
 
571
    {
 
572
        /* Real Browsers */
 
573
        return new XMLHttpRequest();
 
574
    }
 
575
    catch (e)
 
576
    {
 
577
        /* Internet Explorer */
 
578
        try
 
579
        {
 
580
            return new ActiveXObject("Msxml2.XMLHTTP");
 
581
        }
 
582
        catch (e)
 
583
        {
 
584
            try
 
585
            {
 
586
                return new ActiveXObject("Microsoft.XMLHTTP");
 
587
            }
 
588
            catch (e)
 
589
            {
 
590
                throw("Your browser does not support AJAX. "
 
591
                    + "IVLE requires a modern browser.");
 
592
            }
 
593
        }
 
594
    }
 
595
}
 
596
 
 
597
/** Creates a random string of length length,
 
598
 * consisting of alphanumeric characters.
 
599
 */
 
600
var rand_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"
 
601
               + "abcdefghiklmnopqrstuvwxyz";
 
602
function random_string(length)
 
603
{
 
604
    var str = Array(length);
 
605
    var v;
 
606
    for (var i=0; i<length; i++)
 
607
    {
 
608
        v = Math.floor(Math.random() * rand_chars.length);
 
609
        str[i] = rand_chars.charAt(v);
 
610
    }
 
611
    return str.join('');
 
612
}
 
613
 
 
614
/** Makes an XMLHttpRequest call to the server.
 
615
 * Sends the XMLHttpRequest object containing the completed response to a
 
616
 * specified callback function.
527
617
 *
 
618
 * \param callback A callback function. Will be called when the response is
 
619
 *      complete. Passed 1 parameter, an XMLHttpRequest object containing the
 
620
 *      completed response. If callback is null this is a syncronous request 
 
621
 *      otherwise this is an asynchronous request.
528
622
 * \param app IVLE app to call (such as "fileservice").
529
623
 * \param path URL path to make the request to, within the application.
530
624
 * \param args Argument object, as described in parse_url and friends.
531
 
 * \param method String; "GET" or "POST"
532
 
 * \param content_type String, optional. Only applies if method is "POST".
533
 
 *      May be "application/x-www-form-urlencoded" or "multipart/form-data".
 
625
 * \param method String; "GET", "POST", "PUT", or "PATCH"
 
626
 * \param content_type String, optional.
534
627
 *      Defaults to "application/x-www-form-urlencoded".
535
 
 * \return An XMLHttpRequest object containing the completed response.
536
628
 */
537
 
function ajax_call(app, path, args, method, content_type)
 
629
function ajax_call(callback, app, path, args, method, content_type)
538
630
{
539
 
    if (content_type != "multipart/form-data")
 
631
    if (!content_type)
540
632
        content_type = "application/x-www-form-urlencoded";
541
633
    path = app_path(app, path);
542
634
    var url;
543
635
    /* A random string, for multipart/form-data
544
636
     * (This is not checked against anywhere else, it is solely defined and
545
637
     * used within this function) */
546
 
    var boundary = "48234n334nu7n4n2ynonjn234t683jyh80j";
547
 
    var xhr = new XMLHttpRequest();
 
638
    var boundary = random_string(20);
 
639
    var xhr = new_xmlhttprequest();
 
640
    var asyncronous = callback != null;
 
641
    if (asyncronous)
 
642
    {
 
643
        xhr.onreadystatechange = function()
 
644
            {
 
645
                if (xhr.readyState == 4)
 
646
                {
 
647
                    callback(xhr);
 
648
                }
 
649
            }
 
650
    }
548
651
    if (method == "GET")
549
652
    {
550
653
        /* GET sends the args in the URL */
551
654
        url = build_url({"path": path, "args": args});
552
 
        /* open's 3rd argument = false -> SYNCHRONOUS (wait for response)
553
 
         * (No need for a callback function) */
554
 
        xhr.open(method, url, false);
 
655
        /* open's 3rd argument = true -> asynchronous */
 
656
        xhr.open(method, url, asyncronous);
555
657
        xhr.send(null);
556
658
    }
557
659
    else
558
660
    {
559
 
        /* POST sends the args in application/x-www-form-urlencoded */
 
661
        /* POST & PUT & PATCH sends the args in the request body */
560
662
        url = encodeURI(path);
561
 
        xhr.open(method, url, false);
 
663
        xhr.open(method, url, asyncronous);
562
664
        var message;
563
665
        if (content_type == "multipart/form-data")
564
666
        {
565
667
            xhr.setRequestHeader("Content-Type",
566
 
                "multipart/form-data, boundary=" + boundary);
 
668
                "multipart/form-data; boundary=" + boundary);
567
669
            message = make_multipart_formdata(args, boundary);
568
670
        }
569
 
        else
 
671
        else if (content_type == "application/x-www-form-urlencoded")
570
672
        {
571
673
            xhr.setRequestHeader("Content-Type", content_type);
572
674
            message = make_query_string(args);
573
675
        }
 
676
        else if (content_type == "application/json")
 
677
        {
 
678
            xhr.setRequestHeader("Content-Type", content_type);
 
679
            message = JSON.stringify(args);
 
680
        }
 
681
        else
 
682
        {
 
683
            xhr.setRequestHeader("Content-Type", content_type);
 
684
            message = args;
 
685
        }
574
686
        xhr.send(message);
575
687
    }
576
 
    return xhr;
 
688
    /* Only return the XHR for syncronous requests */
 
689
    if (!asyncronous)
 
690
    { 
 
691
        return xhr;
 
692
    }
577
693
}
578
694
 
 
695
/** Attempts to JSON decodes a response object
 
696
 * If a non-200 response or the JSON decode fails then returns null
 
697
 */
 
698
function decode_response(response)
 
699
{
 
700
    if (response.status == 200)
 
701
    {
 
702
        try
 
703
        {
 
704
            var responseText = response.responseText;
 
705
            return JSON.parse(responseText);
 
706
        }
 
707
        catch (e)
 
708
        {
 
709
            // Pass
 
710
        }
 
711
     }
 
712
    
 
713
     return null;
 
714
}