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

209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
1
/* IVLE - Informatics Virtual Learning Environment
2
 * Copyright (C) 2007-2008 The University of Melbourne
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 2 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
 *
18
 * Module: Listing (File Browser, client)
19
 * Author: Matt Giuca
20
 * Date: 13/1/2008
21
 *
22
 * Handles directory listings on the client side.
23
 */
24
234 by mattgiuca
browser/listing.js:
25
/* Note: The DOM "tr" nodes of the file listing have extra attributes added
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
26
 * to them:
27
 *  filename: String.
28
 *  fileinfo: The file object as returned by the server.
29
 */
215 by mattgiuca
listing.js:
30
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
31
/* DOM nodeType constants */
32
ELEMENT_NODE = 1;
33
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
34
/** The current sort order (a list of fields to sort by, in order of
35
 * priority), and whether it is ascending or descending. */
36
sort_order = [];
37
sort_ascending = true;
38
229 by mattgiuca
Images: Reduced "small" icons from 22x22 to 16x16. Reduced "large" icons from
39
/** The width/height of filetype, svnstatus and publishstatus icons */
40
icon_size = 16;
41
215 by mattgiuca
listing.js:
42
/** ACTIONS **/
43
44
function action_rename(fromfilename)
45
{
219 by mattgiuca
Browser.js: Added handlers for subversion actions.
46
    var tofilename = prompt("Rename file \"" + fromfilename + "\" to?");
215 by mattgiuca
listing.js:
47
    if (tofilename == null) return;
48
    do_action("move", current_path, {"from":fromfilename, "to":tofilename});
49
    return false;
50
}
51
52
function action_remove(files)
53
{
54
    do_action("remove", current_path, {"path":files});
55
    return false;
56
}
57
592 by mattgiuca
fileservice, browser/listing: Added new fileservice action, "mkdir".
58
function action_mkdir()
59
{
60
    var path = prompt("New directory name?");
61
    if (path == null) return;
62
    do_action("mkdir", current_path, {"path":path});
63
    return false;
64
}
65
611 by mattgiuca
"New File" now works. (This is a MUCH better replacement for having to go to
66
function action_newfile()
67
{
68
    var path = prompt("New file name?");
69
    if (path == null) return;
70
    /* "Upload" a blank file */
71
    do_action("putfile", current_path, {"path":path, "data":""});
72
    return false;
73
}
74
215 by mattgiuca
listing.js:
75
function action_copy(files)
76
{
77
    do_action("copy", current_path, {"path":files});
78
    return false;
79
}
80
81
function action_cut(files)
82
{
83
    do_action("cut", current_path, {"path":files});
84
    return false;
85
}
86
87
function action_paste()
88
{
89
    do_action("paste", current_path, {"path":"."});
90
    return false;
91
}
92
219 by mattgiuca
Browser.js: Added handlers for subversion actions.
93
function action_add(files)
94
{
95
    do_action("svnadd", current_path, {"path":files});
96
    return false;
97
}
98
99
function action_revert(files)
100
{
101
    do_action("svnrevert", current_path, {"path":files});
102
    return false;
103
}
104
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
105
function action_publish(files)
106
{
107
    do_action("svnpublish", current_path, {"path":files});
108
    return false;
109
}
110
111
function action_unpublish(files)
112
{
113
    do_action("svnunpublish", current_path, {"path":files});
114
    return false;
115
}
116
219 by mattgiuca
Browser.js: Added handlers for subversion actions.
117
function action_commit(files)
118
{
119
    /* Get a commit log from the user */
120
    var logmsg = prompt("Enter commit log:");
223 by mattgiuca
util.js: Added "urlencode_path" which is specially designed to encode paths.
121
    if (logmsg == null) return;
219 by mattgiuca
Browser.js: Added handlers for subversion actions.
122
    do_action("svncommit", current_path, {"path":files, "logmsg": logmsg});
123
    return false;
124
}
125
387 by mattgiuca
Implemented file uploads.
126
/* Shows or hides the "upload panel" in the side panel.
127
 * toshow is true for showing, false for hiding.
128
 */
388 by mattgiuca
browser/listing: Upload button now toggles the upload panel instead of just
129
uploadpanel_shown = false;
387 by mattgiuca
Implemented file uploads.
130
function show_uploadpanel(toshow)
131
{
388 by mattgiuca
browser/listing: Upload button now toggles the upload panel instead of just
132
    if (toshow == null)
133
        uploadpanel_shown = !uploadpanel_shown;
134
    else
135
        uploadpanel_shown = toshow;
387 by mattgiuca
Implemented file uploads.
136
    document.getElementById("uploadpanel").setAttribute("style",
388 by mattgiuca
browser/listing: Upload button now toggles the upload panel instead of just
137
        "display: " + (uploadpanel_shown ? "auto" : "none") + ";");
387 by mattgiuca
Implemented file uploads.
138
    return false;
139
}
140
141
/* Called when a form upload comes back (from an iframe).
142
 * Refreshes the page.
143
 */
144
function upload_callback()
145
{
146
    /* This has a pretty nasty hack, which happens to work.
147
     * upload_callback is set as the "onload" callback for the iframe which
148
     * receives the response from the server for uploading a file.
149
     * This means it gets called twice. Once when initialising the iframe, and
150
     * a second time when the actual response comes back.
151
     * All we want to do is call navigate to refresh the page. But we CAN'T do
152
     * that on the first load or it will just go into an infinite cycle of
153
     * refreshing. We need to refresh the page ONLY on the second refresh.
154
     * upload_callback_count is reset to 0 just before the iframe is created.
155
     */
156
    upload_callback_count++;
157
    if (upload_callback_count == 2)
158
    {
159
        navigate(current_path);
160
        /* Keep upload panel open */
161
        show_uploadpanel(true);
162
    }
163
}
164
215 by mattgiuca
listing.js:
165
/** END ACTIONS **/
166
597 by mattgiuca
Major refactor of actions in File browser.
167
/** Updates the side-panel AND the actions in the top-bar. Expects selected_files
168
 * reflects the current selected files.
211 by mattgiuca
fileservice/listing: Slight change to date format.
169
 */
170
function update_sidepanel(total_file_size_sel)
171
{
172
    var sidepanel = document.getElementById("sidepanel");
173
    var filename;
174
    var file;
175
    var p;
387 by mattgiuca
Implemented file uploads.
176
    var div;
211 by mattgiuca
fileservice/listing: Slight change to date format.
177
    /* Is this dir under svn? */
602 by mattgiuca
util.js: Added shallow_copy_object function.
178
    var under_subversion = "svnstatus" in current_file;
211 by mattgiuca
fileservice/listing: Slight change to date format.
179
    dom_removechildren(sidepanel);
180
    if (selected_files.length <= 1)
181
    {
182
        if (selected_files.length == 0)
183
        {
184
            /* Display information about the current directory instead */
185
            filename = path_basename(current_path);
602 by mattgiuca
util.js: Added shallow_copy_object function.
186
            file = current_file;
211 by mattgiuca
fileservice/listing: Slight change to date format.
187
        }
188
        else if (selected_files.length == 1)
189
        {
215 by mattgiuca
listing.js:
190
            filename = selected_files[0];
211 by mattgiuca
fileservice/listing: Slight change to date format.
191
            file = file_listing[filename];
192
        }
193
        var filetype;
194
        if ("isdir" in file && file.isdir)
195
            filetype = "text/directory";
196
        else if ("type" in file)
197
            filetype = file.type;
198
        else
199
            filetype = "text/plain";
200
213 by mattgiuca
Fileservice / Files (Python and JS files):
201
        if ("type_nice" in file)
202
            filetype_nice = file.type_nice;
203
        else
204
            filetype_nice = "File";
205
211 by mattgiuca
fileservice/listing: Slight change to date format.
206
        p = document.createElement("p");
207
        sidepanel.appendChild(p);
208
        p.appendChild(dom_make_img(mime_type_to_icon(filetype, true),
209
            null, null, filetype));
210
        p = dom_make_text_elem("h2", filename);
211
        sidepanel.appendChild(p);
213 by mattgiuca
Fileservice / Files (Python and JS files):
212
        p = dom_make_text_elem("p", filetype_nice);
211 by mattgiuca
fileservice/listing: Slight change to date format.
213
        sidepanel.appendChild(p);
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
214
        var mini_icons = document.createElement("p");
215
        sidepanel.appendChild(mini_icons);
216
        var icon;
213 by mattgiuca
Fileservice / Files (Python and JS files):
217
        if (under_subversion)
218
        {
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
219
            icon = svnstatus_to_icon(file.svnstatus);
230 by mattgiuca
Removed "unversioned" icon from subversion status. Now unversioned files do
220
            if (icon)
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
221
                mini_icons.appendChild(dom_make_img(icon, icon_size, icon_size,
230 by mattgiuca
Removed "unversioned" icon from subversion status. Now unversioned files do
222
                    svnstatus_to_string(file.svnstatus)));
213 by mattgiuca
Fileservice / Files (Python and JS files):
223
            p = dom_make_text_elem("p", svnstatus_to_string(file.svnstatus));
224
            sidepanel.appendChild(p);
225
        }
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
226
        if ("published" in file && file.published)
227
        {
228
            icon = make_path(path_join(published_icon));
229
            if (icon)
230
            {
231
                if (mini_icons.childNodes.length > 0)
232
                    mini_icons.appendChild(document.createTextNode(" "));
233
                mini_icons.appendChild(dom_make_img(icon, icon_size, icon_size,
327 by mattgiuca
browser: Renamed "Published directory" label to "Published to the web".
234
                    "Published to the web"));
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
235
            }
327 by mattgiuca
browser: Renamed "Published directory" label to "Published to the web".
236
            p = dom_make_text_elem("p", "Published to the web");
269 by mattgiuca
browser: Added publish functionality to JavaScript client side.
237
            p.setAttribute("title",
238
                "Anybody on the web can view the files in this directory.");
239
            sidepanel.appendChild(p);
240
        }
241
        /* If we never wrote any mini-icons, remove this element */
242
        if (mini_icons.childNodes.length == 0)
243
            sidepanel.removeChild(mini_icons);
211 by mattgiuca
fileservice/listing: Slight change to date format.
244
        if ("size" in file)
245
        {
246
            p = dom_make_text_elem("p", "Size: " + nice_filesize(file.size));
247
            sidepanel.appendChild(p);
248
        }
249
        if ("mtime_nice" in file)
250
        {
608 by mattgiuca
browser/listing: REMOVED the generation of all action links to the right
251
            /* Break into lines on comma (separating date from time) */
252
            filetime_lines = file.mtime_nice.split(",");
253
            p = document.createElement("p");
254
            p.appendChild(document.createTextNode("Modified:"));
255
            for (var i=0; i<filetime_lines.length; i++)
256
            {
257
                p.appendChild(document.createElement("br"));
258
                p.appendChild(document.createTextNode(filetime_lines[i]));
259
            }
211 by mattgiuca
fileservice/listing: Slight change to date format.
260
            sidepanel.appendChild(p);
261
        }
262
    }
263
    else
264
    {
265
        /* Multiple files selected */
266
        p = document.createElement("p");
267
        sidepanel.appendChild(p);
268
        p.appendChild(dom_make_img(
224 by mattgiuca
util.js: Removed urlencoding support from "encoded_app_path" (now called
269
            app_path(type_icons_path_large, "multi.png"),
211 by mattgiuca
fileservice/listing: Slight change to date format.
270
            null, null, "Multiple files"));
271
        p = dom_make_text_elem("h2",
272
            selected_files.length.toString() + " files selected");
273
        sidepanel.appendChild(p);
274
        p = dom_make_text_elem("p", "Total size: "
275
            + nice_filesize(total_file_size_sel));
276
        sidepanel.appendChild(p);
277
    }
278
608 by mattgiuca
browser/listing: REMOVED the generation of all action links to the right
279
    /* TEMPORARY: Move to top bar */
387 by mattgiuca
Implemented file uploads.
280
    /* The "Upload" button expands the following panel with upload tools */
281
    /* This panel has a form for submitting the file to, and an iframe to load
282
     * the target page in (this avoids the entire page being refreshed) */
283
    div = document.createElement("div");
284
    div.setAttribute("id", "uploadpanel");
285
    /* This deliberately hides the upload panel whenever the selection
286
     * changes. It can be re-shown by clicking "upload". */
287
    div.setAttribute("style", "display: none;");
288
    sidepanel.appendChild(div);
289
    p = dom_make_text_elem("h3", "Upload File");
290
    div.appendChild(p);
291
    var form = document.createElement("form");
292
    form.setAttribute("method", "POST");
293
    form.setAttribute("enctype", "multipart/form-data");
294
    form.setAttribute("action", app_path("fileservice", current_path));
295
    form.setAttribute("target", "upload_iframe");
296
    div.appendChild(form);
297
    var input;
298
    input = document.createElement("input");
299
    input.setAttribute("type", "hidden");
300
    input.setAttribute("name", "action");
301
    input.setAttribute("value", "putfiles");
302
    form.appendChild(input);
303
304
    input = document.createElement("input");
305
    input.setAttribute("type", "hidden");
306
    input.setAttribute("name", "path");
307
    input.setAttribute("value", "");
308
    form.appendChild(input);
309
310
    p = document.createElement("p");
311
    form.appendChild(p);
312
    input = document.createElement("input");
313
    input.setAttribute("type", "file");
314
    input.setAttribute("name", "data");
608 by mattgiuca
browser/listing: REMOVED the generation of all action links to the right
315
    input.setAttribute("size", "10");
387 by mattgiuca
Implemented file uploads.
316
    p.appendChild(input);
317
318
    p = document.createElement("p");
319
    form.appendChild(p);
320
    input = document.createElement("input");
390 by mattgiuca
Added automatic unzipping on file upload.
321
    input.setAttribute("type", "checkbox");
322
    input.setAttribute("name", "unpack");
323
    input.setAttribute("value", "true");
324
    input.setAttribute("checked", "on");
325
    p.appendChild(input);
326
    p.appendChild(document.createTextNode(" Unpack zip file"));
327
328
    p = document.createElement("p");
329
    form.appendChild(p);
330
    input = document.createElement("input");
387 by mattgiuca
Implemented file uploads.
331
    input.setAttribute("type", "button");
332
    input.setAttribute("value", "Hide");
333
    input.setAttribute("onclick", "show_uploadpanel(false)");
334
    p.appendChild(input);
335
    p.appendChild(document.createTextNode(" "));
336
    input = document.createElement("input");
337
    input.setAttribute("type", "submit");
338
    input.setAttribute("value", "Send");
339
    p.appendChild(input);
340
341
    /* Now we create an invisible iframe which will receive the upload.
342
     * The form submits to fileservice, loading the result into this iframe
343
     * instead of the whole browser window (this is an alternative to Ajax,
344
     * since Ajax doesn't allow reading the file from the user's disk).
345
     * Note this iframe's id is the same as the form's target.
346
     */
347
    var upload_iframe = document.createElement("iframe");
348
    upload_iframe.setAttribute("id", "upload_iframe");
349
    upload_iframe.setAttribute("name", "upload_iframe");
350
    upload_iframe.setAttribute("style", "display: none;");
351
    /* When we get a callback, simply cause a nav to the current path, so we
352
     * update the directory listing. */
353
    upload_callback_count = 0;      /* See upload_callback */
354
    upload_iframe.setAttribute("onload", "upload_callback()");
355
    div.appendChild(upload_iframe);
356
    /* END Upload panel */
211 by mattgiuca
fileservice/listing: Slight change to date format.
357
}
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
358
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
359
/** Updates the side-panel and status bar to reflect the current set of
360
 * selected files. This is done by inspecting the states of the check boxes.
361
 * Also changes the styling to highlight selected files.
362
 */
363
function update_selection()
364
{
365
    /* First get a list of all files that are selected, and
366
     * reset the styling on each file's row. */
367
    var files_children = document.getElementById("files").childNodes;
368
    var tr;
369
    var checkbox;
370
    var row_toggle = 1;
371
    selected_files = [];  /* Clear global selected_files */
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
372
373
    var total_file_size = 0;    /* In bytes */
374
    var total_file_size_sel = 0;
375
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
376
    /* Children are trs */
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
377
    var filename;
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
378
    var file;
379
    if (file_listing == null) return;
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
380
    for (var i=0; i<files_children.length; i++)
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
381
    {
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
382
        filename = files_children[i].filename;
383
        file = files_children[i].fileinfo;
384
        /* Count total file size so we can write to the status bar later
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
385
         */
386
        if ("size" in file)
387
            total_file_size += file.size;
388
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
389
        tr = files_children[i];
390
        checked = tr.firstChild.firstChild.checked;
391
        /* Set the class for every row based on both the checked state,
392
         * and whether it is odd or even */
393
        tr.setAttribute("class", "row" + row_toggle.toString() +
394
            (checked ? "sel" : ""))
395
        row_toggle = row_toggle == 1 ? 2 : 1;
396
        if (checked)
397
        {
398
            /* Add the filename (column 3) to the selected_files list */
399
            selected_files[selected_files.length] = filename;
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
400
            if ("size" in file)
401
                total_file_size_sel += file.size;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
402
        }
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
403
    }
404
597 by mattgiuca
Major refactor of actions in File browser.
405
    /* Write to the side-panel and actions bar */
406
    update_actions();
211 by mattgiuca
fileservice/listing: Slight change to date format.
407
    update_sidepanel(total_file_size_sel);
408
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
409
    /* Write to the status bar */
410
    var statusbar = document.getElementById("statusbar");
411
    var statusmsg;
412
    var file_plural;
413
    if (selected_files.length > 0)
414
    {
415
        statusmsg = selected_files.length.toString() + " file"
416
            + (selected_files.length == 1 ? "" : "s") + " selected, "
417
            + nice_filesize(total_file_size_sel);
418
    }
419
    else
420
    {
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
421
        statusmsg = files_children.length.toString() + " file"
422
            + (files_children.length == 1 ? "" : "s") + ", "
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
423
            + nice_filesize(total_file_size);
424
    }
425
    dom_removechildren(statusbar);
426
    statusbar.appendChild(document.createTextNode(statusmsg));
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
427
}
428
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
429
/** SORTING FUNCTIONS **/
430
431
/** Sorts the file table. Physically manipulates the DOM table to reflect the
432
 * sorted nodes, and also updates the little sort arrow.
433
 *
434
 * \param sort_field The name of the field to sort on primarily. This can
435
 * either be "filename", or one of the fields of a fileinfo object. Note that
436
 * while this determines the primary sort key, the secondary sort keys are
437
 * determined by the global sort_order. Calling sort_listing reorders
438
 * sort_order, bringing the specified sort_field to the top.
439
 * Also note that sorting by "isdir" is more prominent than whatever field is
440
 * provided here.
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
441
 * \param ascending If true, sorts ascending. If false, descending.
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
442
 */
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
443
function sort_listing(sort_field, ascending)
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
444
{
445
    var i;
446
    var files = document.getElementById("files");
447
    var files_children = files.childNodes;
448
    var files_array = new Array(files_children.length);
449
    /* Update sort_order, bringing sort_field to the top. */
557 by agdimech
/browser/listing.js: Fixed ascending/descending functionality when clicked.
450
    if(sort_order[sort_order.length-1] == sort_field)
451
    {
452
        sort_ascending = ascending != false ? true : false;
453
    }
454
    else
455
    {
456
        sort_ascending = true;
457
        sort_order.removeall(sort_field);
458
        sort_order.push(sort_field);
459
    }
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
460
461
    /* Build an array of DOM tr elements (with the additional 'filename' and
462
     * 'fileinfo' attributes as written when the listing is created). */
463
    /* Note: Must manually create an array from files_children, which is a DOM
464
     * NodeList, not an array. */
465
    for (i=0; i<files_children.length; i++)
466
        files_array[i] = files_children[i];
467
468
    /* Sort this array */
469
    files_array.sort(compare_files);
470
471
    /* Clean out the table (the TRs are safely stored in the array) */
472
    dom_removechildren(files);
473
474
    /* Insert the TRs back into the table, in their sorted order */
475
    for (i=0; i<files_array.length; i++)
476
        files.appendChild(files_array[i]);
477
478
    /* Fix the coloring classes on the rows so they are interleaved. */
479
    update_selection();
480
481
    return false;
482
}
483
484
/** Comparison function used for sorting. Compares two DOM tr nodes (with
485
 * the additional 'filename' and 'fileinfo' attributes as written when the
486
 * listing is created).
487
 * Returns an integer, which is -1 if a < b, 0 if a == b, and 1 if a > b.
488
 * The fields to compare by are determined by the global variable sort_order.
489
 */
490
function compare_files(a, b)
491
{
236 by mattgiuca
listing.js: Correct sorting by directory. (Now sorts all directories to the
492
    /* First sort by whether or not it is a directory */
493
    var aisdir = a.fileinfo.isdir == true;
494
    var bisdir = b.fileinfo.isdir == true;
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
495
    var LESS = sort_ascending == true ? -1 : 1;
496
    var GREATER = -LESS;
497
    if (aisdir > bisdir) return LESS;
498
    else if (aisdir < bisdir) return GREATER;
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
499
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
500
    /* Reverse order of sort_order. (top is highest priority) */
501
    for (var i=sort_order.length-1; i>=0; i--)
502
    {
503
        var field = sort_order[i];
504
        if (field == "filename")
505
        {
506
            if (a.filename < b.filename) return LESS;
507
            else if (a.filename > b.filename) return GREATER;
508
        }
509
        else
510
        {
511
            /* null > anything else (so it appears at the bottom) */
543 by agdimech
browser/listing.js: Fixed sorting for date and size by adding .fileinfo
512
            if (!(field in a.fileinfo))
555 by agdimech
browser/listing.js: Fixed priority queue for sorting due to layout issues.
513
            {
514
                if (field in b.fileinfo)
515
                    return GREATER;
516
                else
517
                    break;
518
            }
543 by agdimech
browser/listing.js: Fixed sorting for date and size by adding .fileinfo
519
            if (!(field in b.fileinfo)) return LESS;
240 by mattgiuca
browser/listing.js: Wrote real comparison function and set up sort_order array
520
            if (a.fileinfo[field] < b.fileinfo[field]) return LESS;
521
            else if (a.fileinfo[field] > b.fileinfo[field]) return GREATER;
522
        }
523
    }
235 by mattgiuca
listing.js: Added sorting functions and a bit of infrastructure to facilitate
524
525
    return 0;
526
}
527
528
/** END SORTING **/
529
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
530
/** Clears all selected files and causes the single file specified to become
531
 * selected.
234 by mattgiuca
browser/listing.js:
532
 * \param filename The file in the list to select.
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
533
 */
234 by mattgiuca
browser/listing.js:
534
function select_file(filename)
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
535
{
536
    var files_children = document.getElementById("files").childNodes;
537
    var checkbox;
234 by mattgiuca
browser/listing.js:
538
    var tr;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
539
    for (var i=0; i<files_children.length; i++)
540
    {
541
        tr = files_children[i];
542
        checkbox = tr.firstChild.firstChild;
234 by mattgiuca
browser/listing.js:
543
        checkbox.checked = tr.filename == filename;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
544
    }
545
    update_selection();
546
}
547
548
/** Initialises the DOM elements required to present a dir listing,
549
 * assuming that clear_page has just been called or the page just
550
 * loaded for the first time.
551
 */
552
function setup_for_dir_listing()
553
{
554
    var filesbody = document.getElementById("filesbody");
555
381 by mattgiuca
media/browser/listing.js: Replaced table-based layout in file listing with
556
    /* There are 2 divs in the filesbody: middle and statusbar
557
     * middle has 2 divs: filetable, sidepanel
558
     */
559
    /* Middle */
560
    var middle = document.createElement("div");
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
561
    filesbody.appendChild(middle);
562
    middle.setAttribute("id", "middle");
381 by mattgiuca
media/browser/listing.js: Replaced table-based layout in file listing with
563
    /* File table */
564
    var filetable = document.createElement("div");
565
    middle.appendChild(filetable);
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
566
    filetable.setAttribute("id", "filetable");
567
    var filetablediv = document.createElement("div");
568
    filetable.appendChild(filetablediv);
569
    filetablediv.setAttribute("id", "filetablediv");
570
    /* A nested table within this div - the actual files listing */
571
    var filetabletable = document.createElement("table");
572
    filetablediv.appendChild(filetabletable);
573
    filetabletable.setAttribute("width", "100%");
574
    var filetablethead = document.createElement("thead");
575
    filetabletable.appendChild(filetablethead);
576
    var filetablethead_tr = document.createElement("tr");
577
    filetablethead.appendChild(filetablethead_tr);
578
    filetablethead_tr.setAttribute("class", "rowhead");
579
    /* Row headers */
580
    var filetablethead_th = document.createElement("th");
581
    filetablethead_tr.appendChild(filetablethead_th);
582
    filetablethead_th.setAttribute("class", "col-check");
583
    filetablethead_th = dom_make_link_elem("th", "Filename",
545 by agdimech
browser/listing.js: Fixed part of the ascending/descending sort however it doesnt take into account changes in primary key.
584
        "Sort by filename", null,
585
	"return sort_listing(\"filename\", !sort_ascending)");
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
586
    filetablethead_tr.appendChild(filetablethead_th);
587
    filetablethead_th.setAttribute("class", "col-filename");
588
    filetablethead_th.setAttribute("colspan", 3);
589
    filetablethead_th = dom_make_link_elem("th", "Size",
545 by agdimech
browser/listing.js: Fixed part of the ascending/descending sort however it doesnt take into account changes in primary key.
590
        "Sort by file size", null, "return sort_listing(\"size\",!sort_ascending)");
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
591
    filetablethead_tr.appendChild(filetablethead_th);
592
    filetablethead_th.setAttribute("class", "col-size");
593
    filetablethead_th = dom_make_link_elem("th", "Modified",
545 by agdimech
browser/listing.js: Fixed part of the ascending/descending sort however it doesnt take into account changes in primary key.
594
        "Sort by date modified", null, "return sort_listing(\"mtime\",!sort_ascending)");
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
595
    filetablethead_tr.appendChild(filetablethead_th);
596
    filetablethead_th.setAttribute("class", "col-date");
597
    /* Empty body */
598
    var filetabletbody = document.createElement("tbody");
599
    filetabletable.appendChild(filetabletbody);
600
    filetabletbody.setAttribute("id", "files");
601
381 by mattgiuca
media/browser/listing.js: Replaced table-based layout in file listing with
602
    /* Side-panel */
603
    /* 2 nested divs, so we can set the width exactly and have padding inside
604
     * of that */
605
    var sidepanel_outer = document.createElement("div");
606
    middle.appendChild(sidepanel_outer);
607
    sidepanel_outer.setAttribute("id", "sidepanel_outer");
608
    var sidepanel = document.createElement("div");
609
    sidepanel_outer.appendChild(sidepanel);
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
610
    sidepanel.setAttribute("id", "sidepanel");
611
612
    /* Now after the table "middle", there is a status bar */
381 by mattgiuca
media/browser/listing.js: Replaced table-based layout in file listing with
613
    var statusbar_outer = document.createElement("div");
614
    filesbody.appendChild(statusbar_outer);
615
    statusbar_outer.setAttribute("id", "statusbar_outer");
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
616
    var statusbar = document.createElement("div");
381 by mattgiuca
media/browser/listing.js: Replaced table-based layout in file listing with
617
    statusbar_outer.appendChild(statusbar);
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
618
    statusbar.setAttribute("id", "statusbar");
619
}
620
621
/** Presents the directory listing.
622
 */
623
function handle_dir_listing(path, listing)
624
{
625
    setup_for_dir_listing();
626
    var row_toggle = 1;
627
    /* Nav through the top-level of the JSON to the actual listing object. */
628
    var listing = listing.listing;
629
630
    /* Is this dir under svn? */
602 by mattgiuca
util.js: Added shallow_copy_object function.
631
    var under_subversion = "svnstatus" in current_file;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
632
633
    var files = document.getElementById("files");
634
    var file;
635
    var row;
636
    var td;
637
    var checkbox;
638
639
    var selection_string;
640
386 by mattgiuca
browser/listing: Fixed long-standing bug, files get deselected when you
641
    /* Convert selected_files array into a dictionary which can be efficiently
642
     * searched. */
643
    sel_files_dict = {};
644
    for (var i=0; i<selected_files.length; i++)
645
    {
646
        sel_files_dict[selected_files[i]] = true;
647
    }
648
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
649
    /* Create all of the files */
650
    for (var filename in listing)
651
    {
234 by mattgiuca
browser/listing.js:
652
        selection_string = "select_file(" + repr(filename) + ")";
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
653
        file = listing[filename];
234 by mattgiuca
browser/listing.js:
654
        /* Make a 'tr' element. Store the filename and fileinfo in
655
         * here. */
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
656
        row = document.createElement("tr");
234 by mattgiuca
browser/listing.js:
657
        row.filename = filename;
658
        row.fileinfo = file;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
659
        /* Column 1: Selection checkbox */
660
        row.setAttribute("class", "row" + row_toggle.toString())
661
        row_toggle = row_toggle == 1 ? 2 : 1;
662
        td = document.createElement("td");
663
        checkbox = document.createElement("input");
664
        checkbox.setAttribute("type", "checkbox");
665
        checkbox.setAttribute("title", "Select this file");
666
        checkbox.setAttribute("onchange", "update_selection()");
386 by mattgiuca
browser/listing: Fixed long-standing bug, files get deselected when you
667
        /* Check the box if selected_files says it's selected */
668
        checkbox.checked = filename in sel_files_dict;
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
669
        td.appendChild(checkbox);
670
        row.appendChild(td);
671
        if (file.isdir)
672
        {
673
            /* Column 2: Filetype and subversion icons. */
674
            td = document.createElement("td");
675
            td.setAttribute("class", "thincol");
676
            td.setAttribute("onclick", selection_string);
677
            td.appendChild(dom_make_img(mime_type_to_icon("text/directory"),
229 by mattgiuca
Images: Reduced "small" icons from 22x22 to 16x16. Reduced "large" icons from
678
                icon_size, icon_size, file.type_nice));
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
679
            row.appendChild(td);
680
            td = document.createElement("td");
681
            td.setAttribute("class", "thincol");
682
            if (under_subversion)
230 by mattgiuca
Removed "unversioned" icon from subversion status. Now unversioned files do
683
            {
684
                var icon = svnstatus_to_icon(file.svnstatus);
685
                if (icon)
686
                    td.appendChild(dom_make_img(icon, icon_size, icon_size,
687
                        svnstatus_to_string(file.svnstatus)));
688
            }
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
689
            row.appendChild(td);
690
            /* Column 3: Filename */
691
            td = dom_make_link_elem("td", filename,
692
                "Navigate to " + path_join(path, filename),
224 by mattgiuca
util.js: Removed urlencoding support from "encoded_app_path" (now called
693
                app_path(this_app, path, filename)/*,
215 by mattgiuca
listing.js:
694
                "navigate(" + repr(path_join(path, filename)) + ")"*/);
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
695
            td.setAttribute("onclick", selection_string);
696
            row.appendChild(td);
697
        }
698
        else
699
        {
700
            /* Column 2: Filetype and subversion icons. */
701
            td = document.createElement("td");
702
            td.setAttribute("class", "thincol");
703
            td.appendChild(dom_make_img(mime_type_to_icon(file.type),
229 by mattgiuca
Images: Reduced "small" icons from 22x22 to 16x16. Reduced "large" icons from
704
                icon_size, icon_size, file.type_nice));
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
705
            row.appendChild(td);
706
            td = document.createElement("td");
707
            td.setAttribute("class", "thincol");
708
            if (under_subversion)
230 by mattgiuca
Removed "unversioned" icon from subversion status. Now unversioned files do
709
            {
710
                var icon = svnstatus_to_icon(file.svnstatus);
711
                if (icon)
712
                    td.appendChild(dom_make_img(icon, icon_size, icon_size,
713
                        svnstatus_to_string(file.svnstatus)));
714
            }
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
715
            row.appendChild(td);
716
            /* Column 3: Filename */
717
            td = dom_make_text_elem("td", filename);
718
            td.setAttribute("onclick", selection_string);
719
            row.appendChild(td);
720
        }
721
        /* Column 4: Size */
722
        td = dom_make_text_elem("td", nice_filesize(file.size));
723
        td.setAttribute("onclick", selection_string);
724
        row.appendChild(td);
725
        /* Column 4: Date */
726
        td = dom_make_text_elem("td", file.mtime_short, file.mtime_nice);
727
        td.setAttribute("onclick", selection_string);
728
        row.appendChild(td);
729
        files.appendChild(row);
730
    }
731
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
732
    /* Apply an initial sort by filename */
733
    sort_listing("filename");
734
210 by mattgiuca
File browser: listing.js - The status bar is now updated whenever the
735
    /* Do a selection update (create initial elements for side panel and
736
     * status bar). */
237 by mattgiuca
listing: bugfix, update_selection no longer dependent on dictionary ordering
737
    /* Commented out; already called by sort_listing */
738
    /*update_selection();*/
209 by mattgiuca
browser.js: Split out dir-listing code into listing.js (it's going to get
739
}
740