10 min read

How Drupal handles JavaScript

How is JavaScript typically used? Mostly, it is used to provide additional functionality to a web page, which is usually delivered to a web browser as an HTML document. The browser receives the HTML from the server and then begins the process of displaying the page. During this parsing and rendering process, the browser may request additional resources from the server such as images, CSS, or Flash. It then incorporates these elements into the document displayed to the user.

In this process, there are two ways that JavaScript code can be sent from the server to the browser. First, the code can be placed directly inside the HTML. This is done by inserting code inside the <script> and </script> tags:

<script type="text/javascript">
alert('hello world');
</script>

This is called including the script inline.

Second, the code can be loaded separately from the rest of the HTML. Again, this is usually done using the <script> and </script> tags. However, instead of putting the code between the tags, we use the src attribute to instruct the browser to retrieve an additional document from the server.

<script type="text/javascript" src="some/script.js"></script>

In this example, src=”some/script.js” points the browser to an additional script file stored on the same server as the HTML document in which this script tag is embedded. So, if the HTML is located at http://example.com/index.html, the browser will request the script file using the URL http://example.com/some/script.js.

The </script> tag is required

When XML was first standardized, it introduced a shorthand notation for writing tags that have no content. Instead of writing <p></p>, one could simply write <p/>. While this notation is supported by all modern mainstream browsers, it cannot be used for <script></script> tags. Some browsers do not recognize <script/> and expect that any <script> tag will be accompanied by a closing </script> tag even if there is no content between the tags.

If we were developing static HTML files, we would simply write HTML pages that include <script></script> tags anytime we needed to add some JavaScript to the page. But we’re using Drupal, not static HTML, and the process for adding JavaScript in this environment is done differently.

Where Drupal JavaScript comes from?

As with most web content management systems, Drupal generates HTML dynamically. This is done through interactions between the Drupal core, modules, and the theme system. A single request might involve several different modules. Each module is responsible for providing information for a specific portion of the resulting page. The theme system is used to transform that information from PHP data structures into HTML fragments, and then compose a full HTML document.

But this raises some interesting questions: What part of Drupal should be responsible for deciding what JavaScript is needed for a page? And where will this JavaScript come from?

In some cases, it makes sense for the Drupal core to handle JavaScript. It could automatically include JavaScript in cases where scripts are clearly needed.

JavaScript can also be used to modify the look and feel of a site. In that case, the script is really functioning as a component of a theme. It would be best to include the script as a part of a theme.

JavaScript can also provide functional improvements, especially when used with AJAX and related technologies. These features can be used to make more powerful modules. In that case, it makes sense to include the script as a part of a module.

So which one is the best: modules, themes, or core? Rather than deciding on your behalf, Drupal developers have made it possible to incorporate JavaScript into all three:

  • The Drupal core handles including the core JavaScript support as needed. The Drupal and jQuery libraries are included automatically when necessary.
  • When theme developers needs to add some JavaScript, they can do so within the theme. There is no need to tamper with the core, or to accompany a theme with a module.
  • Finally, module developers can add JavaScript directly to a module. In this way, modules can provide advanced JavaScript functionality without requiring modification of the theme.

In this article we will add scripts to themes and modules. As we get started, we will begin with a theme.

Module or theme?

How do you decide whether your script ought to go in a theme or in a module? Here’s a basic guideline. If the script provides functionality specific to the layout details of a theme, it should be included in a theme. If the script provides general behavior that should work regardless of the theme, then it should be included in a module.

Sometimes it is hard to determine when a script belongs to a theme and when it should to be placed in a module. In fact, the script we create here will be one such a case. We are going to create a script that provides a printer-friendly version of a page’s main content. Once we have the script, we will attach it to a theme. Of course, if we want to provide this functionality across themes, we might instead create a module to house the script.

We will start out simply with a JavaScript-enabled theme.

Project overview: printer-friendly page content

The JavaScript that we will write creates a pop-up printer-friendly window, and automatically launches the print dialog. This is usually launched from File | Print in your browser’s menu.

Once we write the script, we will incorporate it into a theme, and add a special printing feature to the page(s) displayed with that theme. As we walk through this process, we will also create our first theme. (Technically, it will be a subtheme derived from the Bluemarine theme.)

By the end of this project, you should know how to create Drupal-friendly JavaScript files. You will also know how to create themes and add scripts to them.

The first step in the process is to write the JavaScript.

The printer script

Our script will fetch the main content of a page and then open a new window, populating that window’s document with the main content of the page. From there, it will open the browser’s print dialog, prompting the user to print the document.

Since this is our first script, we will keep it simple. The code will be very basic, employing the sort of classical procedural JavaScript that web developers have been using since the mid-1990’s. But don’t expect this to be the norm.

To minimize clutter and maximize the reusability of our code, we will store this new script in its own script file. The file will be named printer_tool.js:

