Updated: Comment #0

Problem/Motivation

It is possible to change javascript settings via hook_js_alter(), but the settings are returned unaltered from ajax request.

For example:

function mymodule_js_alter(&$javascript) {
    $javascript['settings']['data'][1]['pathPrefix'] = 'whatever/';
}

Proposed resolution

Use the altered JS settings - if they are available.

Remaining tasks

* Create proper patch.

Patch:

diff --git a/docroot/includes/ajax.inc b/docroot/includes/ajax.inc
index ab0111c..dc0491e 100644
--- a/docroot/includes/ajax.inc
+++ b/docroot/includes/ajax.inc
@@ -267,7 +267,10 @@ function ajax_render($commands = array()) {
   // HTML in the page. We pass TRUE as the $skip_alter argument to prevent the
   // data from being altered again, as we already altered it above. Settings are
   // handled separately, afterwards.
+
+  $scripts = array();
   if (isset($items['js']['settings'])) {
+    $scripts['settings'] = $items['js']['settings'];
     unset($items['js']['settings']);
   }
   $styles = drupal_get_css($items['css'], TRUE);
@@ -289,7 +292,10 @@ function ajax_render($commands = array()) {
   }
 
   // Now add a command to merge changes and additions to Drupal.settings.
-  $scripts = drupal_add_js();
+  // Only reload the settings when its not yet set.
+  if (!isset($scripts['settings'])) {
+    $scripts = drupal_add_js();
+  }
   if (!empty($scripts['settings'])) {
     $settings = $scripts['settings'];
     array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));

Comments

fabianx’s picture

Issue summary: View changes
wiifm’s picture

Status: Active » Needs review
StatusFileSize
new1.22 KB

Here is a patch, slightly updated to match current HEAD.

Status: Needs review » Needs work

The last submitted patch, 2: 2171113-alter-js-settings.patch, failed testing.

wiifm’s picture

Status: Needs work » Needs review

2: 2171113-alter-js-settings.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 2: 2171113-alter-js-settings.patch, failed testing.

wiifm’s picture

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

Was wondering why the patch was not applying. Cue penny drop.

wiifm’s picture

Status: Needs work » Needs review

2: 2171113-alter-js-settings.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 2: 2171113-alter-js-settings.patch, failed testing.

fabianx’s picture

Status: Needs work » Needs review

2: 2171113-alter-js-settings.patch queued for re-testing.

fabianx’s picture

Status: Needs review » Needs work
Issue tags: +Needs backport to 7.x, +Needs tests

Adding Needs Backport tag and being a bug this unfortunately needs a test.

dawehner’s picture

Note, this will certainly somehow conflict with #1959574: Remove the deprecated Drupal 7 Ajax API ... given that we have a nice new ajax API already.

zazaidi’s picture

Issue tags: -

I concur that this issue is obsolete due to the changes made to the ajax api in #1959574 mentioned above. I tested altering JS settings by setting them via _js_alter() and then calling them back via ajax and the settings are returning altered as expected so I believe this issue can be closed.

zazaidi’s picture

Status: Needs work » Needs review
zazaidi’s picture

Status: Needs review » Closed (cannot reproduce)

Was not able to reproduce the issue in the latest Drupal. Please reopen if necessary.

fabianx’s picture

Version: 8.x-dev » 7.x-dev
Status: Closed (cannot reproduce) » Needs review

Then back to 7.x with this bug.

fabianx’s picture

Priority: Normal » Major
Status: Needs review » Reviewed & tested by the community

Lets see if this still applies, this works fine in production since 10 months, also bumping to major.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 2: 2171113-alter-js-settings.patch, failed testing.

fabianx’s picture

