From 0f9489f9fed14e4bbf7c2008dda65aa6515a364c Mon Sep 17 00:00:00 2001 From: webchick <webchick@24967.no-reply.drupal.org> Date: Fri, 18 Jan 2013 10:00:29 -0800 Subject: [PATCH] Issue #1875632 follow-up by nod_, Wim Leers, effulgentsia: Added wrapper function for JS settings merging behavior, fix tabledrag. --- core/includes/ajax.inc | 6 +- core/includes/common.inc | 64 ++++++++++++++++++- core/lib/Drupal/Core/Ajax/AjaxResponse.php | 5 +- core/modules/file/file.module | 2 +- .../lib/Drupal/simpletest/WebTestBase.php | 2 +- 5 files changed, 68 insertions(+), 11 deletions(-) diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc index a7fbe7bb124f..d8eb913c7715 100644 --- a/core/includes/ajax.inc +++ b/core/includes/ajax.inc @@ -5,8 +5,6 @@ * Functions for use with Drupal's Ajax framework. */ -use Drupal\Component\Utility\NestedArray; - /** * @defgroup ajax Ajax framework * @{ @@ -291,8 +289,8 @@ function ajax_render($commands = array()) { // Now add a command to merge changes and additions to Drupal.settings. $scripts = drupal_add_js(); if (!empty($scripts['settings'])) { - $settings = $scripts['settings']; - array_unshift($commands, ajax_command_settings(NestedArray::mergeDeepArray($settings['data']), TRUE)); + $settings = drupal_merge_js_settings($scripts['settings']['data']); + array_unshift($commands, ajax_command_settings($settings, TRUE)); } // Allow modules to alter any Ajax response. diff --git a/core/includes/common.inc b/core/includes/common.inc index 2638468f44e2..fef91758fe3a 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3868,6 +3868,63 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS return drupal_render($elements); } +/** + * Merges an array of settings arrays into a single settings array. + * + * This function merges the items in the same way that + * + * @code + * jQuery.extend(true, {}, $settings_items[0], $settings_items[1], ...) + * @endcode + * + * would. This means integer indeces are preserved just like string indeces are, + * rather than re-indexed as is common in PHP array merging. + * + * Example: + * @code + * function module1_page_build(&$page) { + * $page['#attached']['js'][] = array( + * 'type' => 'setting', + * 'data' => array('foo' => array('a', 'b', 'c')), + * ); + * } + * function module2_page_build(&$page) { + * $page['#attached']['js'][] = array( + * 'type' => 'setting', + * 'data' => array('foo' => array('d')), + * ); + * } + * // When the page is rendered after the above code, and the browser runs the + * // resulting <SCRIPT> tags, the value of drupalSettings.foo is + * // ['d', 'b', 'c'], not ['a', 'b', 'c', 'd']. + * @endcode + * + * By following jQuery.extend() merge logic rather than common PHP array merge + * logic, the following are ensured: + * - drupal_add_js() is idempotent: calling it twice with the same parameters + * does not change the output sent to the browser. + * - If pieces of the page are rendered in separate PHP requests and the + * returned settings are merged by JavaScript, the resulting settings are the + * same as if rendered in one PHP request and merged by PHP. + * + * @param $settings_items + * An array of settings arrays, as returned by: + * @code + * $js = drupal_add_js(); + * $settings_items = $js['settings']['data']; + * @endcode + * + * @return + * A merged $settings array, suitable for JSON encoding and returning to the + * browser. + * + * @see drupal_add_js() + * @see drupal_pre_render_scripts() + */ +function drupal_merge_js_settings($settings_items) { + return NestedArray::mergeDeepArray($settings_items, TRUE); +} + /** * #pre_render callback to add the elements needed for JavaScript tags to be rendered. * @@ -3949,7 +4006,7 @@ function drupal_pre_render_scripts($elements) { switch ($item['type']) { case 'setting': $element['#value_prefix'] = $embed_prefix; - $element['#value'] = 'var drupalSettings = ' . drupal_json_encode(NestedArray::mergeDeepArray($item['data'], TRUE)) . ";"; + $element['#value'] = 'var drupalSettings = ' . drupal_json_encode(drupal_merge_js_settings($item['data'])) . ";"; $element['#value_suffix'] = $embed_suffix; break; @@ -4574,6 +4631,9 @@ function drupal_get_library($module, $name = NULL) { */ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgroup = NULL, $source = NULL, $hidden = TRUE, $limit = 0) { $js_added = &drupal_static(__FUNCTION__, FALSE); + $tabledrag_id = &drupal_static(__FUNCTION__ . '_setting', FALSE); + $tabledrag_id = (!isset($tabledrag_id)) ? 0 : $tabledrag_id + 1; + if (!$js_added) { // Add the table drag JavaScript to the page before the module JavaScript // to ensure that table drag behaviors are registered before any module @@ -4585,7 +4645,7 @@ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgro // If a subgroup or source isn't set, assume it is the same as the group. $target = isset($subgroup) ? $subgroup : $group; $source = isset($source) ? $source : $target; - $settings['tableDrag'][$table_id][$group][] = array( + $settings['tableDrag'][$table_id][$group][$tabledrag_id] = array( 'target' => $target, 'source' => $source, 'relationship' => $relationship, diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponse.php b/core/lib/Drupal/Core/Ajax/AjaxResponse.php index d87c4a625569..111c1ed1a26a 100644 --- a/core/lib/Drupal/Core/Ajax/AjaxResponse.php +++ b/core/lib/Drupal/Core/Ajax/AjaxResponse.php @@ -9,7 +9,6 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Drupal\Component\Utility\NestedArray; /** * JSON response object for AJAX requests. @@ -134,8 +133,8 @@ protected function ajaxRender(Request $request) { // Prepend a command to merge changes and additions to Drupal.settings. $scripts = drupal_add_js(); if (!empty($scripts['settings'])) { - $settings = $scripts['settings']; - $this->addCommand(new SettingsCommand(NestedArray::mergeDeepArray($settings['data']), TRUE), TRUE); + $settings = drupal_merge_js_settings($scripts['settings']['data']); + $this->addCommand(new SettingsCommand($settings, TRUE)); } $commands = $this->commands; diff --git a/core/modules/file/file.module b/core/modules/file/file.module index 5f56a9fc7dd3..6481d6026280 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -776,7 +776,7 @@ function file_ajax_upload() { $output = theme('status_messages') . drupal_render($form); $js = drupal_add_js(); - $settings = NestedArray::mergeDeepArray($js['settings']['data']); + $settings = drupal_merge_js_settings($js['settings']['data']); $response = new AjaxResponse(); return $response->addCommand(new ReplaceCommand(NULL, $output, $settings)); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 5f2a3eeb5840..5a1f21207786 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -1404,7 +1404,7 @@ protected function drupalPostAJAX($path, $edit, $triggering_element, $ajax_path foreach ($return as $command) { switch ($command['command']) { case 'settings': - $drupal_settings = NestedArray::mergeDeep($drupal_settings, $command['settings']); + $drupal_settings = drupal_merge_js_settings(array($drupal_settings, $command['settings'])); break; case 'insert': -- GitLab