This tutorial is sponsored by the Save Joseph campaign, a grassroots effort to find a good friend, stellar artist and all around amazing person a satisfying, creative job in the next 9 days. I know the Drupal community could use this kind of talent. Learn more about the effort at savejoseph.org.

Views Slideshow is a nice module that leverages the jQuery Cycle plugin to create a highly-customizable, attractive slideshow. It comes with an option to display simple text controls to go forward or back through the slides. What I wanted was to customize this experience with images instead of the Previous and Next links.

The first step is create a view using Views Slideshow and enable the controls on the top of the slideshow. This is done via the Views style settings dialog:

Once this is set, you should see some links above the slideshow:

To turn these links into images, we first need to find a unique identifier for each one. Views Slideshow adds a unique ID, so we can use that. Here's what I see in Firebug when I inspect the element:

You can see there is a unique ID for each element. Now, all we need to do is set a number of styles for the link.

First, we need to set the background of the element to use our image:


Next, we need to set the dimensions of the element to match our image, which is 71 pixels by 71 pixels. If we didn't have to worry about the text, we would just set the width and height. But, we need to hide the text, so we're going to set the height o 0, and the top padding to 71, which will bump the text out of view:


If you refresh your page at this point, you'll still see some text:

This is because we need to explicitly set any the element to hide any content that's outside of it's bounds. We do so by defining the overflow property to hidden:


Finally, I didn't want a pause button, so I set to not display:


The final result looks like this:

By the way, the artwork you see is produced by Joseph Cowman, if you haven't seen his stuff, it's brilliant.

And the code, with some particular styles for what I needed, is this:

#views_slideshow_singleframe_prev_gallery-block_1, #views_slideshow_singleframe_next_gallery-block_1 {
#views_slideshow_singleframe_prev_gallery-block_1 {
#views_slideshow_singleframe_next_gallery-block_1 {
#views_slideshow_singleframe_playpause_gallery-block_1 {
OCR-ed content: 
Controls Top Determine if controls for the slideshow (start/stop/next/previous) should appear, and if so whether they should appear before or after the slideshow. and SO sli J:sh- Jk MR *-ii iv iujj- .uui iun~ t_ui in wis" Lup iitui iulk <div id-Views_slideshow_singleframe_controls_gallery- DLock_l class- Views_slideshow_singleframe_controls views_slideshow_controls" style-"display BLOCK block_l" views_slideshovi_previous" href-"# Previous block_l" views_slideshov»_pause" href-"# Pause <Za> block_l" views_slideshov»_next" href-"# V Next </c> </div> href href= DOS LUIZ AKA ID "views slideshow singleframe prev gallery- block CLASS " views Sl ideshow singlefrome previous VIEWS si ides how previous AKA id="views_ slideshow_ singleframe. playpause„ gallery- block III class "vietvs slideshow singleframe PAUSE VIEWS si ides how pause AKA id= VIEWS slideshow. singleframe. NEXT gallery- block III class " views slideshow singlefrome NEXT VIEWS ides how next" href BIG lp> s-11 vi avs_sl ingle romc_p rev us vi c*s_5 id us how_previ ou t.a bio ck.l11 las s-11 wi cws_sl ideshofl_si ngl ramc_pou sc clos vi ew_sl ideshow.si ngl romc_n cxt STYLE DISPLAY id=" vi ews_sli deshow_singl ef r ame_ controls„gal lery- class- "views si ideshow singLetrome controls vi ews_sl id eshow controls idU" view s_sl idesho*_si ngl ef rame_cont rol s_gal ry- bio ck_l s-11 viaws_sl ideshorrsi ngl ramecont rols uiews_l eshow_cont rol iglef slideshoiv idehoiv_ PL Ldc'iC.pr OF Icr clcchon TOO lr- I -i Jos dechon WING Icr LIES single dechon £tiq GAS sinjlcT 0,0 wic.prc jo jsnc. lock. viCi.s_s"L .dcfiho.Liii raric_playpflus jo vid.r.l.dcfiho" lock. JAR ni- BTR SQUAT IF .tnsilft ls,? WWI ilk:. 4i" t£t WILF FIG i >a 1 1 BOOB LO GRAMP IS«H|tll TO HR H'.-xl LT. Previous

It's a horrendously long blog title, I know, but I wanted to mash in all the keywords I was looking for when trying to find a solution to this very sticky problem so that other folks running into the same issue can spend the next six hours doing something more productive.

jQuery makes grabbing one group of elements from a page, duplicating them and adding them somewhere else really easy. You just use a combination of clone() and something like append(), as in the following:


The problem with dynamically adding form elements in IE

Woot! So easy! Right, until you start goofing with forms and IE (Internet Explorer) (appropriate sound). The problem is that IE doesn't allow you to manipulate the 'name' attribute in the DOM directly. So, something like this won't work:

