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

« back to all changes in this revision

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

  • Committer: wagrant
  • Date: 2008-07-24 06:19:30 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:949
specialhome: Only show the subjects header if we are enrolled in some
             subjects.

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
    "missing": "missing.png",
67
67
    "deleted": "deleted.png",
68
68
    "modified": "modified.png",
 
69
    "conflicted": "conflicted.png",
69
70
    "revision": "revision.png"
70
71
};
71
72
 
104
105
/** The listing object returned by the server as JSON */
105
106
file_listing = null;
106
107
current_file = null;
 
108
current_revision = null;
107
109
current_path = "";
108
110
 
109
111
/** Filenames of all files selected
143
145
             * to the user */
144
146
            var error = response.getResponseHeader("X-IVLE-Action-Error");
145
147
            if (error != null)
146
 
                alert("Error: " + error.toString() + ".");
 
148
                /* Note: This header (in particular) comes URI-encoded, to
 
149
                 * allow multi-line error messages. Decode */
 
150
                alert("Error: " + decodeURIComponent(error.toString()) + ".");
147
151
            /* Now read the response and set up the page accordingly */
148
152
            if (ignore_response != true)
149
 
                handle_response(path, response);
 
153
                handle_response(path, response, true);
150
154
        }
151
155
    /* Call the server and perform the action. This mutates the server. */
152
156
    ajax_call(callback, service_app, path, args, "POST", content_type);
165
169
    callback = function(response)
166
170
        {
167
171
            /* Read the response and set up the page accordingly */
168
 
            handle_response(path, response, url.args);
 
172
            handle_response(path, response, false, url.args);
169
173
        }
170
174
    /* Get any query strings */
171
175
    url = parse_url(window.location.href);
179
183
 */
180
184
function refresh()
181
185
{
182
 
    navigate(current_path);
 
186
    if (maybe_save('All changes since the last save will be lost!'))
 
187
        navigate(current_path);
183
188
}
184
189
 
185
190
/** Determines the "handler type" from a MIME type.
211
216
 * things) be used to update the URL in the location bar.
212
217
 * \param response XMLHttpRequest object returned by the server. Should
213
218
 * contain all the response data.
 
219
 * \param is_action Boolean. True if this is the response to an action, false
 
220
 * if this is the response to a simple listing. This is used in handling the
 
221
 * error.
214
222
 * \param url_args Arguments dict, for the arguments passed to the URL
215
223
 * in the browser's address bar (will be forwarded along).
216
224
 */
217
 
function handle_response(path, response, url_args)
 
225
function handle_response(path, response, is_action, url_args)
218
226
{
219
227
    /* TODO: Set location bar to "path" */
220
228
    current_path = path;
233
241
        return;
234
242
    }
235
243
 
 
244
    var subjects = null;
 
245
    var top_level_dir = path==username;
 
246
    if (top_level_dir)
 
247
    {
 
248
        var req = ajax_call(null, "userservice", "get_enrolments", null, "GET")
 
249
        subjects = decode_response(req);
 
250
    }
 
251
 
 
252
 
236
253
    /* This will always return a listing, whether it is a dir or a file.
237
254
     */
238
255
    var listing = response.responseText;
244
261
    }
245
262
    catch (e)
246
263
    {
247
 
        handle_error("The server returned an invalid directory listing");
 
264
        if (is_action)
 
265
        {
 
266
            var err = document.createElement("div");
 
267
            var p = dom_make_text_elem("p", "Error: "
 
268
                    + "There was an unexpected server error processing "
 
269
                    + "the selected command.");
 
270
            err.appendChild(p);
 
271
            p = dom_make_text_elem("p", "If the problem persists, please "
 
272
                    + "contact the system administrator.")
 
273
            err.appendChild(p);
 
274
            p = document.createElement("p");
 
275
            var refresh = document.createElement("input");
 
276
            refresh.setAttribute("type", "button");
 
277
            refresh.setAttribute("value", "Back to file view");
 
278
            refresh.setAttribute("onclick", "refresh()");
 
279
            p.appendChild(refresh);
 
280
            err.appendChild(p);
 
281
            handle_error(err);
 
282
        }
 
283
        else
 
284
        {
 
285
            var err = document.createElement("div");
 
286
            var p = dom_make_text_elem("p", "Error: "
 
287
                    + "There was an unexpected server error retrieving "
 
288
                    + "the requested file or directory.");
 
289
            err.appendChild(p);
 
290
            p = dom_make_text_elem("p", "If the problem persists, please "
 
291
                    + "contact the system administrator.")
 
292
            err.appendChild(p);
 
293
            handle_error(err);
 
294
        }
248
295
        return;
249
296
    }
