How to add Javascript in Drupal 7 with jQuery

I thought this would be an easy one. Not so. What works in Drupal 6 doesn't necessarrily work in Drupal 7. Let's take a simple example. How about a script that allows you to show/hide one or more paragraphs. I did a quick Google search and found numerous examples. Here's the one I picked & slightly modified for the sake of clarity.

<script type="text/javascript">
    $(document).ready(function(){
      $(".toggler").click(function(){
        $(this).next().slideToggle("slow");
        return false;
      }).next().hide();
    });
</script>
    
<p class="toggler" style="cursor:pointer;">Show/Hide the following paragraph(s).</p>
<div>
    This paragraphe is initially hidden. Clicking on the link above will reveal (Show) all the content inside the DIV that immediately follows a "toggler" class paragraph.
</div>

In Drupal 6, simply paste this code in the Body field of a Page or Article node and it works. Well, as usual, there are a few requirements. For the most part, this should do it.

  • Go to admin/settings/filters/2 (Full HTML settings) and uncheck the HTML filter
  • Set the Input format of the Body field to Full HTML
  • Disable rich-text
  • Paste the above code, save and enjoy a moment of true happiness

The Drupal 7 way

I tried this exact same method in Drupal 7 but by default the <script></script> tags and its content are removed (deleted) by the system for security reasons. There are probably ways to bypass this but it's bad practice. So we can't embed this script in a Drupal 7 Article node. In the present case, the next best way - a proper way - is to embed the script directly into the Article template of the theme. In doing so, the script will be available for all nodes created with the Article content type. Now, that's even better. So how do we do this?

Click here to Show or Hide the next paragraph!

I'm using the Antonelli theme, a fluid width subtheme for Bartik. In the Antonelli theme folder (sites/all/themes/antonelli), there is not a simgle template. So I had to look to Antonelli's parent theme for help. In the Bartik folder (themes/bartik), under templates, there is no template for nodes created with the Article content type. But I found node.tpl.php, a generic template for all nodes. This is the template I'll use to create a custom node template for the Article content type. Here's how to do it.       
  • Duplicate node.tpl.php and rename it node--article.tpl.php
  • Open it up with your favorite text editor
  • Insert the <script></script> tags before the first line of HTML
  • The script must then be wrapped inside a jQuery closure function. Otherwise it just won't work. See the References block for more information
  • Finally, there are advantages to use Drupal behaviors rather than document.ready()
<script type="text/javascript">
    (function($) {
      Drupal.behaviors.customToggler = {
        attach: function(context, settings) {
          // javascript code
        }
      };
    }) (jQuery);
</script>
  • Save it in your theme's folder. For me, that would be sites/all/themes/antonelli.
  • To load the template you just created Resave your theme or Flush all caches.

In the end, here's what the node--article.tpl.php should roughly look like.

...

 * @see template_preprocess()
 * @see template_preprocess_node()
 * @see template_process()
 */
?>

<script type="text/javascript">
    (function($) {
       Drupal.behaviors.customToggler = {
         attach: function(context, settings){
            $(".toggler", context).once('custom-toggler').click(function(){
              $(this).next().slideToggle("slow");
              return false;
            }).next().hide();
          }
        };
    })(jQuery);
</script>

<div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>

...

Ready for some magic?

  • Create a new article
  • Make sure the Input format of the Body field is set to Full HTML
  • Disable rich-text
  • Paste the following code (CSS is optional)
<style type="text/css">
  p.toggler:hover {
    color:#008000;
  }
</style>

<p class="toggler" style="cursor:pointer;">Show/Hide the following paragraph(s).</p>
<div>
    This paragraphe is initially hidden. Clicking on the link above will reveal (Show) all the content inside the DIV that immediately follows a "toggler" class paragraph.
</div>

Save and then Show/Hide to your heart's content!