~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-03-28 07:23:56 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:717
Tutorial: Bugfix - Reset Text was not escaped, so bad, horribly bad things
    happened for partial solutions with weird characters.
    Now URLencoded, and the JavaScript unencodes it.
    Also refactored code to print out all the buttons, since one huge format
    string was not good.

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
default_type_icon = "txt.png";
56
56
 
57
57
/* Relative to IVLE root */
58
 
type_icons_path = "+media/ivle.webapp.core/images/mime";
59
 
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";
60
60
 
61
61
/* Mapping SVN status to icons, just the file's basename */
62
62
svn_icons = {
63
 
    "unversioned": "unversioned.png",
64
 
    "ignored": null,                    /* Supposed to be innocuous */
 
63
    "unversioned": null,
65
64
    "normal": "normal.png",
66
65
    "added": "added.png",
67
66
    "missing": "missing.png",
68
67
    "deleted": "deleted.png",
69
 
    "replaced": "replaced.png",
70
68
    "modified": "modified.png",
71
 
    "conflicted": "conflicted.png",
72
69
    "revision": "revision.png"
73
70
};
74
71
 
75
72
/* Mapping SVN status to "nice" strings */
76
73
svn_nice = {
77
74
    "unversioned": "Temporary file",
78
 
    "ignored": "Temporary file (ignored)",
79
75
    "normal": "Permanent file",
80
76
    "added": "Temporary file (scheduled to be added)",
81
77
    "missing": "Permanent file (missing)",
90
86
default_svn_icon = null;
91
87
default_svn_nice = "Unknown status";
92
88
 
93
 
svn_icons_path = "+media/ivle.webapp.core/images/svn";
 
89
svn_icons_path = "media/images/svn";
94
90
 
95
 
published_icon = "+media/ivle.webapp.core/images/interface/published.png";
 
91
published_icon = "media/images/interface/published.png";
96
92
 
97
93
/* List of MIME types considered "executable" by the system.
98
94
 * Executable files offer a "run" link, implying that the "serve"
108
104
/** The listing object returned by the server as JSON */
109
105
file_listing = null;
110
106
current_file = null;
111
 
current_revision = null;
112
107
current_path = "";
113
108
 
114
109
/** Filenames of all files selected
137
132
 *      May be "application/x-www-form-urlencoded" or "multipart/form-data".
138
133
 *      Defaults to "application/x-www-form-urlencoded".
139
134
 *      "multipart/form-data" is recommended for large uploads.
140
 
 * \param callback, optional.
141
 
 *      A callback function for after the action has been handled.
142
135
 */
143
 
function do_action(action, path, args, content_type, callback)
 
136
function do_action(action, path, args, content_type, ignore_response)
144
137
{
145
138
    args.action = action;
146
139
    /* Callback action, when the server returns */
147
 
    var callback_inner = function(response)
 
140
    var callback = function(response)
148
141
        {
149
142
            /* Check for action errors reported by the server, and report them
150
143
             * to the user */
151
144
            var error = response.getResponseHeader("X-IVLE-Action-Error");
152
 
            if (error != null && error != "")
153
 
                /* Note: This header (in particular) comes URI-encoded, to
154
 
                 * allow multi-line error messages. Decode */
155
 
                alert("Error: " + decodeURIComponent(error.toString()) + ".");
 
145
            if (error != null)
 
146
                alert("Error: " + error.toString() + ".");
156
147
            /* Now read the response and set up the page accordingly */
157
 
            if (callback != null)
158
 
                callback(path, response);
 
148
            if (ignore_response != true)
 
149
                handle_response(path, response);
159
150
        }
160
151
    /* Call the server and perform the action. This mutates the server. */
161
 
    ajax_call(callback_inner, service_app, path, args, "POST", content_type);
 
152
    ajax_call(callback, service_app, path, args, "POST", content_type);
162
153
}
163
154
 
164
155
/** Calls the server using Ajax, requesting a directory listing. This should
174
165
    callback = function(response)
175
166
        {
176
167
            /* Read the response and set up the page accordingly */
177
 
            handle_response(path, response, false, url.args);
 
168
            handle_response(path, response, url.args);
178
169
        }
