diff --git a/core/core.libraries.yml b/core/core.libraries.yml index cfbaf473de52ee6aefb5c51ee7b8ba06f385c611..179382bf0c93ae62d578647f8ac8983a7cc84ccb 100644 --- a/core/core.libraries.yml +++ b/core/core.libraries.yml @@ -52,6 +52,10 @@ drupal: drupalSettings: version: VERSION + js: + # Need to specify a negative weight like drupal.js until + # https://www.drupal.org/node/1945262 is resolved. + misc/drupalSettingsLoader.js: { weight: -18 } drupalSettings: # These placeholder values will be set by system_js_settings_alter(). path: diff --git a/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php index 01f75ac887558e7b4d45f12ea4653e3089c97567..70832e9d9d1027b5240043666fed1bde39e58ad0 100644 --- a/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php +++ b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php @@ -51,12 +51,6 @@ public function render(array $js_assets) { // query-string instead, to enforce reload on every page request. $default_query_string = $this->state->get('system.css_js_query_string') ?: '0'; - // For inline JavaScript to validate as XHTML, all JavaScript containing - // XHTML needs to be wrapped in CDATA. To make that backwards compatible - // with HTML 4, we need to comment out the CDATA-tag. - $embed_prefix = "\n<!--//--><![CDATA[//><!--\n"; - $embed_suffix = "\n//--><!]]>\n"; - // Defaults for each SCRIPT element. $element_defaults = array( '#type' => 'html_tag', @@ -73,9 +67,13 @@ public function render(array $js_assets) { // Element properties that depend on item type. switch ($js_asset['type']) { case 'setting': - $element['#value_prefix'] = $embed_prefix; - $element['#value'] = 'var drupalSettings = ' . Json::encode($js_asset['data']) . ";"; - $element['#value_suffix'] = $embed_suffix; + $element['#attributes'] = array( + // This type attribute prevents this from being parsed as an + // inline script. + 'type' => 'application/json', + 'data-drupal-selector' => 'drupal-settings-json', + ); + $element['#value'] = Json::encode($js_asset['data']); break; case 'file': diff --git a/core/misc/drupal.js b/core/misc/drupal.js index 75f85bbacdef78ec093c713a3aa96c32c13caf30..8ef8167b73679891703f20989c55da7fca1f8266 100644 --- a/core/misc/drupal.js +++ b/core/misc/drupal.js @@ -11,14 +11,6 @@ * @prop {number} length=0 */ -/** - * Variable generated by Drupal with all the configuration created from PHP. - * - * @global - * - * @var {object} drupalSettings - */ - /** * Variable generated by Drupal that holds all translated strings from PHP. * diff --git a/core/misc/drupalSettingsLoader.js b/core/misc/drupalSettingsLoader.js new file mode 100644 index 0000000000000000000000000000000000000000..ab3911dea88f8afa10303716a2e047c7442db1a7 --- /dev/null +++ b/core/misc/drupalSettingsLoader.js @@ -0,0 +1,24 @@ +/** + * @file + * Parse inline JSON and initialize the drupalSettings global object. + */ + +(function () { + + "use strict"; + + var settingsElement = document.querySelector('script[type="application/json"][data-drupal-selector="drupal-settings-json"]'); + + /** + * Variable generated by Drupal with all the configuration created from PHP. + * + * @global + * + * @type {object} + */ + window.drupalSettings = {}; + + if (settingsElement !== null) { + window.drupalSettings = JSON.parse(settingsElement.textContent); + } +})(); diff --git a/core/modules/simpletest/src/AssertContentTrait.php b/core/modules/simpletest/src/AssertContentTrait.php index 1918d424545388464b57cb94eda9889e4abb3fb8..a425f4f954c66bcfc7b3433e68bd6401256a10c4 100644 --- a/core/modules/simpletest/src/AssertContentTrait.php +++ b/core/modules/simpletest/src/AssertContentTrait.php @@ -66,7 +66,7 @@ protected function setRawContent($content) { $this->plainTextContent = NULL; $this->elements = NULL; $this->drupalSettings = array(); - if (preg_match('/var drupalSettings = (.*?);$/m', $content, $matches)) { + if (preg_match('@<script type="application/json" data-drupal-selector="drupal-settings-json">([^<]*)</script>@', $content, $matches)) { $this->drupalSettings = Json::decode($matches[1]); } } diff --git a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php index 52e3933982d56bb6fed1bdaa25ea55a2ed738d31..43f2ef9ab9bb8e0be0baebac63fb3b6f9e8f06c3 100644 --- a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php +++ b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php @@ -185,9 +185,9 @@ function testAggregation() { $rendered_footer_js = \Drupal::service('asset.js.collection_renderer')->render($footer_js); $this->assertTrue( count($rendered_footer_js) == 2 - && substr($rendered_footer_js[0]['#value'], 0, 20) === 'var drupalSettings =' + && $rendered_footer_js[0]['#attributes']['data-drupal-selector'] === 'drupal-settings-json' && substr($rendered_footer_js[1]['#attributes']['src'], 0, 7) === 'http://', - 'There are 2 JavaScript assets in the footer: one with drupalSettings, one with the sole aggregated JavaScript asset.' + 'There are 2 JavaScript assets in the footer: one with drupal settings, one with the sole aggregated JavaScript asset.' ); } @@ -206,9 +206,9 @@ function testSettings() { $rendered_js = $this->renderer->renderPlain($js_render_array); // Parse the generated drupalSettings <script> back to a PHP representation. - $startToken = 'drupalSettings = '; + $startToken = '{'; $endToken = '}'; - $start = strpos($rendered_js, $startToken) + strlen($startToken); + $start = strpos($rendered_js, $startToken); $end = strrpos($rendered_js, $endToken); $json = Unicode::substr($rendered_js, $start, $end - $start + 1); $parsed_settings = Json::decode($json);