Working with JavaScript in Drupal 6: Part 2

by Matt Butcher | February 2009 | AJAX Content Management Drupal Open Source

In the previous part of the article, we saw how Drupal handles JavaScript and we created a JavaScript tool.

In this part by Matt Butcher, we're going to:

  • Create a simple theme
  • Add JavaScript to a theme

Creating a theme

Drupal separates layout and styling information from processing code. HTML is usually stored in templates or theme functions. The CSS along with other styling information (including some images) are also stored separately from the functional code.

A theme is a collection of resources, (usually template files, CSS, JavaScript, and images) that can be plugged into Drupal to provide layout and styling to a site.

If we want to change the look and feel of a site, the best place to start is with a theme.

We've already created a JavaScript file that provides additional printing functionality. In this section, we are going to create a new theme, and then incorporate our new script.

Typically, a theme must provide the following things:

  • HTML markup for common Drupal structures such as pages, blocks, comments, and nodes. This will include navigational elements.
  • Any styles needed. This is typically done in the CSS files.
  • Any necessary images or media elements that will play a substantial role in layout.
  • Information about the theme, including a screenshot.

In addition to these, many themes will also provide:

  • JavaScript files that may be necessary for added functionality.
  • Other sorts of media, such as Flash animations, may occasionally be needed.
  • PHP code that performs complex layout tasks may sometimes be used.

