1

Drupal Version: 6.x

Currently, I have a custom module created. In my template, I keep html code that I would like to embed within a container, such as a div, with a particular id. For this question, let's say <div id = "embeddableContainer"></div>. Right now, I am able to perform the task of embedding the html code from the template like this:

function first_order_decay_init() {
  $path = drupal_get_path('module', 'first_order_decay');
  $path .= '/';

  $code = file_get_contents($path . 'templates/first_order_decay-static.tpl.php', false);
  $code = preg_replace("/[\r\n]*/","",$code);
  drupal_add_js('var code = \'' . $code . '\'', 'inline');
  drupal_add_js($path . 'scripts/jquery.flot.js');
  drupal_add_js($path .'scripts/jquery.flot.dashes.js');
  drupal_add_js($path . 'scripts/jquery.flot.selection.js');
  drupal_add_js($path . 'scripts/flotScript.js');
}

The flotScript.js file appends the code within the "embeddableContainer". However, I am not particularly certain that adding these scripts on module_init is the best practice. Is there a way to load these scripts only on a page that contains an "embeddableContainer"? (Later in the question, you will read about my issue with jmol. I was told jmol uses a certain hook to load scripts correctly) The issue is that the php is executed before the page load, so I do not see a way this is possible.

The second issue I have is that the module does not correctly work with the jmol module we use to display interactive images. When including an instance of jmol in the same page, my scripts are not executed. To fix this, I tried adjusting my module's weight to load the scripts before jmol scripts, but nothing changed. We also use jsmol. Here's a link to some drupal documentation about jmol: https://www.drupal.org/project/jmol. I am not particularly knowledgeable about the module, and I was wondering if anyone else had experience with it or a similar issue as mine. I know that jmol/jsmol works by identifying a container in a similar manner. I believe it searches for text like this, [JMOL](13C60), that matches one of our jmol/jsmol instances. I am not particularly certain about the implementation of the scripts it uses because they are minified, and I do not know the source of them or even where I would begin looking within them.

To sum everything up, how can I load scripts on only pages with "embeddableContainers," and how can I avoid the conflict with jmol/jsmol?

EDIT: MORE INFORMATION ON JMOL

I was given this information about jmol.

"The Jmol module uses hook_nodeapi (specifically during the "alter" operation) to replace the placeholders on page load. Hook_nodeapi allows for modules to modify the content of nodes defined by other modules ("alter" occurs after the node content has been filtered and rendered by drupal and is used for simple text operations)."

In my script, flotScript.js, I wait for $(document).ready. Could this have any effect when replacing the text? I am thinking about making a separate js file that replaces only the text within the container. I am thinking that I should not be using $(document).ready for replacing the text.

Relevant jmol code:

function jmol_nodeapi(&$node, $op, $a3, $a4) {
  if($op == 'alter') {
    $placeholders = _jmol_get_placeholders($node->body);

    // If the node doesn't have any placeholders, do nothing
    if(count($placeholders) != 0) {
      _jmol_replace_placeholders($node, $placeholders);
    }
  }
}

function _jmol_get_placeholders($text) {
  $placeholders = array();

  // Match placeholders of the form [JMOL]('placeholder')
  preg_match_all('/\\[JMOL\\]\(([[:graph:]]+?)\)/', $text, $placeholders);

  return $placeholders;
}

function _jmol_replace_placeholders(&$node, $placeholders) {
  foreach($placeholders[0] as $i=>$placeholder) {
    // Load the instance associated with this placeholder from the db
    $instance = _jmol_load_instance_by_placeholder($placeholders[1][$i]);

    $applet_container_html = jmol_get_applet_container_html($instance);

    // Replace the placeholder with the applet container html
    $node->body = str_replace($placeholder, $applet_container_html, $node->body);
  }
}

function _jmol_load_instance_by_placeholder($placeholder) {
  $instance = db_fetch_object(db_query('SELECT * FROM {jmol_instances} WHERE placeholder=\'%s\'', $placeholder));

  if($instance === FALSE) return FALSE;

  // Get the models associated with the instance
  $instance->models = _jmol_get_models($instance->jid);

  return $instance;
}

