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