179
170
    /* Get any query strings */
180
171
    url = parse_url(window.location.href);
188
179
 */
189
180
function refresh()
190
181
{
191
 
    if (maybe_save('All changes since the last save will be lost!'))
192
 
        navigate(current_path);
 
182
    navigate(current_path);
193
183
}
194
184
 
195
185
/** Determines the "handler type" from a MIME type.
221
211
 * things) be used to update the URL in the location bar.
222
212
 * \param response XMLHttpRequest object returned by the server. Should
223
213
 * contain all the response data.
224
 
 * \param is_action Boolean. True if this is the response to an action, false
225
 
 * if this is the response to a simple listing. This is used in handling the
226
 
 * error.
227
214
 * \param url_args Arguments dict, for the arguments passed to the URL
228
215
 * in the browser's address bar (will be forwarded along).
229
216
 */
230
 
function handle_response(path, response, is_action, url_args)
 
217
function handle_response(path, response, url_args)
231
218
{
232
219
    /* TODO: Set location bar to "path" */
233
220
    current_path = path;
246
233
        return;
247
234
    }
248
235
 
249
 
    var subjects = null;
250
 
    /* Remove trailing slash (or path==username won't compare properly) */
251
 
    if (path[path.length-1] == "/")
252
 
        path = path.substr(0, path.length-1);
253
 
    var top_level_dir = path==username;
254
 
    if (top_level_dir)
255
 
    {
256
 
        var req = ajax_call(null, "userservice", "get_enrolments", null, "GET")
257
 
        subjects = decode_response(req);
258
 
    }
259
 
 
260
 
 
261
236
    /* This will always return a listing, whether it is a dir or a file.
262
237
     */
263
238
    var listing = response.responseText;
269
244
    }
270
245
    catch (e)
271
246
    {
272
 
        if (is_action)
273
 
        {
274
 
            var err = document.createElement("div");
275
 
            var p = dom_make_text_elem("p", "Error: "
276
 
                    + "There was an unexpected server error processing "
277
 
                    + "the selected command.");
278
 
            err.appendChild(p);
279
 
            p = dom_make_text_elem("p", "If the problem persists, please "
280
 
                    + "contact the system administrator.")
281
 
            err.appendChild(p);
282
 
            p = document.createElement("p");
283
 
            var refresh = document.createElement("input");
284
 
            refresh.setAttribute("type", "button");
285
 
            refresh.setAttribute("value", "Back to file view");
286
 
            refresh.setAttribute("onclick", "refresh()");
287
 
            p.appendChild(refresh);
288
 
            err.appendChild(p);
289
 
            handle_error(err);
290
 
        }
291
 
        else
292
 
        {
293
 
            var err = document.createElement("div");
294
 
            var p = dom_make_text_elem("p", "Error: "
295
 
                    + "There was an unexpected server error retrieving "
296
 
                    + "the requested file or directory.");
297
 
            err.appendChild(p);
298
 
            p = dom_make_text_elem("p", "If the problem persists, please "
299
 
                    + "contact the system administrator.")
300
 
            err.appendChild(p);
301
 
            handle_error(err);
302
 
        }
 
247
        handle_error("The server returned an invalid directory listing");
303
248
        return;
304
249
    }
305
250
    /* Get "." out, it's special */
306
251
    current_file = file_listing["."];     /* Global */
307
252
    delete file_listing["."];
308
253
 
309
 
    if ('revision' in listing)
310
 
    {
311
 
        current_revision = listing.revision;
312
 
    }
313
 
 
314
254
    /* Check if this is a directory listing or file contents */
315
255
    var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
316
256
    if (isdir)
