Welcome!

ColdFusion Authors: Yakov Fain, Maureen O'Gara, Nancy Y. Nee, Tad Anderson, Daniel Kaar

Related Topics: ColdFusion

ColdFusion: Article

Extending ColdFusion

Building a slide show

If you own a digital camera, you probably have many (probably hundreds) pictures filling up your hard drive. If you're a parent, you probably have even more. Sharing those pictures with the world can be pretty simple. If you turn on directory browsing on your Web server, you can simply copy the pictures to a folder and share the URL. However, that's not a very clean solution. In this month's Extending ColdFusion, we're going to look at a custom tag, <cf_slideshow>, that will automatically create a simple slide show from a folder of pictures. It will handle generating links from one picture to the next, creating a thumbnail directory, and even allowing for captions.

Listing 1 contains the custom tag. Let's take a look line by line. Our very first line simply turns on the enablecfoutputonly setting. This removes the white space generated by our CFML code. It also means we need to wrap all of our output with <cfoutput> tags. Line 11 simply says that if our custom tag is called in "end" mode, we should turn off the enablecfoutputonly setting and then simply exit the tag. So, if someone calls the custom tag like so: <cf_slideshow ..... />, the extra slash at the end won't make the tag run twice.

For our custom tag to work, it needs to know two things - what directory contains the pictures, and what URL should be used for those pictures. In order to require these attributes, we use the <cfparam> tag on lines 15 and 17 without default parameters. As soon as you try to call the custom tag without them, ColdFusion will throw an error. The dir attribute will represent the full path to the pictures, for example, c:webpicturesjune2003. The urldir attribute will represent the URL path to that folder. An example could be "/pictures/june/2003".

Lines 20-22 allow us to specify how the thumbnail directory should work. All have default values and can normally be left as is. Attributes.thumb_width and Attributes.thumb_height determine the width and height for the thumbnails. These values are defaulted to settings that will work best with pictures that are sized at 640x480. Attributes.thumb_perRow determines how many thumbnails are displayed per row.

In order for our custom tag to know which slide to display, it will pass along a URL parameter. In case this value does not exist, we use a cfparam on line 25 and default the value to 1, or the first slide.

Lines 27-29 use the directoryExists() function to ensure that the value specified by attributes.dir actually points to a real folder. If it does not, we throw an error to the user. Line 31 then uses the <cfdirectory> tag to list all the JPGs in the folder. (If you wanted, you could modify this to check for GIFs, or use a bit more code to filter by both.) We sort by name, but you could also sort by other properties as well, for example, by the last updated value of the file.

Lines 33-36 simply say that if the directory is empty (or if there were no JPGs found), we turn off the enablecfoutputonly setting and exit the tag. We don't throw an error because the folder may not contain pictures yet, but will later on.

The next thing we want to do is validate the slide URL parameter. It's possible that a user may change the value by hand, so we want to make sure that the value will work correctly. Line 39 first checks to see if the value is numeric, and then checks to see if the number makes sense. Don't forget that -1 is a number, but obviously our slide show won't have a negative-first slide. We also compare the value against the number of JPGs we found in our <cfdirectory> call. If it's bigger than the result, or if anything else was wrong, we simply reset the value to 1.

The next block of code is a bit confusing, so let's break it down. Our slide show will need to generate links from one slide to the next. At the same time it's possible that the page calling the custom tag already had some URL parameters defined. When we create our links from inside the custom tag, we want to preserve the original URL parameters, but remove the ones the custom tag adds. This line

<cfset qs = cgi.query_string>

gets the current set of URL parameters as defined in the query string. The next line

<cfset qs = rereplacenocase(qs,"&*slide=[0-9]*","")>

will use regular expressions to remove the slide parameter. We use regular expressions since we don't know exactly what the value will be. The regular expression, "&*slide=[0-9]*", will match zero or more & characters, the phrase slide=, and then any number. The next line works almost the same way:

<cfset qs = rereplacenocase(qs,"&*thumbs=1","")>

This will match zero or more & characters and then the phrase thumbs=1.

Let's look at a real example. Imagine if the value of cgi.query_string was "dir=foo&z=1". After running the slide show, the query string would look like "dir=foo&z=1&slide=2". Our code will remove the slide=2. Later on when we generate our link to slide 3, we won't have to worry about the old slide value getting in the way.

Now we get into the meat of our tag. Line 48 checks to see if url.thumbs is defined. If it isn't, then we're doing a normal slide display. Line 50 begins this display. I'm going to ignore the simple HTML markup and focus on the code. Line 53 simply outputs the current slide by using url.slide to point to one of the rows of the query returned by the <cfdirectory> tag.

Support for captions is done by checking for a specially named file. In a file with the same name as the picture, but with ".txt" at the end, we simply include the file and output the contents. Note that line 60 uses a <span> tag with a class of "caption". This isn't defined in the custom tag but can instead be set in your own site's style sheet if you choose.

Next we need to determine if we should display a Previous Picture or Next Picture link. Obviously we only display a Previous Picture link if we're not on the first slide. Notice the link in line 68:

<a href="#cgi.script_name#?#qs#&slide=#decrementvalue(url.slide)#">

#cgi.script_name# points to the current file, not the custom tag, but the file that called it. #qs# is the stripped query_string value we created earlier. The slide parameter is simply one less then the current value of url.slide. The link for the next picture is almost exactly the same, except that we use incrementvalue instead.

Last, we output a link for the thumbnails. This is done by using just #qs# and thumbs=1. The thumbnails are output in lines 82-89. We simply loop over all the results of the original <cfdirectory> call and output direct links for each picture. Also note that we constrain the height and width by the attributes we discussed earlier. Please note that these are not real thumbnails. They are the original pictures just sized smaller. For anyone on a dial-up modem, this is going to be a slow-loading page. However, it does allow you to see all the pictures at once, and for those on a high-speed connection, it will work just fine.

So how do we use it? The entire slide show can be run with one simple call:

<cf_slideshow dir="#expandPath("./pics")#" urldir="./pics">

You can even make a simple template to query a root folder of subfolders, each being a different set of pictures. You would then simply allow the user to pick a folder, and at that point call cf_slideshow.

More Stories By Ray Camden

A longtime ColdFusion user, Raymond is a co-author of the "Mastering ColdFusion" series published by Sybex Inc, as well as the lead author for the ColdFusion MX Developer's Handbook. He also presents at numerous conferences and contributes to online webzines. He and Rob Brooks-Bilson created and run the Common Function Library Project (www.cflib.org), an open source repository of ColdFusion UDFs. Raymond has helped form three ColdFusion User Groups and is the manager of the Acadiana MMUG.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.