250
297
    /* Get "." out, it's special */
251
298
    current_file = file_listing["."];     /* Global */
252
299
    delete file_listing["."];
253
300
 
 
301
    if ('revision' in listing)
 
302
    {
 
303
        current_revision = listing.revision;
 
304
    }
 
305
 
254
306
    /* Check if this is a directory listing or file contents */
255
307
    var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
256
308
    if (isdir)
257
309
    {
 
310
        setup_for_dir_listing(listing, subjects);
258
311
        handle_dir_listing(path, listing);
259
312
    }
260
313
    else
323
376
     */
324
377
    upload_callback_count++;
325
378
    if (upload_callback_count >= 2)
 
379
    {
 
380
        document.getElementsByName('data')[0].value = '';
326
381
        refresh();
 
382
    }
327
383
}
328
384
 
329
385
/** Deletes all "dynamic" content on the page.
335
391
    dom_removechildren(document.getElementById("filesbody"));
336
392
}
337
393
 
 
394
/* Checks if a file needs to be saved. If it does, the user will be asked
 
395
 * if they want to continue anyway. The caller must specify a warning
 
396
 * sentence which indicates the consequences of continuing.
 
397
 * Returns true if we should continue, and false if we should not.
 
398
 */
 
399
function maybe_save(warning)
 
400
{
 
401
    if (warning == null) warning = '';
 
402
    if (current_file.isdir) return true;
 
403
    if (document.getElementById("save_button").disabled) return true;
 
404
    return confirm("This file has unsaved changes. " + warning +
 
405
                   "\nAre you sure you wish to continue?");
 
406
}
 
407
 
338
408
/** Deletes all "dynamic" content on the page necessary to navigate from
339
409
 * one directory listing to another (does not clear as much as clearpage
340
410
 * does).
351
421
/*** HANDLERS for different types of responses (such as dir listing, file,
352
422
 * etc). */
353
423
 
 
424
/* handle_error.
 
425
 * message may either be a string, or a DOM node, which will be placed inside
 
426
 * a div.
 
427
 */
354
428
function handle_error(message)
355
429
{
356
430
    var files = document.getElementById("filesbody");
357
 
    var txt_elem = dom_make_text_elem("div", "Error: "
358
 
        + message.toString() + ".")
 
431
    var txt_elem;
 
432
    if (typeof(message) == "string")
 
433
    {
 
434
        txt_elem = dom_make_text_elem("div", "Error: "
 
435
                   + message.toString() + ".")
 
436
    }
 
437
    else
 
438
    {
 
439
        /* Assume message is a DOM node */
 
440
        txt_elem = document.createElement("div");
 
441
        txt_elem.appendChild(message);
 
442
    }
359
443
    txt_elem.setAttribute("class", "padding error");
360
444
    files.appendChild(txt_elem);
361
445
}
362
446
 
 
447
/** Given a path, filename and optional revision, returns a URL to open that
 
448
 *  revision of that file.
 
449
 */
 
450
function build_revision_url(path, filename, revision)
 
451
{
 
452
    bits = {'path': app_path(this_app, path, filename)};
 
453
    if (current_revision)
 
454
    {
 
455
        bits['query_string'] = 'r=' + revision;
 
456
    }
 
457
    return build_url(bits);
 
458
}
 
459
 
363
460
/** Given a mime type, returns the path to the icon.
364
461
 * \param type String, Mime type.
365
462
 * \param sizelarge Boolean, optional.
423
520
    div.appendChild(par2);
424
521
}
425
522
 
 
523
/* Enable or disable actions1 moreactions actions. Takes either a single
 
524
 * name, or an array of them.*/
 
525
function set_action_state(names, which, allow_on_revision)
 
526
{
 
527
    if (!(names instanceof Array)) names = Array(names);
 
528
 
 
529
    for (var i=0; i < names.length; i++)
 
530
    {
 
531
        element = document.getElementById('act_' + names[i]);
 
532
        if (which &&
 
533
            !(current_file.svnstatus == 'revision' && !allow_on_revision))
 
534
        {
 
535
            /* Enabling */
 
536
            element.setAttribute("class", "choice");
 
537
            element.removeAttribute("disabled");
 
538
        }
 
539
        else
 
540
        {
 
541
            /* Disabling */
 
542
            element.setAttribute("class", "disabled");
 
543
            element.setAttribute("disabled", "disabled");
 
544
        }
 
545
    }
 
546
}
 
547
 
