There are three main difficulties that an inexperienced developer faces when trying to understand JavaScript as used in Drupal:
First and foremost, the lack of documentation has made Drupal's JavaScript code difficultly accessible to the inexperienced developer. This document is an attempt at filling a little a huge gap.
Also, this site (api.drupal.org) uses the api.module to automatically extract the documentation from the source code in order to present it here. Unfortunately, the API parser works only on PHP code. A parser for JavaScript code is needed. If you are good at this kind of stuff, your help will be appreciated.
Lastly, some .js files in Drupal core and in contrib modules could do with a bit more in-code documentation. Patches are welcome.
The second difficulty concerns the programmer who is mostly self-taught, with little or no formal training in programming, and who knows only HTML and PHP as used within Drupal. Other programmers, the professionals, those who have learned other computer languages using OOP (like C, C++, Java, etc.) would already be familiar with OOP.
While PHP does support OOP, the fact is that Drupal does not use OOP. So a programmer who has learned only as much PHP as necessary to program for Drupal may find the OOP in JavaScript confusing.
Indeed, the very first line of JavaScript code in Drupal core, in drupal.js, is an Object declaration:
var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} };
In this code, Drupal
is an Object declared to be equal to itself, or, if not yet set, equal to { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} }
which is an Object containing 4 methods (settings
, behaviors
, themes
, and locale
) each of which is itself an Object. This line of code is an Object Initializer.
So, if you find yourself unfamiliar with Object Oriented Programming, you need to learn a bit more on the topic in order to understand what follows. See in particular the following:
Maybe the major problem in understanding the JavaScript code found within Drupal is because there is not one language (JavaScript), but many different APIs and Specifications involved. Within a .js
file, there could be DOM components and Drupal Form API elements tied together with JavaScript, jQuery, some core Drupal JavaScript Objects and functions, as well as the module's own JavaScript code and HTML markup. The real difficulty is understanding what does what. This section is about clarifying a bit this big mess.
For an experienced PHP devoloper, reading the Core JavaScript 1.5 Guide can be both easy and frustrating.
The JavaScript language is easy to understand because it is very similar to PHP. There are some important and obvious differences, like the operator used for concatenation: php uses the dot (full stop), while JavaScript, as should be obvious by reading any js code, uses the + sign. Other than that, JavaScript and PHP are both dynamically typed language (i.e. without strong typing like in C++), and share many language structures. As noted above, Javascript code makes heavy use of OOP. It is still recommended to have at least a quick read through the available documentation.
The frustrating part is that reading the documentation does not seem to answer any of the questions that prompted us to read it in the first place. The fact is, for a php developer, JavaScript is easy to understand. What we have a problem with is not it, but the other elements involved in js code.
JavaScript uses the DOM to manipulate elements in the web page.
This Document Object is the reason why JavaScript programming in inherently Object Oriented.
In short, the object in question is your browser window, the top element of which is the <html> tag.
The HTML DOM will create the object called document
which you will find in many js code.
Rather than repeating what has been better said elsewhere, here is a list of important resources about the DOM specifications and its relationship with JavaScript. It is recommended that you become fairly familiar with at least the general content of the following documents:
jQuery enhances JavaScript and the DOM by adding new methods to the document object. Understanding the jQuery documentation assumes that you have a fair grasp of both Object Oriented Programming and the DOM. Do not proceed further if you are still unclear about either.
Here are some useful links:
When reading example code is the Tutorials section, it help to try figuring out which parts of the code are JavaScript constructs, which are DOM specs implementations, and which are jQuery extensions.
Building up on all the previous elements, core Drupal js files create a Drupal
Object with a few methods that modules can use, like Drupal.behaviors
, Drupal.settings
, etc. Those will be covered in more details below.
More often than not, JavaScript is used within Drupal to enhance the forms' User Interface.
In order to make the most of Drupal js, we can use some FORM API attributes, like #ahah. Details to come.
As we have seen, js code is a mix of different APIs and Specifications. We are now going to provide some examples to show how tightly integrated those different parts are.
if (Drupal.jsEnabled) {
// Global Killswitch on the <html> element
document.documentElement.className = 'js';
// 'js enabled' cookie
document.cookie = 'has_js=1; path=/';
// Attach all behaviors.
$(document).ready(Drupal.attachBehaviors);
}
In this block of code we have:
->
, as in a node object (e.g. $node->nid
).document.documentElement.className = 'js';
does, is add the class 'js' to the element <html>, so that in effect we have <html class="js" >
.<?php module_invoke_all('Behaviors');?>
.
attachBehaviors is a method of the Object Drupal which calls all the Behavior functions declared by modules.
If you have some difficulty understanding some js code, your first task is to figure out what API is defining the part you don't understand. Is is a DOM complient method? A jQuery method? a Drupal one? Is it the Object Oriented Programming style? Or the way jQuery objects are bound together in a long succession of methods?
If you can identify what troubles you, then finding the solution becomes easier, because you know in which documentation to look.
This section is to be completed... If you want to give a hand, please do! :)
When most of us learn jQuery for the first time, we learn to put all our code inside the $(document).ready function, like this:
$(document).ready(function(){
// do some fancy stuff
});
This ensures that our code will get run as soon as the DOM has loaded, manipulating elements and binding behaviours to events as per our instructions. However, as of Drupal 6, we don't need to include the $(document).ready() function in our jQuery code at all. Instead we put all our code inside a function that we assign as a property of Drupal.behaviors. The Drupal.behaviors object is itself a property of the Drupal object, as explained above, and when we want our module to add new jQuery behaviours, we simply extend this object. The entire jQuery code for your module could be structured like this:
Drupal.behaviors.myModuleBehavior = function (context) {
//do some fancy stuff
};
drupal.js has a $(document).ready() function which calls the Drupal.attachBehaviors function, which in turn cycles through the Drupal.behaviors object calling every one of its properties, these all being functions declared by various modules as above, and passing in the document as the context.
The reason for doing it this way is that if your jQuery code makes AJAX calls which result in new DOM elements being added to the page, you might want your behaviours (e.g. hiding all h3 elements or whatever) to be attached to that new content as well. But since it didn't exist when the DOM was loaded and Drupal.attachBehaviors ran it doesn't have any behaviours attached. With the above set-up, though, all you need to do is call Drupal.behaviors.myModuleBehavior(newcontext), where newcontext would be the new, AJAX-delivered content, thus ensuring that the behaviours don't get attached to the whole document all over again. There are full instructions on how to use this code on the Converting 5.x modules to 6.x page.
This usage is not in fact exclusive to Drupal 6: the jstools package in Drupal 5 uses this exact pattern to control the behaviours of its modules - collapsiblock, tabs, jscalendar, etc.