58
55
default_type_icon = "txt.png";
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";
64
61
/* Mapping SVN status to icons, just the file's basename */
66
"unversioned": "unversioned.png",
67
"ignored": null, /* Supposed to be innocuous */
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"
78
72
/* Mapping SVN status to "nice" strings */
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)",
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.
146
function do_action(action, path, args, content_type, callback)
136
function do_action(action, path, args, content_type, ignore_response)
148
138
args.action = action;
149
139
/* Callback action, when the server returns */
150
var callback_inner = function(response)
140
var callback = function(response)
152
142
/* Check for action errors reported by the server, and report them
154
144
var error = response.getResponseHeader("X-IVLE-Action-Error");
155
if (error != null && error != "")
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);
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);
167
157
/** Calls the server using Ajax, requesting a directory listing. This should
310
287
current_file = file_listing["."]; /* Global */
311
288
delete file_listing["."];
313
if ('revision' in listing)
315
current_revision = listing.revision;
318
290
/* Check if this is a directory listing or file contents */
319
291
var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
325
/* Top-level dir, with subjects */
326
special_home_listing(listing, subjects, path);
294
handle_dir_listing(path, listing);
298
/* Need to make a 2nd ajax call, this time get the actual file
300
callback = function(response)
302
/* Read the response and set up the page accordingly */
303
handle_contents_response(path, response);
305
/* Call the server and request the listing. */
307
args = shallow_clone_object(url_args);
330
/* Not the top-level dir. Do a normal dir listing. */
331
handle_dir_listing(path, listing.listing);
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);
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");
341
314
update_actions(isdir);
344
function handle_contents_response(path, content_type)
317
function handle_contents_response(path, response)
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)
354
handle_text(path, content_type);
328
handle_text(path, response.responseText,
329
would_be_handler_type);
360
handle_html5_media(path, content_type, "video");
332
/* TODO: Custom image handler */
333
handle_binary(path, response.responseText);
363
handle_html5_media(path, content_type, "audio");
366
handle_object(path, content_type);
336
/* TODO: Custom audio handler */
337
handle_binary(path, response.responseText);
369
340
handle_binary(path);
554
490
div.appendChild(par2);
557
/** Displays an image file.
559
function handle_image(path)
561
/* Disable save button */
562
using_codepress = false;
566
var url = app_url(service_app, path) + "?return=contents";
569
var img = $("<img />");
570
img.attr("alt", path);
571
img.attr("src", url);
574
var div = $('<div class="padding" />');
575
div.append('<h1>Image Preview</h1>');
577
$("#filesbody").append(div);
580
/* Displays a media file using an HTML5 <audio> or <video> tag.
581
* Falls back to <object> if the format is unsupported.
583
function handle_html5_media(path, type, tag_name)
585
/* Disable save button and hide the save panel */
586
using_codepress = false;
590
var url = app_url(service_app, path) + "?return=contents";
591
var download_url = app_url(download_app, path);
593
/* Fallback download 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);
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));
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.
609
if (support == "probably" || support == "maybe") {
610
var element = html5_element;
612
var element = $('<object />');
613
element.attr("type", type);
614
element.attr("data", url);
616
element.append(link);
619
var div = $('<div class="padding" />');
620
div.append('<h1>File preview</h1>');
622
$("#filesbody").append(div);
625
/** Display generic object content
627
function handle_object(path, content_type)
629
/* Disable save button and hide the save panel */
630
using_codepress = false;
634
var url = app_url(service_app, path) + "?return=contents";
635
var download_url = app_url(download_app, path);
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);
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');
650
var div = $('<div class="padding" />');
651
div.append('<h1>Preview</h1>');
654
$("#filesbody").append(div);
657
/* Present an element for the given path.
658
* Gives it a title and download link.
660
function present_custom_handler(path, type, element)
662
/* Disable save button and hide the save panel */
663
using_codepress = false;
667
var url = app_url(service_app, path) + "?return=contents";
668
var download_url = app_url(download_app, path);
670
/* Fallback download 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);
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));
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.
686
if (support == "probably" || support == "maybe") {
687
var element = html5_element;
689
var element = $('<object />');
690
element.attr("type", type);
691
element.attr("data", url);
693
element.append(link);
696
var div = $('<div class="padding" />');
697
div.append('<h1>File preview</h1>');
699
$("#filesbody").append(div);
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)
706
497
if (!(names instanceof Array)) names = Array(names);
708
499
for (var i=0; i < names.length; i++)
710
501
element = document.getElementById('act_' + names[i]);
712
!(current_file.svnstatus == 'revision' && !allow_on_revision))
715
505
element.setAttribute("class", "choice");
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)
792
567
serve.setAttribute("class", "choice");
793
568
serve.setAttribute("onclick",
794
569
"return maybe_save('The last saved version will be served.')");
796
571
serve.setAttribute("href",
797
app_url(serve_app, current_path));
572
app_path(serve_app, current_path));
799
574
serve.setAttribute("href",
800
app_url(serve_app, current_path, filename));
575
app_path(serve_app, current_path, filename));
838
/* Always available for current files.
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.
844
618
var download = document.getElementById("act_download");
845
if (current_file.svnstatus == 'revision')
847
download.setAttribute("class", "disabled");
848
download.removeAttribute("onclick");
850
else if (numsel <= 1)
852
download.setAttribute("class", "choice")
855
623
download.setAttribute("href",
856
app_url(download_app, current_path));
624
app_path(download_app, current_path));
858
626
download.setAttribute("title",
859
627
"Download the current directory as a ZIP file");
896
663
var pubcond = numsel <= 1 && file.isdir;
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)
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";
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";
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));
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
950
single_versioned_path = (
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);
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");
960
/* Log should be available for revisions as well. */
961
set_action_state("svnlog", single_versioned_path, true);
963
/* Cleanup should be available for revisions as well. */
964
set_action_state("svncleanup", single_versioned_path, true);
966
single_ivle_versioned_path = (
968
(numsel == 1 && (stat = file_listing[selected_files[0]])) ||
969
(numsel == 0 && (stat = current_file))
970
) && svnstatus_versioned(stat.svnstatus)
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);
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");
714
/* current_path == username: We are at the top level */
715
set_action_state("svncheckout", current_path == username);
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
1021
768
action_unpublish(selected_files);
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')
1027
if (selected_files.length == 1)
1028
stat = file_listing[selected_files[0]];
1030
stat = current_file;
1031
url = stat.svnurl.substr(svn_base.length); // URL-encoded
1032
path = decodeURIComponent(url);
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},
1043
window.location = path_join(app_path('+submit'), url) + '?revision=' + result.svnrevision;
776
alert("Not yet implemented: Submit");
1049
779
action_rename(filename);
1052
action_delete(selected_files);
782
action_remove(selected_files);
1055
785
action_copy(selected_files);
1073
803
action_add(selected_files);
1076
action_svnremove(selected_files);
1079
action_svnrename(selected_files);
1081
805
case "svnrevert":
1082
806
action_revert(selected_files);
1085
window.location = path_join(app_url('diff'), current_path, selected_files[0] || '');
1088
action_update(selected_files);
1091
action_resolved(selected_files);
809
window.location = path_join(app_path('diff'), current_path, selected_files[0]);
1093
811
case "svncommit":
1094
812
action_commit(selected_files);
1097
window.location = path_join(app_url('svnlog'), current_path, selected_files[0] || '');
1100
action_svncopy(selected_files);
1103
action_svncut(selected_files);
1106
action_svncleanup(".");
815
window.location = path_join(app_path('svnlog'), current_path, selected_files[0]);