Transloading a Lightbox Slideshow

Posted September 27, 2011 by Shaun Gorneau

OK, so I really have no idea what to call this..."transloading" seems like the most appropriate term to use. It is not "remote loading" since it is the same domain. Anyhow...I think explaining the scenario will help to better set this up.

The environment

I created/maintain/enhance a client's Drupal web site. This web site has a content type of "Gallery" which is very straight forward; standard node fields with a CCK Image field (unlimited images). The node_gallery.tpl.php file outputs the images as an unordered list of <a> tags, all configured for Lightbox2 and surrounding thumbnails of the images <img> (thumbnails delivered via ImageCache). Simple enough. With a little CSS, the Lightbox2 gallery looks elegant and simple.

This site also features "vacation packages" (amongst other packages) with packages being another content type.

The question

The client asks, "How can I get photo galleries on these package pages?" Not being sure exactly what the client wants, I ask, "Do you want to display images on the page, or do you have something else in mind?" To which the client answers, "Well, we have the text 'Accommodations' on this package page. We have a Gallery already created for our accommodations. How do I get that [Lightbox2] gallery to load when I click on 'Accommodations' on this package page?" I think to myself, "interesting question"...and say to the client "I'll get something put together."

The Goal

Create a simple process for the content manager that does not involve too much code. Use jQuery to do the heavy lifting; jQuery is already a requirement for the Drupal Lightbox2 module, so let's build on that.

The thought process

Identify links associated with Lightbox2 slideshows (thisLink)
Grab the prepared <ul> from the associated lightbox's gallery node URL
Append the <ul> to the body of the current page
Use the first <ul><li><a> tag's href as the modified href for the current <a> (thisLink)
Lightbox process the retrieved <ul><li><a> tags and the source link <a> tag (thisLink)

The execution

OK, so we have a Gallery content type for which its own node_gallery.tpl.php outputs some simple HTML; an unordered list of thumbnails (<img> tags) surrounded by <a> tags configured for lightbox2. Here is the tpl.php code

<? 
$images = $variables['field_photo_gallery_image_list'];
$default_title = $images[0]['data']['title'];
$default_image = $images[0]['filepath'];
?>
<div class="photo-gallery-thumbs">
    <ul>
    <? foreach( $images as $id=>$image ){?>
    	<? $thumb = imagecache_create_path('GalleryThumb', $image['filepath']);?>
        <li><a href="/<? print $image['filepath'];?>" style="background-image: url(/<? print $thumb;?>);" title="<? print $image['data']['title'];?>" rel="lightbox[gallery]"><img src="/<? print $thumb;?>" alt="<? print $image['data']['title'];?>" /></a></li>
    <? }?>
    </ul>
</div>

I should note that the image is applied as a background to the <a> tag so I can do some cropping and padding for better presentation. The actual <img> is hidden (display: none;).

Pretty simple, right? How do I get that prepared <ul> onto the other page (or any other page, for that matter) without forcing the client to rebuild that <ul> instance elsewhere? What can my client use to tie a string of text to a lightbox-processed <ul> on another page?

Identify links associated with Lightbox2

Well, for starters, the client is comfortable with creating links on pages both via WYSIWYG and source mode. So, why not start with that. Create a simple link on the text with the href pointing to the path of the desired photo gallery. This is a good start, even if I did nothing else, the link would bring the site user to the photo gallery. +1 for accessibility. Now, how do I intercept that link...how do I recognize it as being associated with a Lightbox2 slideshow elsewhere? Well, why don't I give it a rel="associated-lightbox"...that should help. So far we have this

<a href="/path/to/gallery" rel="associated-lightbox">Link Text</a>

Now, thinking ahead at this point...what if I need more than one link on a page, each launching a different gallery? I'll have to group these. So our rel="associated-lightbox" needs a group identifier. How about the gallery's node id? So we now have

<a href="/path/to/gallery" rel="associated-lightbox[123]">Link Text</a>

OK, at this point, I think I've setup the "user" end. Seems pretty simple even for someone that might not be too comfortable with HTML markup. Now, what to do with these prepared <a> tags?

Well, I'll have to find them and process them. Finding them is easy with a little jQuery

$('a[rel~="associated-lightbox"]').each( function(){});

Grab the prepared <ul>