A theme must have at least one pre-defined file (the theme's .info file). Commonly though, full themes have eight or more files.

Full themes and subthemes

The first step in creating our theme is deciding whether we want to start from scratch or begin with an existing theme. If we were to start from scratch, we would create a full theme. But if we wanted to build on another theme, we could create another kind of theme called a subtheme.

To create a full theme, we would need to implement all of the required features of a theme, and perhaps add on some other features as well. Typically, this would involve creating all of the necessary templates, a couple of CSS files, and a couple of helper files.

Sometimes, it is more expedient to begin with an existing theme and just override the things we want to change. This is the capability that subthemes, a new addition in Drupal 6, provide.

From a technical perspective, creating a full theme is not difficult, but it is time-consuming. In contrast, a subtheme can be created quickly. Since our focus is on JavaScript, and not theming, we will be creating a subtheme. That way, we can make the most of an existing project and keep our work to a minimum.

As the name implies, a subtheme is derived from another theme. Therefore, we will need to pick a theme to start with. Drupal comes with six themes pre-installed, and these vary in method and complexity. For example, Garland is a complex theme with templates, JavaScript, CSS, and lots of special PHP. In contrast, Chameleon generates simpler HTML, but does all of this in pure PHP code, without reliance on template files.

Since we want to focus our attention on JavaScript, it would be best to start with a simple theme. From there, we will selectively override only what we need.

Our theme of choice will be the Bluemarine theme, which has a very basic PHPTemplate-based structure that is easy to customize.

Looking for a good base theme to start with? Check out the Zen theme in the contributed themes at http://drupal.org/project/zen. It's built to enable subtheming. You will need to create some CSS content, but the HTML structure is all in place.

We will with Bluemarine and create a new subtheme, borrowing as much as possible from the base theme.

Creating a theme: first steps

To create a theme, we will do the following:

  1. Create a directory for the theme.
  2. Create the theme's .info (dot-info) file.
  3. Add our first files.

After we've finished these three short steps, we will add our JavaScript to the theme.

A precaution for theme developers
To get build our theme correctly, we will need to be able to view it. But to view it, we will need to have it enabled. What if we make a mistake that prevents Drupal from rendering correctly? We could lock ourselves out of the administration page. To prevent this from happening, it is wise to set the administration theme to one of the default themes. This is done in Administer | Site configuration | Administration theme.

Creating a theme directory

Every theme should have its own directory.

When you install Drupal, one of the directories created is called themes/. If you take a look inside that directory, you will see all of the top-level (non-subtheme) themes that Drupal provides. Do not put your themes in there. This directory is only for themes that come with Drupal's core.

Themes, like modules, go inside the sites/ subtree. The sites/ area also appears inside the Drupal directory and is created when you install Drupal. Inside the sites/ directory, two folders are created by default: sites/all/ and sites/default/.

To better understand these two directories, keep in mind that one installation of Drupal can serve multiple sites. For example, if I have a site called example.com and a site called anotherexample.com, I can use one installation of Drupal to serve both.

The first site I install will be installed in sites/default/. The next site I install will need to go in its own folder (for example, sites/anotherexample.com/). Content that only belongs to a single site should go in that site's directory.

For example, if I want to install a special theme for anotherexample.com, I should put the theme in sites/anotherexample.com/themes/.

In other cases, I may want to share a theme or module across all sites. In these cases, files would go in sites/all/. In this article, we will be putting all of our themes and modules in sites/all/themes/ and sites/all/modules/.

If in doubt, put files in sites/all/. This makes it easier to share your work between sites.

With that background material behind us, let's create our theme directory. The name we give to this directory will be the name of our theme.

Theme and module names should always be in a lower case, and may be composed only of letters, numbers, and underscores. In the .info file, we will be able to attach a human-readable name to the theme. That may use spaces, capital letters, and other special characters.

Our first theme will be in sites/all/themes/frobnitz/ as seen in the following screehshot:.

If this is the first theme you create, you may also need to create the sites/all/themes/ directory.

Once the directory is created, we need to add a special file to tell Drupal about the theme.

Creating the .info file

Inside sites/all/themes/frobnitz/, we need to create a file to provide important information about our theme. The file will always be named after the theme, and end with the extension .info. Because of the extension, it is usually called the theme's dot-info file.

We will create frobnitz.info, and add the following contents to the file:

; $Id$
name = Frobnitz
description = Table-based multi-column theme with JavaScript
enhancements.
version = 1.0
core = 6.x
base theme = bluemarine

The .info file contains a handful of lines with the form name = value. These entries provide basic information about the theme.

Some of this information is displayed to the user (for example, name and description). Some information is used by Drupal to make sure that this theme will work with the installed version of Drupal. The core parameter is used for that.

Later in this article, we will see some other entries that contain information directly related to the display of the theme. With those parameters, we can change the way the theme looks and behaves just by altering the values.

The name, description, version, and core fields are required for all themes.

  • The name field is used to give our theme a human-friendly name. You can use capital letters and spaces in this field.
  • The description parameter is used to provide a one-sentence explanation of what the theme does.
  • The version field should indicate which version number of this theme is. As with most software, you typically start with 1.0.
  • Finally, the core field should indicate what version of Drupal this theme works with. For us, it will always be 6.x.

There's one additional parameter in our file:

base theme = bluemarine

The base theme parameter is what we use to inform Drupal that our theme is a subtheme, derived from bluemarine. If we were creating a theme from scratch, we would not include this line.

For the time being, this is all we need in our theme file. Later, we will add more.

Modifying .info files and clearing the cache
To improve performance, Drupal caches theme information, particularly the theme's .info file. When you change the contents of that file (for example, when you add a new script or stylesheet), you will need to clear the theme information cache to force Drupal to re-read the .info file. The most reliable way to do this is through Administer | Site configuration | Performance. At the bottom of that page is a button labeled Clear cached data. Press that button to clear the cache.

Adding files to the theme

At this point, we've actually created a working theme. Only the theme's directory and .info file are required. With just those two elements, we can now go to Administer | Site building | Themes and select our Frobnitz theme.

Of course, all Frobnitz will be at this point is an exact duplicate of Bluemarine The following screenshot shows a sample of the Frobnitz theme:

The logo image, titles, and all other information in the screenshot is showing through the regular site configuration. The look and feel should be identical whether we choose Bluemarine or our new Frobnitz style.

What we want to do now is add something new to our theme, and what better place to start than with a stylesheet.

Our theme will import all of the stylesheets of its parent. So in our theme, we inherit style.css from Bluemarine. Looking at the HTML source for a page rendered with Frobnitz, we would see a line like this:

<link type="text/css" rel="stylesheet" media="all" 
href="/drupal/themes/bluemarine/style.css" />

If we didn't want that style to be loaded from Bluemarine, we could simply create another file named style.css in our own theme's directory. This new file would override Bluemarine's.

But we don't want to start over and rebuild the stylesheet. We just want to add a few extra styles. To do this, we will create a new stylesheet called frobnitz.css. This CSS file will also go inside our sites/all/themes/frobnitz/ folder.

Like PHP and JavaScript, the Drupal project defines coding standards for CSS. You can learn more about these here: http://drupal.org/node/302199.

To begin, all we will do is add a black, one-pixel border on the right side of the lefthand column. The stylesheet looks like this:

#sidebar-left {
border-right: 1px solid black;
}

