I wanted to create a project gallery for myself. Typo supports Lightbox-style galleries, but I wanted something simpler - a simple scrolling list of thumbnails that when clicked, would update a larger gallery photo on the page without going to a modal overlay. I decided to build a gallery using some unobtrusive Javascript techniques employing Builder and a simple Scriptaculous fade-in. You can view my completed javascript include here.
The markup for the galleries is simple: a div wrapper containing an unordered list of links to images. My markup code looks like this:
<div class="bb_gallery">
<ul>
<li>
<a href="path_to_full_image"><img src="path_to_thumbnail"/></a>
<p>Caption text</p>
</li>
... more list items ...
</ul>
</div>
Without the Javascript, the gallery renders as a scrolling UL of thumbnail images. Each thumbnail is linked to its full-size version. The Javascript init routine runs when the layout finishes loading, called via Prototype’s dom:loaded event:
document.observe("dom:loaded", function() {
McArtzt.Gallery.init();
});
The init() function iterates through all the bbGallery divs and inserts some additional markup for the gallery image. The completed markup for the gallery looks like this:
<div class="bb_gallery">
<div class="bb_show">
<div class="caption">Caption text</div>
<div class="last"><img class="last" src="path_to_previous_gallery_image_or_spacer"/></div>
<div class="current"><img class="current" src="path_to_current_gallery_image"/></div>
</div>
<ul>
... same as before
</ul>
</div>
The init() also sets an event handler on each thumbnail link so that when clicked, it will swap out the gallery image with the clicked image:
anchors.each(function(a){a.observe('click', McArtzt.Gallery.click);});
The current and last images are both positioned absolute, so current overlays last. Additionally, the current div enclosing the current image has a spinner background graphic that shows while the image is being retrieved from my webserver. Once the image is loaded, the background spinner is hidden.
On init(), I also insert an onload event handler on the current image - when the image finishes loading, the callback function uses a Scriptaculous fade-in to reveal the current image over the last image. I bound the event handler to the current gallery image. This is necessary because the event passed to the event handler is attached to the document object, which does not help me determine which image to fade in.
Getting the observe to work, I encountered some cross-browser difficulties. Firefox and Safari on the Mac worked well with the following statement:
// imgCurrent is a Builder node
imgCurrent.observe('load',McArtzt.Gallery.loaded.bind(imgCurrent));
Internet Explorer 7 could not deal. I’m not exactly sure why, but I suspect that on IE, the builder node is not automatically hooked into the Element extended methods added by Prototype. Wrapping the builder node reference as follows fixed that:
$(imgCurrent).observe('load',McArtzt.Gallery.loaded.bind(imgCurrent));
The event handler is simple:
loaded : function(event) {
// this refers to the bound gallery image (imgCurrent from above)
new Effect.Appear(this,{duration:1.0});
}
There are some good discussions of binding at the following links. I find this aspect of Javascript development really interesting (and challenging).