OMG! Dynamic jCarousel with Themed Panels 2 pane node parts!

Panels 2, the quiet revolution indeed! This tutorial will go through a series of detailed exploratory steps to achieve a dynamic jCarousel panel whose content is derived from the attached files of the node context of a panel page configured for node override. That is, the jCarousel pictured in the following image contains the thumbnails of all the images attached to the node providing the context to the shown panel page. And this is achieved by overriding theme_panels_pane(), the default theming function for individual panels in a panel page.

Panels 2, the quiet revolution indeed! This tutorial will go through a series of detailed exploratory steps to achieve a dynamic jCarousel panel whose content is derived from the attached files of the node context of a panel page configured for node override. That is, the jCarousel pictured in the following image contains the thumbnails of all the images attached to the node providing the context to the shown panel page. And this is achieved by overriding theme_panels_pane(), the default theming function for individual panels in a panel page.

Dynamic jCarousel with Themed Panels 2 pane node parts!

Dynamic jCarousel with Themed Panels 2 pane node parts!

In plain English, what I want is a panel page which overrides nodes of type "vehicle". On the top I want one pane which has a jCarousel slideshow of all the images I have uploaded by attaching files to the node using the glorious killes masterpiece Upload Image module. Then just below this I want to include a teaser like field which is also included in the cck generated content type. And on the bottom will come the rest of the node’s content.

Panels 2 References

This is an intermediate level tutorial, if you are completely new to Panels 2 (practically everyone), you would be well served by checking out the following background info, tid-bits and tutorials:

Project page: http://drupal.org/project/panels


panels 5.x-2.0-beta2: http://drupal.org/node/210923


Panels 2 Documentation & Handbook on drupal.org: http://drupal.org/node/201914


Group on g.d.o.: http://groups.drupal.org/panels


Early but interesting "Panels 2 documentation" on g.d.o: http://groups.drupal.org/node/7350


Panels 2 Tabs module (Wim Leers): http://drupal.org/project/panels_tabs


Demo: http://nodequeue.demo.logrus.com/


merlinofchaos snippet on creating panels templates: http://drupal.org/node/206317

Step 1: How does jCarousel work on Drupal, anyway?

A very convenient way of making Drupal jCarousel-ready is by installing Wim Leers thoughtful jCarousel module. As advertised, this simply installs (no small measure of convenience) the version of the jQuery jCarousel plugin which is compatible with jjeff‘s jQuery Update module (version 1.1.2 instead of the ancient 1.0.1 which comes bundled with Drupal 5.x), and provides a convenience function for modules or theming templates to call.

So first you install jQuery Update and then jCarousel.

Step 2: Let’s give jCarousel a dry-run test on Drupal

Just to make sure we have all our ducks in a row, let’s just set up a test page, shall we? Create a page content type, and invoke the php input filter, and paste in the following:


Just hit submit, and we should have that working.

Let’s modify it a bit just to get the autoscrolling going:


To see more fun possibilities, check out the source code (jquery.jcarousel.js) to see "var defaults".

Step 3: Preparing the panel page

The panel page takes after the node override example in the Drupal Handbook. The main thing is to set the path to "node/%" in the settings tab, then in the context tab, add a "Node ID" argument, enabling the content type under "Node types" and "Own display". After choosing suitable layout settings according to the layout of your choice, go to the main content tab, where we have to click on the "Node ID 1 Page" tab (not the default tab) in order to add content by clicking on a pane’s "+" sign. In the pop-up "Add content to …", under "Node context" click on "Node content" for one pane; and, in another pane, click on "Attached files". It is the latter that is of interest in this tutorial.

The whole idea is to be able to distribute bits and pieces of the node satisfying the panel argument in different panes, together with content related to it as well; this is the idea of “context” (the context of the panel is the argument) and a whole revolution in total layout control.

It is assumed that several images have already been uploaded to some nodes of the type. That being the case, when you navigate to http://example.com/node/123 (where 123 is the nid of a node of the kind specified in the panel page, and has attached files already uploaded) in the "attached files" pane a list of attached files will be seen, while in the "Node content" pane, the node content will be visualized.

