diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc index 8817356..ac8ae1a 100644 --- a/core/includes/ajax.inc +++ b/core/includes/ajax.inc @@ -289,9 +289,9 @@ 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']; + $javascript_settings = drupal_add_js_settings(); + if (!empty($javascript_settings['settings'])) { + $settings = $javascript_settings['settings']; array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE)); } diff --git a/core/includes/common.inc b/core/includes/common.inc index 17c626b..273daa1 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4072,69 +4072,115 @@ function drupal_add_js($data = NULL, $options = NULL) { $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 script and prefix using hook_url_outbound_alter(). - // Instead of running the hook_url_outbound_alter() again here, extract - // them from url(). - // @todo Make this less hacky: http://drupal.org/node/1547376. - $scriptPath = $GLOBALS['script_path']; - $pathPrefix = ''; - url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix)); - $javascript = array( - 'settings' => array( - 'data' => array( - array('basePath' => base_path()), - array('scriptPath' => $scriptPath), - array('pathPrefix' => $pathPrefix), + if ($options['type'] == 'setting') { + drupal_add_js_settings($data); + } + else { + // Add jquery.js and drupal.js the first time a JavaScript file is added. + if (empty($javascript)) { + $javascript = array( + 'core/misc/drupal.js' => array( + 'data' => 'core/misc/drupal.js', + 'type' => 'file', + 'scope' => 'header', + 'group' => JS_LIBRARY, + 'every_page' => TRUE, + 'weight' => -1, + 'preprocess' => TRUE, + 'cache' => TRUE, + 'defer' => FALSE, + 'browsers' => array(), ), - 'type' => 'setting', - 'scope' => 'header', - 'group' => JS_SETTING, - 'every_page' => TRUE, - 'weight' => 0, - 'browsers' => array(), - ), - 'core/misc/drupal.js' => array( - 'data' => 'core/misc/drupal.js', - 'type' => 'file', - 'scope' => 'header', - 'group' => JS_LIBRARY, - 'every_page' => TRUE, - 'weight' => -1, - 'preprocess' => TRUE, - 'cache' => TRUE, - 'defer' => FALSE, - 'browsers' => array(), - ), - ); - // Register all required libraries. - drupal_add_library('system', 'jquery', TRUE); - drupal_add_library('system', 'jquery.once', TRUE); - drupal_add_library('system', 'html5shiv', TRUE); + ); + // Register all required libraries. + drupal_add_library('system', 'jquery', TRUE); + drupal_add_library('system', 'jquery.once', TRUE); + drupal_add_library('system', 'html5shiv', TRUE); + } + switch ($options['type']) { + 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; + } } + } - 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; + // If any JavaScript file has been added to the page, then lets + // add our JavaScript settings. + if (!empty($javascript)) { + $js_settings = drupal_add_js_settings(); + $javascript['settings'] = $js_settings['settings']; + } - case 'inline': - $javascript[] = $options; - break; + return $javascript; +} - 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; - } +/** + * Adds a JavaScript setting to the page. + * + * This function is the global storage of JavaScript settings. It is called + * from drupal_add_js when settings are added to the page. All settings will + * be accessible at Drupal.settings. + * + * Calling drupal_static_reset('drupal_add_js_settings') will clear all JavaScript + * settings added so far. + * + * @param $data + * (optional) If given, 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. + * + * @return + * The current array of JavaScript settings including Drupal defaults and + * anything previously added with calls to drupal_add_js(). + * + * @see drupal_add_js() + */ + +function drupal_add_js_settings($data = NULL) { + $js_settings = &drupal_static(__FUNCTION__, array()); + + // All JavaScript settings are placed in the header of the page with + // the library weight so that inline scripts appear afterwards. + if (empty($js_settings)) { + // url() generates the script and prefix using hook_url_outbound_alter(). + // Instead of running the hook_url_outbound_alter() again here, extract + // them from url(). + // @todo Make this less hacky: http://drupal.org/node/1547376. + $scriptPath = $GLOBALS['script_path']; + $pathPrefix = ''; + url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix)); + $js_settings['settings'] = array( + 'data' => array( + array('basePath' => base_path()), + array('scriptPath' => $scriptPath), + array('pathPrefix' => empty($prefix) ? '' : $prefix), + ), + 'type' => 'setting', + 'scope' => 'header', + 'group' => JS_SETTING, + 'every_page' => TRUE, + 'weight' => 0, + 'browsers' => array(), + ); } - return $javascript; + + if (isset($data)) { + $js_settings['settings']['data'][] = $data; + } + + return $js_settings; } + + /** * Constructs an array of the defaults that are used for JavaScript items. * diff --git a/core/modules/system/tests/common.test b/core/modules/system/tests/common.test index 46b379e..4b64918 100644 --- a/core/modules/system/tests/common.test +++ b/core/modules/system/tests/common.test @@ -1163,7 +1163,8 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase { * Test adding settings. */ function testAddSetting() { - $javascript = drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting'); + drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting'); + $javascript = drupal_add_js_settings(); $this->assertEqual(280342800, $javascript['settings']['data'][3]['dries'], t('JavaScript setting is set correctly.')); $this->assertEqual('rocks', $javascript['settings']['data'][3]['drupal'], t('The other JavaScript setting is set correctly.')); } @@ -1191,6 +1192,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase { // Only the second of these two entries should appear in Drupal.settings. drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting'); drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting'); + drupal_add_js('core/misc/jquery.js'); $javascript = drupal_get_js('header'); $this->assertTrue(strpos($javascript, 'basePath') > 0, t('Rendered JavaScript header returns basePath setting.')); @@ -1553,6 +1555,16 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase { $query_string = variable_get('css_js_query_string', '0'); $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, t('Query string was appended correctly to js.')); } + + /** + * Tests that Drupal.settings aren't added when not needed. + */ + function testPageWithoutJavascript() { + $this->drupalGet(''); + $content = $this->drupalGetContent(); + $this->assertTrue(strpos($content, 'Drupal.settings') === FALSE, t('Drupal.settings is not added to the page.')); + $this->assertTrue(strpos($content, '.js') === FALSE, t('No javascript is added to the page.')); + } } /**