Cascade: the 'C' in 'CSS'
Drupal will add styles in a specific order, with theme styles added last. Because of this, you can predictably make use of the CSS cascading behavior. The previous declaration will be added to the declaration made in Bluemarine's style.css file. That means we will get the combination of styles in style.css and frobnitz.css, with frobnitz.css's declarations taking precedence.

But before our new stylesheet will have any effect, we need to tell Drupal to include it as part of the theme. This is done with a simple addition to the frobnitz.info file:

; $Id$
name = Frobnitz
description = Table-based multi-column theme with JavaScript enhancements.
version = 1.0
core = 6.x
base theme = bluemarine
stylesheets[all][] = frobnitz.css

Only that last line, which is highlighted, is different. This informs Drupal that there is a stylesheet that should be used on all format types for this page, and is named frobnitz.css.

The all keyword indicates that this stylesheet applies to all media format types. CSS format types include print (for printed media), screen (for screen displays), and other types.

While this directive uses an array-like syntax, it does not function like an array. You cannot, for example, refer to stylesheets[all][1].

The empty square brackets on the end emulate the PHP array assignment operation. This stylesheet is added to a list of stylesheets. This array-like syntax, which we will see again in the next section, indicates that an attribute can be used multiple times. For example, we could add another stylesheet using stylesheets[all][] = anotherstyle.css.

The base path for a stylesheet included using stylesheets[][] is always the path of the theme. In other words, stylesheets[all][] = frobnitz.css will point to sites/all/themes/frobnitz/frobnitz.css.

Remember to clear the theme cache to see the updates after changing this file (see the information box a few pages back).

Now, after clearing the cache, we can see the results of our labor:

Notice the black line between the lefthand menu and the main page contents. That's what we added with our new stylesheet.

These last three segments were a rushed tour through the process of creating a new theme. In the next section, we will work with theme templates and theme JavaScript. However, this is not a comprehensive introduction to themes.

If you are interested in learning more about theming in Drupal 6, the best place to start is with the official theming handbook: http://drupal.org/theme-guide.

The CSS file

Next, we need to make a quick addition to the CSS file—the frobnitz.css file mentioned in the last section. This will provide a very simple style for the tool we are going to add. Here is what it looks like:

#printer-button {
float: right;
font-weight: bold;
padding-right: 20px;
}

This CSS simply adds a definition for some element with the ID of printer-button. We will see that element a little later in this article. The styles here will float that element to the right side of the screen, add a little padding, and make the font bold.

Adding JavaScript to a theme

We now have a shiny new theme to work with. Let's turn our attention to incorporating our JavaScript print tool into that theme.

This will require three short steps:

  1. Add a template that will display a Print link.
  2. Make a minor adjustment to the stylesheet to make this link stand out.
  3. Add the JavaScript to our page.

Let's start with the template.

Overriding a template

Bluemarine already has all of the templates required for displaying Drupal. However, we want to add a link on the righthand side of the main content display that will show a Print link. When clicked, this link will run our JavaScript.

To do this, we want to override Bluemarine's page.tpl.php file. In other words, we want to provide a Frobnitz template that will be used instead of Bluemarine's. Since we want it to primarily look the same, we will start by copying themes/bluemarine/page.tpl.php into sites/all/themes/frobnitz/.

The page template (page.tpl.php) is responsible for rendering the main structure of a Drupal page, including the main body of the HTML.

Let's take a quick look at the page template just to see how it's structured. Don't worry about the details. Most of it is just boilerplate HTML:

<?php
// $Id: page.tpl.php,v 1.28 2008/01/24 09:42:52 goba Exp $
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
lang="<?php print $language->language ?>"
xml:lang="<?php print $language->language ?>"
dir="<?php print $language->dir ?>">

