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

« back to all changes in this revision

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

  • Committer: mattgiuca
  • Date: 2008-07-15 07:19:34 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:875
Added "migrations" directory, which contains incremental database update
    scripts.
Updated users.sql, uniqueness key on offering table.
Added migration matching this update to the migrations directory. Mm handy!

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 * "text" : When navigating to a text file, the text editor is opened.
32
32
 * "image" : When navigating to an image, the image is displayed (rather than
33
33
 *              going to the text editor).
34
 
 * "video" : When navigation to a video file, a "play" button is presented.
35
34
 * "audio" : When navigating to an audio file, a "play" button is presented.
36
35
 * "binary" : When navigating to a binary file, offer it as a download through
37
36
 *              "serve".
44
43
    "application/x-javascript" : "text",
45
44
    "application/javascript" : "text",
46
45
    "application/json" : "text",
47
 
    "application/xml" : "text",
48
 
    "application/ogg" : "audio",
49
 
    "image/svg+xml": "object"
 
46
    "application/xml" : "text"
50
47
};
51
48
 
52
49
/* Mapping MIME types to icons, just the file's basename */
58
55
default_type_icon = "txt.png";
59
56
 
60
57
/* Relative to IVLE root */
61
 
type_icons_path = "+media/ivle.webapp.core/images/mime";
62
 
type_icons_path_large = "+media/ivle.webapp.core/images/mime/large";
 
58
type_icons_path = "media/images/mime";
 
59
type_icons_path_large = "media/images/mime/large";
63
60
 
64
61
/* Mapping SVN status to icons, just the file's basename */
65
62
svn_icons = {
66
 
    "unversioned": "unversioned.png",
67
 
    "ignored": null,                    /* Supposed to be innocuous */
 
63
    "unversioned": null,
68
64
    "normal": "normal.png",
69
65
    "added": "added.png",
70
66
    "missing": "missing.png",
71
67
    "deleted": "deleted.png",
72
 
    "replaced": "replaced.png",
73
68
    "modified": "modified.png",
74
 
    "conflicted": "conflicted.png",
75
69
    "revision": "revision.png"
76
70
};
77
71
 
78
72
/* Mapping SVN status to "nice" strings */
79
73
svn_nice = {
80
74
    "unversioned": "Temporary file",
81
 
    "ignored": "Temporary file (ignored)",
82
75
    "normal": "Permanent file",
83
76
    "added": "Temporary file (scheduled to be added)",
84
77
    "missing": "Permanent file (missing)",
93
86
default_svn_icon = null;
94
87
default_svn_nice = "Unknown status";
95
88
 
96
 
svn_icons_path = "+media/ivle.webapp.core/images/svn";
 
89
svn_icons_path = "media/images/svn";
97
90
 
98
 
published_icon = "+media/ivle.webapp.core/images/interface/published.png";
 
91
published_icon = "media/images/interface/published.png";
99
92
 
100
93
/* List of MIME types considered "executable" by the system.
101
94
 * Executable files offer a "run" link, implying that the "serve"
111
104
/** The listing object returned by the server as JSON */
112
105
file_listing = null;
113
106
current_file = null;
114
 
current_revision = null;
115
107
current_path = "";
116
108
 
117
109
/** Filenames of all files selected
140
132
 *      May be "application/x-www-form-urlencoded" or "multipart/form-data".
141
133
 *      Defaults to "application/x-www-form-urlencoded".
142
134
 *      "multipart/form-data" is recommended for large uploads.
143
 
 * \param callback, optional.
144
 
 *      A callback function for after the action has been handled.
145
135
 */
146
 
function do_action(action, path, args, content_type, callback)
 
136
function do_action(action, path, args, content_type, ignore_response)
147
137
{
148
138
    args.action = action;
149
139
    /* Callback action, when the server returns */
150
 
    var callback_inner = function(response)
 
140
    var callback = function(response)
151
141
        {
152
142
            /* Check for action errors reported by the server, and report them
153
143
             * to the user */
154
144
            var error = response.getResponseHeader("X-IVLE-Action-Error");
155
 
            if (error != null && error != "")
 
145
            if (error != null)
156
146
                /* Note: This header (in particular) comes URI-encoded, to
157
147
                 * allow multi-line error messages. Decode */
158
148
                alert("Error: " + decodeURIComponent(error.toString()) + ".");
159
149
            /* Now read the response and set up the page accordingly */
160
 
            if (callback != null)
161
 
                callback(path, response);
 
150
            if (ignore_response != true)
 
151
                handle_response(path, response, true);
162
152
        }
163
153
    /* Call the server and perform the action. This mutates the server. */
164
 
    ajax_call(callback_inner, service_app, path, args, "POST", content_type);
 
154
    ajax_call(callback, service_app, path, args, "POST", content_type);
165
155
}
166
156
 
167
157
/** Calls the server using Ajax, requesting a directory listing. This should
196
186
}
197
187
 
198
188
/** Determines the "handler type" from a MIME type.
199
 
 * The handler type is a string, either "text", "image", "video", "audio", 
200
 
 * "object" or "binary".
 
189
 * The handler type is a string, either "text", "image", "audio" or "binary".
201
190
 */
202
191
function get_handler_type(content_type)
203
192
{
209
198
    {   /* Based on the first part of the MIME type */
210
199
        var handler_type = content_type.split('/')[0];
211
200
        if (handler_type != "text" && handler_type != "image" &&
212
 
            handler_type != "video" && handler_type != "audio")
 
201
            handler_type != "audio")
213
202
            handler_type = "binary";
214
203
        return handler_type;
215
204
    }
250
239
        return;
251
240
    }
