diff --git a/core/includes/common.inc b/core/includes/common.inc index 4c8695324e2f969223d71add68b5fc8389beb0f4..383dd29a37ccfb2f2030214371e92395fc9b9271 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3759,15 +3759,15 @@ function drupal_region_class($region) { * else being the same, JavaScript added by a call to drupal_add_js() that * happened later in the page request gets added to the page after one for * which drupal_add_js() happened earlier in the page request. - * - defer: If set to TRUE, the defer attribute is set on the <script> - * tag. Defaults to FALSE. - * - async: If set to TRUE, the async attribute is set on the <script> - * tag. Defaults to FALSE. * - cache: If set to FALSE, the JavaScript file is loaded anew on every page * call; in other words, it is not cached. Used only when 'type' references * a JavaScript file. Defaults to TRUE. * - preprocess: If TRUE and JavaScript aggregation is enabled, the script * file will be aggregated. Defaults to TRUE. + * - attributes: An associative array of attributes for the <script> tag. This + * may be used to add 'defer', 'async', or custom attributes. Note that + * setting any attributes will disable preprocessing as though the + * 'preprocess' option was set to FALSE. * - browsers: An array containing information specifying which browsers * should load the JavaScript item. See * drupal_pre_render_conditional_comments() for details. @@ -3793,8 +3793,8 @@ function drupal_add_js($data = NULL, $options = NULL) { } $options += drupal_js_defaults($data); - // Preprocess can only be set if caching is enabled. - $options['preprocess'] = $options['cache'] ? $options['preprocess'] : FALSE; + // Preprocess can only be set if caching is enabled and no attributes are set. + $options['preprocess'] = $options['cache'] && empty($options['attributes']) ? $options['preprocess'] : FALSE; // Tweak the weight so that files of the same weight are included in the // order of the calls to drupal_add_js(). @@ -3861,9 +3861,8 @@ function drupal_js_defaults($data = NULL) { 'weight' => 0, 'scope' => 'header', 'cache' => TRUE, - 'defer' => FALSE, - 'async' => FALSE, 'preprocess' => TRUE, + 'attributes' => array(), 'version' => NULL, 'data' => $data, 'browsers' => array(), @@ -4090,16 +4089,9 @@ function drupal_pre_render_scripts($elements) { break; } - // The defer and async attributes must not be specified if the src - // attribute is not present. - if (!empty($element['#attributes']['src'])) { - // Both may be specified for legacy browser fallback purposes. - if (!empty($item['async'])) { - $element['#attributes']['async'] = 'async'; - } - if (!empty($item['defer'])) { - $element['#attributes']['defer'] = 'defer'; - } + // Attributes may only be set if this script is output independently. + if (!empty($element['#attributes']['src']) && !empty($item['attributes'])) { + $element['#attributes'] += $item['attributes']; } $elements[] = $element; diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php index 4c4198cd98831b37bd09683ad28b41bc6b745d19..f52907f7ab939c6f5de6d6c58c69015ebde84930 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php @@ -97,39 +97,42 @@ function testAddExternal() { } /** - * Tests adding external JavaScript Files with the async attribute. + * Tests adding JavaScript files with additional attributes. */ - function testAsyncAttribute() { + function testAttributes() { $default_query_string = variable_get('css_js_query_string', '0'); drupal_add_library('system', 'drupal'); - drupal_add_js('http://example.com/script.js', array('async' => TRUE)); - drupal_add_js('core/misc/collapse.js', array('async' => TRUE)); + drupal_add_js('http://example.com/script.js', array('attributes' => array('defer' => 'defer'))); + drupal_add_js('core/misc/collapse.js', array('attributes' => array('defer' => 'defer'))); $javascript = drupal_get_js(); - $expected_1 = '<script src="http://example.com/script.js?' . $default_query_string . '" async="async"></script>'; - $expected_2 = '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" async="async"></script>'; + $expected_1 = '<script src="http://example.com/script.js?' . $default_query_string . '" defer="defer"></script>'; + $expected_2 = '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" defer="defer"></script>'; - $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct async attribute.'); - $this->assertTrue(strpos($javascript, $expected_2) > 0, 'Rendered internal JavaScript with correct async attribute.'); + $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct defer attribute.'); + $this->assertTrue(strpos($javascript, $expected_2) > 0, 'Rendered internal JavaScript with correct defer attribute.'); } /** - * Tests adding external JavaScript Files with the defer attribute. + * Tests that attributes are maintained when JS aggregation is enabled. */ - function testDeferAttribute() { + function testAggregatedAttributes() { + // Enable aggregation. + config('system.performance')->set('preprocess.js', 1)->save(); + $default_query_string = variable_get('css_js_query_string', '0'); drupal_add_library('system', 'drupal'); - drupal_add_js('http://example.com/script.js', array('defer' => TRUE)); - drupal_add_js('core/misc/collapse.js', array('defer' => TRUE)); + drupal_add_js('http://example.com/script.js', array('attributes' => array('defer' => 'defer'))); + drupal_add_js('core/misc/collapse.js', array('attributes' => array('defer' => 'defer'))); $javascript = drupal_get_js(); $expected_1 = '<script src="http://example.com/script.js?' . $default_query_string . '" defer="defer"></script>'; $expected_2 = '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" defer="defer"></script>'; - $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct defer attribute.'); - $this->assertTrue(strpos($javascript, $expected_2) > 0, 'Rendered internal JavaScript with correct defer attribute.'); + $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct defer attribute with aggregation enabled.'); + $this->assertTrue(strpos($javascript, $expected_2) > 0, 'Rendered internal JavaScript with correct defer attribute with aggregation enabled.'); } /**