There are cases where modules will want to *remove* Javascript that has been added using drupal_add_js(). I do not believe that this is possible using the current static variable method.

I see two different options for fixing this situation:

1) Use a global variable instead of a static variable. This would obviously make it super-easy for any function to modify the array.

2) Use a drupal_alter() call inside of drupal_get_js() and allow modules to implement hook_js_alter(). This seems like a lot more overhead to me, but it does avoid adding more variables in the global scope.

Use example: The JQuery Update module requires some complex installation that includes having to replace the core jquery.js file with the one included with the module. If the module could modify this array, then installation would be a lot easier (no need to replace core file) and the module would simply say "use my jquery file, not the core jquery file".

Additional note: Whatever gets decided for this will also want to be mirrored in drupal_add_css. This would be another issue, but there are many reasons to alter the local/static $css variable in this same way.

CommentFileSizeAuthor
#9 drupal-HEAD.patch1.01 KBsun
#4 d6-add-js-ref.patch.txt1.02 KBjjeff
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jjeff’s picture

fyi: the "sister" (drupal_add_css()) issue is here http://drupal.org/node/173946

Crell’s picture

I'm not a fan of the CSS one, but this one I can definitely see a use for, via alter hook. (Once again, globals are bad, m'kay?) The main question in my mind is whether or not it's too late to get this into D6. My inclination is yes.

jjeff’s picture

The main problem with the hook_css_alter() approach is that the theme has no ability to implement. I could imagine that there are situations where themes might want to remove JS files. Perhaps a Flash-based theme might not want textarea.js. Or a mobile theme might want to remove jquery.js altogether. Or someone might want to build a super-ajaxified theme based on the Dojo library (and not use JQuery).

I do realize that global variables are generally frowned upon, but that's certainly the easiest way to allow the array to be alterable.

How about some sort of pass-by-reference option? I'm not quite sure how this would work -- it would need to be more of a return-by-reference. Hmmm.... How about something like this?

function drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE, $preprocess = TRUE, &$jsref = NULL) {
  static $javascript = array();
    
  $jsref = &$javascript;

  //...

This would allow a module to do something like this:

drupal_add_js(NULL, 'module', 'header', FALSE, TRUE, TRUE, $js);
unset($js['header']['core']);

I *think* that would work!

jjeff’s picture

Status: Active » Needs review
FileSize
1.02 KB

I've figured it out!!!

The attached patch adds just ONE CHARACTER (an & before the drupal_add_js() function name. This causes the returned value of the function to pass by reference, thus allowing modules/themes/etc to alter the $javascript array.

I had hoped to keep this as a one character patch, but I broke down and added some documentation reminding people that return values are passed by reference.

I've tested this and it works just as expected.

jjeff’s picture

BTW, here's the "how to" on altering the arrays after this patch has been applied:

drupal_add_js('foo = ""', 'module', 'inline'); // this "primes the pump" and fills out the array 
$js =& drupal_add_js(NULL, NULL, NULL); // this returns the array by reference
print_r($js);  // you'll get the entire array
unset($js['header']['core']);  // remove all of the core javascript

$newjs = drupal_add_js(NULL, NULL, NULL); // populate a new variable with the javascript array
print_r($newjs); // core javascript is now gone
catch’s picture

this one character (!) (no not that character) patch still applies with a big offset. Seems like a very trivial change and one which would make the jQuery update module far simpler. Someone else more familiar with drupal_add_js() should RTBC it quick.

mfer’s picture

Can we still get this in?

catch’s picture

Status: Needs review » Reviewed & tested by the community

bumping to RTBC so it goes into Gabor's queue for a decision. Otherwise just needs bumping to D7.

sun’s picture

FileSize
1.01 KB

New patch, should apply without fuzz.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Closed (won't fix)

IMHO this looks just as hackish as using yourtheme_preprocess_page() or yourmodule_preprocess_page() and fiddle with $variables['scripts'] and $variables['styles'], which is after all the styles and themes structure built up for you and is in the process of being handed over to the theme. Any module or theme can ship with code here to add or replace styles. This kind of theme value altering is what's available in Drupal 6 will hopefully be common practice, instead of one-off hacks like returning references for a static var.

sun’s picture

Version: 6.x-dev » 7.x-dev
Status: Closed (won't fix) » Needs work

Discussed in IRC... let's implement hook_css_alter() and hook_js_alter() with two simple drupal_alter() invocations, so modules are able to alter the output.

Crell’s picture

I think there's some overlap with #251578: More flexible js/css ordering and an alter operation. This one should probably be a marked as a dupe of that.

quicksketch’s picture

Status: Needs work » Closed (duplicate)

The #251578: More flexible js/css ordering and an alter operation issue is a much better place to continue this. It's features include a $reset flag on drupal_add_js(), a drupal_remove_js() function, and full support for hook_js_alter(). Seems like it's everything we want it to be.

bartclarkson’s picture

Version: 7.x-dev » 6.x-dev

Since Drupal 6 bled into this thread (and is how I ended up here), here's an alternative approach if you're desperately trying to not hack another module's implementation of drupal_add_js, but you really need the associated javascript to not happen. I looked at the jquery_update approach for a server-side solution, but that's just a race to be the last load, and jquery_update may as well be the king of that valley.

Alternative: either use your theme preprocess functions or a custom module of greater weight to introduce a secondary drupal_add_js that redefines/unsets the function(s) or variable(s) in the javascript environment.

For example, I needed to do something different with the excellent Ajaxblocks module, so in my own drupal_add_js() (within a custom module of greater weight), I added a js file that contained this:

Drupal.ajaxblocksSendRequest = function (request, delay, required) {
  // The added required argument kills the ready and loads registered by the original ajaxblocks.js
  // There was no good way to unbind the the function literals that were past to the .ready and .load
  if (!required) {
    return;
  }
  ...

and this:

if (Drupal.jsEnabled) $(document).ready(function () {
  if (typeof Drupal.settings.ajaxblocks !== 'undefined') {
    Drupal.ajaxblocksSendRequest(Drupal.settings.ajaxblocks, Drupal.settings.ajaxblocks_delay, true);
  }
});

A bit of javascript creativity applies, but there is always a way if the javascript waits for ready.