252
241
 
253
 
    var subjects = null;
254
 
    /* Remove trailing slash (or path==username won't compare properly) */
255
 
    if (path[path.length-1] == "/")
256
 
        path = path.substr(0, path.length-1);
257
 
    var top_level_dir = path==username;
258
 
    if (top_level_dir)
259
 
    {
260
 
        var req = ajax_call(null, "userservice", "get_enrolments", null, "GET")
261
 
        subjects = decode_response(req);
262
 
    }
263
 
 
264
 
 
265
242
    /* This will always return a listing, whether it is a dir or a file.
266
243
     */
267
244
    var listing = response.responseText;
310
287
    current_file = file_listing["."];     /* Global */
311
288
    delete file_listing["."];
312
289
 
313
 
    if ('revision' in listing)
314
 
    {
315
 
        current_revision = listing.revision;
316
 
    }
317
 
 
318
290
    /* Check if this is a directory listing or file contents */
319
291
    var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
320
292
    if (isdir)
321
293
    {
322
 
        setup_for_listing();
323
 
        if (top_level_dir)
324
 
        {
325
 
            /* Top-level dir, with subjects */
326
 
            special_home_listing(listing, subjects, path);
327
 
        }
 
294
        handle_dir_listing(path, listing);
 
295
    }
 
296
    else
 
297
    {
 
298
        /* Need to make a 2nd ajax call, this time get the actual file
 
299
         * contents */
 
300
        callback = function(response)
 
301
            {
 
302
                /* Read the response and set up the page accordingly */
 
303
                handle_contents_response(path, response);
 
304
            }
 
305
        /* Call the server and request the listing. */
 
306
        if (url_args)
 
307
            args = shallow_clone_object(url_args);
328
308
        else
329
 
        {
330
 
            /* Not the top-level dir. Do a normal dir listing. */
331
 
            handle_dir_listing(path, listing.listing);
332
 
        }
333
 
    }
334
 
    else
335
 
    {
336
 
        /* Read the response and set up the page accordingly */
337
 
        var content_type = current_file.type;
338
 
        handle_contents_response(path, content_type, url_args);
339
 
 
 
309
            args = {};
 
310
        /* This time, get the contents of the file, not its metadata */
 
311
        args['return'] = "contents";
 
312
        ajax_call(callback, service_app, path, args, "GET");
340
313
    }
