Using JavaScript and jQuery in Drupal Themes

Exclusive offer: get 50% off this eBook here
Drupal 6 Theming Cookbook

Drupal 6 Theming Cookbook — Save 50%

Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes

$26.99    $13.50
by Karthik Kumar | February 2011 | Content Management Drupal Open Source

Until a few years ago, mentioning the word JavaScript to a themer would usually result in groans about inconsistencies in browser support, lack of standards, difficulty in debugging, and a myriad of other complaints. Thankfully, however, things have changed considerably since then. Browsers have evolved and standards have improved. JavaScript is now a potent weapon in any themer's armory and this is especially true with the introduction of cross-browser libraries and frameworks which address most of the aforementioned issues with it.

In this article by Karthik Kumar, author of the book Drupal 6 Theming Cookbook, we will be covering the following recipes:

  • Including JavaScript files from a theme
  • Including a JavaScript file only for certain pages
  • Giving the username textfield keyboard focus

 

Drupal 6 Theming Cookbook

Drupal 6 Theming Cookbook

Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes

  • Take control of the look and feel of your Drupal website
  • Tips and tricks to get the most out of Drupal's theming system
  • Learn how to customize existing themes and create unique themes from scratch
  • Part of Packt's Cookbook series: Each recipe is a carefully organized sequence of instructions to complete the task as efficiently as possible
        Read more about this book      

(For more resources on Drupal, see here.)

Introduction

JavaScript libraries take out the majority of the hassle involved in writing code which will be executed in a variety of browsers each with its own vagaries. Drupal, by default, uses jQuery, a lightweight, robust, and well-supported package which, since its introduction, has become one of the most popular libraries in use today. While it is possible to wax eloquent about its features and ease of use, its most appealing factor is that it is a whole lot of fun!

jQuery's efficiency and flexibility lies in its use of CSS selectors to target page elements and its use of chaining to link and perform commands in sequence. As an example, let us consider the following block of HTML which holds the items of a typical navigation menu.

<div class="menu">
<ul class="menu-list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>

Now, let us consider the situation where we want to add the class active to the first menu item in this list and, while we are at it, let us also color this element red. Using arcane JavaScript, we would have accomplished this with something like the following:

var elements = document.getElementsByTagName("ul");
for (var i = 0; i < elements.length; i++) {
if (elements[i].className === "menu-list") {
elements[i].childNodes[0].style.color = '#F00';
if (!elements[i].childNodes[0].className) {
elements[i].childNodes[0].className = 'active';
}
else {
elements[i].childNodes[0].className = elements[i].childNodes[0].
className + ' active';
}
}
}

Now, we would accomplish the same task using jQuery as follows:

$("ul.menu-list li:first-child").css('color', '#F00').
addClass('active');

The statement we have just seen can be effectively read as: Retrieve all UL tags classed menu-list and having LI tags as children, take the first of these LI tags, style it with some CSS which sets its color to #F00 (red) and then add a class named active to this element.

For better legibility, we can format the previous jQuery with each chained command on a separate line.

$("ul.menu-list li:first-child")
.css('color', '#F00')
.addClass('active');

We are just scratching the surface here. More information and documentation on jQuery's features are available at http://jquery.com and http://www.visualjquery.com. A host of plugins which, like Drupal's modules, extend and provide additional functionality, are available at http://plugins.jquery.com.

Another aspect of JavaScript programming that has improved in leaps and bounds is in the field of debugging. With its rising ubiquity, developers have introduced powerful debugging tools that are integrated into browsers and provide tools, such as interactive debugging, flow control, logging and monitoring, and so on, which have traditionally only been available to developers of other high-level languages. Of the many candidates out there, the most popular and feature-rich is Firebug. It can be downloaded and installed from https://addons.mozilla.org/en-US/ firefox/addon/1843.

Including JavaScript files from a theme

This recipe will list the steps required to include a JavaScript file from the .info file of the theme. We will be using the file to ensure that it is being included by outputting the standard Hello World! string upon page load.

Getting ready

While the procedure is the same for all the themes, we will be using the Zen-based myzen theme in this recipe.

How to do it...

The following steps are to be performed inside the myzen theme folder at sites/all/ themes/myzen.

  1. Browse into the js subfolder where JavaScript files are conventionally stored.
  2. Create a file named hello.js and open it in an editor.
  3. Add the following code:

    alert("Hello World!!");

  4. Save the file and exit the editor.
  5. Browse back up to the myzen folder and open myzen.info in an editor.
  6. Include our new script using the following syntax:

    scripts[] = js/hello.js

  7. Save the file and exit the editor.
  8. Rebuild the theme registry and if JavaScript optimization is enabled for the site, the cache will also need to be cleared.
  9. View any page on the site to see our script taking effect.

