jQuery, created by John Resig, responds to the common frustrations and limitations that developers might havewith JavaScript. JavaScript code is cumbersome to write and verbose, and it can be difficult to target the
specific HTML or CSS elements you wish to manipulate. jQuery gives you a way to find these elements
quickly and easily within your document. The technical name for targeting an object is DOM traversal. DOM stands for Document Object Model. The model provides a tree-like way to access page elements
through their tags and other elements through JavaScript, as shown in Figure 18-1.
When writing JavaScript code, you usually have to spend time dealing with browser and operating system
incompatibilities. jQuery handles this for you. Also, there aren’t many high-level functions within JavaScript.
Common tasks such as animating parts of a page, dragging things around, or having sortable elements don’t exist.jQuery over comes these limitations as well. Like Drupal, jQuery has a small and efficient codebase, weighing
in at just under 30 kilobytes. At the heart of jQuery is an extensible framework that JavaScript developers can hook into, and hundreds of jQuery plug-ins are already available at http://plugins.jquery.com/.
Mozilla DOM Inspector tool, which installs with the Firefox browser
The Old Way
Let’s first do a quick review of the pure JavaScript way of DOM traversal. The following code shows how Drupal usedto find elements within a page (in this case, the legend element within all collapsible fieldsets) before jQuery came along:
var fieldsets = document.getElementsByTagName('fieldset'); var legend, fieldset;
for (var i = 0; fieldset = fieldsets[i]; i++) {
if (!hasClass(fieldset, 'collapsible')) { continue;}
legend = fieldset.getElementsByTagName('legend'); if (legend.length == 0) {
continue;}legend = legend[0];...}
And here’s the updated code within Drupal after jQuery entered the scene:
jQuery('fieldset.collapsible > legend:not(.collapse-processed)', context).each(function()
{... });
As you can see, jQuery lives up to its tagline of “Write Less, Do More.” jQuery takes the common, repetitive tasks of manipulating the DOM using JavaScript and encapsulates them behind concise and intuitive syntax. The end result is
code that’s short, smart, and easy to read.
How jQuery Works
jQuery is a tool for finding things in a structured document. Elements from the document can be selected by using CSS
selectors or jQuery’s own custom selectors (a jQuery plug-in supports the use of XPath selectors as well).
The use of CSS selectors for DOM traversal is helpful to the developer, because most developers are already familiar
with CSS syntax. jQuery has full support of CSS 1 to 3. Let’s go through some very basic examples of jQuery syntax
before we dive into using jQuery with Drupal.
Using a CSS ID Selector
Let’s do a quick review of basic CSS syntax. Suppose the HTML you want to manipulate is the following:
<p id="intro">Welcome to the World of Widgets.</p>
If you want to set the background color of the paragraph to blue, you use CSS to target this specific paragraph in
your style sheet using the #intro CSS ID selector. According to the HTML specification, IDs must be unique within a
given document, so we are assured that no other element has this ID. Within the style sheet that will be applied to your document, the following entry will make your paragraph blue:
#intro {
background-color: blue;}
Note that there are essentially two tasks here: find the element that has the #intro ID, and set the background color
of that element to blue. Here’s how you can select your paragraph and turn the background color to blue using
jQuery: jQuery("#intro").css("background-color", "blue");
You could even add a little jQuery pizzazz, and slowly fade in the paragraph text:
jQuery("#intro").css("background-color", "blue").fadeIn("slow")
Using a CSS Class Selector
Here’s a similar example using a CSS class selector instead of using a CSS ID as we did in the preceding section. The HTML would be as follows:
<p class="intro">Welcome to the World of Widgets.</p>
<p class="intro">Widgets are available in many sizes.</p>
Our CSS would look like this:
.intro {background-color: blue;}
The following would also work, and is a slightly more specific rule:
p.intro {background-color: blue;}
Here’s how the CSS translates to jQuery code: jQuery(".intro").css("background color", "blue").fadeIn("slow");
or jQuery("p.intro").css("background-color", "blue").fadeIn("slow");
In the first of the preceding examples, you’re asking jQuery to find any HTML element that has the intro class, while in the second example you ask for any paragraph tag with an intro class. Note that the last example will be slightly
faster because there’s less HTML for jQuery to search through, given the example’s restriction to just the paragraph
tags using p.intro. Now that you’ve had a taste of how jQuery works, let’s see it in action within Drupal.
jQuery Within Drupal
Using jQuery within Drupal is easy because jQuery is preinstalled and is automatically made available when JavaScript isadded. In Drupal, JavaScript files are added via the drupal_add_js() function or in the theme’s .info file.In this section, you’ll investigate some basic jQuery functionality within Drupal.
Your First jQuery Code
Let’s get set up to play with jQuery.
1. Log into your Drupal site as user 1 (the administrative account).
2. On the Modules page, enable the PHP filter module.
3. Create a new node of type Basic Page, but on the node creation form, be sure to select “PHP code” under the “Input formats” section, as shown in Figure 18-2. Enter Testing jQuery as the title, and add the following to the
body section of the form:
<?php
drupal_add_js('jQuery(document).ready(function () { jQuery("p").hide(); jQuery("p").fadeIn("slow");
});', 'inline');?>
<p id="one">Paragraph one</p>
<p>Paragraph two</p>
<p>Paragraph three</p>
4. Click Submit, and reload the page. The three paragraphs you created will slowly fade in. Cool, eh? Refresh the
page to see it again. Let’s study this example a little more.
Figure 18-2. Experimenting with jQuery using the PHP filter
The jQuery code is contained in a file, misc/jquery.js. This file is not loaded for every page within Drupal. Instead, anytime a drupal_add_js() call is made, jquery.js is loaded. Two parameters are passed into
drupal_add_js(). The first parameter is the JavaScript code you wish to have executed, and the second
parameter (inline) tells Drupal to write the code inside a pair of
<script></script> tags within the document’s <head> element.
Let’s look at the JavaScript jQuery code in more detail.
<?php
drupal_add_js('jQuery(document).ready(function () { jQuery("p").hide(); jQuery("p").fadeIn("slow");});',
'inline');
?>
The jQuery(document).ready function needs a little more explanation. When the browser is rendering a page, it gets toa point where it has received the HTML and fully parsed the DOM structure of the page. The next step is to render
that DOM,which includes loading additional local—and possibly even remote—files. If you try to execute JavaScript code
before the DOM has been generated, the code may throw errors and not run because the objects it wants to manipulate are not there yet. JavaScript programmers used to get around this by using some variation of the following code snippet:window.onload = function(){ ... }
The difficulty with using window.onload is that it has to wait for the additional files to also load, which is too long of await. Additionally, the window.onload approach allows the assignment of only a single function. To circumvent both
problems,jQuery has a simple statement that you can use:
jQuery(document).ready(function(){// Your code here.});
jQuery(document).ready() is executed just after the DOM is generated. You’ll always want to wrap jQuery code in
the preceding statement for the reasons listed earlier. The function() call defines an anonymous function in JavaScript—in this case,containing the code you want to execute. That leaves us with the actual meat of the code, which ought to be self-explanatory at this point:
// Hide all the paragraphs.
jQuery("p").hide();
// Fade them into visibility.
jQuery("p").fadeIn("slow");
The preceding code finds all paragraph tags, hides them, and then slowly reveals them within the page. In jQuery lingo,the fadeIn() part is referred to as a method. The “p” isn’t preceded by a “.” or “#” due to the p being a HTML tag
instead of a CSS class (“.”) or ID (“#”).
Targeting an Element by ID
Let’s repeat our experiment, but this time target only the first paragraph, which we’ve identified with the ID of one:
<?php
drupal_add_js('jQuery(document).ready(function () { jQuery("#one").hide();
jQuery("#one").fadeIn("slow");});', 'inline');?>
<p id="one">Paragraph one</p>
<p>Paragraph two</p>
<p>Paragraph three</p>
Method Chaining
We can concatenate a series of jQuery methods because most methods within jQuery return a jQuery object. Let’s chainsome methods together in a single jQuery command:
// Hide all the p tags, fade them in to visibility, then slide them up and down.
jQuery("p").hide().fadeIn("slow").slideUp("slow").slideDown("slow");
jQuery calls are invoked from left to right. The preceding snippet finds all the paragraph tags, fades them in, and then uses a sliding effect to move the paragraphs up and then down. Because each of these methods returns the jQuery
wrapper object containing the same set it was given (all the p elements), we can manipulate the same set of elements
over and over again until the final effect is achieved.
Adding or Removing a Class
jQuery can dynamically change the CSS class of an element. Here, we turn the first paragraph of our example red by
selecting it by ID and then assigning Drupal’s error class to it:
jQuery("#one").addClass("error");
The counterpart to the addClass() method is the removeClass() method. The following snippet will remove the error class we just added:
jQuery("#one").removeClass("error");
And then there’s the toggleClass() method, which adds or removes a class each time it is called:
jQuery("#one").toggleClass("error"); // Adds class "error". jQuery("#one").toggleClass("error");
// Removes class "error". jQuery("#one").toggleClass("error"); // Adds class "error" again.
Wrapping Existing Elements
Instead of just adding an error class to the <p id="one"> element, let’s wrap that element in a div so that the red will show up better. The following jQuery snippet will do that:
<?php
drupal_add_js('jQuery(document).ready(function () { jQuery("#one").wrap("<div class=\'error\'></div>");
});', 'inline');?>
<p id="one">Paragraph one</p>
<p>Paragraph two</p>
<p>Paragraph three</p>
Note the escaping of the single quotes, which is necessary because we already have open single quotes inside the drupal_add_js() function. The result of the div wrapping is shown in Figure 18-3.
Figure 18-3. The paragraph with ID “one” is wrapped in a div tag of class “error”.
Changing Values of CSS Elements
jQuery can be used to assign (or reassign) values to CSS elements. Let’s set the border surrounding the first paragraph
to solid(see Figure 18-4):
jQuery("#one").wrap("<div class=\'error\'></div>").css("border", "solid");
Notice that the css method is still acting on the p element, not on the div element, because the wrap method returned
the targeted p element after wrapping it.
Figure 18-4. The border property of the target element is changed.
The preceding examples have demonstrated some basic tasks that barely scratched the surface of what jQuery can do.You are urged to learn more at http://jquery.com/ or by picking up a good book on the subject.
Where to Put JavaScript
In the preceding examples, you have been testing jQuery by writing JavaScript in a node with the PHP filter enabled.
While this is handy for testing, that’s not a good approach for a production site, where best practices dictate that the
PHP filter be unavailable if at all possible. There are several different options for including JavaScript files in your Drupalsite. For example, you can add them to your theme, include them from a module, or even include them but give others the option of modifying or overriding your code.
Adding JavaScript via a Theme .info File
The most convenient but least flexible way to include JavaScript files is to include a line in your theme’s .info file.
Let’s add an effect to your site that emphasizes the logo of your site by making it fade out and then fade in again
when a page is loaded. Place the following JavaScript code in a file called logofade.js in your current theme. For
example, if you areusing the Bartik theme, it would be at themes/bartik/logofade.js.
// Selects the theme element with the id "logo", fades it out,
// then fades it in slowly.
jQuery(document).ready(function(){ jQuery("#logo").fadeOut("fast").fadeIn("slow");});
The JavaScript file is in place; now we just have to tell Drupal to load it. Add the following line to your current
theme’s .info file: scripts[] = logofade.jsThe last step is to make Drupal reread the .info file so that it will see that it
needs to load logofade.js.To do that, go to Appearance, temporarily switch to a different theme, and then switch back.
This method of adding JavaScript is useful if the JavaScript will be loaded on every single page of your web site. In
the next section, you’ll see how to add JavaScript only when a module that uses it is enabled.
A Module That Uses jQuery
Let’s build a small module that includes some jQuery functions in a JavaScript file. First, we’ll need a use case. Hmm,
how about some JavaScript code that controls blocks? Blocks can be helpful in Drupal: they can show you your login status, tell you who’s new on the site or who’s online, and provide helpful navigation. But sometimes you just want tofocus on the content of the page! Wouldn’t it be nice to hide blocks by default and show them only if you want to
see them? The following module does just that, using jQuery to identify and hide the blocks in the left and right side
bar regions and providing a helpful button that will bring the blocks back. Here’s sites/all/modules/custom/blockaway.info:
name = Block-Away
description = Uses jQuery to hide blocks until a button is clicked.
package = Pro Drupal Development core = 7.x files[]=blockaway.module
And here’s sites/all/modules/custom/blockaway.module:
<?php
/**
* @file
* Use this module to learn about jQuery.
*/
/**
* Implements hook_init().
*/
function blockaway_init() {
drupal_add_js(drupal_get_path('module', 'blockaway') .'/blockaway.js');}
All the module does is include the following JavaScript file, which you can put at sites/all/modules/custom/blockaway/
blockaway.js:
/**
* Hide blocks in sidebars, then make them visible at the click of a button.
*/
jQuery(document).ready(function() {
// Get all div elements of class 'block' inside the left sidebar.
// Add to that all div elements of class 'block' inside the
// right sidebar. Check your theme’s page.tpl.php file to see what
// selectors you should use – the following are for garland.
var blocks = jQuery('#sidebar-first div.block, #sidebar-second div.block');
// Hide them.
blocks.hide();
// Add a button that, when clicked, will make them reappear.
jQuery('#sidebar-first').prepend('<div id="collapsibutton">Show Blocks</div>'); jQuery('#collapsibutton').css({
'width': '90px', 'border': 'solid', 'border-width': '1px', 'padding': '5px','background-color': '#fff'});
// Add a handler that runs once when the button is clicked.
jQuery('#collapsibutton').one('click', function() {
// Button clicked! Get rid of the button.
jQuery('#collapsibutton').remove();
// Display all our hidden blocks using an effect.
blocks.slideDown("slow");});});
When you enable the module on the Modules page, any blocks you have visible should disappear and be replaced with a plain
button, as shown in Figure 18-5.
Figure 18-5. A node being viewed with blockaway.module enabled
After clicking the button, the blocks should appear using a sliding effect, becoming visible as shown in Figure 18-6.
Figure 18-6. After the Show Blocks button is clicked, blocks become visible.
Overridable JavaScript
The code in blockaway.module is simple and easy to understand. It just makes sure the blockaway.js file is included.However, if the module were more complicated, it would be friendlier to others to put the drupal_add_js() function call
in a theme function instead of in hook_init(). That way, those who wanted to use your module but customize the
JavaScript code in some way could do so without touching your module code at all (see Chapter 9 for how the theme
system works its magic). The code that follows is a revised version of blockaway.module thatdeclares a theme function using hook_theme(), moves the drupal_add_js() call into the theme function, and calls the theme function from hook_init(). The functionality is the same, but savvy developers can now override the blockaway.js file.
<?php
/**
* @file
* Use this module to learn about jQuery.
*/
/**
* Implements hook_init().
*/
function blockaway_init() { theme('blockaway_javascript');
}
/**
* Implements hook_theme().
* Register our theme function.
*/
function blockaway_theme() { return array('blockaway_javascript' => array( 'arguments' => array(),),);}
/**
* Theme function that just makes sure our JavaScript file
* gets included.
*/
function theme_blockaway_javascript() { drupal_add_js(drupal_get_path('module', 'blockaway') .'/blockaway.js');
}
Let’s go ahead and see if this approach works. We’re going to override the JavaScript provided by the module with
JavaScript provided by the theme. Copy sites/all/modules/custom/blockaway/ blockaway.js to your current theme—for example, themes/bartik/blockaway.js. Let’s change the JavaScript file slightly so that we’ll know which JavaScript
file is being used. Change the effect from slideDown("slow") to fadeIn(5000); this will fade in the blocks over a
period of five seconds. Here is the new file:
/**
* Hide blocks in sidebars, then make them visible at the click of a button.
*/
jQuery(document).ready(function() {
// Get all div elements of class 'block' inside the left sidebar.
// Add to that all div elements of class 'block' inside the
// right sidebar.
var blocks = jQuery('#sidebar-first div.block, #sidebar-second div.block');
// Hide them.
blocks.hide();
// Add a button that, when clicked, will make them reappear.
jQuery('#sidebar-first').prepend('<div id="collapsibutton">Show Blocks</div>'); jQuery('#collapsibutton').css({
'width': '90px', 'border': 'solid','border-width': '1px', 'padding': '5px', 'background-color': '#fff'});
// Add a handler that runs once when the button is clicked.
jQuery('#collapsibutton').one('click', function() {
// Button clicked! Get rid of the button.
jQuery('#collapsibutton').remove();
// Display all our hidden blocks using an effect.
blocks.fadeIn("5000");});});
The last change we need to make is to tell Drupal to load this new JavaScript file instead of the one in sites/all/
modules/custom/blockaway. We do that by overriding the theme function. Add the following function to the template.php file of your theme (if your theme doesn’t have a template.php file, it’s okay to create one):
/**
* Override theme_blockaway_javascript() with the
* following function.
*/
function bartik_blockaway_javascript() { drupal_add_js(path_to_theme() . '/blockaway.js');}
Visit the Modules page to rebuild the theme registry so your changes will be recognized. When you visit a page in yourweb browser, you should see the Show Blocks button, and clicking it should reveal the blocks via a gradual fade-in effect instead of the slide effect we were using earlier. Congratulations!
You’ve learned how to use jQuery in your module, how to write it in a way that is friendly to themers and other developers, and coincidentally, how to cleanly override or enhance JavaScript files provided by other module developers who have been equally courteous.
Before we leave this example, let me demonstrate how to override a template file. First, remove the bartik_blockaway_javascript() function that you added to the template.php file. Next, in your current theme, create an empty file called blockawayjavascript. tpl.php. For example, if you are using the Bartik theme, create themes/bartik/blockaway-javascript.tpl.php. Don’t put anything inside this file.
Now visit the Modules page. The act of visiting this page will rebuild the theme registry. Drupal will find the template file and use it instead of the theme function in your module. The result is that blockaway.js will never be loaded; you’veessentially commented out the theme function by creating an empty template file (recall from Chapter 9 that, when
building the theme registry,Drupal will look for a template file and then for theme functions).
Now, add the following to your blockaway-javascript.tpl.php file:
<?php drupal_add_js(path_to_theme() . '/blockaway.js'); ?>
When you reload your page, you should see that the JavaScript file is now loading. Do you see how these techniques
can be useful for substituting your own enhanced JavaScript file in a third-party module or for preventing some
JavaScript from loading?
Không có nhận xét nào:
Đăng nhận xét