120
133
* Defaults to "application/x-www-form-urlencoded".
121
134
* "multipart/form-data" is recommended for large uploads.
123
function do_action(action, path, args, content_type)
136
function do_action(action, path, args, content_type, ignore_response)
125
138
args.action = action;
139
/* Callback action, when the server returns */
140
var callback = function(response)
142
/* Check for action errors reported by the server, and report them
144
var error = response.getResponseHeader("X-IVLE-Action-Error");
146
alert("Error: " + error.toString() + ".");
147
/* Now read the response and set up the page accordingly */
148
if (ignore_response != true)
149
handle_response(path, response);
126
151
/* Call the server and perform the action. This mutates the server. */
127
response = ajax_call(service_app, path, args, "POST", content_type);
128
/* Check for action errors reported by the server, and report them to the
130
error = response.getResponseHeader("X-IVLE-Action-Error");
132
alert("Error: " + error.toString() + ".");
133
/* Now read the response and set up the page accordingly */
134
handle_response(path, response);
152
ajax_call(callback, service_app, path, args, "POST", content_type);
137
155
/** Calls the server using Ajax, requesting a directory listing. This should
236
/* This will always return a listing, whether it is a dir or a file.
238
var listing = response.responseText;
239
/* The listing SHOULD be valid JSON text. Parse it into an object. */
242
listing = JSON.parse(listing);
243
file_listing = listing.listing; /* Global */
247
handle_error("The server returned an invalid directory listing");
250
/* Get "." out, it's special */
251
current_file = file_listing["."]; /* Global */
252
delete file_listing["."];
208
254
/* Check if this is a directory listing or file contents */
209
255
var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
210
if (!editmode && isdir)
212
var listing = response.responseText;
213
/* The listing SHOULD be valid JSON text. Parse it into an object. */
216
listing = JSON.parse(listing);
220
handle_error("The server returned an invalid directory listing");
223
258
handle_dir_listing(path, listing);
227
/* Treat this as an ordinary file. Get the file type. */
228
var content_type = response.getResponseHeader("Content-Type");
229
var handler_type = get_handler_type(content_type);
230
/* If we're in "edit mode", always treat this file as text */
231
would_be_handler_type = handler_type;
232
if (editmode) handler_type = "text";
233
/* handler_type should now be set to either
234
* "text", "image", "audio" or "binary". */
235
switch (handler_type)
240
handle_text(path_join(path, "untitled"), "",
241
would_be_handler_type);
245
handle_text(path, response.responseText,
246
would_be_handler_type);
250
/* TODO: Custom image handler */
251
handle_binary(path, response.responseText);
254
/* TODO: Custom audio handler */
255
handle_binary(path, response.responseText);
262
/* Need to make a 2nd ajax call, this time get the actual file
264
callback = function(response)
266
/* Read the response and set up the page accordingly */
267
handle_contents_response(path, response);
269
/* Call the server and request the listing. */
271
args = shallow_clone_object(url_args);
274
/* This time, get the contents of the file, not its metadata */
275
args['return'] = "contents";
276
ajax_call(callback, service_app, path, args, "GET");
278
update_actions(isdir);
281
function handle_contents_response(path, response)
283
/* Treat this as an ordinary file. Get the file type. */
284
var content_type = response.getResponseHeader("Content-Type");
285
var handler_type = get_handler_type(content_type);
286
would_be_handler_type = handler_type;
287
/* handler_type should now be set to either
288
* "text", "image", "audio" or "binary". */
289
switch (handler_type)
292
handle_text(path, response.responseText,
293
would_be_handler_type);
296
/* TODO: Custom image handler */
297
handle_binary(path, response.responseText);
300
/* TODO: Custom audio handler */
301
handle_binary(path, response.responseText);
309
/* Called when a form upload comes back (from an iframe).
310
* Refreshes the page.
312
function upload_callback()
314
/* This has a pretty nasty hack, which happens to work.
315
* upload_callback is set as the "onload" callback for the iframe which
316
* receives the response from the server for uploading a file.
317
* This means it gets called twice. Once when initialising the iframe, and
318
* a second time when the actual response comes back.
319
* All we want to do is call navigate to refresh the page. But we CAN'T do
320
* that on the first load or it will just go into an infinite cycle of
321
* refreshing. We need to refresh the page ONLY on the second refresh.
322
* upload_callback_count is reset to 0 just before the iframe is created.
324
upload_callback_count++;
325
if (upload_callback_count >= 2)
264
329
/** Deletes all "dynamic" content on the page.
284
348
dom_removechildren(document.getElementById("sidepanel"));
287
/** Sets the mode to either "file browser" or "text editor" mode.
288
* This modifies the window icon, and selected tab.
289
* \param editmode If True, editor mode. Else, file browser mode.
291
function setmode(editmode)
293
/* Find the DOM elements for the file browser and editor tabs */
294
var tabs = document.getElementById("apptabs");
295
var tab_files = null;
299
for (var i=0; i<tabs.childNodes.length; i++)
301
/* Find the href of the link within */
302
if (!tabs.childNodes[i].getElementsByTagName) continue;
303
a = tabs.childNodes[i].getElementsByTagName("a");
304
if (a.length == 0) continue;
305
href = a[0].getAttribute("href");
306
if (href == null) continue;
307
if (endswith(href, this_app))
308
tab_files = tabs.childNodes[i];
309
else if (endswith(href, edit_app))
310
tab_edit = tabs.childNodes[i];
315
tab_files.removeAttribute("class");
316
tab_edit.setAttribute("class", "thisapp");
320
tab_edit.removeAttribute("class");
321
tab_files.setAttribute("class", "thisapp");
325
351
/*** HANDLERS for different types of responses (such as dir listing, file,
328
354
function handle_error(message)
331
356
var files = document.getElementById("filesbody");
332
357
var txt_elem = dom_make_text_elem("div", "Error: "
333
358
+ message.toString() + ".")
427
423
div.appendChild(par2);
426
function update_actions()
429
var numsel = selected_files.length;
434
/* Display information about the current directory instead */
435
filename = path_basename(current_path);
438
else if (numsel == 1)
440
filename = selected_files[0];
441
file = file_listing[filename];
444
/* Update each action node in the topbar.
445
* This includes enabling/disabling actions as appropriate, and
446
* setting href/onclick attributes. */
450
/* Available if exactly one file is selected */
451
var open = document.getElementById("act_open");
454
open.setAttribute("class", "choice");
456
open.setAttribute("title",
457
"Navigate to this directory in the file browser");
459
open.setAttribute("title",
460
"Edit or view this file");
461
open.setAttribute("href", app_path(this_app, current_path, filename));
465
open.setAttribute("class", "disabled");
466
open.removeAttribute("title");
467
open.removeAttribute("href");
471
/* Available if exactly one file is selected,
472
* and only if this is a file, not a directory */
473
var serve = document.getElementById("act_serve");
474
if (numsel == 1 && !file.isdir)
476
serve.setAttribute("class", "choice");
477
serve.setAttribute("href",
478
app_path(serve_app, current_path, filename));
482
serve.setAttribute("class", "disabled");
483
serve.removeAttribute("href");
487
/* Available if exactly one file is selected,
488
* and it is a Python file.
494
* If 0 files selected, download the current file or directory as a ZIP.
495
* If 1 directory selected, download it as a ZIP.
496
* If 1 non-directory selected, download it.
497
* If >1 files selected, download them all as a ZIP.
499
var download = document.getElementById("act_download");
504
download.setAttribute("href",
505
app_path(download_app, current_path));
507
download.setAttribute("title",
508
"Download the current directory as a ZIP file");
510
download.setAttribute("title",
511
"Download the current file");
515
download.setAttribute("href",
516
app_path(download_app, current_path, filename));
518
download.setAttribute("title",
519
"Download the selected directory as a ZIP file");
521
download.setAttribute("title",
522
"Download the selected file");
527
/* Make a query string with all the files to download */
528
var dlpath = urlencode_path(app_path(download_app, current_path)) + "?";
529
for (var i=0; i<numsel; i++)
530
dlpath += "path=" + encodeURIComponent(selected_files[i]) + "&";
531
dlpath = dlpath.substr(0, dlpath.length-1);
532
download.setAttribute("href", dlpath);
533
download.setAttribute("title",
534
"Download the selected files as a ZIP file");
537
/* Refresh - No changes required */
539
/* Publish and Submit */
540
/* If this directory is under subversion and selected/unselected file is a
542
var publish = document.getElementById("act_publish");
543
var submit = document.getElementById("act_submit");
544
if (numsel <= 1 && file.isdir)
546
/* 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");
555
publish.setAttribute("class", "disabled");
556
publish.setAttribute("disabled", "disabled");
557
submit.setAttribute("class", "disabled");
558
submit.setAttribute("disabled", "disabled");
562
/* If exactly 1 non-directory file is selected/opened, and its parent
563
* directory is published.
565
var share = document.getElementById("act_share");
566
if (numsel <= 1 && !file.isdir)
568
/* TODO: Work out if parent dir is published */
569
share.setAttribute("class", "choice");
570
share.removeAttribute("disabled");
574
share.setAttribute("class", "disabled");
575
share.setAttribute("disabled", "disabled");
579
/* If exactly 1 file is selected */
580
var rename = document.getElementById("act_rename");
583
rename.setAttribute("class", "choice");
584
rename.removeAttribute("disabled");
588
rename.setAttribute("class", "disabled");
589
rename.setAttribute("disabled", "disabled");
592
/* Delete, cut, copy */
593
/* 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");
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");
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");
616
/* Paste, new file, new directory, upload */
617
/* Always enabled (assuming this is a directory) */
619
/* 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");
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");
637
/** Event handler for when an item of the "More actions..." dropdown box is
638
* selected. Performs the selected action. */
639
function handle_moreactions()
641
var moreactions = document.getElementById("moreactions");
642
if (moreactions.value == "top")
644
var selectedaction = moreactions.value;
645
/* Reset to "More actions..." */
646
moreactions.selectedIndex = 0;
648
/* If 0 files selected, filename is the name of the current dir.
649
* If 1 file selected, filename is that file.
651
if (selected_files.length == 0)
652
filename = path_basename(current_path);
653
else if (selected_files.length == 1)
654
filename = selected_files[0];
658
/* Now handle the selected action */
659
switch(selectedaction)
662
action_publish(selected_files);
665
action_unpublish(selected_files);
669
alert("Not yet implemented: Sharing files");
673
alert("Not yet implemented: Submit");
676
action_rename(filename);
679
action_remove(selected_files);
682
action_copy(selected_files);
685
action_cut(selected_files);
697
show_uploadpanel(true);
700
action_add(selected_files);
703
action_revert(selected_files);
706
action_commit(selected_files);
430
711
/** Called when the page loads initially.
432
713
window.onload = function()