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

« back to all changes in this revision

Viewing changes to www/media/browser/browser.js

  • Committer: mattgiuca
  • Date: 2008-01-31 01:44:30 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:345
Global CSS change: ivlebody no longer has 1em of padding (it has none).
This is because most apps were disabling it (and it had to change anyway for
other reasons -- see below).

Hence, all apps which WERE disabling the padding have had that removed, and
just work by default. (console, browser, tutorial)
All apps which WEREN'T disabling the padding (very few) now have to manually
include an extra div. This has been done on all such apps, and has been
heavily documented (both in the CSS file and doc/app_howto). (help, dummy,
debuginfo).

media/common/ivle.css: 
    The real change here (which isn't yet being used) is that ivlebody is now
    positioned absolutely and takes up all the space on the canvas. This is
    to be used for full-page layouts in console and browser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 * Date: 11/1/2008
21
21
 */
22
22
 
 
23
/* Url names for apps */
 
24
this_app = "files";
 
25
edit_app = "edit";
 
26
service_app = "fileservice";
 
27
serve_app = "serve";
 
28
download_app = "download";
 
29
 
 
30
/* Mapping MIME types onto handlers.
 
31
 * "text" : When navigating to a text file, the text editor is opened.
 
32
 * "image" : When navigating to an image, the image is displayed (rather than
 
33
 *              going to the text editor).
 
34
 * "audio" : When navigating to an audio file, a "play" button is presented.
 
35
 * "binary" : When navigating to a binary file, offer it as a download through
 
36
 *              "serve".
 
37
 *
 
38
 * If a file is not on the list, its default action is determined by the first
 
39
 * part of its content type, where "text/*", "image/*" and "audio/*" are
 
40
 * treated as above, and other types are simply treated as binary.
 
41
 */
 
42
type_handlers = {
 
43
    "application/x-javascript" : "text",
 
44
    "application/javascript" : "text",
 
45
    "application/json" : "text",
 
46
    "application/xml" : "text",
 
47
};
 
48
 
 
49
/* Mapping MIME types to icons, just the file's basename */
 
50
type_icons = {
 
51
    "text/directory": "dir.png",
 
52
    "text/x-python": "py.png",
 
53
};
 
54
 
 
55
default_type_icon = "txt.png";
 
56
 
 
57
/* Relative to IVLE root */
 
58
type_icons_path = "media/images/mime";
 
59
type_icons_path_large = "media/images/mime/large";
 
60
 
 
61
/* Mapping SVN status to icons, just the file's basename */
 
62
svn_icons = {
 
63
    "unversioned": null,
 
64
    "normal": "normal.png",
 
65
    "added": "added.png",
 
66
    "missing": "missing.png",
 
67
    "deleted": "deleted.png",
 
68
    "modified": "modified.png",
 
69
};
 
70
 
 
71
/* Mapping SVN status to "nice" strings */
 
72
svn_nice = {
 
73
    "unversioned": "Temporary file",
 
74
    "normal": "Permanent file",
 
75
    "added": "Temporary file (scheduled to be added)",
 
76
    "missing": "Permanent file (missing)",
 
77
    "deleted": "Permanent file (scheduled for deletion)",
 
78
    "replaced": "Permanent file (replaced)",
 
79
    "modified": "Permanent file (modified)",
 
80
    "merged": "Permanent file (merged)",
 
81
    "conflicted": "Permanent file (conflicted)",
 
82
};
 
83
 
 
84
default_svn_icon = null;
 
85
default_svn_nice = "Unknown status";
 
86
 
 
87
svn_icons_path = "media/images/svn";
 
88
 
 
89
published_icon = "media/images/interface/published.png";
 
90
 
 
91
/* List of MIME types considered "executable" by the system.
 
92
 * Executable files offer a "run" link, implying that the "serve"
 
93
 * application can interpret them.
 
94
 */
 
95
types_exec = [
 
96
    "text/x-python",
 
97
];
 
98
 
 
99
 
 
100
/* Global variables */
 
101
 
 
102
current_path = "";
 
103
 
 
104
/** Calls the server using Ajax, performing an action on the server side.
 
105
 * Receives the response from the server and performs a refresh of the page
 
106
 * contents, updating it to display the returned data (such as a directory
 
107
 * listing, file preview, or editor pane).
 
108
 * Always makes a POST request.
 
109
 * No return value.
 
110
 *
 
111
 * \param action String. Name of the action to perform, as defined in the
 
112
 *     fileservice API.
 
113
 * \param path URL path to make the request to, within the application.
 
114
 * \param args Argument object, as described in util.parse_url and friends.
 
115
 *      This should contain the arguments to the action, but NOT the action
 
116
 *      itself. (Also a minor side-effect; the "args" object will be mutated
 
117
 *      to include the action attribute).
 
118
 * \param content_type String, optional.
 
119
 *      May be "application/x-www-form-urlencoded" or "multipart/form-data".
 
120
 *      Defaults to "application/x-www-form-urlencoded".
 
121
 *      "multipart/form-data" is recommended for large uploads.
 
122
 */
 
123
function do_action(action, path, args, content_type)
 
124
{
 
125
    args.action = action;
 
126
    /* 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
 
129
     * user */
 
130
    error = response.getResponseHeader("X-IVLE-Action-Error");
 
131
    if (error != null)
 
132
        alert("Error: " + error.toString() + ".");
 
133
    /* Now read the response and set up the page accordingly */
 
134
    handle_response(path, response);
 
135
}
 
136
 
 
137
/** Calls the server using Ajax, requesting a directory listing. This should
 
138
 * not modify the server in any way. Receives the response from the server and
 
139
 * performs a refresh of the page contents, updating it to display the
 
140
 * returned data (such as a directory listing, file preview, or editor pane).
 
141
 * Called "navigate", can also be used for a simple refresh.
 
142
 * Always makes a GET request.
 
143
 * No return value.
 
144
 * \param editmode Optional boolean. If true, then the user navigated here
 
145
 * with an "edit" URL so we should favour using the editor.
 
146
 */
 
147
function navigate(path, editmode)
 
148
{
 
149
    /* Call the server and request the listing. This mutates the server. */
 
150
    response = ajax_call(service_app, path, null, "GET");
 
151
    /* Now read the response and set up the page accordingly */
 
152
    handle_response(path, response, editmode);
 
153
}
 
154
 
 
155
/** Determines the "handler type" from a MIME type.
 
156
 * The handler type is a string, either "text", "image", "audio" or "binary".
 
157
 */
 
158
function get_handler_type(content_type)
 
159
{
 
160
    if (!content_type)
 
161
        return null;
 
162
    if (content_type in type_handlers)
 
163
        return type_handlers[content_type];
 
164
    else
 
165
    {   /* Based on the first part of the MIME type */
 
166
        var handler_type = content_type.split('/')[0];
 
167
        if (handler_type != "text" && handler_type != "image" &&
 
168
            handler_type != "audio")
 
169
            handler_type = "binary";
 
170
        return handler_type;
 
171
    }
 
172
}
 
173
 
 
174
/** Given an HTTP response object, cleans up and rebuilds the contents of the
 
175
 * page using the response data. This does not navigate away from the page, it
 
176
 * merely rebuilds most of the data.
 
177
 * Note that depending on the type of data returned, this could result in a
 
178
 * directory listing, an image preview, an editor pane, etc.
 
179
 * Figures out the type and calls the appropriate function.
 
180
 * \param path URL path which the request was made for. This can (among other
 
181
 * things) be used to update the URL in the location bar.
 
182
 * \param response XMLHttpRequest object returned by the server. Should
 
183
 * contain all the response data.
 
184
 * \param editmode Optional boolean. If true, then the user navigated here
 
185
 * with an "edit" URL so we should favour using the editor.
 
186
 */
 
187
function handle_response(path, response, editmode)
 
188
{
 
189
    /* TODO: Set location bar to "path" */
 
190
    current_path = path;
 
191
 
 
192
    /* Clear away the existing page contents */
 
193
    clearpage();
 
194
    /* Display the path at the top, for navigation */
 
195
    presentpath(path);
 
196
 
 
197
    /* Check the status, and if not 200, read the error and handle this as an
 
198
     * error. */
 
199
    if (response.status != 200)
 
200
    {
 
201
        var error = response.getResponseHeader("X-IVLE-Return-Error");
 
202
        if (error == null)
 
203
            error = response.statusText;
 
204
        handle_error(error);
 
205
        return;
 
206
    }
 
207
 
 
208
    /* Check if this is a directory listing or file contents */
 
209
    var isdir = response.getResponseHeader("X-IVLE-Return") == "Dir";
 
210
    if (!editmode && isdir)
 
211
    {
 
212
        var listing = response.responseText;
 
213
        /* The listing SHOULD be valid JSON text. Parse it into an object. */
 
214
        try
 
215
        {
 
216
            listing = JSON.parse(listing);
 
217
        }
 
218
        catch (e)
 
219
        {
 
220
            handle_error("The server returned an invalid directory listing");
 
221
            return;
 
222
        }
 
223
        handle_dir_listing(path, listing);
 
224
    }
 
225
    else
 
226
    {
 
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)
 
236
        {
 
237
        case "text":
 
238
            if (isdir)
 
239
            {
 
240
                handle_text(path_join(path, "untitled"), "",
 
241
                    would_be_handler_type);
 
242
            }
 
243
            else
 
244
            {
 
245
                handle_text(path, response.responseText,
 
246
                    would_be_handler_type);
 
247
            }
 
248
            break;
 
249
        case "image":
 
250
            /* TODO: Custom image handler */
 
251
            handle_binary(path, response.responseText);
 
252
            break;
 
253
        case "audio":
 
254
            /* TODO: Custom audio handler */
 
255
            handle_binary(path, response.responseText);
 
256
            break;
 
257
        case "binary":
 
258
            handle_binary(path);
 
259
            break;
 
260
        }
 
261
    }
 
262
}
 