How it works...

Once the theme registry is rebuilt and the cache cleared, Drupal adds hello.js to its list of JavaScript files to be loaded and embeds it in the HTML page. The JavaScript is executed before any of the content is displayed on the page and the resulting page with the alert dialog box should look something like the following screenshot:

Using JavaScript and jQuery in Drupal Themes

There's more...

While we have successfully added our JavaScript in this recipe, Drupal and jQuery provide efficient solutions to work around this issue of the JavaScript being executed as soon as the page is loaded.

Executing JavaScript only after the page is rendered

A solution to the problem of the alert statement being executed before the page is ready, is to wrap our JavaScript inside jQuery's ready() function. Using it ensures that the code within is executed only once the page has been rendered and is ready to be acted upon.

if (Drupal.jsEnabled) {
$(document).ready(function () {
alert("Hello World!!");
});
}

Furthermore, we have wrapped the ready() function within a check for Drupal.jsEnabled which acts as a global killswitch. If this variable is set to false, then JavaScript is turned off for the entire site and vice versa. It is set to true by default provided that the user's browser meets Drupal's requirements.

Drupal's JavaScript behaviors

While jQuery's ready() function works well, Drupal recommends the use of behaviors to manage our use of JavaScript. Our Hello World example would now look like this:

Drupal.behaviors.myzenAlert = function (context) {
alert("Hello World!!");
};

All registered behaviors are called automatically by Drupal once the page is ready. Drupal.behaviors also allows us to forego the call to the ready() function as well as the check for jsEnabled as these are done implicitly.

As with most things Drupal, it is always a good idea to namespace our behaviors based on the module or theme name to avoid conflicts. In this case, the behavior name has been prefixed with myzen as it is part of the myzen theme.

Drupal 6 Theming Cookbook Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on Drupal, see here.)

Including a JavaScript file only for certain pages

This recipe will list the steps required to include a JavaScript file from a module rather than a theme. Unlike themes, modules offer a lot more options on when and how JavaScript files should be included. We will be taking advantage of this feature to ensure that our JavaScript is being included only for node pages.

We will be testing this by outputting the standard Hello World! string as we saw in the previous recipe.

Getting ready

We will be using the mysite module to hold our odds and ends. This module has been created in the article 'Drupal 6 Theming: Adding and Optimizing CSS Files' and is enabled.

How to do it...

The following steps are to be performed inside the mysite module folder at sites/all/ modules/mysite.

  1. If it does not already exist, create a folder within titled js.
  2. Inside this new folder, create a file named hello.js and open it in an editor.
  3. Insert the following JavaScript:

    Drupal.behaviors.mysiteHello = function (context) {
    alert("Hello World!!");
    };

  4. Save the file and exit the editor.
  5. Navigate up one level back to the base folder of the mysite module.
  6. Open the file mysite.module in an editor.
  7. Look for an implementation of the mysite_init() hook. If it is unavailable, create one and add the following code so that the resulting function looks like the following:

    /**
    * Implementation of hook_init().
    */
    function mysite_init() {
    // The path to the mysite module.
    $path = drupal_get_path('module', 'mysite');

    // Include file only for node pages.
    if (arg(0) == 'node') {
    drupal_add_js($path . '/js/hello.js');
    }
    }

  8. Save the file and exit the editor.
  9. Clear the Drupal cache, if necessary.
  10. Confirm that the script is being included correctly by viewing node pages and others such as administration pages. The Hello World! alert should only be triggered for the former.

How it works...

The mysite_init() function is executed for all pages. Within it, we check if the string node is the first component of the current path. If it is, we queue our JavaScript file for inclusion. Subsequently, when a node page is viewed, our included JavaScript file is executed resulting in the page displaying a Hello World! alert box.

The arg() function is used to return components of the current path. For example, if we are viewing a node with node ID 13, or in other words, if we are accessing node/13, then arg(0) will return node while arg(1) will return 13. More information on the arg() function is available at http://api. drupal.org/api/function/arg/6.

There's more...

While targeting individual pages, it is important to ensure that we match said pages as accurately as possible.

Checking paths with greater accuracy

In this recipe, we checked if the user was viewing a node page by checking for arg(0) == 'node'. While this will certainly work fine, let us consider the following additional paths:

URL

Description

node

 

The default Drupal front page containing a list of all published nodes.

node/add

 

A page listing all available content types which can be created.

node/add/page

 

The page type creation form.

node/13

A standard node display page which is what we are targeting.

 

node/13/edit

A node edit page.

As the table we just saw demonstrates, we need to be aware of these other permutations which might trigger false positives and include the JavaScript file unnecessarily and, in some, cases to detrimental effect. Keeping this in mind, we could refine our path-checking code to:

if (arg(0) == 'node' && is_numeric(arg(1))) {

By ensuring that the second component of the path is a number through the use of PHP's is_ numeric() check, this would target only URLs of the form node/13 and avoid most of the other permutations. It would, however, still be triggered for paths of the form node/13/edit. If this is unacceptable, we will need to refine our if statement further by checking if the third argument is present:

if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {

Giving the username textfield keyboard focus

This recipe will detail how keyboard focus can be assigned to the username field in the login block. This will ensure that the user does not need to use the mouse or tab through the page to log in to the site.

Getting ready

We will be using the mysite module to hold our odds and ends. This module has been created in the article 'Drupal 6 Theming: Adding and Optimizing CSS Files' and is enabled.

How to do it...

The following steps are to be performed inside the mysite module folder at sites/all/ modules/mysite.

  1. Create if necessary, and navigate to the JavaScript folder at sites/all/modules/ mysite/js.
  2. Create a JavaScript file named userfocus.js and open it in an editor.
  3. Add or merge the following JavaScript to the file:

    Drupal.behaviors.mysiteUserFocus = function(context) {
    // console.log($('input#edit-name'));
    $('input#edit-name').focus();
    }

    The line of jQuery functionally relevant to this recipe has been highlighted. The ID of the username textfield—edit-name—was located using Firebug.

    Use Firebug's console.log() function as commented out in the previous code block, to verify that we are targeting the correct element.

  4. Save the file and exit the editor.
  5. Open the file mysite.module in an editor.
  6. Look for an implementation of hook_init() or, if unavailable, create one.
  7. Add the code to include our JavaScript file so that the mysite_init() function resembles something like the following:

    /**
    * Implementation of hook_init().
    */
    function mysite_init() {
    global $user;
    // The path to the mysite module.
    $path = drupal_get_path('module', 'mysite');
    // Only include the JS file for anonymous users.
    if ($user->uid == 0) {
    drupal_add_js($path . '/js/userfocus.js');
    }
    }

  8. Save the file and exit the editor.
  9. Empty the Drupal cache, if necessary.
  10. Preview a page as an anonymous user to check if the username textfield is assigned keyboard focus.
  11. View the HTML source, first as an anonymous user and then as an authenticated user to ensure that the JavaScript file is only being included for the former.

How it works...

Since we are targeting the login form, it can also be assumed that we are only targeting anonymous users, that is, those who are yet to log in. In other words, if the user ID of the current user is 0, we can include our JavaScript file:

if ($user->uid == 0) {
drupal_add_js($path . '/js/userfocus.js');
}

To locate the element with ID edit-name, userfocus.js uses jQuery and applies the JavaScript function focus() to it, thereby giving the textfield keyboard focus. Viewing a page on the site as an anonymous user should now default to the keyboard cursor blinking inside the username textfield as in the following screenshot:

Using JavaScript and jQuery in Drupal Themes

While we have added our code to a separate file named userfocus.js to allow selective loading solely for anonymous users, it could have been placed in a more generic mysite.js containing other, possibly even unrelated, code. Whether this should or should not have been done is a question of preference, flexibility, and code manageability.

There's more...

If we are not certain about which field to give keyboard focus to, it is usually safe to assign focus to the first available textfield.

Keyboard focus on the first available textfield

This recipe can be adapted to assign keyboard focus to the first available textfield instead of a specific textfield as in this case. This is usually handy as a default option in cases where we are not completely aware of the structure or content of a page.

Summary

This article covered the use of JavaScript and jQuery in Drupal themes. In particular we saw including JavaScript files from a theme, including a JavaScript file only for certain pages, and giving the username textfield keyboard focus.


Further resources on this subject:


Drupal 6 Theming Cookbook Over 100 clear step-by-step recipes to create powerful, great-looking Drupal themes
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Karthik Kumar

Karthik Kumar is a Drupal developer residing in Chennai, India. He first came across Drupal in late 2004 and has been a fan ever since. He maintains a number of modules on http://drupal.org under the moniker Zen – http://drupal.org/user/21209.

Books From Packt


Drupal 7
Drupal 7

Drupal 6 Attachment Views
Drupal 6 Attachment Views

Drupal 7 Module Development
Drupal 7 Module Development

Drupal 6 Performance Tips
Drupal 6 Performance Tips

Drupal 6 Panels Cookbook
Drupal 6 Panels Cookbook

Drupal E-commerce with Ubercart 2.x
Drupal E-commerce with Ubercart 2.x

Drupal Intranets with Open Atrium
Drupal Intranets with Open Atrium

Drupal Web Services
Drupal Web Services


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
T
i
H
k
5
n
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