// $Id$
/**
* Add printer-friendly tool to page.
*/
var PrinterTool = {};
PrinterTool.windowSettings = 'toolbar=no,location=no,' +
'status=no,menu=no,scrollbars=yes,width=650,height=400';
/**
* Open a printer-friendly page and prompt for printing.
* @param tagID
* The ID of the tag that contains the material that should
* be printed.
*/
PrinterTool.print = function (tagID) {
var target = document.getElementById(tagID);
var title = document.title;
if(!target || target.childNodes.length === 0) {
alert("Nothing to Print");
return;
}
var content = target.innerHTML;
var text = '<html><head><title>' +
title +
'</title><body>' +
content +
'</body></html>';
printerWindow = window.open('', '', PrinterTool.windowSettings);
printerWindow.document.open();
printerWindow.document.write(text);
printerWindow.document.close();
printerWindow.print();
};

First, let’s talk about some of the structural aspects of the code.

Drupal coding standards

In general, well-formatted code is considered a mark of professionalism. In an open source project such as Drupal, where many people are likely to view and contribute to the code, enforced coding standards can make reading and understanding what the code does easier.

When contributing code to the Drupal project, developers adhere to a Drupal coding standard (http://drupal.org/coding-standards). Add-on modules and themes are expected to abide by these rules.

It is advised that you follow the Drupal standards even in code that you do no anticipate submitting to the Drupal project. Along with keeping your code stylistically similar to Drupal’s, it will also help you develop good coding habits for those occasions when you do contribute something to the community.

For the most part, the official Drupal coding standards are focused on the PHP code. But many of these rules are readily applicable to JavaScript as well. Here are a few important standards:

  • Every file should have a comment near the top that has the contents $Id$. This is a placeholder for the version control system to insert version information.

    Drupal uses CVS (Concurrent Versioning System) for source code versioning. Each time a file is checked into CVS, it will replace $Id$ with information about the current version of the software. To learn more about CVS, visit http://www.nongnu.org/cvs/.

  • Indenting should be done with two spaces (and no tabs). This keeps the code compact, but still clear.
  • Comments should be used wherever necessary.
    • Doxygen-style documentation blocks (/** … */) should be used to comment files and functions.
    • Any complex or potentially confusing code should be commented with // or /* … */.
    • Comments should be written in sentences with punctuation.
  • Control structure keywords (if, else, for, switch, and so on) should appear at the beginning of a line, and be followed by a single space (if (), not if()). Here’s an example:
      if (a) {
      // Put code here.
      }
      else if (b) {
      // Put code here.
      }
      else {
      // Put code here.
      }
  • Operators (+, =, *, &&, ||, and so on) should have a single space on each side, for example: 1 + 2. The exception to this rule is the member operator (.), which is used to access a property of an object. There should be no spaces surrounding these. Example: window.document (never window . document).

Stylistic differences between PHP and JavaScript

Not all PHP coding standards apply to JavaScript. PHP variables and function names are declared in all lower case with underscores (_) to separate words. JavaScript typically follows different conventions.

JavaScript variables and functions are named using camel case (sometimes called StudlyCaps). For a variable or function, the first word is all lower case. Any subsequent words in the variable or function name are capitalized. Underscores are not used to separate words. Here are some examples:

var myNewVariable = "Hello World";
function helloWorld() {
alert(myNewVariable);
}

While this convention is employed throughout the Drupal JavaScript code, there is currently no hard-and-fast set of JavaScript-specific coding conventions. The working draft, which covers most of the important recommendations, can be found at http://drupal.org/node/260140.

Here is a summary of the more important (and widely followed) conventions:

  • Variables should always be declared with the var keyword. This can go a long way towards making the scope of variables explicit. JavaScript has a particularly broad notion of scope. Functions inherit the scope of their parent context, which means a parent’s variables are available to the children. Using var makes it easier to visually identify the scoping of a variable. It also helps to avoid ambiguous cases which may lead to hard-to-diagnose bugs or issues.
  • Statements should always end with a semicolon (;). This includes statements that assign functions, for example, myFunction = function() {};. Our print function, defined earlier, exhibits this behavior.
  • Why do we require trailing semicolons?

    In JavaScript, placing semicolons at the end of statements is considered optional. Without semicolons, the script interpreter is responsible for determining where the statement ends. It usually uses line endings to help determine this. However, explicitly using semicolons can be helpful. For example, JavaScript can be compressed by removing whitespace and line endings. For this to work, every line must end with a semicolon.

  • When an anonymous function is declared, there should be a space between  the function and the parentheses, for example, function () {}, not function() {}. This preserves the whitespace that would be there in in a non-anonymous function declaration (function myFunction() {}).

There are other conventions, many of which you will see here. But the ones mentioned here cover the most frequently needed.

With coding standards behind us, let’s take a look at the beginning of the printer_tool.js file.

LEAVE A REPLY

Please enter your comment!
Please enter your name here