263
 
 
264
/** Deletes all "dynamic" content on the page.
 
265
 * This returns the page back to the state it is in when the HTML arrives to
 
266
 * the browser, ready for another handler to populate it.
 
267
 */
 
268
function clearpage()
 
269
{
 
270
    dom_removechildren(document.getElementById("path"));
 
271
    dom_removechildren(document.getElementById("filesbody"));
 
272
}
 
273
 
 
274
/** Deletes all "dynamic" content on the page necessary to navigate from
 
275
 * one directory listing to another (does not clear as much as clearpage
 
276
 * does).
 
277
 * This is the equivalent of calling clearpage() then
 
278
 * setup_for_dir_listing(), assuming the page is already on a dir listing.
 
279
 */
 
280
function clearpage_dir()
 
281
{
 
282
    dom_removechildren(document.getElementById("path"));
 
283
    dom_removechildren(document.getElementById("files"));
 
284
    dom_removechildren(document.getElementById("sidepanel"));
 
285
}
 
286
 
 
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.
 
290
 */
 
291
function setmode(editmode)
 
292
{
 
293
    /* Find the DOM elements for the file browser and editor tabs */
 
294
    var tabs = document.getElementById("apptabs");
 
295
    var tab_files = null;
 
296
    var tab_edit = null;
 
297
    var a;
 
298
    var href;
 
299
    for (var i=0; i<tabs.childNodes.length; i++)
 
300
    {
 
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];
 
311
    }
 
