| 7 common.inc | drupal_add_js( |
| 4.7 common.inc | drupal_add_js( |
| 5 common.inc | drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE) |
| 6 common.inc | drupal_add_js($data = NULL, |
| 8 common.inc | drupal_add_js($data = NULL, $options = NULL) |
Adds a JavaScript file, setting, or inline code to the page.
The behavior of this function depends on the parameters it is called with. Generally, it handles the addition of JavaScript to the page, either as reference to an existing file or as inline code. The following actions can be performed using this function:
- Add a file ('file'): Adds a reference to a JavaScript file to the page.
- Add inline JavaScript code ('inline'): Executes a piece of JavaScript code on the current page by placing the code directly in the page (for example, to tell the user that a new message arrived, by opening a pop up, alert box, etc.). This should only be used for JavaScript that cannot be executed from a file. When adding inline code, make sure that you are not relying on $() being the jQuery function. Wrap your code in
(function ($) {... })(jQuery); or use jQuery() instead of $().
- Add external JavaScript ('external'): Allows the inclusion of external JavaScript files that are not hosted on the local server. Note that these external JavaScript references do not get aggregated when preprocessing is on.
- Add settings ('setting'): Adds settings to Drupal's global storage of JavaScript settings. Per-page settings are required by some modules to function properly. All settings will be accessible at Drupal.settings.
Examples:
drupal_add_js('misc/collapse.js');
drupal_add_js('misc/collapse.js', 'file');
drupal_add_js('jQuery(document).ready(function () { alert("Hello!"); });', 'inline');
drupal_add_js('jQuery(document).ready(function () { alert("Hello!"); });',
array('type' => 'inline', 'scope' => 'footer', 'weight' => 5)
);
drupal_add_js('http://example.com/example.js', 'external');
drupal_add_js(array('myModule' => array('key' => 'value')), 'setting');
Calling drupal_static_reset('drupal_add_js') will clear all JavaScript added so far.
If JavaScript aggregation is enabled, all JavaScript files added with $options['preprocess'] set to TRUE will be merged into one aggregate file. Preprocessed inline JavaScript will not be aggregated into this single file. Externally hosted JavaScripts are never aggregated.
The reason for aggregating the files is outlined quite thoroughly here: http://www.die.net/musings/page_load_time/ "Load fewer external objects. Due to request overhead, one bigger file just loads faster than two smaller ones half its size."
$options['preprocess'] should be only set to TRUE when a file is required for all typical visitors and most pages of a site. It is critical that all preprocessed files are added unconditionally on every page, even if the files are not needed on a page. This is normally done by calling drupal_add_js() in a hook_init() implementation.
Non-preprocessed files should only be added to the page when they are actually needed.
Parameters
$data: (optional) If given, the value depends on the $options parameter, or $options['type'] if $options is passed as an associative array:
- 'file': Path to the file relative to base_path().
- 'inline': The JavaScript code that should be placed in the given scope.
- 'external': The absolute path to an external JavaScript file that is not hosted on the local server. These files will not be aggregated if JavaScript aggregation is enabled.
- 'setting': An associative array with configuration options. The array is merged directly into Drupal.settings. All modules should wrap their actual configuration settings in another variable to prevent conflicts in the Drupal.settings namespace. Items added with a string key will replace existing settings with that key; items with numeric array keys will be added to the existing settings array.
$options: (optional) A string defining the type of JavaScript that is being added in the $data parameter ('file'/'setting'/'inline'/'external'), or an associative array. JavaScript settings should always pass the string 'setting' only. Other types can have the following elements in the array:
- type: The type of JavaScript that is to be added to the page. Allowed values are 'file', 'inline', 'external' or 'setting'. Defaults to 'file'.
- scope: The location in which you want to place the script. Possible values are 'header' or 'footer'. If your theme implements different regions, you can also use these. Defaults to 'header'.
- group: A number identifying the group in which to add the JavaScript.
Available constants are:
- JS_LIBRARY: Any libraries, settings, or jQuery plugins.
- JS_DEFAULT: Any module-layer JavaScript.
- JS_THEME: Any theme-layer JavaScript.
The group number serves as a weight: JavaScript within a lower weight group is presented on the page before JavaScript within a higher weight group.
- every_page: For optimal front-end performance when aggregation is enabled, this should be set to TRUE if the JavaScript is present on every page of the website for users for whom it is present at all. This defaults to FALSE. It is set to TRUE for JavaScript files that are added via module and theme .info files. Modules that add JavaScript within hook_init() implementations, or from other code that ensures that the JavaScript is added to all website pages, should also set this flag to TRUE. All JavaScript files within the same group and that have the 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE are aggregated together into a single aggregate file, and that aggregate file can be reused across a user's entire site visit, leading to faster navigation between pages. However, JavaScript that is only needed on pages less frequently visited, can be added by code that only runs for those particular pages, and that code should not set the 'every_page' flag. This minimizes the size of the aggregate file that the user needs to download when first visiting the website. JavaScript without the 'every_page' flag is aggregated into a separate aggregate file. This other aggregate file is likely to change from page to page, and each new aggregate file needs to be downloaded when first encountered, so it should be kept relatively small by ensuring that most commonly needed JavaScript is added to every page.
- weight: A number defining the order in which the JavaScript is added to
the page relative to other JavaScript with the same 'scope', 'group',
and 'every_page' value. In some cases, the order in which the JavaScript
is presented on the page is very important. jQuery, for example, must be
added to the page before any jQuery code is run, so jquery.js uses the
JS_LIBRARY group and a weight of -20, jquery.once.js (a library drupal.js
depends on) uses the JS_LIBRARY group and a weight of -19, drupal.js uses
the JS_LIBRARY group and a weight of -1, other libraries use the
JS_LIBRARY group and a weight of 0 or higher, and all other scripts use
one of the other group constants. The exact ordering of JavaScript is as
follows:
- First by scope, with 'header' first, 'footer' last, and any other scopes provided by a custom theme coming in between, as determined by the theme.
- Then by group.
- Then by the 'every_page' flag, with TRUE coming before FALSE.
- Then by weight.
- Then by the order in which the JavaScript was added. For example, all else being the same, JavaScript added by a call to drupal_add_js() that happened later in the page request gets added to the page after one for which drupal_add_js() happened earlier in the page request.
- defer: If set to TRUE, the defer attribute is set on the <script> tag. Defaults to FALSE.
- cache: If set to FALSE, the JavaScript file is loaded anew on every page call; in other words, it is not cached. Used only when 'type' references a JavaScript file. Defaults to TRUE.
- preprocess: If TRUE and JavaScript aggregation is enabled, the script file will be aggregated. Defaults to TRUE.
Return value
The current array of JavaScript files, settings, and in-line code, including Drupal defaults, anything previously added with calls to drupal_add_js(), and this function call's additions.
See also
- ajax_forms_test_lazy_load_form_submit in modules/
simpletest/ tests/ ajax_forms_test.module - Form submit handler: Adds JavaScript and CSS that wasn't on the original form.
- ajax_render in includes/
ajax.inc - Renders a commands array into JSON.
- ajax_test_render in modules/
simpletest/ tests/ ajax_test.module - Menu callback; Return an element suitable for use by ajax_deliver().
- block-admin-display-form.tpl.php in modules/
block/ block-admin-display-form.tpl.php - Default theme implementation to configure blocks.
- color.inc in themes/
bartik/ color/ color.inc
- DrupalRenderTestCase::testDrupalRenderChildrenAttached in modules/
simpletest/ tests/ common.test - Test #attached functionality in children elements.
- JavaScriptTestCase::setUp in modules/
simpletest/ tests/ common.test - Sets up a Drupal site for running functional and integration tests.
- JavaScriptTestCase::testAggregationOrder in modules/
simpletest/ tests/ common.test - Tests JavaScript aggregation when files are added to a different scope.
- JavaScriptTestCase::testReset in modules/
simpletest/ tests/ common.test - Test to see if resetting the JavaScript empties the cache.
- overlay_render_region in modules/
overlay/ overlay.module - Renders an individual page region.
File
- includes/
common.inc, line 4115 - Common functions that many Drupal modules will need to reference.
Code
function drupal_add_js($data = NULL, $options = NULL) {
$javascript = &drupal_static(__FUNCTION__, array());
// Construct the options, taking the defaults into consideration.
if (isset($options)) {
if (!is_array($options)) {
$options = array('type' => $options);
}
}
else {
$options = array();
}
$options += drupal_js_defaults($data);
// Preprocess can only be set if caching is enabled.
$options['preprocess'] = $options['cache'] ? $options['preprocess'] : FALSE;
// Tweak the weight so that files of the same weight are included in the
// order of the calls to drupal_add_js().
$options['weight'] += count($javascript) / 1000;
if (isset($data)) {
// Add jquery.js and drupal.js, as well as the basePath setting, the
// first time a JavaScript file is added.
if (empty($javascript)) {
// url() generates the prefix using hook_url_outbound_alter(). Instead of
// running the hook_url_outbound_alter() again here, extract the prefix
// from url().
url('', array('prefix' => &$prefix));
$javascript = array(
'settings' => array(
'data' => array(
array('basePath' => base_path()),
array('pathPrefix' => empty($prefix) ? '' : $prefix),
),
'type' => 'setting',
'scope' => 'header',
'group' => JS_LIBRARY,
'every_page' => TRUE,
'weight' => 0,
),
'misc/drupal.js' => array(
'data' => 'misc/drupal.js',
'type' => 'file',
'scope' => 'header',
'group' => JS_LIBRARY,
'every_page' => TRUE,
'weight' => -1,
'preprocess' => TRUE,
'cache' => TRUE,
'defer' => FALSE,
),
);
// Register all required libraries.
drupal_add_library('system', 'jquery', TRUE);
drupal_add_library('system', 'jquery.once', TRUE);
}
switch ($options['type']) {
case 'setting':
// All JavaScript settings are placed in the header of the page with
// the library weight so that inline scripts appear afterwards.
$javascript['settings']['data'][] = $data;
break;
case 'inline':
$javascript[] = $options;
break;
default: // 'file' and 'external'
// Local and external files must keep their name as the associative key
// so the same JavaScript file is not added twice.
$javascript[$options['data']] = $options;
}
}
return $javascript;
}
Comments
add conditional js under theme.info
PermalinkHaving the ability to conditionally load js files depending on browser would help cross browser compatibility tremendously. add_js can be a little to stern to deal with and needs more flexibility.
Cross-browser issues
PermalinkThe jQuery version bundled with D7 automatically runs a couple of tests to determine how capable the visiting browser is. The results are stored as properties of jQuery.support, which makes for easier branching in your scrpts based on available [or working] features.
I personally prefer a couple of branches (if put in the right places) rather than dealing with two or more files. It's easy to forget syncing multiple files and I think aggregation works better with just one.
Feature detection and browser based decision making on the client is also a lot more reliable than what Drupal's serverside code could do in drupal_add_js().
Canvas support in IE
PermalinkI needed to add an separate js file only for IE browsers to support canvas, I was hoping drupal_add_js would allow this.
Only solution I found is
$forie = array('#type' => 'markup',
'#markup' => '<!--[if IE]><script language="javascript" type="text/javascript" src="..."></script><![endif]-->',
);
drupal_add_html_head($forie, 'mymodule');
Using in mytheme_preprocess_page
PermalinkQuick example of use in your theme's template.php (I hunted around for a while trying to find such an example):
function MYTHEME_preprocess_page(&$variables) {drupal_add_js(drupal_get_path('theme', 'MYTHEME') .'/mytheme.js', 'file');
}
If it's included on every
PermalinkIf it's included on every page then it's better to include it in your theme's mytheme.info file as it gets added to the theme registry.
scripts[] = js/script.jsscripts[] = js/otherscript.js
tip for drupal_add_js() and weight
PermalinkDrupal 7 supports a weight attribute which is easy to use, like so:
$path = drupal_get_path('module', 'MODULE_NAME_HERE');
drupal_add_js($path . '/SCRIPT_NAME_HERE.js', array('weight' => 1));
Tip: DO NOT rely on firebug to check if the order of your scripts have changed, as firebug automatically groups and re-orders the scripts for display!
What you want to do is view the actual source-code instead...
I wasted a couple of hours on this.
Hope this helps someone else to avoid the same.
yap tnx i was doing it too :)
Permalinkyap tnx i was doing it too :)
Beware of including existing libraries
PermalinkAs a Drupal newbie I thought it was logical to call drupal_add_js (or drupal_add_library) to add jQuery in my module, just to point out that the other javascript files used in the module depend on this library. I figured surely it couldn't hurt and in worst case scenario the library is already in the queue. Turns out that doing so somehow reset or messed up the queue order and I got a lot of "jQuery not defined" errors in firebug as jQuery was no longer being included before jquery.once.js and drupal.js (and more).
I didn't realize the queue system worked like this, surely should it not ignore subsequent calls to libraries already in the queue? I suppose this scenario must be relevant for other libraries as well.
Just beware:)
When they say javascript file, it's not what you think
PermalinkWhat they call a "javascript file" is not really a javascript file. It's that weird jQuery format. So if your external file has
<script type="javascript/text" >...</script>, then forget it because it will not work. You will need to wrap it in that jQuery syntax. I spent a good 2 hours banging my head on this.Are you sure?
Permalinktype="text/javascript" is correct.
If the file has script tags
PermalinkIf the file has script tags wrapped around it, it's not a pure Javascript file. The script tags show up only to wrap JS that is being included inline in HTML. Any Javascript external file should not include them - not just ones that use the jQuery syntax.
See hook_js_alter() to alter
PermalinkSee
hook_js_alter()to alter js files added usingdrupal_add_js()JohnAlbin also gave the
PermalinkJohnAlbin also gave the useful comment in IRC about ordering the files:
When you use drupal_add_js() it defaults to "i'm a module adding a js" and module JS come before theme JS. So you'll need to set the group for the new JS file as well.
Ctools Javascipt is not execute
PermalinkSolution : For this We can call the theme for call the javascipt like :
$form['pager'] = array('#theme' => 'copy_import_pagination');
drupal_add_js called from .module file, is it possible?
PermalinkHello,
I'm trying to code the behaviour of a new customized module, and for that, I need some extra jQuery functionalities.
I included the drupal_add_js function calling my new js file at the beginning of the hook_block_view of my module, and, it seems to be loaded at the browser when de page is loaded, you can see it in the code of the page, but it doesn't work.
Maybe is something in the load order files?
Or perhaps the js files loades in the module level doesn't have to work?
Thank you very much!
These are very cool
PermalinkThese are very cool improvements over v6. Thank you guys! :-)
My favorite feature is in external resources you can use protocol-relative URLs:
For example, if you need to include a javascript to load webfonts:
<?phpdrupal_add_js('//fast.fonts.com/jsapi/00000000-0000-0000-0000-000000000000.js', array(
'type' => 'external',
'scope' => 'header',
'group' => JS_THEME,
'every_page' => TRUE,
'weight' => -1,
));
?>
I am guessing drupal_add_css also works the same way, and also in .info files too. I'll check that out later.
Any idea how I can add this
PermalinkAny idea how I can add this ?
<script type='text/javascript' src='https://www.smartrecruiters.com/img/script/smartWidget/smart_widget.js'></script>
<script type='text/javascript' class='job_widget'>
widget({
"company_code":"XXX",
"bg_color_widget":"#ffffff",
"bg_color_headers":"#969696",
"txt_color_headers":"#292929",
"custom_css_url":"https://www.smartrecruiters.com/img/style/smartWidget/smart_widget.css",
});
</script>
I don't know how to specify "class='job_widget'"...
[Disregard...] Multiple parameters don't work
PermalinkThat was just me being silly. It looks wrong in the source code, but gets sent correctly to the server.
---
If an external javascript file need multiple GET-parameters, drupal_add_js() doesn't work. For example:
$path = 'http://example.com';$options = array(
'external' => TRUE,
'query' => array(
'foo' => '1',
'bar' => '2',
),
);
$script_url = url($path, $options);
// The script_url is fine when it's given to drupal_add_js...
drupal_add_js($script_url, array('scope' => 'footer', 'type' => 'external'));
// ..but the version printed in the page source has encoded the ampersand,
// rendering the link useless.
This looks like a bug to me, is there an open bug report somewhere?
Is there any workaround for this?
Browser dependent JS
PermalinkIn my case I copied the example from the "add_css" and modified it a little:
drupal_add_js(path_to_theme() . '/js/html5shiv.js', array('group' => JS_LIBRARY, 'weight' => 115, 'browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE), 'preprocess' => FALSE));It seems to work fine. Please give me some feedback on this cause I am just a themer and no programmer ;-)
This won't work
PermalinkIt doesn't work because unlike drupal_add_css, drupal_add_js still doesn't have a 'browsers' option. A patch to remedy this appears to have been committed to D8 but a D7 re-roll has yet to appear.
See here for more details.
In the meantime, you may get away with using drupal_add_html_head like so:
$selectivizr = array('#tag' => 'script',
'#attributes' => array( // Set up an array of attributes inside the tag
'src' => drupal_get_path('theme', 'bb_sub_theme') . '/js/lib/selectivizr-min.js',
),
'#prefix' => '<!--[if (gte IE 6)&(lte IE 8)]>',
'#suffix' => '</script><![endif]-->',
);
drupal_add_html_head($selectivizr, 'selectivizr');
You've added JS, now it doesn't work:
PermalinkSo you've successfully loaded your JS file and it won't work? Make sure your code is wrapped in anonymous function that casts jQuery as $:
jQuery(document).ready(function ($) {});
Make sure to read Working with JavaScript and jQuery
Add conditional javascript for IE
PermalinkSample code on how to add conditional scripts in html head section.
Scripts will apply to IE browsers except IE9.
Place the following code inside template.php inside hook_preprocess_html().
<?php// IE Conditional scripts
$ie_scripts = array(
path_to_theme() . '/js/script1.js',
path_to_theme() . '/js/script2.js',
path_to_theme() . '/js/script3.js',
);
foreach ($ie_scripts as $key => $value) {
$ie_script = array(
'#browsers' => array('IE' => 'lt IE 9', '!IE' => FALSE),
'#tag' => 'script',
'#attributes' => array(
'type' => "text/javascript",
'src' => $value,
),
'#pre_render' => array('drupal_pre_render_conditional_comments'),
'#weight' => 999 + $key,
);
drupal_add_html_head($ie_script, "mytheme$key");
}
?>
This did not work for me. I
PermalinkThis did not work for me. I am pretty new thou. can you give the example inside the hook_preprocess_html(). perhaps I am missing something? Thanks
Add HTML5 async attribute
PermalinkIs there a way to create new attribute types. For example the new async attribute of HTML5.
<script src="async_file.js" async='async'></script>HTML5 script async attribute
PermalinkActually, there is already an issue for this. Add async, onload property to script tags
Add external javascript with options
PermalinkThe above example for loading external libraries is great if you don't have any options for them:
<?php drupal_add_js('http://example.com/example.js', 'external'); ?>But if you do, you'll want to add it to the options array with a flag of 'type'.
For example, to change the weight of an external library:
<?phpdrupal_add_js('http://example.com/example.js', array(
'weight' => '-1000',
'type' => 'external',
)
);
?>
This can be figured out from the code but hopefully this will help make it a bit easier for some folks.
Can't get it to work
PermalinkI am still having alot of troubles getting a simple code to work.
It is working when I am logged on but not when logged off.
Maybe I am just missing something. I have read through so many examples and I am not much into the codes and everything.
But I have this code in template.php
function verhuur_preprocess_html(&$variables) {$theme_path = path_to_theme();
$url = request_uri();
if ($url == '/gamma/') {
drupal_add_js($theme_path . '/js/test.js');
}
}
And then this code in the test.js
(function ($){jQuery(document).ready(function ($) {
$('#block-block-1').click(function () {
$(this).animate({
left: '200px'
}, 1000);
});
});
})(jQuery);
Please help, trying for days now just to get a script going on drupal 7