If one has been on the internet for 3 seconds, it is obvious that dynamic photo galleries are useful and popular things.  After all, who wants to scroll through pages of pictures when they can all be loaded into one interface that can be controlled like a CD player (remember those…)?

Historically, the best photo galleries have been handled by Flash.  After all, it is a super easy thing to do, can be highly stylized and customized, and just generally works well.  The attendant problem,  however, has been two-fold.  Although generally lightweight, Flash is still pretty bulky, and as Interent Explorer has made us painfully aware, is not always treated with open arms by browsers.  Second, unless one has gone to trouble of coding to read an XML file, or is using remoting to connect to a database, Flash is just a pain to manage and can be time consuming to make simple additions, deletions, etc.

In recent years, some very good javascript alternatives have popped up.  While some are far better than others, the appeal of all is that they are generally less bandwidth expensive than flash and can be *more easily* modified than their flash alternatives.  

Spry has made its own contribution to the now glutted market of javascript photo galleries.  While I am not expert enough to be able to seriously evaluate it in light of the other contenders, I have found it extremely easy to use and fairly extensible.  In this post, I simply want to show how easy it is to not only implement the Spry gallery, but also show some cool enhancements that can be made from the out-of-the-box version.

As with all other Spry data applications that will be accessing remote data sources, you import the following files:

xpath.js
SpryData.js
SpryXML.js

As the gallery has some default fading effects on it, I also import the SpryEffects.js file.

Next, I create my dataset, populated from a call to a ColdFusion component which gets a query of values from my database:

 

var dsPhotos = new Spry.Data.XMLDataSet("preview.cfc?method=getPreviewPictures", "previews/photo");

Finally, I import Spry's gallery javascript file, gallery.js.

After all of this is created, an out of the box deployment with a "control panel" might look like this:

<div id="preview">
    <div id="pictureholder">
        <img id="mainImage" alt="" title="" border="0"/>
    </div>
                          
    <div id="controlpanel">
        <a href="javascript:;" onclick="StopSlideShow(); AdvanceToNextImage(true);" title="Previous">
            <img src="images/previous.gif" alt="Previous" border="0" align="texttop" class="previous" />                    
        </a>
        <a href="javascript:;" onclick="if (gSlideShowOn) StopSlideShow(); else StartSlideShow();" title="Play/Pause">
            <img src="" id="playpause" title="" alt="" border="0" align="texttop" />                    
    </a>
            <a href="javascript:;" onclick="StopSlideShow(); AdvanceToNextImage();" title="Next">
            <img src="images/next.gif" alt="Next" border="0" align="texttop" />                    
        </a>                
    </div>
</div>

Nothing really major here.  The reader will note, however, that it is lacking in spry regions.  That is because the image src which is being assigned to the "mainImage" div is spawned from an evaluation in javascript from the gallery.js file, and is not the direct result of a spry dataset.  This is a very important point to understand.

So we have a simple gallery that works.  But it's kind of boring.  The first thing that bothers me about this is the transitions.  While the fade in of a new image is cool, I don't particularly know why the default gallery does not have the last image fade out.  The hard break from picture to dead-air background is entirely not sexy.  So I decided to fix it.

Here's what I did.  In the gallery.js file, there is a function called AdvanceToNextImage() which, cryptically enough, advances images either backwards or forwards, depending on whether the "moveBackwards" argument is true or false (see control panel above). To add the fade out, I began by declaring a new Spry.Effect.Fade function for the image, set my arguments, and then immediately invoked the function as follows:

var fadeOutImage = new Spry.Effect.Fade('mainImage', { to: 0, from: 100, duration: 500});
fadeOutImage.start();

Simple enough.

Now another thing I wanted to do was to enable a way to show which row number was currently active in the gallery window.  On the HTML side, this is easily enough done.  Spry assigns and keeps track of dataset rowID's, rowNumbers, and a whole lot of other stuff automatically, and these values can be accessed at any time for a lot of useful purposes.  One of the dataset's native variables is  ds_RowNumberPlus1.  This is necessary to use in this situation because in Spry datasets, the row numbering begins at 0, not 1, and "0" for the current row just doesn't seem very user friendly.  So I just add this:

<span id='control{ds_RowNumber}'>{ds_RowNumberPlus1}</span>

Notice that I have also wrapped it in a span that gets a unique ID–this will be important in a second.

So now I can display the number of rows that are included in the dataset.  But how do I make them clickable so that they will jump to the right picture?  This was a little trickier.  As I mentioned before, the AdvanceToNextImage() function takes a single argument, "moveBackwards," and the internal processing of the function has two evalutions to handle what happens when the function is invoked.  So either another argument has to be added to the function, or something else must be done.  

What I decided was to add an additional piece of logic to the current function, rather than try to add additional arguments.  This function takes the single argument, "moveBackwards," and the out of the box function processes it boolean by default.  However, "moveBackwards" is not itself boolean–it can be anything.  Therefore, what I did was to add something to see if "moveBackwards" is passed in as a numeric value, and then to proceed from there.  The result is as follows:

