Fancybox API – Using Callbacks
If you’re not familiar with the fancybox jQuery plugin, I highly recommend you check it out. Lightweight, portable and powerful it is your basic Lightbox-style gallery viewer that supports embedding of images, inline content, iframe content, AJAX derived content and even SWF files (without the need for an external library like SWFObject). Very sweet.
Recently on a Zeitguys project, we had a situation where we had a gallery of dozens of SWFs (thankfully) all the same size. We wanted to display a static graphic in place of each SWF as the page loaded, and then on click, load the appropriate SWF in place. All of this is pretty easy to do right out-of-the-fancybox, so to speak. But there was an added catch: the whole thing had to be built on progressive enchancement principles, so we needed a structure that first worked perfectly with JavaScript disabled. In other words, each anchor tag in our gallery has to have a link to a static HTML page that contains just that SWF embedded on it. Only once that structure was working, could we overlay the fancybox functionality.
The challenge is that the way fancybox (and most of its other “competitors”) work is by hijacking the content of the href attribute of the anchor tag to which fancybox is attached. This is a Beautiful Thing if you have a bunch of IMGs wrapped inside A tags. The anchor’s href points to the IMG source and BAM, if JavaScript is enabled and you’ve attached fancybox to those anchor tags, fancybox reads the href on click and generates the necessary DOM elements to display it in a nicely-formatted, centered box.
But with a gallery of “poster frame” images that have to point to legitimate HTML pages for when JavaScript (or fancybox) are unavailable, we need to roll up our sleeves.
Fancybox Callbacks
Fancybox provides a number of callbacks that you can use when you attach the fancybox method to your jQuery elements. These are:
- onStart
- onCancel
- onComplete
- onCleanup
- onClosed
For anyone familiar with JavaScript or ActionScript events, this should all look very familiar: a callback in this context is a function that you provide, that will only be executed when the event we’ve attached to to fires. onComplete, for example, executes the function you pass to it when the content is being displayed within the fancybox frame.
Here’s an example on the fancybox documentation page of all the callbacks in action, to give you a better idea of their execution order.
You add a callback when you attach the fancybox method to your jQuery elements by passing an anonymous object to fancybox with the callback as a key and your function as the value, like so:
$("a").fancybox({ onComplete: function(){ alert("complete!"); } }); |
Yeah that’s a lot of braces and brackets, but that’s life in the JavaScript fast lane. Once you get past that it should be fairly easy to grok what’s going on here: we create an anonymous function that executes an alert, and pass that as the value of the onComplete parameter when we attach the fancybox method to all the anchor tags on our page (in this example I’m being pretty generic about the selector we’re using, just to keep the example simple).
The callback function: a closer look
What the fancybox API documentation page doesn’t really discuss are the arguments and return values for the callbacks, and the source code isn’t a paragon of best-practices JSDoc documentation either, so the nuances of the callback functions may escape the casual observer. In fact, that’s the whole point of this post, to hopefully demystify those callbacks and reveal their true power.
All of the callbacks (okay, I’m actually making an assumption here because I was only interested in the onStart event) take the following template:
function(itemArray, selectedIndex, selectedOpts){ return options; } |
itemArray is the complete list of all fancybox elements within the current group (elements that you designate with a common rel=”" attribute).
selectedIndex is the numerical index (0 offset) of the fancybox element being currently evaluated.
To get access to the currently evaluated element, just access itemArray[selectedIndex] and away you go.
selectedOpts are all the fancybox options that are active on the element currently being evaluated. This includes all sorts of good stuff like width, height, href, etc… (including the callbacks, but I wouldn’t recommend modifying them from within a callback – you may grow a third arm)
The return value is an Object that contains fancybox options that get added (or replace) the options on the currently evaluated element. This is where the real magic can happen.
Dynamically loading SWFs based on the name attribute
So, going back to our specific situation, let’s recap:
- a series of IMGs wrapped in A tags, where the href attribute must point to a static HTML page containing the embedded SWF (along with other stuff, so we can’t just load that page in via Ajax unfortunately)
- When fancybox is active, on click we need to load and show an SWF instead of the static page
- It’s impractical to embed all the SWFs in their own hidden divs somewhere on the page so that fancybox can simply use its inline method to display them.
As I write this, another solution just occurred to me using jQuery to simply substitute the href on all the eligible anchor tags once we’ve established that fancybox is active, but I digress. Let’s continue on with our callback example.
We needed a place to store the URL of the SWF in a way that wouldn’t break the static non-JavaScript version. The name attribute of the anchor tag was deemed viable: it wasn’t being used, it was valid markup and reasonably easily accessible to javascript and jQuery. The plan: use the fancybox onStart callback to populate the href attribute of the element being evaluated before fancybox got too deeply involved. Here’s how that worked:
$('a').fancybox({ autoDimensions: false, width: 490, height: 320, onStart: function(selectedArray, selectedIndex, selectedOptions){ return { href : "videos/" + selectedArray[selectedIndex].name } } }) |
We start by passing a number of parameters that hard-code the width and height of our SWFs. This helps with certain browsers (I’m looking at you Firefox) who can’t properly figure out the height until the SWF has completed loading, by which time fancybox has already “centered” itself (incorrectly). This could also be handled with another callback (though I’m not sure that onComplete really bothers to check whether its content has fully loaded before firing).
Then we define a simple function that grabs the name attribute – using standard DOM JavaScript, not jQuery as it turns out in this example, though you could easily wrap $(selectedArray[selectedIndex]).attr(‘name’) – and returns the URI as the href option, which fancybox then uses to do its magic. Sweet!
Well, I hope this reveals a little more about the callbacks that may not have been too obvious from the (rather sparse) documentation available on the fancybox main site. Enjoy this useful plugin and start getting fancy!