312
 
 
313
    if (editmode)
 
314
    {
 
315
        tab_files.removeAttribute("class");
 
316
        tab_edit.setAttribute("class", "thisapp");
 
317
    }
 
318
    else
 
319
    {
 
320
        tab_edit.removeAttribute("class");
 
321
        tab_files.setAttribute("class", "thisapp");
 
322
    }
 
323
}
 
324
 
 
325
/*** HANDLERS for different types of responses (such as dir listing, file,
 
326
 * etc). */
 
327
 
 
328
function handle_error(message)
 
329
{
 
330
    setmode(false);
 
331
    var files = document.getElementById("filesbody");
 
332
    var txt_elem = dom_make_text_elem("div", "Error: "
 
333
        + message.toString() + ".")
 
334
    txt_elem.setAttribute("class", "padding error");
 
335
    files.appendChild(txt_elem);
 
336
}
 
337
 
 
338
/** Presents a path list (address bar inside the page) for clicking.
 
339
 */
 
340
function presentpath(path)
 
341
{
 
342
    var dom_path = document.getElementById("path");
 
343
    var href_path = make_path(this_app);
 
344
    var nav_path = "";
 
345
    var dir;
 
346
 
 
347
    /* Also set the document title */
 
348
    document.title = path_basename(path) + " - IVLE";
 
349
    /* Create all of the paths */
 
350
    var pathlist = path.split("/");
 
351
    for (var i=0; i<pathlist.length; i++)
 
352
    {
 
353
        dir = pathlist[i];
 
354
        if (dir == "") continue;
 
355
        /* Make an 'a' element */
 
356
        href_path = path_join(href_path, dir);
 
357
        nav_path = path_join(nav_path, dir);
 
358
        var link = dom_make_link_elem("a", dir, "Navigate to " + nav_path,
 
359
                href_path/*, "navigate(" + repr(href_path) + ")"*/);
 
360
        dom_path.appendChild(link);
 
361
        dom_path.appendChild(document.createTextNode("/"));
 
362
    }
 
363
    dom_path.removeChild(dom_path.lastChild);
 
364
}
 