@@ -295,6 +298,7 @@ function ajax_render($commands = array()) {
   // Only reload the settings when its not yet set.
   if (!isset($scripts['settings'])) {
     $scripts = drupal_add_js();
+    drupal_alter('js', $scripts);
   }
   if (!empty($scripts['settings'])) {
     $settings = $scripts['settings'];
@@ -468,6 +472,7 @@ function ajax_base_page_theme() {
  * @see drupal_deliver_html_page()
  */
 function ajax_deliver($page_callback_result) {

Need to add the following, too to ensure it works in all cases.

mw4ll4c3’s picture

Assigned: Unassigned » mw4ll4c3

Tackling this quickly for #devdays

mw4ll4c3’s picture

Re-rolled the patch, and included the addition suggested in #18.

mw4ll4c3’s picture

Assigned: mw4ll4c3 » Unassigned
Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 20: d7_alter_js_settings_ajax-n2171113-20.patch, failed testing.

mw4ll4c3’s picture

Not so tackled, not so quickly... investigation into test failures (and the ramifications of this change) are necessary.

douggreen’s picture

rerolled patch for D7

sdstyles’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 24: d7_alter_js_settings_ajax-n2171113-24.patch, failed testing.

David_Rothstein’s picture

Status: Needs work » Needs review
StatusFileSize
new522 bytes

The test failures on the patch in #24 are real and are in fact causing a problem on a site where I'm using it.

The problem is that the patch collects the JavaScript settings too early (before calling drupal_get_css() and drupal_get_js(), both of which add new information to the 'ajaxPageState' setting when they are called). So those changes to ajaxPageState never make it into the final page output.

The practical problem this leads to is that Drupal can no longer track which CSS and JavaScript files were dynamically added to the page. So on an Ajax request that lazy-loads CSS or JavaScript files (e.g. an Ajax-enabled "upload" button where the code that renders already-uploaded files has some associated CSS or JavaScript), with the patch from #24 applied Drupal will keep re-adding new copies of the lazy-loaded CSS and JavaScript files to the page again and again, once for each time the "upload" button is clicked.

The duplicate files can be a particular problem with JavaScript, since depending on how the JavaScript is written multiple copies of it can interfere with each other (e.g. if the code defines a JavaScript object which is trying to maintain some kind of internal state between Ajax requests, the duplicate file will overwrite the object with a fresh copy and thereby throw out the internal state).

For a different fix that doesn't have this problem, is there any reason the attached one-line patch wouldn't work? As far as I can see it meets the goal of this issue.

fabianx’s picture

#27: That should probably work fine.

I am unsure if calling drupal_alter() more times than normal could lead to any issues, but the patch is clearly simpler.

However I would suggest to move the alter() inside of the !empty() clause.

David_Rothstein’s picture

Isn't it possible (although unlikely) that a hook_js_alter() implementation adds something to $scripts['settings'] even when it was previously empty? That's why I had it outside the !empty() clause.

valthebald’s picture

Status: Needs review » Reviewed & tested by the community

I second @David_Rothstein that it could happen that we'd want to add something to previously empty settings in alter hook

stefan.r’s picture

Issue tags: +Drupal 7.60 target

Guessing we might not need tests for this?

David_Rothstein’s picture

I think tests would be great in theory, but in this case they might be more annoying than they are worth. Especially if Drupal 8 has no equivalent tests to backport (which I don't think it does) I would vote for skipping them.

pol’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new764 bytes

Patch updated.

The drupal_alter() is inside of the !empty() clause.
Updated the code style of the block.

pol’s picture

Issue tags: +Needs framework manager review
mustanggb’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Novice, -Needs tests, -Needs framework manager review

Updated tags:
- No tests needed
- No D8 patch needed
- Has been rerolled

Looks good to go:
- RTBC

pol’s picture

Issue tags: +Pending Drupal 7 commit
joseph.olstad’s picture

Issue tags: -Drupal 7.60 target +Drupal 7.61 target

Bumping to 7.61, this didn't make it into 7.60

joseph.olstad’s picture

joseph.olstad’s picture

pol’s picture

Updating credits.

pol’s picture

@MustangGB Why no D8 patch is needed ? Could you develop ?

pol’s picture

Issue tags: -Drupal 7.64 target +Drupal 7.65 target, +Already In D8

Deleting the wrong comment.

joseph.olstad’s picture

Issue tags: -Drupal 7.65 target +Drupal 7.66 target
mcdruid’s picture

Issue tags: -Drupal 7.66 target +Drupal 7.68 target
joseph.olstad’s picture

mcdruid’s picture

#29 and #30 argued that it's...

... possible (although unlikely) that a hook_js_alter() implementation adds something to $scripts['settings'] even when it was previously empty? That's why I had it outside the !empty() clause.

Then #33 moved the drupal_alter() inside the !empty() clause (based on #28 probably).

#33 also re-formats a long line of code which is not part of the change being made.

So I'd be inclined to go back to the patch in #27.

I'll leave it to @Fabianx to make the final call on that though.

joseph.olstad’s picture

I agree with mcdruid on this for the same reasons. Patch 27 yes

mcdruid’s picture

Issue tags: +Drupal 7 bugfix target
fabianx’s picture

Assigned: Unassigned » mcdruid

RTBM for #27 - let’s get that in.

I agree with David Rothstein and my suggestion to move it into the if does not make sense.

  • mcdruid committed 4d080b6 on 7.x
    Issue #2171113 by Pol, wiifm, mw4ll4c3, David_Rothstein, douggreen,...
mcdruid’s picture

Assigned: mcdruid » Unassigned
Status: Reviewed & tested by the community » Fixed
Issue tags: -Pending Drupal 7 commit, -Drupal 7 bugfix target

Thank you contributors!

mustanggb’s picture

Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.