You have tried to create facebook-like chat panel with meebo before. Now we are going to try it with drupal modules. You decide which module you prefer. See the post again for all available chat modules in drupal.

If the module outputs a block, you are good to go. Otherwise, you'd better ask the module maintainer for one. For the sake of tutorial, you may try the one I tested here, tribune.module. I picked the latest 6.x-1.10 when I posted this. When it works, you can always change it into your own module and adjust everything accordingly.

There are three ways I know how to deal with modules theming, chat module in our case. If you have other ways, please leave a comment so I can learn better. We are going to walk through this one at a time, and see the difference.

I am trying to refine the previous post now as well. What you are going to see here is to reflect the latest change I did in my own development site. We are always getting better over time. That's the beauty of learning or teaching by doing. :)

I assume you are familiar with how to add files (.js, .css, .tpl) and register them. There are six files to edit totally:, template.php, page.tpl, block.tpl, script.js and style.css, and tribune.module to copy some themeable functions over into template.php.

Preparing the container

We need some jquery code to toggle the chat block, CSS selectors and variables to dynamically output the classes.

Adding the regions into .info

We are going to have three collapsible blocks in the dockbottom regio. Add this into your .info:

regions[dockbottom_first]   = dock bottom first
regions[dockbottom_middle]  = dock bottom middle
regions[dockbottom_last]    = dock bottom last

Adding script.js

>See another post how to add custom script and custom function to jquery. This time we are going to add height rather than width to create a slide up or slide down effect. And make it more generic so that other regions in bottom docks may have the same slide up effects more easily.