365
 
 
366
/** Given a mime type, returns the path to the icon.
 
367
 * \param type String, Mime type.
 
368
 * \param sizelarge Boolean, optional.
 
369
 * \return Path to the icon. Has applied make_path, so it is relative to site
 
370
 * root.
 
371
 */
 
372
function mime_type_to_icon(type, sizelarge)
 
373
{
 
374
    var filename;
 
375
    if (type in type_icons)
 
376
        filename = type_icons[type];
 
377
    else
 
378
        filename = default_type_icon;
 
379
    if (sizelarge)
 
380
        return make_path(path_join(type_icons_path_large, filename));
 
381
    else
 
382
        return make_path(path_join(type_icons_path, filename));
 
383
}
 
384
 
 
385
/** Given an svnstatus, returns the path to the icon.
 
386
 * \param type String, svn status.
 
387
 * \return Path to the icon. Has applied make_path, so it is relative to site
 
388
 * root. May return null to indicate no SVN icon.
 
389
 */
 
390
function svnstatus_to_icon(svnstatus)
 
391
{
 
392
    var filename;
 
393
    if (svnstatus in svn_icons)
 
394
        filename = svn_icons[svnstatus];
 
395
    else
 
396
        filename = default_svn_icon;
 
397
    if (filename == null) return null;
 
398
    return make_path(path_join(svn_icons_path, filename));
 
399
}
 
400
 
 
401
/** Given an svnstatus, returns the "nice" string.
 
402
 */
 
403
function svnstatus_to_string(svnstatus)
 
404
{
 
405
    if (svnstatus in svn_nice)
 
406
        return svn_nice[svnstatus];
 
407
    else
 
408
        return default_svn_nice;
 
409
}
 
410
 
 
411
/** Displays a download link to the binary file.
 
412
 */
 
413
function handle_binary(path)
 
414
{
 
415
    setmode(false);
 
416
    var files = document.getElementById("filesbody");
 
417
    var div = document.createElement("div");
 
418
    files.appendChild(div);
 
419
    div.setAttribute("class", "padding");
 
420
    var download_link = app_path(download_app, path);
 
421
    var par1 = dom_make_text_elem("p",
 
422
        "The file " + path + " is a binary file. To download this file, " +
 
423
        "click the following link:");
 
424
    var par2 = dom_make_link_elem("p",
 
425
        "Download " + path, "Download " + path, download_link);
 
426
    div.appendChild(par1);
 
427
    div.appendChild(par2);
 
428
}
 
429
 
23
430
/** Called when the page loads initially.
24
431
 */
25
432
window.onload = function()
26
433
{
 
434
    /* Navigate (internally) to the path in the URL bar.
 
435
     * This causes the page to be populated with whatever is at that address,
 
436
     * whether it be a directory or a file.
 
437
     */
 
438
    var path = parse_url(window.location.href).path;
 
439
    /* Strip out root_dir + "/files" from the front of the path */
 
440
    var strip = make_path(this_app);
 
441
    var editmode = false;
 
442
    if (path.substr(0, strip.length) == strip)
 
443
        path = path.substr(strip.length+1);
 
444
    else
 
445
    {
 
446
        /* See if this is an edit path */
 
447
        strip = make_path(edit_app);
 
448
        if (path.substr(0, strip.length) == strip)
 
449
        {
 
450
            path = path.substr(strip.length+1);
 
451
            editmode = true;
 
452
        }
 
453
    }
 
454
 
 
455
    if (path.length == 0)
 
456
    {
 
457
        /* Navigate to the user's home directory by default */
 
458
        /* TEMP? */
 
459
        path = username;
 
460
    }
 
461
 
 
462
    navigate(path, editmode);
27
463
}