Generate tabs for blocks using jQuery
The following will allow your site to generate a tab for every block assigned to a region. It requires jQuery and the tabs plugin from stilbuero.
Each block from Drupal will have its' own tab for a designated region. It's an efficient way to save space and clear out the clutter from your sidebars or wherever else you have more than one block. -look below for live example in a drupal site.
The main problem is the way blocks are structured out of Drupal. The subjects need to be grouped together in an unordered list with a link pointing to a block it's related to. Drupal outputs the subject right above the block content which is difficult to override server side.
Drupal's output:
<code>
<div id="block-1" class="block">
<h2 class="title">subject 1</h2>
<div class="content">
...
</div>
</div>
<div id="block-2" class="block">
<h2 class="title">subject 2</h2>
<div class="content">
...
</div>
</div>
<div id="block-3" class="block">
<h2 class="title">subject 3</h2>
<div class="content">
...
</div>
</div>desired results:
<code>
<div id="tab-container">
<ul class="tab-title-group">
<li class="tab-title"><a href="#block-1">subject 1</a></li>
<li class="tab-title"><a href="#block-2">subject 1</a></li>
<li class="tab-title"><a href="#block-3">subject 1</a></li>
</ul>
<div id="block-1" class="block tab-block">
<div class="content">
...
</div>
</div>
<div id="block-2" class="block tab-block">
<div class="content">
...
</div>
</div>
<div id="block-3" class="block tab-block">
<div class="content">
...
</div>
</div>
</div>One way to achieve this is to use jQuery's DOM manipulation. A big bonus of this is that the tabs will not break the site if someone is browsing without javascript. It will just be another block to them. Your block.tpl.php does have to output a unique id, a class of "block" and the subject must have a class of "title". -look above for the assumed structure.
First prepare a new region in your template or dedicate an existing one for the tabs. Inside your page.tpl.php file, look for a region and surround it with a unique div. Lets say for example that you have a region named "tab-region". The id of "tab-container" is what will be called to trigger the tab plugin.
<code>
<?php if ($tab-region) { ?>
<div id="tab-container">
<?php print $tab-region ?>
</div>
<?php } ?>Now you must include the jQuery library. If your using version 4.7, a patch is available. Be aware that it can cause complication down the line since it is not supported! It's part of Drupal core for version 5 though.
An easy alternative is to link to jQuery directly in the page.tpl.php. The biggest side effect is that it can conflict with the functions inside autocomplete.js and upload.js files. This is a known problem so you can try and modify core files or use the code below which checks for the files and disables itself if it is present. It's a cheap solution until you decide to patch 4.7 or upgrade to 5. Considering that your site shouldn't break when it's disabled, it's not an unreasonable tradeoff.
<code>
<!-- check for autocomplete.js -->
<?php if (!preg_match("/autocomplete.js/",$head) || !preg_match("/upload.js/",$head)) { ?>
<link rel="stylesheet" href="<?php echo url($directory.'/tabs.css') ?>" type="text/css" media="print, projection, screen" />
<!--[if lte IE 7]>
<link rel="stylesheet" href="<?php echo url($directory.'/tabs-ie.css') ?>" type="text/css" media="projection, screen" />
<![endif]-->
<script type="text/javascript" src="<?php echo url($directory.'/scripts/jQuery.js') ?>"></script>
<script type="text/javascript" src="<?php echo url($directory.'/scripts/jQuery.tabs.js') ?>"></script>
<script type="text/javascript">
$(document).ready(function(){
// new class is added for separate optional theming.
$("#tab-container > .block").addClass("tab-block");
// iterate through each block chaining functions.
$("#tab-container > .tab-block").each(
function() {
$(".title",this)
// wrap .title in li.
.wrap('<li class="tab-title"></li>')
// make link fragment from block id. Must be unique! $(this) = .tab-block or .block
.wrap('<a href="#' + $(this).id() + '"></a>');
// copy inner text of .title into the link.
$("li.tab-title > a",this).append($(".title",this).text());
// delete old .title since markup associated with it doesn't make sense here.
$("li.tab-title .title",this).remove();
}
);
// add an unordered list container to the top of #tab-container.
$("#tab-container").prepend('<ul class="tab-title-group"></ul>');
// move all list items to unordered list container.
$("#tab-container > .tab-title-group").prepend($("#tab-container .tab-title"));
// trigger tabs with optional effects. More options available. Look at the documentation.
$("#tab-container").tabs({fxAutoheight: false, fxSlide: false, fxFade: true, fxSpeed: 180});
});
</script>
<?php
}?>Place all the files into your theme folder including the css files included with the plugin. From there it should function but you must style the css files to match your theme. Use the new classes to style so the blocks don't look out of place when the script is disabled or when a visitor has javascript turned off.
Generated classes:
<code>
.tab-title-group {
...
}
.tab-title {
...
}
.tab-block {
...
}Any blocks added to your "administration > blocks" page will have its' own tab now. You can reorder them, hide/show them as usual.
Take a look at stilbuero's demo page for usage information.
notes:
- this came out of a forum question http://drupal.org/node/88558.
- working example in a drupal site. -scroll down Theme isn't finished so it will break in Internet Explorer.
- If you know of a way to make it more efficient then please post. The author of this post is by no means an expert.