EDIT: SOLUTION TO CONFLICT WITH JMOL

function first_order_decay_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if($op == 'alter') {
    $path = drupal_get_path('module', 'first_order_decay');
    $path .= '/';

    $code = file_get_contents($path . 'templates/first_order_decay-static.tpl.php', false);
    $code = preg_replace("/[\r\n]*/","",$code);
    drupal_add_js('var code = \'' . $code . '\'', 'inline');
    drupal_add_js($path . 'scripts/jquery.flot.js');
    drupal_add_js($path .'scripts/jquery.flot.dashes.js');
    drupal_add_js($path . 'scripts/jquery.flot.selection.js');
    drupal_add_js($path . 'scripts/flotScript.js');
  }
}

Will I still be able to check content types for loading scripts?

4
  • Do you know which module is outputting the embeddableContainer div? That's the first thing to find out.
    – rooby
    Commented Jul 31, 2014 at 3:51
  • The embeddableContainer is meant to be a placeholder within a page. The div is created in full HTML mode of CKEditor (php mode of CKEditor is not an option). The goal is to have a small piece of code (one line or so) that allows a page editor with no experience coding to insert what needs to be there. If you have any other ideas as to how I could support this feature, I am open to any of them. I'm not sure if my way is the most practical. Commented Jul 31, 2014 at 5:43
  • I found a solution. Posting in edit. Thanks for the help! Commented Jul 31, 2014 at 18:19
  • I made a modification to how I add in my html. I search for a specific string of text, [FLOT](kinetics 1) (they wanted it to look like JMOL instances), and then I replace it with a div which my javascript later appends to. I count the amount of replacement, and if it's greater than 0, I load my scripts because I know my html should be present. That way the scripts load only when needed regardless of content type. Commented Aug 1, 2014 at 1:57

2 Answers 2

1

If you are dealing with content on node pages you could add something like this in your init function:

if ($node = menu_get_item()) {
  // If we have an article node, add our js.
  if ($node->type == 'article') {
    // Add your js here.
  }
}

You could do other similar things to make it so you are not unnecessarily loading your js as much (although it may still be unnecessarily loading sometimes).

That will probably not help you if you also have this markup on listing pages because it deals with individual node pages.

For all node views you could do something like this:

function MODULENAME_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'view':
      // Your js gets loaded here.
      // You can also single out specific node types here, or check
      // nodes for a specific field having a non-empty value, or check
      // the view mode, etc. to further limit the adding of your js.
      break;
  }
}

If you are also dealing with non-node entities then there are other similar hooks that could help you out. You might need to have a function that adds all your js and then call it from a few places to catch all your use cases.

1
  • I tried the second option, using MODULE_nodeapi. My scripts are loading to the page, but the jmol is still taking priority. I received some more information about how jmol works, and I'll put that in an edit. Commented Jul 31, 2014 at 18:02
2

It is probably better to create a input filter by using hook_filter and then applying that filter to the 'Full HTML' input format (at /admin/settings/filters).

Input filters are used to massage HTML before output.

4
  • This is probably the way that will get you the most specific targeting of which pages to add your js to, however it has a drawback: you will likely have to set "no cache" to TRUE for your filter, which means any content that uses a text format (like Filtered HTML) that your input filter is used on will not be cached and will have to run through all input filters every time it is viewed, which is bad for performance. If it is not something you use very often you could create a text format specifically for these nodes so you aren't taking the performance hit as often.
    – rooby
    Commented Jul 31, 2014 at 7:02
  • It depends on whether it is better overall for performance to not cache this input filtered content or to include the js on all pages. The answer to that will be specific to your site and requirements.
    – rooby
    Commented Jul 31, 2014 at 7:04
  • For anonymous users, the whole page will be cached anyway. Right? Commented Jul 31, 2014 at 7:04
  • Generally, although it depends on the site configuration.
    – rooby
    Commented Jul 31, 2014 at 7:06

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.