if (!moveBackwards && i >= rows.length)
   &nbs
p;
i = 0;

else if (moveBackwards && i < 0)
    i = rows.length – 1;

else if (typeof(moveBackwards)== 'number')
    i = moveBackwards;

curRow = rows[i];
dsPhotos.setCurrentRow(curRow["ds_RowID"]);    
ShowCurrentImage();

The first condition evaluates if moveBackwards is NOT defined AND if the current value for setting the row is greater than or equal to the total number of rows.  Basically, this logic says that if the user has not tried to moveBackwards AND they have reached the last row and are trying to go forward, go ahead and go back to the first row (0).

The second condition evaluates if moveBackwards is defined and the current value for setting the row is less than 0.  Again, it says that if the user wants to go "back" and the current value will end up equaling less than 0, jump forward to the last row of the dataset /  or if the user is on, say, row 3, move to row 2.  *Note: Javascript's evaluation of the rows.length will be one value greater than the  final row of Spry's dataset–remember, the dataset row begins at 0, but Javascript does not count "0" as a number in a length evaluation.  Therefore, 1 must be subtracted to match the two up.

So these are the default evaluations.  To evaluate our new condition, the third section begins by evaluating whether or not moveBackwards is a numeric value.  If it is, the current value for setting the row is set to the value passed in, here "moveBackwards" as a numeric value.

After these conditions are evaluated, the Spry function "setCurrentRow()" is invoked and the resulting value of "i" from the three conditional statements is passed as an argument.

So now we have a way of displaying the number of pictures in our gallery, as well as providing a means of navigating directly to the picture by clicking on the number.  But how will we know, by looking at the numbers, which picture is currently active?  We need a visual representation!

Remember when we set the unique ID on the row number span?  Here's why that's important:

var controlID = "control"+i;
var currentRowStyle = document.getElementById(controlID);
currentRowStyle.style.textDecoration = "underline";

After we have determined the value of i, we can use that to apply an underline style to the uniquely ID'ed span surrounding the current row number.  

Of course, we need a way of unsetting this once a new row number has been set:

for (var i = 0; i < rows.length; i++) {
    if (rows[i] == curRow) {
        var controlID = "control"+i;
        var currentRowStyle = document.getElementById(controlID);
        currentRowStyle.style.textDecoration = "none";
        if (moveBackwards)
            –i;
        else
            ++i;
        break;
    }
}

This is the section where the initial value of i is set, before the conditional evaluation–an ideal place to remove previously set formatting.

So that's about it for our souping up of the Spry gallery.  Nonetheless, I would like to point out one more element that I have added.  With an eye towards accessibity, it would be nice to place alt and title attributes on our images (dynamic ones, of course), as well as possibly link our image to some website, internal site section, etc.  

My initial thought was to do the following:

<div id="pictureholder" spry:region="dsPhotos">
        <a id="mainLink" href="{link}"><img id="mainImage" alt="{alt}" title="{title}" border="0"/></a>
    </div>

>As with other Spry dataset applications, one would expect this work, and it does—for the first record set.  But remember, the changing of the image is based on the src attribute alone.  This means that although the image will change, the remaining dataset references will remain fixed on the first record.  Therefore, it is necessary to push the correct values to the aforementioned attributes along with the image, a task accomplished easily enough (this is in the SetMainImage() function of gallery.js immediately after the src push:

img.title = curRow["name"];
href.href = curRow["link"];

For the interested, here is my final HTML markup:

<div id="preview">
    <div id="pictureholder" spry:region="dsPhotos">
        <a id="mainLink" href=""><img id="mainImage" alt="" title="" border="0"/></a>
    </div>
                
                
    <div id="controlpanel">
        <a href="javascript:;" onclick="StopSlideShow(); AdvanceToNextImage(true);" title="Previous">
            <img src="images/previous.gif" alt="Previous" border="0" align="texttop" class="previous" />                    
        </a>
        <span spry:region="dsPhotos">
            <span spry:repeat="dsPhotos">
            <a href="javascript:;" onclick="AdvanceToNextImage({ds_RowNumber});"class="rotator">
                <span id='control{ds_RowNumber}'>{ds_RowNumberPlus1}</span>
            </a>                        
            </span>                    
        </span>
            <a href="javascript:;" onclick="if (gSlideShowOn) StopSlideShow(); else StartSlideShow();" title="Play/Pause">
            <img src="" id="playpause" title="" alt="" border="0" align="texttop" />                    
        </a>
            <a href="javascript:;" onclick="StopSlideShow(); AdvanceToNextImage();" title="Next">
            <img src="images/next.gif" alt="Next" border

="0" align
="texttop" />                    
        </a>                
    </div>
</div>

So that's about it.  With just a bit of work, an originally cool gallery can be made even sweeter.  Check out my mildly sexy demo here .