317
257
    {
318
 
        setup_for_listing();
319
 
        if (top_level_dir)
320
 
        {
321
 
            /* Top-level dir, with subjects */
322
 
            special_home_listing(listing, subjects, path);
323
 
        }
324
 
        else
325
 
        {
326
 
            /* Not the top-level dir. Do a normal dir listing. */
327
 
            handle_dir_listing(path, listing.listing);
328
 
        }
 
258
        handle_dir_listing(path, listing);
329
259
    }
330
260
    else
331
261
    {
393
323
     */
394
324
    upload_callback_count++;
395
325
    if (upload_callback_count >= 2)
396
 
    {
397
 
        myFrame = frames['upload_iframe'].document;
398
 
        /* Browsers will turn the raw returned JSON into an HTML document. We
399
 
         * need to get the <pre> from inside the <body>, and look at its text.
400
 
         */
401
 
        data = myFrame.firstChild.getElementsByTagName(
402
 
            'body')[0].firstChild.firstChild.nodeValue;
403
 
        data = JSON.parse(data);
404
 
        if ('Error' in data)
405
 
            alert("Error: " + decodeURIComponent(data['Error']));
406
 
        document.getElementsByName('data')[0].value = '';
407
326
        refresh();
408
 
    }
409
327
}
410
328
 
411
329
/** Deletes all "dynamic" content on the page.
417
335
    dom_removechildren(document.getElementById("filesbody"));
418
336
}
419
337
 
420
 
/* Checks if a file needs to be saved. If it does, the user will be asked
421
 
 * if they want to continue anyway. The caller must specify a warning
422
 
 * sentence which indicates the consequences of continuing.
423
 
 * Returns true if we should continue, and false if we should not.
424
 
 */
425
 
function maybe_save(warning)
426
 
{
427
 
    if (warning == null) warning = '';
428
 
    if (current_file == null || current_file.isdir) return true;
429
 
    if (document.getElementById("save_button").disabled) return true;
430
 
    return confirm("This file has unsaved changes. " + warning +
431
 
                   "\nAre you sure you wish to continue?");
432
 
}
433
 
 
434
338
/** Deletes all "dynamic" content on the page necessary to navigate from
435
339
 * one directory listing to another (does not clear as much as clearpage
436
340
 * does).
447
351
/*** HANDLERS for different types of responses (such as dir listing, file,
448
352
 * etc). */
449
353
 
450
 
/* handle_error.
451
 
 * message may either be a string, or a DOM node, which will be placed inside
452
 
 * a div.
453
 
 */
454
354
function handle_error(message)
455
355
{
456
356
    var files = document.getElementById("filesbody");
457
 
    var txt_elem;
458
 
    if (typeof(message) == "string")
459
 
    {
460
 
        txt_elem = dom_make_text_elem("div", "Error: "
461
 
                   + message.toString() + ".")
462
 
    }
463
 
    else
464
 
    {
465
 
        /* Assume message is a DOM node */
466
 
        txt_elem = document.createElement("div");
467
 
        txt_elem.appendChild(message);
468
 
    }
 
357
    var txt_elem = dom_make_text_elem("div", "Error: "
 
358
        + message.toString() + ".")
469
359
    txt_elem.setAttribute("class", "padding error");
470
360
    files.appendChild(txt_elem);
471
361
}
472
362
 
473
 
/** Given a path, filename and optional revision, returns a URL to open that
474
 
 *  revision of that file.
475
 
 */
476
 
function build_revision_url(path, filename, revision)
477
 
{
478
 
    bits = {'path': app_path(this_app, path, filename)};
479
 
    if (current_revision)
480
 
    {
481
 
        bits['query_string'] = 'r=' + revision;
482
 
    }
483
 
    return build_url(bits);
484
 
}
485
 
 
486
363
/** Given a mime type, returns the path to the icon.
487
364
 * \param type String, Mime type.
488
365
 * \param sizelarge Boolean, optional.
528
405
        return default_svn_nice;
529
406
}
530
407
 
531
 
/** Returns true if a file is versioned (not unversioned or ignored).
532
 
 */
533
 
function svnstatus_versioned(svnstatus)
534
 