426
548
function update_actions()
427
549
{
428
550
    var file;
458
580
        else
459
581
            open.setAttribute("title",
460
582
                "Edit or view this file");
461
 
        open.setAttribute("href", app_path(this_app, current_path, filename));
 
583
        open.setAttribute("href", build_revision_url(current_path, filename,
 
584
                                                     current_revision));
462
585
    }
463
586
    else
464
587
    {
468
591
    }
469
592
 
470
593
    /* Serve */
471
 
    /* Available if exactly one file is selected,
 
594
    /* Available if zero or one files are selected,
472
595
     * and only if this is a file, not a directory */
473
596
    var serve = document.getElementById("act_serve");
474
 
    if (numsel == 1 && !file.isdir)
 
597
    if (numsel <= 1 && !file.isdir && current_file.svnstatus != 'revision')
475
598
    {
476
599
        serve.setAttribute("class", "choice");
477
 
        serve.setAttribute("href",
478
 
            app_path(serve_app, current_path, filename));
 
600
        serve.setAttribute("onclick",
 
601
              "return maybe_save('The last saved version will be served.')");
 
602
        if (numsel == 0)
 
603
            serve.setAttribute("href",
 
604
                app_path(serve_app, current_path));
 
605
        else
 
606
            serve.setAttribute("href",
 
607
                app_path(serve_app, current_path, filename));
479
608
    }
480
609
    else
481
610
    {
482
611
        serve.setAttribute("class", "disabled");
483
612
        serve.removeAttribute("href");
 
613
        serve.removeAttribute("onclick");
484
614
    }
485
615
 
486
616
    /* Run */
487
617
    /* Available if exactly one file is selected,
488
618
     * and it is a Python file.
489
619
     */
490
 
    /* TODO */
 
620
    var run = document.getElementById("act_run");
 
621
     
 
622
    if (!file.isdir && file.type == "text/x-python" && numsel <= 1
 
623
        && current_file.svnstatus != 'revision')
 
624
    {
 
625
        if (numsel == 0)
 
626
        {
 
627
            // In the edit window
 
628
            var localpath = path_join('/home', current_path);
 
629
        }
 
630
        else
 
631
        {
 
632
            // In the browser window
 
633
            var localpath = path_join('/home', current_path, filename);
 
634
        }
 
635
        run.setAttribute("class", "choice");
 
636
        run.setAttribute("onclick", "runfile('" + localpath + "')");
 
637
    }
 
638
    else
 
639
    {
 
640
        run.setAttribute("class", "disabled");
 
641
        run.removeAttribute("onclick");
 
642
    }
491
643
 
492
644
    /* Download */
493
 
    /* Always available.
 
645
    /* Always available for current files.
494
646
     * If 0 files selected, download the current file or directory as a ZIP.
495
647
     * If 1 directory selected, download it as a ZIP.
496
648
     * If 1 non-directory selected, download it.
497
649
     * If >1 files selected, download them all as a ZIP.
498
650
     */
499
651
    var download = document.getElementById("act_download");
500
 
    if (numsel <= 1)