341
314
    update_actions(isdir);
342
315
}
343
316
 
344
 
function handle_contents_response(path, content_type)
 
317
function handle_contents_response(path, response)
345
318
{
346
319
    /* Treat this as an ordinary file. Get the file type. */
347
 
    //var content_type = response.getResponseHeader("Content-Type");
 
320
    var content_type = response.getResponseHeader("Content-Type");
348
321
    var handler_type = get_handler_type(content_type);
 
322
    would_be_handler_type = handler_type;
349
323
    /* handler_type should now be set to either
350
 
     * "text", "image", "video", "audio" or "binary". */
 
324
     * "text", "image", "audio" or "binary". */
351
325
    switch (handler_type)
352
326
    {
353
327
    case "text":
354
 
        handle_text(path, content_type);
 
328
        handle_text(path, response.responseText,
 
329
            would_be_handler_type);
355
330
        break;
356
331
    case "image":
357
 
        handle_image(path);
358
 
        break;
359
 
    case "video":
360
 
        handle_html5_media(path, content_type, "video");
 
332
        /* TODO: Custom image handler */
 
333
        handle_binary(path, response.responseText);
361
334
        break;
362
335
    case "audio":
363
 
        handle_html5_media(path, content_type, "audio");
364
 
        break;
365
 
    case "object":
366
 
        handle_object(path, content_type);
 
336
        /* TODO: Custom audio handler */
 
337
        handle_binary(path, response.responseText);
367
338
        break;
368
339
    case "binary":
369
340
        handle_binary(path);
389
360
    upload_callback_count++;
390
361
    if (upload_callback_count >= 2)
391
362
    {
392
 
        myFrame = frames['upload_iframe'].document;
393
 
        /* Browsers will turn the raw returned JSON into an HTML document. We
394
 
         * need to get the <pre> from inside the <body>, and look at its text.
395
 
         */
396
 
        var pre = myFrame.firstChild.getElementsByTagName(
397
 
            'body')[0].firstChild;
398
 
        var data = pre.innerText || pre.textContent;
399
 
        data = JSON.parse(data);
400
 
        if ('Error' in data)
401
 
            alert("Error: " + decodeURIComponent(data['Error']));
402
363
        document.getElementsByName('data')[0].value = '';
403
364
        refresh();
404
365
    }
421
382
function maybe_save(warning)
422
383
{
423
384
    if (warning == null) warning = '';
424
 
    if (current_file == null || current_file.isdir) return true;
 
385
    if (current_file.isdir) return true;
425
386
    if (document.getElementById("save_button").disabled) return true;
426
387
    return confirm("This file has unsaved changes. " + warning +
427
388
                   "\nAre you sure you wish to continue?");
466
427
    files.appendChild(txt_elem);
467
428
}
468
429
 
469
 
/** Given a path, filename and optional revision, returns a URL to open that
470
 
 *  revision of that file.
471
 
 */
472
 
function build_revision_url(path, filename, revision)
473
 
{
474
 
    bits = {'path': app_path(this_app, path, filename)};
475
 
    if (current_revision)
476
 
    {
477
 
        bits['query_string'] = 'r=' + revision;
478
 
    }
479
 
    return build_url(bits);
480
 
}
481
 
 
482
430
/** Given a mime type, returns the path to the icon.
483
431
 * \param type String, Mime type.
484
432
 * \param sizelarge Boolean, optional.
524
472
        return default_svn_nice;
525
473
}
526
474
 
527
 
/** Returns true if a file is versioned (not unversioned or ignored).
528
 
 */
529
 
function svnstatus_versioned(svnstatus)
530
 
{
531
 
    return svnstatus != "unversioned" && svnstatus != "ignored";
532
 
}
533
 
 
534
475
/** Displays a download link to the binary file.
535
476
 */
536
477
function handle_binary(path)
537
478
{
538
 
    // Disable save button
539
 
    using_codepress = false;
540
 
    disable_save();
541
 
 
542
 
    // Show download link
543
479
    var files = document.getElementById("filesbody");
544
480
    var div = document.createElement("div");
545
481
    files.appendChild(div);
546
482
    div.setAttribute("class", "padding");
547
 
    var download_link = app_url(download_app, path);
 
483
    var download_link = app_path(download_app, path);
548
484
    var par1 = dom_make_text_elem("p",
549
485
        "The file " + path + " is a binary file. To download this file, " +
550
486
        "click the following link:");
554
490
    div.appendChild(par2);
555
491
}
556
492
 
557
 
/** Displays an image file.
558
 
 */
559
 
function handle_image(path)
560
 
{
561
 
    /* Disable save button */
562
 
    using_codepress = false;
563
 
    disable_save();
564
 
 
565
 
    /* URL */
566
 
    var url = app_url(service_app, path) + "?return=contents";
567
 
 
568
 
    /* Image Preview */
569
 
    var img = $("<img />");
570
 
    img.attr("alt", path);
571
 
    img.attr("src", url);
572
 
 
573
 
    /* Show Preview */
574
 
    var div = $('<div class="padding" />');
575
 
    div.append('<h1>Image Preview</h1>');
576
 
    div.append(img);
577
 
    $("#filesbody").append(div);
578
 
}
579
 
 
580
 
/* Displays a media file using an HTML5 <audio> or <video> tag.
581
 
 * Falls back to <object> if the format is unsupported.
582
 
 */
583
 
function handle_html5_media(path, type, tag_name)
584
 
{
585
 
    /* Disable save button and hide the save panel */
586
 
    using_codepress = false;
587
 
    disable_save();
588
 
 
589
 
    /* URL */
590
 
    var url = app_url(service_app, path) + "?return=contents";
591
 
    var download_url = app_url(download_app, path);
592
 
 
593
 
    /* Fallback download link */
594
 
    var link = $(
595
 
        '<p>Could not play ' + tag_name + ' file. ' +
596
 
        'Try <a>downloading it</a> instead.</p>');
597
 
    link.find('a').attr("href", download_url);
598
 
 
599
 
    /* HTML 5 media element */
600
 
    var html5_element = $(
601
 
        '<' + tag_name + ' controls="true" autoplay="true" />');
602
 
    html5_element.attr("src", url);
603
 
    var support = (html5_element[0].canPlayType &&
604
 
                   html5_element[0].canPlayType(type));
605
 
 
606
 
    /* If the browser thinks it might be able to play it, use the HTML5
607
 
     * element. Otherwise, fall back to an <object>, which might work.
608
 
     */
609
 
    if (support == "probably" || support == "maybe") {
610
 
        var element = html5_element;
611
 
    } else {
612
 
        var element = $('<object />');
613
 
        element.attr("type", type);
614
 
        element.attr("data", url);
615
 
    }
616
 
    element.append(link);
617
 
 
618
 
    /* Show Preview */
619
 
    var div = $('<div class="padding" />');
620
 
    div.append('<h1>File preview</h1>');
621
 
    div.append(element);
622
 
    $("#filesbody").append(div);
623
 
}
624
 
 
625
 
/** Display generic object content
626
 
 */
627
 
function handle_object(path, content_type)
628
 
{
629
 
    /* Disable save button and hide the save panel */
630
 
    using_codepress = false;
631
 
    disable_save();
632
 
 
633
 
    /* URL */
634
 
    var url = app_url(service_app, path) + "?return=contents";
635
 
    var download_url = app_url(download_app, path);
636
 
 
637
 
    /* Fallback Download Link */
638
 
    var link = $('<p><a /></p>');
639
 
    var a = link.find('a');
640
 
    a.attr("href", download_url);
641
 
    a.text("Download " + path);
642
 
 
643
 
    /* Object Tag */
644
 
    var obj = $('<object width="100%" height="500px" />');
645
 
    obj.attr("type", content_type);
646
 
    obj.attr("data", url);
647
 
    obj.append('Could not load object');
648
 
 
649
 
    /* Show Preview */
650
 
    var div = $('<div class="padding" />');
651
 
    div.append('<h1>Preview</h1>');
652
 
    div.append(obj);
653
 
    div.append(link);
654
 
    $("#filesbody").append(div);
655
 
}
656
 
 
657
 
/* Present an element for the given path.
658
 
 * Gives it a title and download link.
659
 
 */
660
 
function present_custom_handler(path, type, element)
661
 
{
662
 
    /* Disable save button and hide the save panel */
663
 
    using_codepress = false;
664
 
    disable_save();
665
 
 
666
 
    /* URL */
667
 
    var url = app_url(service_app, path) + "?return=contents";
668
 
    var download_url = app_url(download_app, path);
669
 
 
670
 
    /* Fallback download link */
671
 
    var link = $(
672
 
        '<p>Could not play ' + tag_name + ' file. ' +
673
 
        'Try <a>downloading it</a> instead.</p>');
674
 
    link.find('a').attr("href", download_url);
675
 
 
676
 
    /* HTML 5 media element */
677
 
    var html5_element = $(
678
 
        '<' + tag_name + ' controls="true" autoplay="true" />');
679
 
    html5_element.attr("src", url);
680
 
    var support = (html5_element[0].canPlayType &&
681
 
                   html5_element[0].canPlayType(type));
682
 
 
683
 
    /* If the browser thinks it might be able to play it, use the HTML5
684
 
     * element. Otherwise, fall back to an <object>, which might work.
685
 
     */
686
 
    if (support == "probably" || support == "maybe") {
687
 
        var element = html5_element;
688
 
    } else {
689
 
        var element = $('<object />');
690
 
        element.attr("type", type);
691
 
        element.attr("data", url);
692
 
    }
693
 
    element.append(link);
694
 
 
695
 
    /* Show Preview */
696
 
    var div = $('<div class="padding" />');
697
 
    div.append('<h1>File preview</h1>');
698
 
    div.append(element);
699
 
    $("#filesbody").append(div);
700
 
}
701
 
 
702
493
/* Enable or disable actions1 moreactions actions. Takes either a single
703
494
 * name, or an array of them.*/
704
 
function set_action_state(names, which, allow_on_revision)
 
495
function set_action_state(names, which)
705
496
{
706
497
    if (!(names instanceof Array)) names = Array(names);
707
498
 
708
499
    for (var i=0; i < names.length; i++)
709
500
    {
710
501
        element = document.getElementById('act_' + names[i]);
711
 
        if (which &&
712
 
            !(current_file.svnstatus == 'revision' && !allow_on_revision))
 
502
        if (which)
713
503
        {
714
504
            /* Enabling */
715
505
            element.setAttribute("class", "choice");
724
514
    }
725
515
}
726
516
 
727
 
/* Updates the list of available actions based on files selected */
728
517
function update_actions()
729
518
{
730
519
    var file;
731
520
    var numsel = selected_files.length;
732
 
    var svn_selection = false;
733
 
    
734
 
    if (numsel > 0)
735
 
    {
736
 
        svn_selection = true;
737
 
        for (var i = 0; i < selected_files.length; i++){
738
 
            if (!svnstatus_versioned(file_listing[selected_files[i]].svnstatus))
739
 
            {
740
 
                svn_selection = false;
741
 
            }
742
 
        }
743
 
    }
744
 
    
745
521
    if (numsel <= 1)
746
522
    {
747
523
        if (numsel == 0)
773
549
        else
774
550
            open.setAttribute("title",
775
551
                "Edit or view this file");
776
 
        open.setAttribute("href", build_revision_url(current_path, filename,
777
 
                                                     current_revision));
 
552
        open.setAttribute("href", app_path(this_app, current_path, filename));
778
553
    }
779
554
    else
780
555
    {
787
562
    /* Available if zero or one files are selected,
788
563
     * and only if this is a file, not a directory */
789
564
    var serve = document.getElementById("act_serve");
790
 
    if (numsel <= 1 && !file.isdir && current_file.svnstatus != 'revision')
 
565
    if (numsel <= 1 && !file.isdir)
791
566
    {
792
567
        serve.setAttribute("class", "choice");
793
568
        serve.setAttribute("onclick",
794
569
              "return maybe_save('The last saved version will be served.')");
795
570
        if (numsel == 0)
796
571
            serve.setAttribute("href",
797
 
                app_url(serve_app, current_path));
 
572
                app_path(serve_app, current_path));
798
573
        else
799
574
            serve.setAttribute("href",
800
 
                app_url(serve_app, current_path, filename));
 
575
                app_path(serve_app, current_path, filename));
801
576
    }
802
577
    else
803
578
    {
812
587
     */
813
588
    var run = document.getElementById("act_run");
814
589
     
815
 
    if (numsel <= 1 && !file.isdir && file.type == "text/x-python" 
816
 
            && current_file.svnstatus != 'revision')
 
590
    if (!file.isdir && file.type == "text/x-python" && numsel <= 1)
817
591
    {
818
592
        if (numsel == 0)
819
593
        {
835
609
    }
836
610
 
837
611
    /* Download */
838
 
    /* Always available for current files.
 
612
    /* Always available.
839
613
     * If 0 files selected, download the current file or directory as a ZIP.
840
614
     * If 1 directory selected, download it as a ZIP.
841
615
     * If 1 non-directory selected, download it.
842
616
     * If >1 files selected, download them all as a ZIP.
843
617
     */
844
618
    var download = document.getElementById("act_download");
845
 
    if (current_file.svnstatus == 'revision')
846
 
    {
847
 
        download.setAttribute("class", "disabled");
848
 
        download.removeAttribute("onclick");
849
 
    }
850
 
    else if (numsel <= 1)
851
 
    {
852
 
        download.setAttribute("class", "choice")
 
619
    if (numsel <= 1)
 
620
    {
853
621
        if (numsel == 0)
854
622
        {
855
623
            download.setAttribute("href",
856
 
                app_url(download_app, current_path));
 
624
                app_path(download_app, current_path));
857
625
            if (file.isdir)
858
626
                download.setAttribute("title",
859
627
                    "Download the current directory as a ZIP file");
864
632
        else
865
633
        {
866
634
            download.setAttribute("href",
867
 
                app_url(download_app, current_path, filename));
 
635
                app_path(download_app, current_path, filename));
868
636
            if (file.isdir)
869
637
                download.setAttribute("title",
870
638
                    "Download the selected directory as a ZIP file");
876
644
    else
877
645
    {
878
646
        /* Make a query string with all the files to download */
879
 
        var dlpath = app_url(download_app, current_path) + "?";
 
647
        var dlpath = urlencode_path(app_path(download_app, current_path)) + "?";
880
648
        for (var i=0; i<numsel; i++)
881
649
            dlpath += "path=" + encodeURIComponent(selected_files[i]) + "&";
882
650
        dlpath = dlpath.substr(0, dlpath.length-1);
883
 
        download.setAttribute("class", "choice")
884
651
        download.setAttribute("href", dlpath);
885
652
        download.setAttribute("title",
886
653
            "Download the selected files as a ZIP file");
896
663
    var pubcond = numsel <= 1 && file.isdir;
897
664
    if (pubcond)
898
665
    {
 
666
        /* TODO: Work out of file is svn'd */
899
667
        /* If this dir is already published, call it "Unpublish" */
900
668
        if (file.published)
901
669
        {
902
670
            publish.setAttribute("value", "unpublish");
903
671
            publish.setAttribute("title" ,"Make it so this directory "
904
672
                + "can not be seen by anyone on the web");
905
 
            publish.firstChild.nodeValue = "Unpublish";
 
673
            publish.textContent = "Unpublish";
906
674
        } else {
907
675
            publish.setAttribute("value", "publish");
908
676
            publish.setAttribute("title","Make it so this directory "
909
677
                + "can be seen by anyone on the web");
910
 
            publish.firstChild.nodeValue = "Publish";
 
678
            publish.textContent = "Publish";
911
679
        }
912
680
    }
913
681
    set_action_state(["publish", "submit"], pubcond);
934
702
    /* Subversion actions */
935
703
    /* These are only useful if we are in a versioned directory and have some
936
704
     * files selected. */
937
 
    set_action_state(["svnrename"], numsel == 1 && current_file.svnstatus);
938
 
    set_action_state(["svnadd"], numsel >= 1 && current_file.svnstatus);
939
 
    /* And these are only useful is ALL the selected files are versioned */
940
 
    set_action_state(["svnremove", "svnrevert", "svncopy", "svncut"],
941
 
            numsel >= 1 && current_file.svnstatus && svn_selection);
942
 
    /* Commit is useful if ALL selected files are versioned, or the current
943
 
     * directory is versioned */
944
 
    set_action_state(["svncommit"], current_file.svnstatus &&
945
 
            (numsel >= 1 && svn_selection || numsel == 0));
946
 
 
947
 
    /* Diff, log and update only support one path at the moment, so we must
948
 
     * have 0 or 1 versioned files selected. If 0, the directory must be
949
 
     * versioned. */
950
 
    single_versioned_path = (
951
 
         (
952
 
          (numsel == 1 && (svnst = file_listing[selected_files[0]].svnstatus)) ||
953
 
          (numsel == 0 && (svnst = current_file.svnstatus))
954
 
         ) && svnstatus_versioned(svnst));
955
 
    set_action_state(["svndiff", "svnupdate"], single_versioned_path);
956
 
 
957
 
    /* We can resolve if we have a file selected and it is conflicted. */
958
 
    set_action_state("svnresolved", single_versioned_path && numsel == 1 && svnst == "conflicted");
959
 
 
960
 
    /* Log should be available for revisions as well. */
961
 
    set_action_state("svnlog", single_versioned_path, true);
962
 
 
963
 
    /* Cleanup should be available for revisions as well. */
964
 
    set_action_state("svncleanup", single_versioned_path, true);
965
 
 
966
 
    single_ivle_versioned_path = (
967
 
         (
968
 
          (numsel == 1 && (stat = file_listing[selected_files[0]])) ||
969
 
          (numsel == 0 && (stat = current_file))
970
 
         ) && svnstatus_versioned(stat.svnstatus)
971
 
           && stat.svnurl
972
 
           && stat.svnurl.substr(0, svn_base.length) == svn_base);
973
 
    set_action_state(["submit"], single_ivle_versioned_path);
 
705
    set_action_state(["svnadd", "svnrevert", "svncommit"], numsel >= 1 && current_file.svnstatus);
 
706
 
 
707
    /* Diff and log only support one path at the moment. */
 
708
    single_versioned_path = (numsel == 1 &&
 
709
                             (svnst = file_listing[selected_files[0]].svnstatus) &&
 
710
                             svnst != "unversioned");
 
711
    set_action_state("svnlog", single_versioned_path);
 
712
    set_action_state("svndiff", single_versioned_path && svnst != "normal");
 
713
 
 
714
    /* current_path == username: We are at the top level */
 
715
    set_action_state("svncheckout", current_path == username);
974
716
 
975
717
    /* There is currently nothing on the More Actions menu of use
976
718
     * when the current file is not a directory. Hence, just remove
983
725
    {
984
726
        var actions2_directory = document.getElementById("actions2_directory");
985
727
        actions2_directory.setAttribute("style", "display: inline;");
 
728
    }
 
729
    else
 
730
    {
 
731
        var actions2_file = document.getElementById("actions2_file");
 
732
        actions2_file.setAttribute("style", "display: inline;");
986
733
        var moreactions = document.getElementById("moreactions_area");
987
 
        moreactions.setAttribute("style", "display: inline;");
 
734
        moreactions.setAttribute("style", "display: none;");
988
735
    }
989
736
 
990
737
    return;
1021
768
        action_unpublish(selected_files);
1022
769
        break;
1023
770
    case "share":
1024
 
        window.open(public_app_url("~" + current_path, filename), 'share')
 
771
        //alert("Not yet implemented: Sharing files");
 
772
        window.open(public_app_path(serve_app, current_path, filename), 'share')
1025
773
        break;
1026
774
    case "submit":
1027
 
        if (selected_files.length == 1)
1028
 
            stat = file_listing[selected_files[0]];
1029
 
        else
1030
 
            stat = current_file;
1031
 
        url = stat.svnurl.substr(svn_base.length);      // URL-encoded
1032
 
        path = decodeURIComponent(url);
1033
 
 
1034
 
        /* The working copy might not have an up-to-date version of the
1035
 
         * directory. While submitting like this could yield unexpected
1036
 
         * results, we should really submit the latest revision to minimise
1037
 
         * terrible mistakes - so we run off and ask fileservice for the
1038
 
         * latest revision.*/
1039
 
        $.post(app_path(service_app, current_path),
1040
 
            {"action": "svnrepostat", "path": path},
1041
 
            function(result)
1042
 
            {
1043
 
                window.location = path_join(app_path('+submit'), url) + '?revision=' + result.svnrevision;
1044
 
            },
1045
 
            "json");
1046
 
 
 
775
        // TODO
 
776
        alert("Not yet implemented: Submit");
1047
777
        break;
1048
778
    case "rename":
1049
779
        action_rename(filename);
1050
780
        break;
1051
781
    case "delete":
1052
 
        action_delete(selected_files);
 
782
        action_remove(selected_files);
1053
783
        break;
1054
784
    case "copy":
1055
785
        action_copy(selected_files);
1072
802
    case "svnadd":
1073
803
        action_add(selected_files);
1074
804
        break;
1075
 
    case "svnremove":
1076
 
        action_svnremove(selected_files);
1077
 
        break;
1078
 
    case "svnrename":
1079
 
        action_svnrename(selected_files);
1080
 
        break;
1081
805
    case "svnrevert":
1082
806
        action_revert(selected_files);
1083
807
        break;
1084
808
    case "svndiff":
1085
 
        window.location = path_join(app_url('diff'), current_path, selected_files[0] || '');
1086
 
        break;
1087
 
    case "svnupdate":
1088
 
        action_update(selected_files);
1089
 
        break;
1090
 
    case "svnresolved":
1091
 
        action_resolved(selected_files);
 
809
        window.location = path_join(app_path('diff'), current_path, selected_files[0]);
1092
810
        break;
1093
811
    case "svncommit":
1094
812
        action_commit(selected_files);
1095
813
        break;
1096
814
    case "svnlog":
1097
 
        window.location = path_join(app_url('svnlog'), current_path, selected_files[0] || '');
1098
 
        break;
1099
 
    case "svncopy":
1100
 
        action_svncopy(selected_files);
1101
 
        break;
1102
 
    case "svncut":
1103
 
        action_svncut(selected_files);
1104
 
        break;
1105
 
    case "svncleanup":
1106
 
        action_svncleanup(".");
 
815
        window.location = path_join(app_path('svnlog'), current_path, selected_files[0]);
 
816
        break;
 
817
    case "svncheckout":
 
818
        action_checkout();
1107
819
        break;
1108
820
    }
1109
821
}
1132
844
     * This causes the page to be populated with whatever is at that address,
1133
845
     * whether it be a directory or a file.
1134
846
     */
1135
 
    var path = get_path();
1136
 
    navigate(path);
1137
 
}
1138
 
 
1139
 
/** Gets the current path of the window */
1140
 
function get_path() {
1141
847
    var path = parse_url(window.location.href).path;
1142
848
    /* Strip out root_dir + "/files" from the front of the path */
1143
849
    var strip = make_path(this_app);
1160
866
        path = username;
1161
867
    }
1162
868
 
1163
 
    return path;
 
869
    navigate(path);
1164
870
}