Need more than one region?
I just learned how to generalize it by turning it into a function. This way you can have more than one tab region.
<code>function tabTrigger(id) {
var id = $(id);
$("> .block",id).addClass("tab-block")
.each(
function() {
$(".title",this).wrap('<li class="tab-title"></li>').wrap('<a href="#' + $(this).id() + '"></a>');
$("li.tab-title > a",this).append($(".title",this).text());
$("li.tab-title .title",this).remove();
}
);
id.prepend('<ul class="tab-title-group clear"></ul>');
$("> .tab-title-group",id).prepend($(".tab-title",id));
return $(id);
}
Use
tabTrigger("#id")to restructure the DOM and chain it to.tabs(...)like so:<code>$(document).ready(function(){
tabTrigger("#tab-container1").tabs({fxAutoheight: false, fxSlide: true, fxFade: true, fxSpeed: 280});
tabTrigger("#tab-container2").tabs({fxAutoheight: false, fxSlide: true, fxFade: true, fxSpeed: 280});
});
–joon
jstools' tabs module integrates tabs plugin from stilbuero
For the sake of completeness a link to jstools: http://drupal.org/project/jstools .
I have been using tabs.module in the 4.7 version with Erik Arvidsoon's Tab Pane. It took me a while to figure out that I didn't have to write my own wrapper for the tabs plugin from stilbuero - tabs.module for 5.0 integrates it!
former username: lx_barth
Improved tab creation
Hi all, I'm the creator of the Tabs plugin. Although I don't have the time to give additionally support for Drupal/Tabs here, after a Drupal user pointed me to some problems he had I'd like to suggest an improvement. The problem is as follows:
The tabs creation code in the example creates invalid markup (<a><li><h2>) which is not a good choice to start with when DOM scripting and can result in unexpected results in one or the other browser. Here's how I would go about it - it also should perform much better as less queries and less DOM operations are involved:
// create ul for tabs
var ul = $('<ul class="tab-title-group"></ul>').prependTo( $('#tab-container') );
$('#tab-container > .block').addClass('tab-block').each(function() {
// remove .title and get text from it
var title = $('.title', this).remove().text();
// create tab and append to already created list
ul.append('<li class="tab-title"><a href="#' + this.id + '">' + title + '</a></li>');
});
// trigger tabs with optional effects. More options available. Look at the documentation.
$("#tab-container").tabs({fxAutoheight: false, fxSlide: false, fxFade: true, fxSpeed: 180});
This is not meant to spoil anyone's work, but just as help.
Improved tab creation function
I wrapped up the previous script in a function, so that you can use it with multiple tab groups:
function tabTrigger(id){
var out = id + ' > ul';
var id = $(id);
var ul = $('<ul class="tab-title-group"></ul>').prependTo( $(id));
$('.block',id).addClass('tab-block').each(function() {
// remove .title and get text from it
var title = $('.title', this).remove().text();
// create tab and append to already created list
ul.append('<li class="tab-title"><a href="#' + this.id + '">' + title + '</a></li>');
});
return $(out);
}
You can use it like this:
$(document).ready(function(){tabTrigger("#tab-container1").tabs();
tabTrigger("#tab-container2").tabs({fxAutoheight: false, fxSlide: true, fxFade: true, fxSpeed: 280});
});
Since I had no clue what I was doing (I used The Force), please do not hesitate to improve!
A>
Small problem with the above code...
This is a great solution to the "tabbed blocks" question! However...
I used it on a site and found I was running into a problem - everything was cool with the first tab, but any links present in the other tabs' content were getting incorrect hrefs.
The solution, I discovered, is on the last line of the code which generates the list of tabs. Instead of this:
$("#tab-container").tabs({fxAutoheight: false, fxSlide: false, fxFade: true, fxSpeed: 180});
You should use this:
$("#tab-container > ul").tabs({fxAutoheight: false, fxSlide: false, fxFade: true, fxSpeed: 180});
Note the added "> ul") in the selector. Hope this helps someone...
jsTools Tabs
If you use the Tabs module in jstools http://drupal.org/project/jstools or for drupal6 http://drupal.org/project/tabs you can easy add tabs to your site
$block = module_invoke('block', 'block', 'view', 1);
$tab1 = $block['content'];
$tab2 = t('This is some random text you want to add to your user');
$tab3 = t('The number of the day is @number', array('@number' => rand(10, 0)));
$view = views_get_view('archive#),
$tab4 = views_build_view('embed', $view);
$form['tab'] = array(
'#type' => 'tabset',
);
$form['tab']['tab1'] = array(
'#type' => 'tabpage',
'#title' => t('One'),
'#content' => $tab1,
);
$form['tab']['tab2'] = array(
'#type' => 'tabpage',
'#title' => t('Two'),
'#content' => $tab2,
);
$form['tab']['tab3'] = array(
'#type' => 'tabpage',
'#title' => t('Three'),
'#content' => $tab3,
);
$form['tab']['tab4'] = array(
'#type' => 'tabpage',
'#title' => t('Four'),
'#content' => $tab4,
);
print tabs_render($form);
----------------------------------------
Blog: www.freeblogger.org: German IRC-Channel: irc.freenode.net #drupal.de ... Jabber-me: dwehner@im.calug.deXING