{
535
 
    return svnstatus != "unversioned" && svnstatus != "ignored";
536
 
}
537
 
 
538
408
/** Displays a download link to the binary file.
539
409
 */
540
410
function handle_binary(path)
543
413
    var div = document.createElement("div");
544
414
    files.appendChild(div);
545
415
    div.setAttribute("class", "padding");
546
 
    var download_link = app_url(download_app, path);
 
416
    var download_link = app_path(download_app, path);
547
417
    var par1 = dom_make_text_elem("p",
548
418
        "The file " + path + " is a binary file. To download this file, " +
549
419
        "click the following link:");
553
423
    div.appendChild(par2);
554
424
}
555
425
 
556
 
/* Enable or disable actions1 moreactions actions. Takes either a single
557
 
 * name, or an array of them.*/
558
 
function set_action_state(names, which, allow_on_revision)
559
 
{
560
 
    if (!(names instanceof Array)) names = Array(names);
561
 
 
562
 
    for (var i=0; i < names.length; i++)
563
 
    {
564
 
        element = document.getElementById('act_' + names[i]);
565
 
        if (which &&
566
 
            !(current_file.svnstatus == 'revision' && !allow_on_revision))
567
 
        {
568
 
            /* Enabling */
569
 
            element.setAttribute("class", "choice");
570
 
            element.removeAttribute("disabled");
571
 
        }
572
 
        else
573
 
        {
574
 
            /* Disabling */
575
 
            element.setAttribute("class", "disabled");
576
 
            element.setAttribute("disabled", "disabled");
577
 
        }
578
 
    }
579
 
}
580
 
 
581
 
