Collapsible Blocks with Cookies

Want to create collapsible blocks in Drupal 6 that actually remember the state the user left them in?

It's pretty easy with JQuery which is built-in to Drupal 6.

The JQuery Code

First. We want to download the JQuery Cookie Plugin (http://plugins.jquery.com/project/cookie) which will allow us to remember the state of the blocks (shown/hidden). Now upload that file to your theme's directory. Create a new file in a text editor. Call this file blocks.toggle.js. Type the following:

function toggle_block(id, target_id){

}

This function accepts two parameters. id and target_id. id is the clickable item that controls the collapsing/expanding. The variable target_id is the item that is shown/hidden. In this case the block's content.

Within the above function type the following:

$("#"+id).click(function() {

});

This binds the id to a click event. The function within it is executed every time the id is clicked. This is the part of JQuery that I love the most. It reminds me of Listeners in ActionScript.

Our code in blocks.toggle.js should now look like this:

function toggle_block(id, target_id){

$("#"+id).click(function() {

});

}

Now to the fun stuff... Type the following within the click function.

if($.cookie(target_id) != 'shown'){
$("#"+target_id).show('slow');
$.cookie(target_id, 'shown');
}else{
$("#"+target_id).hide('slow');
$.cookie(target_id, 'hidden');
}

All we are doing here is simply testing to see what the cookie reads and making JQuery react based on those parameters. In the first line 'if($.cookie(target_id) != 'shown'){', we are testing to see if the cookie's content does not equal 'shown' (the cookie's content would be 'hidden' or null) when the id selector is clicked. We simply show/hide the target_id based on the content of the cookie, which is this line $("#"+target_id).show('slow'); or $("#"+target_id).hide('slow'); respectively. We also control the speed at which the object collapses/expands, hence the 'slow' parameter in the 'show' function.

The next line $.cookie(target_id, 'shown'); simply sets the cookies content to 'shown' or 'hidden'.

Now our function should look like this:

function toggle_block(id, target_id){

$("#"+id).click(function() {
if($.cookie(target_id) != 'shown'){
$("#"+target_id).show('slow');
$.cookie(target_id, 'shown');
}else{
$("#"+target_id).hide('slow');
$.cookie(target_id, 'hidden');
}
});

}

We just need to add one more thing and we're done here. Underneath the toggle_block function add the following code:

if($.cookie(target_id) != 'shown'){
$('#'+target_id).hide();
}

Unlike the click event, there is no way for us to no what state the cookie is when the page loads. This function (which is located outside of the previous click function) reads the cookie's content and hides the element if it was previously hidden.

Please Note: The CSS that controls your block's content must NOT have 'display:hidden' as an attribute, as this code will not work.

Your finished code should now look like this:

function toggle_block(id, target_id){

$("#"+id).click(function() {
if($.cookie(target_id) != 'shown'){
$("#"+target_id).show('slow');
$.cookie(target_id, 'shown');
}else{
$("#"+target_id).hide('slow');
$.cookie(target_id, 'hidden');
}
});

if($.cookie(target_id) != 'shown'){
$('#'+target_id).hide();
}

}

We are now ready to save the file blocks.toggle.js and upload it to path_to_your_theme/blocks.toggle.js.

AttachmentSize
blocks.toggle.js.txt345 bytes

Modifying block.tpl.php

We're going to be working with path_to_your_theme/blocks.tpl.php from your default Drupal 6 installation. Open up path_to_your_theme/blocks.tpl.php in TextEdit or your favorite editor.

Firstly we need to add the cookies javascript file and our blocks.toggle.js file to the list of scripts in the <head> tag. To do this we'll use Drupal's built in function drupal_add_js.

In the file path_to_your_theme/blocks.tpl.php put in the following code (I usually put drupal_add_js or drupal_add_css functions at the top of files):

<?php

drupal_add_js(path_to_theme() . '/jquery.cookie.js');

drupal_add_js(path_to_theme() . '/blocks.toggle.js');

?>

Save, Upload and view the source. You will now see that both scripts have been added to the <head> tag of your HTML document.

In your blocks.tpl.php file, find this line:

<?php if (!empty($block->subject)): ?>

Replace the line under it:

<h2><?php print $block->subject ?></h2>

with this line:

<h2><a href="#" id="toggle-<?php print $block->module .'-'. $block->delta ?>"><?php print $block->subject ?></a></h2>

What this does is create the selector for JQuery's click event, dynamically.

Now replace this line:

<div class="content"><?php print $block->content ?></div>

With this:

<div class="block-content" id="block-<?php print $block->module .'-'. $block->delta; ?>">

<?php print $block->content ?>

</div>

Now we have our id's being built dynamically and we're almost ready to finish off.

Go back up to the following part of the page:

<?php



drupal_add_js(path_to_theme() . '/jquery.cookie.js');

drupal_add_js(path_to_theme() . '/blocks.toggle.js');

?>

Add the following code underneath the last drupal_add_js line:

$js = '$(document).ready(function(){' .

' toggle_block(\'toggle-' . $block->module .'-'. $block->delta . '\', \'block-' . $block->module .'-'. $block->delta . '\');' .

'});';

drupal_add_js($js,'inline');

Your code should now look like this:

<div id="block-<?php print $block->module .'-'. $block->delta; ?>" class="clear-block block block-<?php print $block->module ?>">

<?php if (!empty($block->subject)): ?>

<h2><a href="#" id="toggle-<?php print $block->module .'-'. $block->delta ?>"><?php print $block->subject ?></a></h2>

<?php endif;?>

<div class="block-content" id="block-<?php print $block->module .'-'. $block->delta; ?>">

<?php print $block->content ?>

</div>



</div>

This simply fires up the 'toggle_block' when the page loads.

Now upload the file block.tpl.php to 'path_to_your_theme/block.tpl.php', clear your site's cache and voila! You should now have 'smart' collapsible blocks on your site!

AttachmentSize
block.tpl_.php.txt464 bytes

Notes

- If you are using a core theme such as Garland, you need to create your own theme. Even if you're only modifying the theme for the purpose of this tutorial (and of course, to get collapsible blocks). It's always recommended that you do not overwrite any sort of core Drupal files.

- This is untested in Drupal 5