7

I have set up a Drupal 7 web site with a few custom blocks and menus written by me.

I have a non-Drupal PHP script displaying users (some of them are external, i.e. not stored in drupal tables) as a table with the DataTables jQuery plugin.

I would like to rewrite that script as a Drupal menu, so that it can be called as http://preferans.de/top.

The content of my.module is the following.

function my_menu() {
  $items['top'] = array (
    'title' => 'Top',
    'description' => 'Top',
    'page callback' => 'my_top_callback',
    'access callback' => TRUE,
    'file' => 'my.top.inc',
    'file path' => drupal_get_path('module', 'my'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

The content of my.top.inc is the following.

function my_top_callback() {
  return array (
    'top_table' => array (
      '#type' => 'markup',
      '#markup' => generate_html_table_with_php(),
    ),
  );
}

My problem is that I don't understand how to add the CSS and JavaScript code, so that it is available for the /top page, but not for any other Drupal paths.

I should probably call:

   drupal_add_css('/demo_table_jui.css', 'file');
   drupal_add_css('/smoothness/jquery-ui-1.8.4.custom.css', 'file');
   drupal_add_js('/jquery.dataTables.min.js', 'file');
   drupal_add_js('
       $(document).ready(function() {
         $("#rating").dataTable( {
            "bJQueryUI": true,
            "sPaginationType": "full_numbers"
          });
        ', 'inline');

(Please see the head-section of my original non-Drupal script).

How do I limit these calls to the /top page and where should I perform these calls? Should I put them in a hook, or by adding some properties to my menu?

1
  • 'file path' is not necessary, if the file is inside the directory containing the module that defines the menu callback.
    – avpaderno
    Commented Mar 25, 2011 at 21:39

2 Answers 2

6

Generally, CSS and JavaScript files are added with hook_init(), which allows those files to be aggregated together, when aggregation is enabled.

Using hook_init() (I suggest you not to do this, anyway) you could conditionally add the files basing on the page being visited.

function my_init() {
  if (arg(0) == 'top') {
    // Add the files.
  }
}

The reason I don't suggest you to do this is that the hook would be called for every pages, including the ones you are not adding the files. hook_init() is generally used to add files to each page.

You can add those files in the menu callback (a.k.a., the page callback); if the menu callback is a form builder function, then you can use the #attached property, as the following code.

$form['#attached']['css'] = array(
  drupal_get_path('module', 'ajax_example') . '/ajax_example.css',
);

$form['#attached']['js'] = array(
  drupal_get_path('module', 'ajax_example') . '/ajax_example.js',
);

About the inline code you are adding, I would recommend you to put also that in a file, and to use Drupal behaviors instead of $(document).ready(). If you need to pass arguments to the JavaScript code, you can use JavaScript settings (see drupal_add_js() to understand in details how to pass settings to JavaScript code).
Managing JavaScript in Drupal 7 explains in details how to manage JavaScript code in Drupal 7, and the section titles Behaviors reports how Drupal behaviors are changed in the latest Drupal version.

4
  • Using hook_init() would cause the code to be added to every page. The question was for how to add them to a specific menu callback.
    – jhedstrom
    Commented Mar 26, 2011 at 0:09
  • That is why I said generally. I was not suggesting that using hook_init() is the solution in this case, but I was explaining why hook_init() is usually used.
    – avpaderno
    Commented Mar 26, 2011 at 0:19
  • Thanks, but I want to add it to a particular path. Something like function my_init() { if (drupal_is_front_page()) { drupal_add_css(....); drupal_add_js(....); } } but for the /top and not the front page. Commented Mar 26, 2011 at 5:54
  • 1
    @Alexander as kiamlaluno explains in the answer, if you make these calls inside the page callback function it will only be applied on these specific pages. Commented Mar 26, 2011 at 11:55
3

You can add the code in your menu callback. Instead of adding the JS code inline, I would suggest that you create your own JS file.

function my_top_callback() {
  drupal_add_css('/demo_table_jui.css');
  drupal_add_css('/smoothness/jquery-ui-1.8.4.custom.css');
  drupal_add_js('/jquery.dataTables.min.js');
  drupal_add_js(drupal_get_path('module', 'my') . '/my.js');
  return array (
    'top_table' => array (
      '#type' => 'markup',
      '#markup' => generate_html_table_with_php(),
    ),
  );
}

You should then add the my.js file to your my module. Notice that $isn't a global variable in Drupal 7 instead use jQuery:

(function($) {
  $(document).ready(function() {
    $("#rating").dataTable( {
      "bJQueryUI": true,
      "sPaginationType": "full_numbers"
    });
  });
})(jQuery);

You could also make this into a JavaScript behavior which is the recommended thing to do. That would look something like this:

(function ($) {

  Drupal.behaviors.my = {
    attach: function(context, settings) {
      $("#rating").dataTable( {
        "bJQueryUI": true,
        "sPaginationType": "full_numbers"
      });
    }
  };
})(jQuery);
2
  • Thank you, but I'm confused - what does this do: (function($) { .... })(jQuery); Commented Mar 25, 2011 at 22:01
  • @Alexander: That's what in JavaScript is called a closure. It's a technique to make sure your variables doesn't impact other JavaScript code, as they all share the same name space, the global window object. This would allow you to run fx the prototype JS library which also uses the $ sign without conflict.
    – googletorp
    Commented Mar 25, 2011 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.