/* Updates the list of available actions based on files selected */
582
426
function update_actions()
583
427
{
584
428
    var file;
585
429
    var numsel = selected_files.length;
586
 
    var svn_selection = false;
587
 
    
588
 
    if (numsel > 0)
589
 
    {
590
 
        svn_selection = true;
591
 
        for (var i = 0; i < selected_files.length; i++){
592
 
            if (!svnstatus_versioned(file_listing[selected_files[i]].svnstatus))
593
 
            {
594
 
                svn_selection = false;
595
 
            }
596
 
        }
597
 
    }
598
 
    
599
430
    if (numsel <= 1)
600
431
    {
601
432
        if (numsel == 0)
627
458
        else
628
459
            open.setAttribute("title",
629
460
                "Edit or view this file");
630
 
        open.setAttribute("href", build_revision_url(current_path, filename,
631
 
                                                     current_revision));
 
461
        open.setAttribute("href", app_path(this_app, current_path, filename));
632
462
    }
633
463
    else
634
464
    {
638
468
    }
639
469
 
640
470
    /* Serve */
641
 
    /* Available if zero or one files are selected,
 
471
    /* Available if exactly one file is selected,
642
472
     * and only if this is a file, not a directory */
643
473
    var serve = document.getElementById("act_serve");
644
 
    if (numsel <= 1 && !file.isdir && current_file.svnstatus != 'revision')
 
474
    if (numsel == 1 && !file.isdir)
645
475
    {
646
476
        serve.setAttribute("class", "choice");
647
 
        serve.setAttribute("onclick",
648
 
              "return maybe_save('The last saved version will be served.')");
649
 
        if (numsel == 0)
650
 
            serve.setAttribute("href",
651
 
                app_url(serve_app, current_path));
652
 
        else
653
 
            serve.setAttribute("href",
654
 
                app_url(serve_app, current_path, filename));
 
477
        serve.setAttribute("href",
 
478
            app_path(serve_app, current_path, filename));
655
479
    }
656
480
    else
657
481
    {
658
482
        serve.setAttribute("class", "disabled");
659
483
        serve.removeAttribute("href");
660
 
        serve.removeAttribute("onclick");
661
484
    }
662
485
 
663
486
    /* Run */
666
489
     */
667
490
    var run = document.getElementById("act_run");
668
491
     
669
 
    if (numsel <= 1 && !file.isdir && file.type == "text/x-python" 
670
 
            && current_file.svnstatus != 'revision')
671
 
    {
672
 
        if (numsel == 0)
673
 
        {
674
 
            // In the edit window
675
 
            var localpath = path_join('/home', current_path);
676
 
        }
677
 
        else
678
 
        {
679
 
            // In the browser window
680
 
            var localpath = path_join('/home', current_path, filename);
681
 
        }
682
 
        run.setAttribute("class", "choice");
 
492
    if (numsel == 0 && !file.isdir && file.type == "text/x-python")
 
493
    {
 
494
        // In the edit window
 
495
        run.setAttribute("class", "choice");
 
496
        localpath = app_path('home',current_path);
 
497
        run.setAttribute("onclick", "runfile('" + localpath + "')");
 
498
    }
 
499
    else if (numsel == 1 && !file.isdir && file.type == "text/x-python")
 
500
    {
 
501
        // In the browser window
 
502
        run.setAttribute("class", "choice");
 
503
        localpath = app_path('home',current_path,filename);
683
504
        run.setAttribute("onclick", "runfile('" + localpath + "')");
684
505
    }
685
506
    else
689
510
    }
690
511
 
691
512
    /* Download */
692
 
    /* Always available for current files.
 
513
    /* Always available.
693
514
     * If 0 files selected, download the current file or directory as a ZIP.
694
515
     * If 1 directory selected, download it as a ZIP.
695
516
     * If 1 non-directory selected, download it.
696
517
     * If >1 files selected, download them all as a ZIP.
697
518
     */
698
519
    var download = document.getElementById("act_download");
699
 
    if (current_file.svnstatus == 'revision')
700
 
    {
701
 
        download.setAttribute("class", "disabled");
702
 
        download.removeAttribute("onclick");
703
 
    }
704
 
    else if (numsel <= 1)
705
 
    {
706
 
        download.setAttribute("class", "choice")
 
520
    if (numsel <= 1)
 
521
    {
707
522
        if (numsel == 0)
708
523
        {
709
524
            download.setAttribute("href",
710
 
                app_url(download_app, current_path));
 
525
                app_path(download_app, current_path));
711
526
            if (file.isdir)
712
527
                download.setAttribute("title",
713
528
                    "Download the current directory as a ZIP file");
718
533
        else
719
534
        {
720
535
            download.setAttribute("href",
721
 
                app_url(download_app, current_path, filename));
 
536
                app_path(download_app, current_path, filename));
722
537
            if (file.isdir)
723
538
                download.setAttribute("title",
724
539
                    "Download the selected directory as a ZIP file");
730
545
    else
731
546
    {
732
547
        /* Make a query string with all the files to download */
733
 
        var dlpath = app_url(download_app, current_path) + "?";
 
548
        var dlpath = urlencode_path(app_path(download_app, current_path)) + "?";
734
549
        for (var i=0; i<numsel; i++)
735
550
            dlpath += "path=" + encodeURIComponent(selected_files[i]) + "&";
736
551
        dlpath = dlpath.substr(0, dlpath.length-1);
737
 
        download.setAttribute("class", "choice")
738
552
        download.setAttribute("href", dlpath);
739
553
        download.setAttribute("title",
740
554
            "Download the selected files as a ZIP file");
747
561
     * directory. */
748
562
    var publish = document.getElementById("act_publish");
749
563
    var submit = document.getElementById("act_submit");
750
 
    var pubcond = numsel <= 1 && file.isdir;
751
 
    if (pubcond)
752
 
    {
753
 
        /* If this dir is already published, call it "Unpublish" */
754
 
        if (file.published)
755
 
        {
756
 
            publish.setAttribute("value", "unpublish");
757
 
            publish.setAttribute("title" ,"Make it so this directory "
758
 
                + "can not be seen by anyone on the web");
759
 
            publish.firstChild.nodeValue = "Unpublish";
760
 
        } else {
761
 
            publish.setAttribute("value", "publish");
762
 
            publish.setAttribute("title","Make it so this directory "
763
 
                + "can be seen by anyone on the web");
764
 
            publish.firstChild.nodeValue = "Publish";
765
 
        }
766
 
    }
767
 
    set_action_state(["publish", "submit"], pubcond);
 
564
    if (numsel <= 1 && file.isdir)
 
565
    {
 
566
        /* TODO: Work out of file is svn'd */
 
567
        /* TODO: If this dir is already published, call it "Unpublish" */
 
568
        publish.setAttribute("class", "choice");
 
569
        publish.removeAttribute("disabled");
 
570
        submit.setAttribute("class", "choice");
 
571
        submit.removeAttribute("disabled");
 
572
    }
 
573
    else
 
574
    {
 
575
        publish.setAttribute("class", "disabled");
 
576
        publish.setAttribute("disabled", "disabled");
 
577
        submit.setAttribute("class", "disabled");
 
578
        submit.setAttribute("disabled", "disabled");
 
579
    }
768
580
 
769
581
    /* Share */
770
 
    /* If exactly 1 non-directory file is selected, and its parent
 
582
    /* If exactly 1 non-directory file is selected/opened, and its parent
771
583
     * directory is published.
772
584
     */
773
 
    set_action_state("share", numsel == 1 && !file.isdir &&
774
 
                     current_file.published);
 
585
    var share = document.getElementById("act_share");
 
586
    if (numsel <= 1 && !file.isdir)
 
587
    {
 
588
        /* TODO: Work out if parent dir is published */
 
589
        share.setAttribute("class", "choice");
 
590
        share.removeAttribute("disabled");
 
591
    }
 
592
    else
 
593
    {
 
594
        share.setAttribute("class", "disabled");
 
595
        share.setAttribute("disabled", "disabled");
 
596
    }
775
597
 
776
598
    /* Rename */
777
599
    /* If exactly 1 file is selected */
778
 
    set_action_state("rename", numsel == 1);
 
600
    var rename = document.getElementById("act_rename");
 
601
    if (numsel == 1)
 
602
    {
 
603
        rename.setAttribute("class", "choice");
 
604
        rename.removeAttribute("disabled");
 
605
    }
 
606
    else
 
607
    {
 
608
        rename.setAttribute("class", "disabled");
 
609
        rename.setAttribute("disabled", "disabled");
 
610
    }
779
611
 
780
612
    /* Delete, cut, copy */
781
613
    /* If >= 1 file is selected */
782
 
    set_action_state(["delete", "cut", "copy"], numsel >= 1);
 
614
    var act_delete = document.getElementById("act_delete");
 
615
    var cut = document.getElementById("act_cut");
 
616
    var copy = document.getElementById("act_copy");
 
617
    if (numsel >= 1)
 
618
    {
 
619
        act_delete.setAttribute("class", "choice");
 
620
        act_delete.removeAttribute("disabled");
 
621
        cut.setAttribute("class", "choice");
 
622
        cut.removeAttribute("disabled");
 
623
        copy.setAttribute("class", "choice");
 
624
        copy.removeAttribute("disabled");
 
625
    }
 
626
    else
 
627
    {
 
628
        act_delete.setAttribute("class", "disabled");
 
629
        act_delete.setAttribute("disabled", "disabled");
 
630
        cut.setAttribute("class", "disabled");
 
631
        cut.setAttribute("disabled", "disabled");
 
632
        copy.setAttribute("class", "disabled");
 
633
        copy.setAttribute("disabled", "disabled");
 
634
    }
783
635
 
784
636
    /* Paste, new file, new directory, upload */
785
 
    /* Disable if the current file is not a directory */
786
 
    set_action_state(["paste", "newfile", "mkdir", "upload"], current_file.isdir);
 
637
    /* Always enabled (assuming this is a directory) */
787
638
 
788
639
    /* Subversion actions */
789
 
    /* These are only useful if we are in a versioned directory and have some
790
 
     * files selected. */
791
 
    set_action_state(["svnadd"], numsel >= 1 && current_file.svnstatus);
792
 
    /* And these are only useful is ALL the selected files are versioned */
793
 
    set_action_state(["svnremove", "svnrevert", "svncopy", "svncut"],
794
 
            numsel >= 1 && current_file.svnstatus && svn_selection);
795
 
    /* Commit is useful if ALL selected files are versioned, or the current
796
 
     * directory is versioned */
797
 
    set_action_state(["svncommit"], current_file.svnstatus &&
798
 
            (numsel >= 1 && svn_selection || numsel == 0));
799
 
 
800
 
    /* Diff, log and update only support one path at the moment, so we must
801
 
     * have 0 or 1 versioned files selected. If 0, the directory must be
802
 
     * versioned. */
803
 
    single_versioned_path = (
804
 
         (
805
 
          (numsel == 1 && (svnst = file_listing[selected_files[0]].svnstatus)) ||
806
 
          (numsel == 0 && (svnst = current_file.svnstatus))
807
 
         ) && svnstatus_versioned(svnst));
808
 
    set_action_state(["svndiff", "svnupdate"], single_versioned_path);
809
 
 
810
 
    /* We can resolve if we have a file selected and it is conflicted. */
811
 
    set_action_state("svnresolved", single_versioned_path && numsel == 1 && svnst == "conflicted");
812
 
 
813
 
    /* Log should be available for revisions as well. */
814
 
    set_action_state("svnlog", single_versioned_path, true);
815
 
 
816
 
    /* Cleanup should be available for revisions as well. */
817
 
    set_action_state("svncleanup", single_versioned_path, true);
818
 
 
819
 
    single_ivle_versioned_path = (
820
 
         (
821
 
          (numsel == 1 && (stat = file_listing[selected_files[0]])) ||
822
 
          (numsel == 0 && (stat = current_file))
823
 
         ) && svnstatus_versioned(stat.svnstatus)
824
 
           && stat.svnurl
825
 
           && stat.svnurl.substr(0, svn_base.length) == svn_base);
826
 
    set_action_state(["submit"], single_ivle_versioned_path);
827
 
 
828
 
    /* There is currently nothing on the More Actions menu of use
829
 
     * when the current file is not a directory. Hence, just remove
830
 
     * it entirely.
831
 
     * (This makes some of the above decisions somewhat redundant).
832
 
     * We also take this opportunity to show the appropriate actions2
833
 
     * bar for this path. It should either be a save or upload widget.
834
 
     */
835
 
    if (current_file.isdir)
836
 
    {
837
 
        var actions2_directory = document.getElementById("actions2_directory");
838
 
        actions2_directory.setAttribute("style", "display: inline;");
839
 
        var moreactions = document.getElementById("moreactions_area");
840
 
        moreactions.setAttribute("style", "display: inline;");
 
640
    /* TODO: Work out when these are appropriate */
 
641
    var svnadd = document.getElementById("act_svnadd");
 
642
    var svnrevert = document.getElementById("act_svnrevert");
 
643
    var svncommit = document.getElementById("act_svncommit");
 
644
    if (true)
 
645
    {
 
646
        svnadd.setAttribute("class", "choice");
 
647
        svnadd.removeAttribute("disabled");
 
648
        svnrevert.setAttribute("class", "choice");
 
649
        svnrevert.removeAttribute("disabled");
 
650
        svncommit.setAttribute("class", "choice");
 
651
        svncommit.removeAttribute("disabled");
 
652
    }
 
653
    var svncheckout = document.getElementById("act_svncheckout");
 
654
    /* current_path == username: We are at the top level */
 
655
    if (current_path == username)
 
656
    {
 
657
        svncheckout.setAttribute("class", "choice");
 
658
        svncheckout.removeAttribute("disabled");
841
659
    }
842
660
    else
843
661
    {
844
 
        var actions2_file = document.getElementById("actions2_file");
845
 
        actions2_file.setAttribute("style", "display: inline;");
 
662
        svncheckout.setAttribute("class", "disabled");
 
663
        svncheckout.setAttribute("disabled", "disabled");
846
664
    }
847
665
 
848
666
    return;
879
697
        action_unpublish(selected_files);
880
698
        break;
881
699
    case "share":
882
 
        window.open(public_app_url("~" + current_path, filename), 'share')
 
700
        // TODO
 
701
        alert("Not yet implemented: Sharing files");
883
702
        break;
884
703
    case "submit":
885
 
        if (selected_files.length == 1)
886
 
            stat = file_listing[selected_files[0]];
887
 
        else
888
 
            stat = current_file;
889
 
        url = stat.svnurl.substr(svn_base.length);      // URL-encoded
890
 
        path = decodeURIComponent(url);
891
 
 
892
 
        /* The working copy might not have an up-to-date version of the
893
 
         * directory. While submitting like this could yield unexpected
894
 
         * results, we should really submit the latest revision to minimise
895
 
         * terrible mistakes - so we run off and ask fileservice for the
896
 
         * latest revision.*/
897
 
        $.post(app_path(service_app, current_path),
898
 
            {"action": "svnrepostat", "path": path},
899
 
            function(result)
900
 
            {
901
 
                window.location = path_join(app_path('+submit'), url) + '?revision=' + result.svnrevision;
902
 
            },
903
 
            "json");
904
 
 
 
704
        // TODO
 
705
        alert("Not yet implemented: Submit");
905
706
        break;
906
707
    case "rename":
907
708
        action_rename(filename);
908
709
        break;
909
710
    case "delete":
910
 
        action_delete(selected_files);
 
711
        action_remove(selected_files);
911
712
        break;
912
713
    case "copy":
913
714
        action_copy(selected_files);
930
731
    case "svnadd":
931
732
        action_add(selected_files);
932
733
        break;
933
 
    case "svnremove":
934
 
        action_remove(selected_files);
935
 
        break;
936
734
    case "svnrevert":
937
735
        action_revert(selected_files);
938
736
        break;
939
 
    case "svndiff":
940
 
        window.location = path_join(app_url('diff'), current_path, selected_files[0] || '');
941
 
        break;
942
 
    case "svnupdate":
943
 
        action_update(selected_files);
944
 
        break;
945
 
    case "svnresolved":
946
 
        action_resolved(selected_files);
947
 
        break;
948
737
    case "svncommit":
949
738
        action_commit(selected_files);
950
739
        break;
951
 
    case "svnlog":
952
 
        window.location = path_join(app_url('svnlog'), current_path, selected_files[0] || '');
953
 
        break;
954
 
    case "svncopy":
955
 
        action_svncopy(selected_files);
956
 
        break;
957
 
    case "svncut":
958
 
        action_svncut(selected_files);
959
 
        break;
960
 
    case "svncleanup":
961
 
        action_svncleanup(".");
 
740
    case "svncheckout":
 
741
        action_checkout();
962
742
        break;
963
743
    }
964
744
}
968
748
 */
969
749
function runfile(localpath)
970
750
{
971
 
    if (!maybe_save('The last saved version will be run.')) return false;
972
 
 
973
751
    /* Dump the entire file to the console */
974
752
    var callback = function()
975
753
    {
981
759
 
982
760
/** Called when the page loads initially.
983
761
 */
984
 
function browser_init()
 
762
window.onload = function()
985
763
{
986
764
    /* Navigate (internally) to the path in the URL bar.
987
765
     * This causes the page to be populated with whatever is at that address,
988
766
     * whether it be a directory or a file.
989
767
     */
990
 
    var path = get_path();
991
 
    navigate(path);
992
 
}
993
 
 
994
 
/** Gets the current path of the window */
995
 
function get_path() {
996
768
    var path = parse_url(window.location.href).path;
997
769
    /* Strip out root_dir + "/files" from the front of the path */
998
770
    var strip = make_path(this_app);
1015
787
        path = username;
1016
788
    }
1017
789
 
1018
 
    return path;
 
790
    navigate(path);
 
791
 
 
792
    /* Set up the console plugin to display as a popup window */
 
793
    console_init(true);
1019
794
}