501
 
    {
 
652
    if (current_file.svnstatus == 'revision')
 
653
    {
 
654
        download.setAttribute("class", "disabled");
 
655
        download.removeAttribute("onclick");
 
656
    }
 
657
    else if (numsel <= 1)
 
658
    {
 
659
        download.setAttribute("class", "choice")
502
660
        if (numsel == 0)
503
661
        {
504
662
            download.setAttribute("href",
529
687
        for (var i=0; i<numsel; i++)
530
688
            dlpath += "path=" + encodeURIComponent(selected_files[i]) + "&";
531
689
        dlpath = dlpath.substr(0, dlpath.length-1);
 
690
        download.setAttribute("class", "choice")
532
691
        download.setAttribute("href", dlpath);
533
692
        download.setAttribute("title",
534
693
            "Download the selected files as a ZIP file");
541
700
     * directory. */
542
701
    var publish = document.getElementById("act_publish");
543
702
    var submit = document.getElementById("act_submit");
544
 
    if (numsel <= 1 && file.isdir)
 
703
    var pubcond = numsel <= 1 && file.isdir;
 
704
    if (pubcond)
545
705
    {
546
706
        /* TODO: Work out of file is svn'd */
547
 
        /* TODO: If this dir is already published, call it "Unpublish" */
548
 
        publish.setAttribute("class", "choice");
549
 
        publish.removeAttribute("disabled");
550
 
        submit.setAttribute("class", "choice");
551
 
        submit.removeAttribute("disabled");
552
 
    }
553
 
    else
554
 
    {
555
 
        publish.setAttribute("class", "disabled");
556
 
        publish.setAttribute("disabled", "disabled");
557
 
        submit.setAttribute("class", "disabled");
558
 
        submit.setAttribute("disabled", "disabled");
559
 
    }
 
707
        /* If this dir is already published, call it "Unpublish" */
 
708
        if (file.published)
 
709
        {
 
710
            publish.setAttribute("value", "unpublish");
 
711
            publish.setAttribute("title" ,"Make it so this directory "
 
712
                + "can not be seen by anyone on the web");
 
713
            publish.textContent = "Unpublish";
 
714
        } else {
 
715
            publish.setAttribute("value", "publish");
 
716
            publish.setAttribute("title","Make it so this directory "
 
717
                + "can be seen by anyone on the web");
 
718
            publish.textContent = "Publish";
 
719
        }
 
720
    }
 
721
    set_action_state(["publish", "submit"], pubcond);
560
722
 
561
723
    /* Share */
562
 
    /* If exactly 1 non-directory file is selected/opened, and its parent
 
724
    /* If exactly 1 non-directory file is selected, and its parent
563
725
     * directory is published.
564
726
     */
565
 
    var share = document.getElementById("act_share");
566
 
    if (numsel <= 1 && !file.isdir)
567
 
    {
568
 
        /* TODO: Work out if parent dir is published */
569
 
        share.setAttribute("class", "choice");
570
 
        share.removeAttribute("disabled");
571
 
    }
572
 
    else
573
 
    {
574
 
        share.setAttribute("class", "disabled");
575
 
        share.setAttribute("disabled", "disabled");
576
 
    }
 
727
    set_action_state("share", numsel == 1 && !file.isdir &&
 
728
                     current_file.published);
577
729
 
578
730
    /* Rename */
579
731
    /* If exactly 1 file is selected */
580
 
    var rename = document.getElementById("act_rename");
581
 
    if (numsel == 1)
582
 
    {
583
 
        rename.setAttribute("class", "choice");
584
 
        rename.removeAttribute("disabled");
585
 
    }
586
 
    else
587
 
    {
588
 
        rename.setAttribute("class", "disabled");
589
 
        rename.setAttribute("disabled", "disabled");
590
 
    }
 
732
    set_action_state("rename", numsel == 1);
591
733
 
592
734
    /* Delete, cut, copy */
593
735
    /* If >= 1 file is selected */
594
 
    var act_delete = document.getElementById("act_delete");
595
 
    var cut = document.getElementById("act_cut");
596
 
    var copy = document.getElementById("act_copy");
597
 
    if (numsel >= 1)
598
 
    {
599
 
        act_delete.setAttribute("class", "choice");
600
 
        act_delete.removeAttribute("disabled");
601
 
        cut.setAttribute("class", "choice");
602
 
        cut.removeAttribute("disabled");
603
 
        copy.setAttribute("class", "choice");
604
 
        copy.removeAttribute("disabled");
605
 
    }
606
 
    else
607
 
    {
608
 
        act_delete.setAttribute("class", "disabled");
609
 
        act_delete.setAttribute("disabled", "disabled");
610
 
        cut.setAttribute("class", "disabled");
611
 
        cut.setAttribute("disabled", "disabled");
612
 
        copy.setAttribute("class", "disabled");
613
 
        copy.setAttribute("disabled", "disabled");
614
 
    }
 
736
    set_action_state(["delete", "cut", "copy"], numsel >= 1);
615
737
 
616
738
    /* Paste, new file, new directory, upload */
617
 
    /* Always enabled (assuming this is a directory) */
 
739
    /* Disable if the current file is not a directory */
 
740
    set_action_state(["paste", "newfile", "mkdir", "upload"], current_file.isdir);
618
741
 
619
742
    /* Subversion actions */
620
 
    /* TODO: Work out when these are appropriate */
621
 
    var svnadd = document.getElementById("act_svnadd");
622
 
    var svnrevert = document.getElementById("act_svnrevert");
623
 
    var svncommit = document.getElementById("act_svncommit");
624
 
    if (true)
625
 
    {
626
 
        svnadd.setAttribute("class", "choice");
627
 
        svnadd.removeAttribute("disabled");
628
 
        svnrevert.setAttribute("class", "choice");
629
 
        svnrevert.removeAttribute("disabled");
630
 
        svncommit.setAttribute("class", "choice");
631
 
        svncommit.removeAttribute("disabled");
632
 
    }
633
 
    var svncheckout = document.getElementById("act_svncheckout");
634
 
    /* current_path == username: We are at the top level */
635
 
    if (current_path == username)
636
 
    {
637
 
        svncheckout.setAttribute("class", "choice");
638
 
        svncheckout.removeAttribute("disabled");
 
743
    /* These are only useful if we are in a versioned directory and have some
 
744
     * files selected. */
 
745
    set_action_state(["svnadd", "svnremove", "svnrevert", "svncommit"], numsel >= 1 && current_file.svnstatus);
 
746
 
 
747
    /* Diff, log and update only support one path at the moment, so we must
 
748
     * have 0 or 1 versioned files selected. If 0, the directory must be
 
749
     * versioned. */
 
750
    single_versioned_path = (
 
751
         (
 
752
          (numsel == 1 && (svnst = file_listing[selected_files[0]].svnstatus)) ||
 
753
          (numsel == 0 && (svnst = current_file.svnstatus))
 
754
         ) && svnst != "unversioned");
 
755
    set_action_state(["svndiff", "svnupdate"], single_versioned_path);
 
756
 
 
757
    /* We can resolve if we have a file selected and it is conflicted. */
 
758
    set_action_state("svnresolved", single_versioned_path && numsel == 1 && svnst == "conflicted");
 
759
 
 
760
    /* Log should be available for revisions as well. */
 
761
    set_action_state("svnlog", single_versioned_path, true);
 
762
 
 
763
    /* There is currently nothing on the More Actions menu of use
 
764
     * when the current file is not a directory. Hence, just remove
 
765
     * it entirely.
 
766
     * (This makes some of the above decisions somewhat redundant).
 
767
     * We also take this opportunity to show the appropriate actions2
 
768
     * bar for this path. It should either be a save or upload widget.
 
769
     */
 
770
    if (current_file.isdir)
 
771
    {
 
772
        var actions2_directory = document.getElementById("actions2_directory");
 
773
        actions2_directory.setAttribute("style", "display: inline;");
 
774
        var moreactions = document.getElementById("moreactions_area");
 
775
        moreactions.setAttribute("style", "display: inline;");
639
776
    }
640
777
    else
641
778
    {
642
 
        svncheckout.setAttribute("class", "disabled");
643
 
        svncheckout.setAttribute("disabled", "disabled");
 
779
        var actions2_file = document.getElementById("actions2_file");
 
780
        actions2_file.setAttribute("style", "display: inline;");
644
781
    }
645
782
 
646
783
    return;
677
814
        action_unpublish(selected_files);
678
815
        break;
679
816
    case "share":
680
 
        // TODO
681
 
        alert("Not yet implemented: Sharing files");
 
817
        //alert("Not yet implemented: Sharing files");
 
818
        window.open(public_app_path(serve_app, current_path, filename), 'share')
682
819
        break;
683
820
    case "submit":
684
821
        // TODO
688
825
        action_rename(filename);
689
826
        break;
690
827
    case "delete":
691
 
        action_remove(selected_files);
 
828
        action_delete(selected_files);
692
829
        break;
693
830
    case "copy":
694
831
        action_copy(selected_files);
711
848
    case "svnadd":
712
849
        action_add(selected_files);
713
850
        break;
 
851
    case "svnremove":
 
852
        action_remove(selected_files);
 
853
        break;
714
854
    case "svnrevert":
715
855
        action_revert(selected_files);
716
856
        break;
 
857
    case "svndiff":
 
858
        window.location = path_join(app_path('diff'), current_path, selected_files[0] || '');
 
859
        break;
 
860
    case "svnupdate":
 
861
        action_update(selected_files);
 
862
        break;
 
863
    case "svnresolved":
 
864
        action_resolved(selected_files);
 
865
        break;
717
866
    case "svncommit":
718
867
        action_commit(selected_files);
719
868
        break;
720
 
    case "svncheckout":
721
 
        action_checkout();
 
869
    case "svnlog":
 
870
        window.location = path_join(app_path('svnlog'), current_path, selected_files[0] || '');
722
871
        break;
723
872
    }
724
873
}
725
874
 
 
875
/** User clicks "Run" button.
 
876
 * Do an Ajax call and print the test output.
 
877
 */
 
878
function runfile(localpath)
 
879
{
 
880
    if (!maybe_save('The last saved version will be run.')) return false;
 
881
 
 
882
    /* Dump the entire file to the console */
 
883
    var callback = function()
 
884
    {
 
885
        console_enter_line("execfile('" + localpath + "')", "block");
 
886
    }
 
887
    start_server(callback)
 
888
    return;
 
889
}
 
890
 
726
891
/** Called when the page loads initially.
727
892
 */
728
 
window.onload = function()
 
893
function browser_init()
729
894
{
730
895
    /* Navigate (internally) to the path in the URL bar.
731
896
     * This causes the page to be populated with whatever is at that address,