Before I grab the <ul> and slap it into the body, I should create a container to hold it. The container holding it should probably have a unique id. So, I'll pick apart the rel attribute of the current link to work with the group identifier. Again, since we are using the Drupal Lightbox2 module, I'll utilize some of Lightbox's tools (line 3) to parse the rel attribute and get the parts. I'll do this

$('a[rel~="associated-lightbox"]').each( function(){
	var thisLink = $(this);
	var rel_parts = Lightbox.parseRel( thisLink );
	var rel = rel_parts["rel"];
	var rel_group = rel_parts["group"];		
	var url = thisLink.attr('href');
});

Now that we have some pieces to help create unique ids, we'll do some building (lines 7 & 8)

$('a[rel~="associated-lightbox"]').each( function(){
	var thisLink = $(this);
	var rel_parts = Lightbox.parseRel( thisLink );
	var rel = rel_parts["rel"];
	var rel_group = rel_parts["group"];		
	var url = thisLink.attr('href');
	$('body').append( '<div id="' + rel_group + '-lightbox-links"></div>' );
	$('#' + rel_group + '-lightbox-links').load(url, function(){});
});

Super…except that this is getting all of the HTML from the URL provided. I just want the <ul>. Fortuanetly, jQuery's load() method offers a nice, easy way to do that; add the element ID to the url like this (line 8)

$('a[rel~="associated-lightbox"]').each( function(){
	var thisLink = $(this);
	var rel_parts = Lightbox.parseRel( thisLink );
	var rel = rel_parts["rel"];
	var rel_group = rel_parts["group"];		
	var url = thisLink.attr('href');
	$('body').append( '<div id="' + rel_group + '-lightbox-links"></div>' );
	$('#' + rel_group + '-lightbox-links').load(url + ' #' + rel_group + '-remote-photo-gallery' , function(){});
});

OK, so now I realize that the <ul> being returned not only contains the lightboxified list of <a> tags…it is also grabbing the <img> thumbnails. This is unnecessary. I'm not displaying the thumbnails, so why bring them over? So, I need to modify my node_gallery.tpl.php to output an alternate list. If I pass "?links-only=1" in the load() url, I can then modify my tpl.php to see that and spit out some more appropriate code like so

<? 
$images = $variables['field_photo_gallery_image_list'];
$default_title = $images[0]['data']['title'];
$default_image = $images[0]['filepath'];

if( $_GET['links-only']=='1' ){?>
<div class="remote-photo-gallery" id="<? print $node->nid;?>-remote-photo-gallery">
    <? foreach( $images as $id=>$image ){?>
        <a href="/<? print $image['filepath'];?>" title="<? print $image['data']['title'];?>" rel="lightbox[gallery-<? print $node->nid;?>]"></a>
    <? }?>
</div>
<? }else{?>
<div class="photo-gallery-thumbs">
    <ul>
    <? foreach( $images as $id=>$image ){?>
    	<? $thumb = imagecache_create_path('GalleryThumb', $image['filepath']);?>
        <li><a href="/<? print $image['filepath'];?>" style="background-image: url(/<? print $thumb;?>);" title="<? print $image['data']['title'];?>" rel="lightbox[gallery]"><img src="/<? print $thumb;?>" alt="<? print $image['data']['title'];?>" /></a></li>
    <? }?>
    </ul>
</div>
<? }?>

And then the jQuery would look like this (notice the get var in line 8)

$('a[rel~="associated-lightbox"]').each( function(){
	var thisLink = $(this);
	var rel_parts = Lightbox.parseRel( thisLink );
	var rel = rel_parts["rel"];
	var rel_group = rel_parts["group"];		
	var url = thisLink.attr('href');
	$('body').append( '<div id="' + rel_group + '-lightbox-links"></div>' );
	$('#' + rel_group + '-lightbox-links').load(url + '?links-only=1 #' + rel_group + '-remote-photo-gallery' , function(){});
});

Cool! Now we're getting somewhere! Ok, so at this point, we have the optimized <ul> in our page. Now, the link that set this all in motion needs to replicate the actions of the first <a> in the returned <ul>…you know, get the gallery a displayin'. So, I'm going to get that link's href and make that the href of the source link (line 9 builds my selector...and then we get the href and rel attributes of that match, then apply those to the sour