What we now want to do is theme the simple list of files into a dynamic jCarousel loaded with that list, according to which node is being displayed.

Step 4: We know about overriding theme functions, but how do you override panels theming?

In the Panels issues queue there is an intriguing interchange between merlinofchaos himself, and an unsung hero pioneer, jockox3@drupal.org, who was basically asking himself this question. The gist (apart from the fascinating discussion about letting Panels 2 take over all Drupal layout duties, very interesting…) is:

"Okay – I spent the day reading the panels module code and assume I have
to override the function theme_panels_pane($content, $pane, $display)
function from the panels.module file."

Cool. So I went to panels.module and dutifully copied over this theming function to my phptemplate file, renaming it to "phptemplate_panels_pane" as I would any theming function I was going to override.

Step 5: Many print_r()’s later, we are in control, folks!

I’m Josh Koenig (joshk) and Drupal Dojo trained, and damn proud of it! I know for a fact from my hatchet bearing mentor (can’t find that video online that shows Josh splitting trunks to show how productive his Drupal shop is, very original! It is hard work!) what he taught us in those first heady free-for-all days of drupal dojo: you can do anything with a bit of nerve, print_r() and running things till the error messages just go away!

So basically I examined the 3 parameters to the theming function and came up with the following code (explained below) to get what I wanted (see image at start of article). Of course, it would have been neater to bundle up everything in terms of a phptemplate callback function, but I was pretty happy with what I got so far:


function phptemplate_panels_pane($content, $pane, $display) {
// start of modified section for node "Attached files" pane
if ($pane -> pid == '32') {
if ($pane -> context -> data -> files) {
jcarousel_add('ie7');
drupal_add_js (
'$(document).ready(function(){
$("#carousel-cars").jcarousel({
scroll: 1,
auto: 3,
wrap: "last"
});
}); ',
'inline');
$cars = '

';
}
$content -> content = $cars;
}
// end of modified section for node "Attached files" pane
// from this point on, the original theming function is left intact
if (!empty($content->content)) {
$idstr = $classstr = '';
if (!empty($content->css_id)) {
$idstr = ' id="' . $content->css_id . '"';
}
if (!empty($content->css_class)) {
$classstr = ' ' . $content->css_class;
}

$output = "

n";
if (user_access('view pane admin links') && !empty($content->admin_links)) {
$output .= "

n";
}
if (!empty($content->title)) {
$output .= "

$content->title

n";
}

if (!empty($content->feeds)) {
$output .= "

" . implode(' ', $content->feeds) . "

n";
}

$output .= "

$content->content

n";

if (!empty($content->links)) {
$output .= "

n";
}

if (!empty($content->more)) {
if (empty($content->more['title'])) {
$content->more['title'] = t('more');
}
$output .= "

n";
}

$output .= "

n";
return $output;
}

Explanation of code

It is important to bear in mind that theme_panels_pane() does just that: it themes a pane in a panel. In order to render a complete panel page, each pane is rendered via a separate call to this function. Here we are on the lookout for the pane with the list of attached images.

We start with a simple if statement looking for the unique panel id of the "Attached files" panel. If there are any files (if the parameter $pane shows there are files under $pane -> $pane -> context -> data -> files) then we enable jcarousel with the jcarousel_add function, invoking the ie7 theme instead of the default tango theme. This has to match the class element "jcarousel-skin-ie7" of the <ul> jcarousel container tag.

Next comes the inline javascript actually invoking the jcarousel function itself, with the parameters necessary for autoscrolling.

We then iterate over the list of attached files present in the parameters and set up the necessary <li> tags as wrappers around the file paths.

We then assigned the accumulated html to the $content -> content variable, and let nature run its course…

I hope this will be of use to someone, I found it fascinating as a small step towards experimenting with this revolutionary way of thinking about layout and contexts in Drupal.