So place this slideUpToggle function inside your custom javascript file, script.js. See the reference and further explanation:

  jQuery.fn.slideUpToggle = function(speed, easing, callback) {
  return this.animate({opacity: 'toggle', height: 'toggle'}, speed, easing, callback);

And then we need to actually implement the slide effect to toggle the chat block:

$(function () {
  $(".toggleup").click(function (){
    $(this).toggleClass("toggledown"); return false;

So we have selectors for CSS: #chat, .toggleup and a dynamic .toggledown which is used to toggle down or close the chat block.

Adding css codes

If you have already had a bottom dock panel set from the previous post, see the relevant changes to match the former. If not, what you see below is the refined codes to reflect the latest change I did in the demo site.

We are preparing things to have the chat panel along with other regions there.

#dockbottoms {
  padding:2px 0 0;
  border:1px solid #999;
  z-index:11000; /*Allow layering*/

#dockbottoms-inner {

/*Reset defaults in the narrow space*/
#dockbottoms-inner .block {
  padding-top:5px; /*Match .slider for chat*/

#dockbottoms-inner #dockbottom-first {

/* Dockbottoms regions
* first | middle | last
#dockbottoms-inner.dockbottoms-1 .column {

#dockbottoms-inner.dockbottoms-2 .column {
  margin:0 14px;

#dockbottoms-inner.dockbottoms-3 .column {
  margin:0 14px;

And the chat block container:

/* Chat block sample, adjust everything here*/
#chat-wrapper {
  z-index:11002; /*value above #dockbottoms-inner*/
  border:1.5px solid #ADADAD

#chat {
  display:none; /*hide the chat block, let jquery toggles*/

.slider {
  z-index:11003; /*value above #chat*/
  margin-top:-5px; /*Match #dockbottoms-inner .block */

/*Add image if necessary, such close or open buttons*/
.toggleup,.toggledown {
  background-color:#E8E9ED; /*Match .slider*/

/*Menu links in the dock. Correct disturbing stuffs from system*/
#dockbottoms li.collapsed,#dockbottoms li.leaf {
  padding:0.2em 0.5em 0 0

#dockbottoms {

Preparing region variables in template.php

Open and edit template.php, and place the code below inside yourtheme_preprocess_page:

// We need a variable to output dynamic relevant classes with number of active sub-regions
  // Borrowed from sweet acquia_marina
$region_list = array(
'dockbottoms' => array('dockbottom_first', 'dockbottom_middle', 'dockbottom_last')
//add more collapsible blocks here if necessary, such as footer, header or content_top blokcs

  foreach (

$region_list as $sub_region_key => $sub_region_list) {
$active_regions = array();
    foreach (
$sub_region_list as $region_item) {
      if (
$vars[$region_item]) {
$active_regions[] = $region_item;
$vars[$sub_region_key] = $sub_region_key .'-'. strval(count($active_regions));

Adding the region variables into page.tpl

Variable dockbottoms is now available in page.tpl. We use it to dynamically add relevant classes whether one, two or three regions are active.

Open and edit page.tpl, and place this somewhere below the footer.:

  <?php if ($dockbottom_first || $dockbottom_middle || $dockbottom_last): ?>
    <div id="dockbottoms"><div id="dockbottoms-inner" class="<?php print $dockbottoms; ?> clearfix">
  <?php if ($dockbottom_first): ?>
    <div id="dockbottom-first" class="column">
      <?php print $dockbottom_first ?>
  <?php endif;?>
  <?php if ($dockbottom_middle): ?>
    <div id="dockbottom-middle" class="column">
      <?php $dockbottom_middle?>
  <?php endif;?>

  <?php if ($dockbottom_last):?>
    <div id="dockbottom-last" class="column">
      <?php print $dockbottom_last; ?>
  <?php endif;?>
  <?php endif; ?>

That's it all for the container. We are proceeding into the actual theming of the chat block.

Theming the chat block

We have three options as said previously. Only pick one over the others after you understand the difference.

1. Via template.php

If your module do not provide any theme overrides, you may skip this step and go on to the second.

I assume you have tribune.module installed and ready to deploy.

  1. Open tribune.module file with text or code editor, and find line #791, theme_tribune_block. This function output the themeable chat block. Copy and paste it into your template.php. I assume you have one and know what it is :). If your theme doesn't have it, you are unlucky :). Just kidding, just create it now.

    See the comments for explanation.

    function yourtheme_tribune_block($posts, $tribune_id) {


    //Add chat container
    $contents = "<div id='chat-wrapper'><div id='chat'>";
      if (
    variable_get('tribune_order', 'top_to_bottom') == 'bottom_to_top') {
    $posts = array_reverse($posts);
    $contents .= "<ul class='tribune-posts tribune-block' id='ul-". $tribune_id ."'>\n";

      if (

    sizeof($posts) > 0) foreach ($posts as $post) {
        if (!
    $post['moderated'] || user_access("moderate tribune")) {
    $contents .= theme("tribune_post", $post) ."\n";


    $contents .= "</ul>\n";


    // We also add chat slider and the chat container closing
    if (variable_get('tribune_order', 'top_to_bottom') == 'bottom_to_top') {
    drupal_get_form('tribune_add_form_block', $tribune_id) . $contents . "</div><div class='slider'><a href='#' class='toggleup'>Chat with Me</a></div></div>";
      } else {
    $contents . drupal_get_form('tribune_add_form_block', $tribune_id) . "</div><div class='slider'><a href='#' class='toggleup'>Chat with Me</a></div></div>";

    Make sure you change yourtheme into your actual theme name.

    You may also want to override theme_post_time (line #877), theme_post_username (line #885), theme_post_message (line #904), theme_tribune_post (line #916) whenever ready to have more fun, such as adding tiny avatars using imagecache, moving post_time around, etc.

  2. Now that you have overriden your module and added the function into your template.php, you must rebuild your theme registry by going to admin/build/themes so that drupal knows your new function.
  3. Go to admin/build/block/list/yourtheme, enable your tribune block into your chat panel.

That's it for option #1. If you follow the previous post, and everything goes as expected, you'll have the chat panel now.

With this option you have all the flexibility to override everything. But please bear in mind that you may also have to follow any possible change of codes with every single release of the module, who knows the code changes radically or you find unexpected behavior.

2. Via block.tpl

You may need to start all the basics from core templates and block suggestions or install themer.module. Or for now, go to admin/build/block/list/yourtheme, and find out yourself the block ID or delta by hovering over "configure" link to the block you want to theme. See the URL on the bottom left of your browser window. Since we work with tribune.module, it says: admin/build/block/configure/tribune/0.

So we get delta 0 for the chat block. Note that in your mind.

  1. Go to your theme folder, I picked Garland. Copy your default block.tpl and name it to block-tribune-0.tpl.
  2. Open it and edit. Add the chat container divs before the title and end it up with the sliding toggler:
    <div id="block-<?php print $block->module .'-'. $block->delta; ?>" class="clear-block block block-<?php print $block->module ?>">

    <div id="chat-wrapper"><div id="chat">
    <?php if (!empty($block->subject)): ?>
      <h2><?php print $block->subject ?></h2>
    <?php endif;?>

      <div class="content"><?php print $block->content ?></div>
      </div><!-- //#chat -->
      <div class="slider"><a href="#" class="toggleup">Chat with Me</a></div>
      </div><!-- //#chat-wrapper -->


  3. A new template is added. You guess it right :) Clear the theme registry. You are familiar already. No? Why not?
  4. Go to admin/build/block/list/yourtheme, enable the block.

If someday you change your mind and want to use the region for a contact or login form instead, you can always create another block template and use the same region for the whole new block. You are in the most flexible way offered here. So please consider this option as priority among others.

That's it for option #2.

3. Via page.tpl

This is the quickest and dirtiest way we have. If you have read the previous post with meebo, think the whole meebo code as a block output by tribune. Since we have no way to put additional slider and divities into block configuration to contain the actual chat block, we need to place the divs directly into page.tpl instead.

  1. Open and edit your page.tpl. See Adding the region variables into page.tpl section above. We just place the chat container directly this time:
      <?php if ($dockbottom_last): ?>
        <div id="dockbottom-last" class="column">
          <div id="chat-wrapper">
            <div id="chat">
              <?php print $dockbottom_last; ?>
            <div class="slider"><a href="#" class="toggleup">Chat with Me</a></div>
      <?php endif;?>
  2. Enable the tribune block into the region. You may need to adjust the block title there.

This way, you have the shortest cut, but the most inflexible way. You dedicate that block for the chat only, I mean those markups semantically bind you into chat :) Use more generic selectors if you want to go this way.

That's it for option #3.

Access permission, user or friend relationships, avatar for the chatters is simply beyond this simple post which covers only all the block theming basics.

To get the look like the screenshot, you may add this to your CSS:

/*Additional theming specific to tribune.module block. Specify #chat to restrict the changes*/
#chat ul#ul-tribune-block-0 {
  overflow-y:scroll; /*Make the chat scroll to not break your design*/

#chat #ul-tribune-block-0 .tribune-post-form input.form-text {
  width:60%; /*Make it inline in narrow space*/

#chat #ul-tribune-block-0 .tribune-posts li.tribune-self-post {
  border-left:0; /*Override default*/

The demo is using the meebo version, but here is the final product.

facebook chat panel

You have to either inspect with firebug, a developer extension for FireFox, or copy over the css files inside your tribune.module to override and theme anything.

I'll be happy to hear your own way and any suggestion. I am learning the best practices as well. Thanks.

tribune chat