Dual mode picture viewer script

Intro:

This was an experiment to see whether client side script can be used for something making a slideshow viewer (with optional annotations in the form of text notes for each slide). The idea was to have the same page work for local viewing of images and also work on the server where the images are posted. This document describes the script a bit, and then ends with some conclusions.

You can try out the script here. To download it, just view source on the page or save it to a file.


The script:

Basically you can't safely access directories directly from javascript, since that could be a security issue. So the first question is how to get the file info we want to display. The standard trick is to load a listing of the directory you are perusing into a hidden frame and then reading the links out of it. This works provided that:

  1. Your browser generates a nicely linked directory listing when you go to a local directory URL.
  2. The links are legible enough to read easily.
  3. Your server allows/generates directory listings on request.
  4. There's no default index.html file or the equivalent to display in lieu of the directory listing.

Given those caveats, you write some script triggered in the onLoad attribute of the listingframe (google "onload frame directory listing" or somesuch for examples). But the real challenge is getting something that will refresh the contents as you tab/enter your way through the image links. This is harder, because you don't have any control over what order the frames are loaded, and you need to call your directory processing after the directory is there to work with. Ultimately I ended up dynamically generating a frame within a frame to get the load call happening at the right time. I also found it helpful to have a scratchspace frame to use as a target that wouldn't inadvertently mess things up. Here's an excerpt of the resulting frame setup:

    html += '<frameset onload="writeListing(\'.\');" rows="5%, 95%, *" frameborder="1">';
    html +=   '<frame name="description" src="about:blank" scrolling="auto">';
    html +=   '<frameset cols="15%, 85%, *">';
    html +=     '<frame name="nav" src="about:blank" scrolling="auto" noresize>';
    html +=     '<frame name="display" src="about:blank" scrolling="auto" noresize>';
    html +=     '<frame name="scratchspace" src="about:blank" scrolling="no" noresize>';
    html +=   '<\/frameset>';
    html +=   '<frame name="listing" src="about:blank" scrolling="no" noresize>';
    html += '<\/frameset>';
The code to generate the source frame within the listing frame is:
    function writeListing(dir) {
        var d = listing.document;
        d.open();
        d.write('<frameset onLoad="parent.writeLinks(\'' + dir + '\');" rows="100%, *">');
        d.write('  <frame name="source" src="' + dir + '" noresize scrolling="no">');
        d.write('<\/frameset>');
        d.close();
    }

Once we have the frames, we basically just need to populate the contents. This amounts to a series of rules in priority order as to what constitutes something we want and what doesn't. For each link:

            if((links[i].href.indexOf(".jpg")>=0)||
               (links[i].href.indexOf(".JPG")>=0)||
               (links[i].href.indexOf(".gif")>=0)||
               (links[i].href.indexOf(".GIF")>=0)) {
                var index=links[i].href.lastIndexOf(".");
                var descr=links[i].href.substring(0,index) + '.txt';
                var descrLink="about:blank"
                for(var j=0;j<links.length;j++) {
                    if(links[j] == descr) {
                        descrLink=descr; } }
                d.write('<a href="' + links[i].href + '" target="display" ' +
                        'onclick="parent.writeDescription(\'' + descrLink + '\')">' +
                        (links[i].text ? links[i].text : links[i].href) +
                        '<\/a><br>'); }
            else if(links[i].href.indexOf("C=")>=0) {
                //apache generated sorting link in directory listing
                //d.write(links[i].text + '<br>'); 
                }
            else if(links[i].href.lastIndexOf("/") == links[i].href.length - 1) {    
                //ends with a terminating slash so must a be a directory link
                d.write('<a href="' + links[i].href + '" target="scratchspace" ' +
                        'onclick="parent.writeListing(\'' + links[i].href + '\')">' + 
                        (links[i].text ? links[i].text : links[i].href) + 
                        '<\/a><br>'); }
            else if(links[i].href.indexOf(".")>=0) {    
                //assume anything with an extension is a non-image file
                //d.write(links[i].text + '<br>'); 
                }
            else { //assume directory by default
                d.write('<a href="' + links[i].href + '" target="scratchspace" ' +
                        'onclick="parent.writeListing(\'' + links[i].href + '\')">' + 
                        (links[i].text ? links[i].text : links[i].href) + 
                        '<\/a><br>'); } }

The full script is here. View source to see the code. All the functionality is contained within the single file.


Conclusions:

You can do some impressive things with client side browser script, but lack of reliable file access (read or write) along with differences between browsers and browser versions pretty much limit this to display formatting. With server side display, you only need to test your resulting display pages across multiple browsers. With client side scripting, you also need to test the display generation code across multiple browsers, as opposed to a single known server environment. Significant UI functionality requires server support to handle what can't be done (or is difficult to do) in script.

So what if I want a simple picture browser running locally on my computer, where I could do things like enter text descriptions to annotate each image? Realistically, I would need to run a server process that would handle the input processing and write the description file. If I could run this server locally, then I would use the identical browser interface for both a standalone client or web installation. Only the URL would be different.

The concept of a browser-interface/local server (BILoc) application is discussed next.

back to techbase index







© 2005 SAND Services Inc.
All Rights Reserved.