$('#form_element').clone().attr('name', 'new-name').appendTo('#my-form);

If you do that with a radio button, the interface will tell you that there's a problem, because since the new radio button has the same name as the original one, only one can be selected. Bugger!

Luckily, the solution is clear, but it took forever to figure it out. Instead of adjusting the name attribute directly with something like attr(), you need to edit it manually in a block of html and then add that html to the page. So, something like this would work:

replace(/orignal_name/, 'new_name').appendTo('#my-form');

There's a couple of key points here:

  1. Because we're getting the html using $.html(), we need to move up the DOM to grab the element surrounding the element we wish to add using $.parent(), then we can grab the html using $.html().
  2. I'm using the javascript replace() function to pass a regex pattern and replacement text to the html.

What about dynamically cloning groups of inputs with jQuery?

In my particular use case, I was grabbing a set of form elements and adding them this way. There were a couple of challenges, which was that I couldn't use $.parent() to get the outer element, and the other was that the names of the form elements were being set dynamically. I learned a couple of tricks to help with this:

Use the regex modifier /g to replace all insteances of a pattern. So, when doing replace(), if I needed to replace ALL instances instead of just one, it would look like this:

replace(/original_name/g, 'new_name')

Because I couldn't use $.parent(), in the end I had to wrap an element around the html using simple contatination, like so:

var newHTML = '<div>' + $('#element').html() + '</div>';

I hope that helps you, it was sure a bugger to figure out.


After reading Drupal 6 Javascript and jQuery (Matt Butcher, Pact Publishing), I gained a new appreciation for writers attempting to expound on a one specific aspect of Drupal development. jQuery, for example, can be used by nearly every layer of Drupal, from module building to theming, from the file system to forms. How does one boil down the many and varied applications of this multi-purpose tool into a reasonably sized book? I think Matt Butcher did a fantastic job of doing just that.

The book was not quite what I expected, and that's a good thing. For one, the author assumed a minimal amount of experience from the reader, and started at square one with some basic terminology and a first 'hello, world' tutorial. Like most tech tutorial books, the chapters are comprised of 1-3 mini projects where some new ideas or techniques are introduced. For the most part, each chapter builds on previous chapters, illustrating more complex functionality. Another thing that struck me from the start and continued to impress me throughout was the quality and creativeness of the example projects. While few of the examples were production-ready, they solved common issues in a compelling way. Here's a quick list of some of the mini-projects:

  • Load an RSS feed via AJAX
  • Create a live in-page alert when new comments are added
  • Create a text editor
  • Create a random, rotating node teasers in jQuery
  • Write a jQuery plugin

A lot of these projects have crossed my mind as things I'd like to dig into at some point anyway. In addition to being interesting ideas, these projects are also executed in a way that brings together many aspects of Drupal. Having used jQuery and Drupal for a couple of years now, I felt like I knew the basics, but I was pleasantly surprised to learn something new in virtually every project. Some things I learned, but didn't expect to:

  • How to use JSON - I've been wanting to wrap my mind around that for a while
  • How to use translations in jQuery
  • What are Drupal behaviors - If you don't know about them now, you absolutely need to! They solve one of the more complex problems I've dealt with in complex jQuery apps
  • How to theme in jQuery - Awesome, I didn't know you could do that
  • Creating jQuery functionality in themes - I had thought this was a purely modular job, but no!

By the time you make it through the book, you've been introduced to all of the major parts of Drupal. If I had known nothing about Drupal from the start, I would come out the other end with the ability to create themes, modules, and jQuery plugins. Not bad for 318 pages, probably half of which is code. And the fact that I was still satisfied even having worked with Drupal and jQuery for the last couple of years says something to the depth of the material covered.

I was excited enough about the new stuff I learned that I picked up a module that had been languishing for a while and re-wrote a bunch of the code using the principles addressed in this book. The code is now a whole lot easier to understand and debug. The 2 major concepts I applied were object oriented javascript and Drupal behaviors. Drupal behaviors is binding jQuery actions to html elements on the fly, so if you load up some new content via ajax, you can then attach all the jQuery stuff to it without affecting the rest of the page (like accidently attaching an action a second time, which can have undesirable consequences). I've found all kinds of ways of dealing with this is the past, and they've all been really ugly in comparison. Behaviors are a breath of fresh air, and there were lots of examples in Drupal 6 Javascript and jQuery to really anchor the coolness of them.

Minor Nitpicks

My criticisms of the book are really minor in comparison with my praise. There were quite a few typos and consistency errors. In another genre of book I wouldn't be as concerned, but when dealing with code where one misplaced character can break an entire script, running into typos in the text reduces confidence that the code will work if copied verbatim, especially for the unexperienced programmer. I actually worked through every example up until the last two chapters, and was pleased to find out that they all (with one exception) worked as advertised. The one exception was in Chapter 7 where a module is required that does not produce valid JSON. It took me a while to discover the problem, look and find a patch to the module. One more really minor thing is that I felt that the tone vacillated a bit, assuming at times that the reader was new to programming, and at others more experienced. Sometimes a good bit of work went into describing more complex programming conventions, and at other times they were more casually alluded to.


Overall, I was really happy to spend the time reading this book. I'm not the fastest reader, and working through the code examples takes me some time, but it was worth it. It anchored some important Drupal 6 conventions, illustrated some best practices for jQuery which can extend from simple to complex projects, and introduced me to some of the ways that jQuery integrates with the different aspects of Drupal. I'm looking forward to reading more from Matt, and would recommend this book to anyone aspiring to jQuery ninja-dom.

Notes in the margin

I made several notes in the margin of the book that didn't make it into the above review, so here they are for those interested:

  • Until later on in the book, the example code snippets were short, which I appreciated
  • I liked the idea of introducing jQuery in the theme layer in early chapters. Really simple, good call.
  • Good callout in the translation chapter, which says 'hey, translations are really important, don't skip this chapter'. By the title, it was the least interesting chapter to me, but I really enjoyed it.
  • Excellent job covering lots of gotchas: Syntax coloring, can't call ajax on a different domain
  • Creating a javascript templating engine - weird and cool!
  • Would have liked a chapter on jQuery.getScript() - dynamically load javascript
  • How to handle cookies in jQuery - yea!
  • I like the .info file trick - stick your own stuff in there, use it later
  • I really liked the using caching for search auto-complete example. Will definitely use that one in the future.

Syndicate content