Status: Duplicate

Solution moved to #1670450: drupal_get_js() stable sort / drupal_add_js automatic weight

Original description

There is a weight and sorting issue with drupal_add_js, if that is called multiple times for the same js. This happens easily with the ['#attached']['js'] thing.

Understanding the problem

This is our test pseudocode.
Obviously, we want $script0 to be included before $script1.

$element['a']['#attached']['js'][$script0] = array();
$element['a']['#attached']['js'][$script1] = array();
$element['b']['#attached']['js'][$script0] = array();
$element['b']['#attached']['js'][$script1] = array();

Now in drupal_add_js():

  // 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;
  [..]
        $javascript[$options['data']] = $options;

Effect:
When the script is added for the second time, no new elements are added to the $javascript array. The original weight of the scripts is overridden. Now they both have the same weight.

Later in drupal_get_js():

  uasort($items, 'drupal_sort_css_js');

The sort is not stable, as none of php sort algorithms is.
Thus, it can happen that $script1 is included before $script0. Ouch!

Solution

Solution A (preferable):
- implement a stable sort
- make sure css and js items are always moved to the end of the array, when they are included again.
- the micro-weight will now be pointless.

Solution B:
Implement a counter for the micro-weight, instead of just count($javascript).

Related issues

The same problem has been reported in
#1388546: Adding CSS or JS files twice changes weight and
#1458436: drupal_add_js/css() weight trickery fails if called for the same files multiple times (duplicate)

I have no idea if this applies to D8, so I just report for D7.

Comments

donquixote’s picture

Status: Active » Needs review
StatusFileSize
new1.77 KB

Patch for the css/js stable sort.

Status: Needs review » Needs work

The last submitted patch, drupal-7--issue-1670450-1--css-js-stable-sort.patch, failed testing.

donquixote’s picture

Status: Needs work » Needs review
StatusFileSize
new1.58 KB

Duh. I just ran the tests on my local, and they already fail without the patch.
I am going to test that with a patch that does nothing.

nod_’s picture

Issue tags: +JavaScript

tag

donquixote’s picture

Found it:
The stable sort does not help if we do not also make sure css is added at the end of the array.

In this comment I will upload a new test that I expect to fail without my fix, that is going to follow. This is to prove that the current solution does not work.

donquixote’s picture

donquixote’s picture

Cool!

EDIT:
I'd like to have a review from a real person.
After that, we can do some work on cleanup and comments.

donquixote’s picture

Version: 7.x-dev » 8.x-dev
StatusFileSize
new1.21 KB

And now for 8.x.
New test expected to fail, as in #5.

donquixote’s picture

And now the fix.

robloach’s picture

Do we want to remove the drupal_sort_css_js() function? Adopt this to CSS as well?

donquixote’s picture

For D8, sure, let's remove :)
For D7 backport, we better keep the drupal_sort_css_js() for compatibility.

"Adopt this to CSS" -> the patch applies to js and css equally.

donquixote’s picture

Removing the old code, and adding some commentary.
I am not sure how much of the old commentary we need to keep. We should focus on those questions that people reading this code actually have.

Maybe we need more information on the sort criteria, especially the first one with $item['group'].

tim.plunkett’s picture

Status: Needs review » Closed (duplicate)
tim.plunkett’s picture

Issue summary: View changes

Add related issues, mention the "move to end of array".

donquixote’s picture

Issue summary: View changes

Mention duplicate in issue description