<head>
<title><?php print $head_title ?></title>
<?php print $head ?>
<?php print $styles ?>
<?php print $scripts ?>
<script type="text/javascript"><?php /* Needed to avoid Flash of
Unstyle Content in IE */ ?> </script>
</head>

<body>

<table border="0" cellpadding="0" cellspacing="0" id="header">
<tr>
<td id="logo">
<?php if ($logo) {
?><a href="<?php print $front_page ?>"
title="<?php print t('Home') ?>"><img
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="<?php print $logo ?>"
alt="<?php print t('Home') ?>" /></a><?php } ?>
<?php if ($site_name) { ?><h1 class='site-name'><a
href="<?php print $front_page ?>"
title="<?php print t('Home') ?>"><?php
print $site_name ?></a></h1><?php } ?>
<?php if ($site_slogan) { ?><div class='site-slogan'>
<?php print $site_slogan ?></div><?php } ?>
</td>
<td id="menu">
<?php if (isset($secondary_links)) { ?><?php print
theme('links', $secondary_links,
array('class' => 'links', 'id' => 'subnavlist'))
?><?php } ?>
<?php if (isset($primary_links)) { ?><?php
print theme('links', $primary_links,
array('class' => 'links', 'id' => 'navlist'))
?><?php } ?>
<?php print $search_box ?>
</td>
</tr>
<tr>
<td colspan="2"><div><?php print $header ?></div></td>
</tr>
</table>

<table border="0" cellpadding="0" cellspacing="0" id="content">
<tr>
<?php if ($left) { ?><td id="sidebar-left">
<?php print $left ?>
</td><?php } ?>
<td valign="top">
<?php if ($mission) { ?><div id="mission"><?php
print $mission ?></div><?php } ?>
<div id="main">
<?php print $breadcrumb ?>
<h1 class="title"><?php print $title ?></h1>
<div class="tabs"><?php print $tabs ?></div>
<?php if ($show_messages) { print $messages; } ?>
<?php print $help ?>
<?php print $content; ?>
<?php print $feed_icons; ?>
</div>
</td>
<?php if ($right) { ?><td id="sidebar-right">
<?php print $right ?>
</td><?php } ?>
</tr>
</table>

<div id="footer">
<?php print $footer_message ?>
<?php print $footer ?>
</div>
<?php print $closure ?>
</body>
</html>

There are a few important things to note about the template.

First, templates are the only place in Drupal where you will see this mix of PHP code and HTML. By design, Drupal keeps programming logic separate from layout. Themes are the only area where these two converge.

PHP logic will always be enclosed inside the PHP processor instruction tag:<?php ... ?>

Second, the PHP code in templates is generally restricted to the following:

  • Simple print statements (print $variable_name)
  • A handful of function calls, usually to either the theming subsystem (theme()) or to the translatation subsystem (t())
  • Control structures, like if/else and foreach, to determine what needs to be displayed

If you are not a PHP expert, you can learn these techniques just by reading the themes.

Finally, the page template creates the basic framework for the page. Smaller sections are created by other templates, and provided to this template late in the rendering process.

For example, in Bluemarine, blocks are themed with block.tpl.php. Then the themed blocks are put in their designated regions. In this example, all of the blocks that are displayed in the lefthand column will be formatted and placed in the siderbar-left region, which is designated in the page.tpl.php file by the $left variable. Then the page.tpl.php file simply prints $left:

<table border="0" cellpadding="0" cellspacing="0" id="content">
<tr>
<?php if ($left) { ?><td id="sidebar-left">
<?php print $left ?>
</td><?php } ?>
<td valign="top">
<?php if ($mission) { ?><div id="mission"><?php
print $mission ?></div><?php } ?>
<div id="main">

There are many variables to keep track of in the page.tpl.php template (block.tpl.php is much simpler). Fortunately for us, we won't be dealing with all of the variables directly. We're more interested in the HTML and JavaScript.

The Garland theme (themes/garland/) is very well-documented. You can get an idea of what each variable stands for by reading the comments at the top of Garland's templates.

What we now want to do is add a snippet of HTML to this theme that will add our new link. Here is our addition:

<table border="0" cellpadding="0" cellspacing="0" id="content">
<tr>
<?php if ($left) { ?><td id="sidebar-left">
<?php print $left ?>
</td><?php } ?>
<td valign="top">
<?php if ($mission) { ?><div id="mission"><?php print $mission
?></div><?php } ?>
<!-- New Content -->
<div id="printer-button"><a
href="javascript:PrinterTool.print('main')" >
Print</a></div>
<!-- End new content -->
<div id="main">
<?php print $breadcrumb ?>
<h1 class="title"><?php print $title ?></h1>
<div class="tabs"><?php print $tabs ?></div>
<?php if ($show_messages) { print $messages; } ?>
<?php print $help ?>
<?php print $content; ?>
<?php print $feed_icons; ?>
</div>
</td>
<?php if ($right) { ?><td id="sidebar-right">
<?php print $right ?>
</td><?php } ?>
</tr>
</table>

This section of code occurs about thirty five lines into page.tpl.php. The highlighted lines are highlighted are the only ones we've added. In these lines we create a new <div></div> tag, and then put a Print link inside. When clicked, this link executes the JavaScript function PrinterTool.print('main').

Recall that PrinterTool.print() takes as an argument the HTML ID (the value of id="" in an HTML tag). Taking a glance at page.tpl.php, we can quickly see what element this ID belongs to. In fact, it's directly below the link we just added:

<div id="main">
<?php print $breadcrumb ?>
<h1 class="title"><?php print $title ?></h1>
<div class="tabs"><?php print $tabs ?></div>
<?php if ($show_messages) { print $messages; } ?>
<?php print $help ?>
<?php print $content; ?>
<?php print $feed_icons; ?>
</div>

This is the section of the template the print function will load into a new window for printing. Of course, all of the PHP calls will be replaced with HTML content.

We have one short step left before we can test out our new JavaScript-enabled theme.

Adding the script file

When we add a new CSS file, we need to inform Drupal about this by adding an entry to the .info file. Adding a JavaScript file is done in the same way.

The first step in adding our JavaScript file will require copying the script into the sites/all/themes/frobnitz/ directory, and then editing the frobnitz.info file.

; $Id$
name = Frobnitz
description = Table-based multi-column theme with JavaScript enhancements.
version = 1.0
core = 6.x
base theme = bluemarine
stylesheets[all][] = frobnitz.css
scripts[] = printer_tool.js

Again, we're making only a one-line change. We're adding printer_tool.js to the list of scripts automatically included by this theme.

Before viewing, don't forget to refresh the theme cache by either clearing it or visiting the Administer | Site building | Themes page.

Now when we visit a page on our site, it should have the Print link as seen here:

Clicking on this new link should execute the JavaScript and launch our new script, which will load a printer-friendly page into its own window. It will then launch the browser's print dialog:

We've just completed our first project. We have added JavaScript to a theme.

Summary

In this article, we created a new theme. We also added some JavaScript functionality to the new theme.

About the Author :


Matt Butcher

Matt is a web developer and author. He has previously written five other books for Packt, including two others on Drupal. He is a senior developer for the New York Times Company, where he works on ConsumerSearch.com, one of the most traffic-heavy Drupal sites in the world. He is the maintainer of multiple Drupal modules and also heads QueryPath – a jQuery-like PHP library. He blogs occasionally athttp://technosophos.com.

 

Books From Packt

Drupal 6 Social Networking
Drupal 6 Social Networking

Drupal 6 Themes
Drupal 6 Themes

Building Websites with Joomla! 1.5
Building Websites with Joomla! 1.5

Joomla! Web Security
Joomla! Web Security

Learning jQuery 1.3
Learning jQuery 1.3

Drupal Multimedia
Drupal Multimedia

Building Powerful and Robust Websites with Drupal 6
Building Powerful and Robust Websites with Drupal 6

WordPress Plugin Development (Beginner's Guide)
WordPress Plugin Development (Beginner's Guide)

Your rating: None Average: 4.5 (4 votes)
Thank you!! by
Matt, thank you soooo much for this tutorial! I'm totally new to Drupal and was very close to giving up because my javascript never worked. Thanks to your tutorial I have it running now!! This was by far the best instruction I found anywhere on the topic! I especially loved that you never assumed your reader knew how to do "simple" tasks already, but you explained them all. That was perfect for me! -- Sandra

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
r
q
n
V
M
y
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software