core/includes/common.inc | 297 +-------------------
.../Core/Asset/{CssDumper.php => AssetDumper.php} | 28 +-
.../lib/Drupal/Core/Asset/AssetDumperInterface.php | 4 +-
.../lib/Drupal/Core/Asset/CssCollectionGrouper.php | 9 +
.../Drupal/Core/Asset/CssCollectionOptimizer.php | 12 +-
core/lib/Drupal/Core/Asset/JsCollectionGrouper.php | 80 ++++++
.../Drupal/Core/Asset/JsCollectionOptimizer.php | 139 +++++++++
.../lib/Drupal/Core/Asset/JsCollectionRenderer.php | 97 +++++++
.../Drupal/system/Tests/Common/JavaScriptTest.php | 44 ++-
core/modules/system/system.module | 4 -
.../Core/Asset/CssCollectionRendererUnitTest.php | 2 +-
11 files changed, 397 insertions(+), 319 deletions(-)
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 0ab390a..eff6d1d 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -29,7 +29,10 @@
use Drupal\Core\Asset\CssCollectionOptimizer;
use Drupal\Core\Asset\CssCollectionGrouper;
use Drupal\Core\Asset\CssOptimizer;
-use Drupal\Core\Asset\CssDumper;
+use Drupal\Core\Asset\JsCollectionRenderer;
+use Drupal\Core\Asset\JsCollectionOptimizer;
+use Drupal\Core\Asset\JsCollectionGrouper;
+use Drupal\Core\Asset\AssetDumper;
/**
* @file
@@ -1952,7 +1955,7 @@ function drupal_pre_render_styles($elements) {
// Aggregate the CSS if necessary, but only during normal site operation.
if (!defined('MAINTENANCE_MODE') && config('system.performance')->get('css.preprocess')) {
- $optimizer = new CssCollectionOptimizer(new CssCollectionGrouper(), new CssOptimizer(), new CssDumper());
+ $optimizer = new CssCollectionOptimizer(new CssCollectionGrouper(), new CssOptimizer(), new AssetDumper());
$css_assets = $optimizer->optimize($css_assets);
}
@@ -2576,214 +2579,17 @@ function drupal_merge_js_settings($settings_items) {
* @see drupal_get_js()
*/
function drupal_pre_render_scripts($elements) {
- // Group and aggregate the items.
- if (isset($elements['#group_callback'])) {
- $elements['#groups'] = $elements['#group_callback']($elements['#items']);
- }
- if (isset($elements['#aggregate_callback'])) {
- $elements['#aggregate_callback']($elements['#groups']);
- }
-
- // A dummy query-string is added to filenames, to gain control over
- // browser-caching. The string changes on every update or full cache
- // flush, forcing browsers to load a new copy of the files, as the
- // URL changed. Files that should not be cached (see drupal_add_js())
- // get REQUEST_TIME as query-string instead, to enforce reload on every
- // page request.
- $default_query_string = variable_get('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\n";
-
- // Since JavaScript may look for arguments in the URL and act on them, some
- // third-party code might require the use of a different query string.
- $js_version_string = variable_get('drupal_js_version_query_string', 'v=');
-
- // Defaults for each SCRIPT element.
- $element_defaults = array(
- '#type' => 'html_tag',
- '#tag' => 'script',
- '#value' => '',
- );
+ $renderer = new JsCollectionRenderer();
+ $js_assets = $elements['#items'];
- // Loop through each group.
- foreach ($elements['#groups'] as $group) {
- // If a group of files has been aggregated into a single file,
- // $group['data'] contains the URI of the aggregate file. Add a single
- // script element for this file.
- if ($group['type'] == 'file' && isset($group['data'])) {
- $element = $element_defaults;
- $element['#attributes']['src'] = file_create_url($group['data']);
- $element['#browsers'] = $group['browsers'];
- $elements[] = $element;
- }
- // For non-file types, and non-aggregated files, add a script element per
- // item.
- else {
- foreach ($group['items'] as $item) {
- // Element properties that do not depend on item type.
- $element = $element_defaults;
- $element['#browsers'] = $item['browsers'];
-
- // Element properties that depend on item type.
- switch ($item['type']) {
- case 'setting':
- $element['#value_prefix'] = $embed_prefix;
- $element['#value'] = 'var drupalSettings = ' . drupal_json_encode(drupal_merge_js_settings($item['data'])) . ";";
- $element['#value_suffix'] = $embed_suffix;
- break;
-
- case 'inline':
- $element['#value_prefix'] = $embed_prefix;
- $element['#value'] = $item['data'];
- $element['#value_suffix'] = $embed_suffix;
- break;
-
- case 'file':
- $query_string = empty($item['version']) ? $default_query_string : $js_version_string . $item['version'];
- $query_string_separator = (strpos($item['data'], '?') !== FALSE) ? '&' : '?';
- $element['#attributes']['src'] = file_create_url($item['data']) . $query_string_separator . ($item['cache'] ? $query_string : REQUEST_TIME);
- break;
-
- case 'external':
- $element['#attributes']['src'] = $item['data'];
- break;
- }
-
- // 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;
- }
- }
+ // Aggregate the JavaScript if necessary, but only during normal site
+ // operation.
+ if (!defined('MAINTENANCE_MODE') && config('system.performance')->get('js.preprocess')) {
+ $optimizer = new JsCollectionOptimizer(new JsCollectionGrouper(), new AssetDumper());
+ $js_assets = $optimizer->optimize($js_assets);
}
- return $elements;
-}
-
-/**
- * Default callback to group JavaScript items.
- *
- * This function arranges the JavaScript items that are in the #items property
- * of the scripts element into groups. When aggregation is enabled, files within
- * a group are aggregated into a single file, significantly improving page
- * loading performance by minimizing network traffic overhead.
- *
- * This function puts multiple items into the same group if they are groupable
- * and if they are for the same browsers. Items of the 'file' type are groupable
- * if their 'preprocess' flag is TRUE. Items of the 'inline', 'settings', or
- * 'external' type are not groupable.
- *
- * This function also ensures that the process of grouping items does not change
- * their relative order. This requirement may result in multiple groups for the
- * same type and browsers, if needed to accommodate other items in
- * between.
- *
- * @param $javascript
- * An array of JavaScript items, as returned by drupal_add_js(), but after
- * alteration performed by drupal_get_js().
- *
- * @return
- * An array of JavaScript groups. Each group contains the same keys (e.g.,
- * 'data', etc.) as a JavaScript item from the $javascript parameter, with the
- * value of each key applying to the group as a whole. Each group also
- * contains an 'items' key, which is the subset of items from $javascript that
- * are in the group.
- *
- * @see drupal_pre_render_scripts()
- */
-function drupal_group_js($javascript) {
- $groups = array();
- // If a group can contain multiple items, we track the information that must
- // be the same for each item in the group, so that when we iterate the next
- // item, we can determine if it can be put into the current group, or if a
- // new group needs to be made for it.
- $current_group_keys = NULL;
- $index = -1;
- foreach ($javascript as $item) {
- // The browsers for which the JavaScript item needs to be loaded is part of
- // the information that determines when a new group is needed, but the order
- // of keys in the array doesn't matter, and we don't want a new group if all
- // that's different is that order.
- ksort($item['browsers']);
-
- switch ($item['type']) {
- case 'file':
- // Group file items if their 'preprocess' flag is TRUE.
- // Help ensure maximum reuse of aggregate files by only grouping
- // together items that share the same 'group' value and 'every_page'
- // flag. See drupal_add_js() for details about that.
- $group_keys = $item['preprocess'] ? array($item['type'], $item['group'], $item['every_page'], $item['browsers']) : FALSE;
- break;
-
- case 'external':
- case 'setting':
- case 'inline':
- // Do not group external, settings, and inline items.
- $group_keys = FALSE;
- break;
- }
-
- // If the group keys don't match the most recent group we're working with,
- // then a new group must be made.
- if ($group_keys !== $current_group_keys) {
- $index++;
- // Initialize the new group with the same properties as the first item
- // being placed into it. The item's 'data' and 'weight' properties are
- // unique to the item and should not be carried over to the group.
- $groups[$index] = $item;
- unset($groups[$index]['data'], $groups[$index]['weight']);
- $groups[$index]['items'] = array();
- $current_group_keys = $group_keys ? $group_keys : NULL;
- }
-
- // Add the item to the current group.
- $groups[$index]['items'][] = $item;
- }
-
- return $groups;
-}
-
-/**
- * Default callback to aggregate JavaScript files.
- *
- * Having the browser load fewer JavaScript files results in much faster page
- * loads than when it loads many small files. This function aggregates files
- * within the same group into a single file unless the site-wide setting to do
- * so is disabled (commonly the case during site development). To optimize
- * download, it also compresses the aggregate files by removing comments,
- * whitespace, and other unnecessary content.
- *
- * @param $js_groups
- * An array of JavaScript groups as returned by drupal_group_js(). For each
- * group that is aggregated, this function sets the value of the group's
- * 'data' key to the URI of the aggregate file.
- *
- * @see drupal_group_js()
- * @see drupal_pre_render_scripts()
- */
-function drupal_aggregate_js(&$js_groups) {
- // Only aggregate during normal site operation.
- if (defined('MAINTENANCE_MODE')) {
- $preprocess_js = FALSE;
- }
- else {
- $config = config('system.performance');
- $preprocess_js = $config->get('js.preprocess');
- }
-
- if ($preprocess_js) {
- foreach ($js_groups as $key => $group) {
- if ($group['type'] == 'file' && $group['preprocess']) {
- $js_groups[$key]['data'] = drupal_build_js_cache($group['items']);
- }
- }
- }
+ return $renderer->render($js_assets);
}
/**
@@ -3286,83 +3092,6 @@ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgro
}
/**
- * Aggregates JavaScript files into a cache file in the files directory.
- *
- * The file name for the JavaScript cache file is generated from the hash of
- * the aggregated contents of the files in $files. This forces proxies and
- * browsers to download new JavaScript when the JavaScript changes.
- *
- * The cache file name is retrieved on a page load via a lookup variable that
- * contains an associative array. The array key is the hash of the names in
- * $files while the value is the cache file name. The cache file is generated
- * in two cases. First, if there is no file name value for the key, which will
- * happen if a new file name has been added to $files or after the lookup
- * variable is emptied to force a rebuild of the cache. Second, the cache file
- * is generated if it is missing on disk. Old cache files are not deleted
- * immediately when the lookup variable is emptied, but are deleted after a set
- * period by drupal_delete_file_if_stale(). This ensures that files referenced
- * by a cached page will still be available.
- *
- * @param $files
- * An array of JavaScript files to aggregate and compress into one file.
- *
- * @return
- * The URI of the cache file, or FALSE if the file could not be saved.
- */
-function drupal_build_js_cache($files) {
- $contents = '';
- $uri = '';
- $map = Drupal::state()->get('system.js_cache_files') ?: array();
- // Create a new array so that only the file names are used to create the hash.
- // This prevents new aggregates from being created unnecessarily.
- $js_data = array();
- foreach ($files as $file) {
- $js_data[] = $file['data'];
- }
- $key = hash('sha256', serialize($js_data));
- if (isset($map[$key])) {
- $uri = $map[$key];
- }
-
- if (empty($uri) || !file_exists($uri)) {
- // Build aggregate JS file.
- foreach ($files as $info) {
- if ($info['preprocess']) {
- // Append a ';' and a newline after each JS file to prevent them from running together.
- $contents .= file_get_contents($info['data']) . ";\n";
- }
- }
- // Prefix filename to prevent blocking by firewalls which reject files
- // starting with "ad*".
- $filename = 'js_' . Crypt::hashBase64($contents) . '.js';
- // Create the js/ within the files folder.
- $jspath = 'public://js';
- $uri = $jspath . '/' . $filename;
- // Create the JS file.
- file_prepare_directory($jspath, FILE_CREATE_DIRECTORY);
- if (!file_exists($uri) && !file_unmanaged_save_data($contents, $uri, FILE_EXISTS_REPLACE)) {
- return FALSE;
- }
- // If JS gzip compression is enabled and the zlib extension is available
- // then create a gzipped version of this file. This file is served
- // conditionally to browsers that accept gzip using .htaccess rules.
- // It's possible that the rewrite rules in .htaccess aren't working on this
- // server, but there's no harm (other than the time spent generating the
- // file) in generating the file anyway. Sites on servers where rewrite rules
- // aren't working can set js.gzip to FALSE in order to skip
- // generating a file that won't be used.
- if (config('system.performance')->get('js.gzip') && extension_loaded('zlib')) {
- if (!file_exists($uri . '.gz') && !file_unmanaged_save_data(gzencode($contents, 9, FORCE_GZIP), $uri . '.gz', FILE_EXISTS_REPLACE)) {
- return FALSE;
- }
- }
- $map[$key] = $uri;
- Drupal::state()->set('system.js_cache_files', $map);
- }
- return $uri;
-}
-
-/**
* Deletes old cached JavaScript files and variables.
*/
function drupal_clear_js_cache() {
diff --git a/core/lib/Drupal/Core/Asset/CssDumper.php b/core/lib/Drupal/Core/Asset/AssetDumper.php
similarity index 55%
rename from core/lib/Drupal/Core/Asset/CssDumper.php
rename to core/lib/Drupal/Core/Asset/AssetDumper.php
index 06fe54c..6e8c0e5 100644
--- a/core/lib/Drupal/Core/Asset/CssDumper.php
+++ b/core/lib/Drupal/Core/Asset/AssetDumper.php
@@ -1,7 +1,7 @@
get('css.gzip') && extension_loaded('zlib')) {
+ if (config('system.performance')->get($file_extension . '.gzip') && extension_loaded('zlib')) {
if (!file_exists($uri . '.gz') && !file_unmanaged_save_data(gzencode($data, 9, FORCE_GZIP), $uri . '.gz', FILE_EXISTS_REPLACE)) {
return FALSE;
}
diff --git a/core/lib/Drupal/Core/Asset/AssetDumperInterface.php b/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
index f0d8ffe..6ee2ef2 100644
--- a/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
+++ b/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
@@ -16,9 +16,11 @@
*
* @param string $data
* An (optimized) asset's contents.
+ * @param string $file_extension
+ * The file extension of this asset.
* @return string
* An URI to access the dumped asset.
*/
- public function dump($data);
+ public function dump($data, $file_extension);
}
diff --git a/core/lib/Drupal/Core/Asset/CssCollectionGrouper.php b/core/lib/Drupal/Core/Asset/CssCollectionGrouper.php
index 2e59d18..93ce0b0 100644
--- a/core/lib/Drupal/Core/Asset/CssCollectionGrouper.php
+++ b/core/lib/Drupal/Core/Asset/CssCollectionGrouper.php
@@ -15,6 +15,15 @@ class CssCollectionGrouper implements AssetCollectionGrouperInterface {
/**
* {@inheritdoc}
+ *
+ * Puts multiple items into the same group if they are groupable and if they
+ * are for the same 'media' and 'browsers'. Items of the 'file' type are
+ * groupable if their 'preprocess' flag is TRUE, items of the 'inline' type
+ * are always groupable, and items of the 'external' type are never groupable.
+ *
+ * Also ensures that the process of grouping items does not change their
+ * relative order. This requirement may result in multiple groups for the same
+ * type, media, and browsers, if needed to accommodate other items in between.
*/
public function group(array $css_assets) {
$groups = array();
diff --git a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
index 1ea1495..3a2abc7 100644
--- a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
+++ b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
@@ -29,9 +29,9 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
protected $optimizer;
/**
- * A CSS asset dumper.
+ * An asset dumper.
*
- * @var \Drupal\Core\Asset\CssDumper object.
+ * @var \Drupal\Core\Asset\AssetDumper object.
*/
protected $dumper;
@@ -111,7 +111,7 @@ public function optimize(array $css_assets) {
$data = preg_replace($regexp, '', $data);
$data = implode('', $matches[0]) . $data;
// Dump the optimized CSS for this group into an aggregate file.
- $uri = $this->dumper->dump($data);
+ $uri = $this->dumper->dump($data, 'css');
// Set the URI for this group's aggregate file.
$css_assets[$order]['data'] = $uri;
// Persist the URI for this aggregate file.
@@ -122,6 +122,7 @@ public function optimize(array $css_assets) {
// Use the persisted URI for the optimized CSS file.
$css_assets[$order]['data'] = $uri;
}
+ $css_assets[$order]['preprocessed'] = TRUE;
}
break;
@@ -138,7 +139,8 @@ public function optimize(array $css_assets) {
case 'external':
// We don't do any aggregation and hence also no caching for external
// CSS assets.
- $css_assets[$order] = $css_group;
+ $uri = $css_group['items'][0]['data'];
+ $css_assets[$order]['data'] = $uri;
break;
}
}
@@ -149,7 +151,7 @@ public function optimize(array $css_assets) {
/**
* Generate a hash for a given group of CSS assets.
*/
- protected function generateHash($css_group) {
+ protected function generateHash(array $css_group) {
$css_data = array();
foreach ($css_group['items'] as $css_file) {
$css_data[] = $css_file['data'];
diff --git a/core/lib/Drupal/Core/Asset/JsCollectionGrouper.php b/core/lib/Drupal/Core/Asset/JsCollectionGrouper.php
new file mode 100644
index 0000000..fb039b8
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JsCollectionGrouper.php
@@ -0,0 +1,80 @@
+grouper = $grouper;
+ $this->dumper = $dumper;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * The cache file name is retrieved on a page load via a lookup variable that
+ * contains an associative array. The array key is the hash of the names in
+ * $files while the value is the cache file name. The cache file is generated
+ * in two cases. First, if there is no file name value for the key, which will
+ * happen if a new file name has been added to $files or after the lookup
+ * variable is emptied to force a rebuild of the cache. Second, the cache file
+ * is generated if it is missing on disk. Old cache files are not deleted
+ * immediately when the lookup variable is emptied, but are deleted after a
+ * set period by drupal_delete_file_if_stale(). This ensures that files
+ * referenced by a cached page will still be available.
+ */
+ public function optimize(array $js_assets) {
+ // Group the assets.
+ $js_groups = $this->grouper->group($js_assets);
+
+ // Now optimize (concatenate, not minify) and dump each asset group, unless
+ // that was already done, in which case it should appear in
+ // system.js_cache_files.
+ // Drupal contrib can override this default JS aggregator to keep the same
+ // grouping, optimizing and dumping, but change the strategy that is used to
+ // determine when the aggregate should be rebuilt (e.g. mtime, HTTPS …).
+ $map = Drupal::state()->get('system.js_cache_files') ?: array();
+ $js_assets = array();
+ foreach ($js_groups as $order => $js_group) {
+ // We have to return a single asset, not a group of assets. It is now up
+ // to one of the pieces of code in the switch statement below to set the
+ // 'data' property to the appropriate value.
+ $js_assets[$order] = $js_group;
+ unset($js_assets[$order]['items']);
+
+ switch ($js_group['type']) {
+ case 'file':
+ // No preprocessing, single JS asset: just use the existing URI.
+ if (!$js_group['preprocess']) {
+ $uri = $js_group['items'][0]['data'];
+ $js_assets[$order]['data'] = $uri;
+ }
+ // Preprocess (aggregate), unless the aggregate file already exists.
+ else {
+ $key = $this->generateHash($js_group);
+ $uri = '';
+ if (isset($map[$key])) {
+ $uri = $map[$key];
+ }
+ if (empty($uri) || !file_exists($uri)) {
+ // Concatenate each asset within the group.
+ $data = '';
+ foreach ($js_group['items'] as $js_asset) {
+ $data .= file_get_contents($js_asset['data']);
+ // Append a ';' and a newline after each JS file to prevent them from running together.
+ $data .= ";\n";
+ }
+ // Dump the optimized JS for this group into an aggregate file.
+ $uri = $this->dumper->dump($data, 'js');
+ // Set the URI for this group's aggregate file.
+ $js_assets[$order]['data'] = $uri;
+ // Persist the URI for this aggregate file.
+ $map[$key] = $uri;
+ Drupal::state()->set('system.js_cache_files', $map);
+ }
+ else {
+ // Use the persisted URI for the optimized JS file.
+ $js_assets[$order]['data'] = $uri;
+ }
+ $js_assets[$order]['preprocessed'] = TRUE;
+ }
+ break;
+
+ case 'external':
+ case 'setting':
+ case 'inline':
+ // We don't do any aggregation and hence also no caching for external,
+ // setting or inline JS assets.
+ $uri = $js_group['items'][0]['data'];
+ $js_assets[$order]['data'] = $uri;
+ break;
+ }
+ }
+
+ return $js_assets;
+ }
+
+ /**
+ * Generate a hash for a given group of JS assets.
+ */
+ protected function generateHash(array $js_group) {
+ $js_data = array();
+ foreach ($js_group['items'] as $js_file) {
+ $js_data[] = $js_file['data'];
+ }
+ return hash('sha256', serialize($js_data));
+ }
+}
diff --git a/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php
new file mode 100644
index 0000000..6f9323e
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php
@@ -0,0 +1,97 @@
+\n";
+
+ // Since JavaScript may look for arguments in the URL and act on them, some
+ // third-party code might require the use of a different query string.
+ $js_version_string = variable_get('drupal_js_version_query_string', 'v=');
+
+ // Defaults for each SCRIPT element.
+ $element_defaults = array(
+ '#type' => 'html_tag',
+ '#tag' => 'script',
+ '#value' => '',
+ );
+
+ // Loop through all JS assets.
+ foreach ($js_assets as $js_asset) {
+ // Element properties that do not depend on JS asset type.
+ $element = $element_defaults;
+ $element['#browsers'] = $js_asset['browsers'];
+
+ // Element properties that depend on item type.
+ switch ($js_asset['type']) {
+ case 'setting':
+ $element['#value_prefix'] = $embed_prefix;
+ $element['#value'] = 'var drupalSettings = ' . drupal_json_encode(drupal_merge_js_settings($js_asset['data'])) . ";";
+ $element['#value_suffix'] = $embed_suffix;
+ break;
+
+ case 'inline':
+ $element['#value_prefix'] = $embed_prefix;
+ $element['#value'] = $js_asset['data'];
+ $element['#value_suffix'] = $embed_suffix;
+ break;
+
+ case 'file':
+ $query_string = empty($js_asset['version']) ? $default_query_string : $js_version_string . $js_asset['version'];
+ $query_string_separator = (strpos($js_asset['data'], '?') !== FALSE) ? '&' : '?';
+ $element['#attributes']['src'] = file_create_url($js_asset['data']);
+ // Only add the cache-busting query string if this isn't an aggregate
+ // file.
+ if (!isset($js_asset['preprocessed'])) {
+ $element['#attributes']['src'] .= $query_string_separator . ($js_asset['cache'] ? $query_string : REQUEST_TIME);
+ }
+ break;
+
+ case 'external':
+ $element['#attributes']['src'] = $js_asset['data'];
+ break;
+
+ default:
+ throw new \Exception('Invalid JS asset type.');
+ }
+
+ // Attributes may only be set if this script is output independently.
+ if (!empty($element['#attributes']['src']) && !empty($js_asset['attributes'])) {
+ $element['#attributes'] += $js_asset['attributes'];
+ }
+
+ $elements[] = $element;
+ }
+
+ return $elements;
+ }
+
+}
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 0a457a6..a00f2b5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
@@ -8,6 +8,7 @@
namespace Drupal\system\Tests\Common;
use Drupal\simpletest\WebTestBase;
+use Drupal\Component\Utility\Crypt;
/**
* Tests the JavaScript system.
@@ -345,8 +346,8 @@ function testAggregation() {
$js_items = drupal_add_js();
$javascript = drupal_get_js();
$expected = implode("\n", array(
- '',
- '',
+ '',
+ '',
));
$this->assertTrue(strpos($javascript, $expected) !== FALSE, 'JavaScript is aggregated in the expected groups and order.');
}
@@ -365,10 +366,14 @@ function testAggregationOrder() {
drupal_add_js('core/misc/autocomplete.js');
$js_items = drupal_add_js();
- drupal_build_js_cache(array(
- 'core/misc/ajax.js' => $js_items['core/misc/ajax.js'],
- 'core/misc/autocomplete.js' => $js_items['core/misc/autocomplete.js']
- ));
+ $scripts_html = array(
+ '#type' => 'scripts',
+ '#items' => array(
+ 'core/misc/ajax.js' => $js_items['core/misc/ajax.js'],
+ 'core/misc/autocomplete.js' => $js_items['core/misc/autocomplete.js']
+ )
+ );
+ drupal_render($scripts_html);
// Store the expected key for the first item in the cache.
$cache = array_keys(\Drupal::state()->get('system.js_cache_files') ?: array());
@@ -384,10 +389,14 @@ function testAggregationOrder() {
// Rebuild the cache.
$js_items = drupal_add_js();
- drupal_build_js_cache(array(
- 'core/misc/ajax.js' => $js_items['core/misc/ajax.js'],
- 'core/misc/autocomplete.js' => $js_items['core/misc/autocomplete.js']
- ));
+ $scripts_html = array(
+ '#type' => 'scripts',
+ '#items' => array(
+ 'core/misc/ajax.js' => $js_items['core/misc/ajax.js'],
+ 'core/misc/autocomplete.js' => $js_items['core/misc/autocomplete.js']
+ )
+ );
+ drupal_render($scripts_html);
// Compare the expected key for the first file to the current one.
$cache = array_keys(\Drupal::state()->get('system.js_cache_files') ?: array());
@@ -562,4 +571,19 @@ function testAddJsFileWithQueryString() {
$query_string = variable_get('css_js_query_string', '0');
$this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, 'Query string was appended correctly to js.');
}
+
+ /**
+ * Calculates the aggregated file name of a group of JavaScript assets.
+ *
+ * @see testAggregation()
+ * @see testAggregationOrder()
+ */
+ protected function calculateAggregateFilename($js_assets) {
+ $data = '';
+ foreach ($js_assets as $js_asset) {
+ $data .= file_get_contents($js_asset['data']) . ";\n";
+ }
+ return file_create_url('public://js/js_' . Crypt::hashBase64($data) . '.js');
+ }
+
}
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 125f807..b06b621 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -284,14 +284,10 @@ function system_element_info() {
$types['styles'] = array(
'#items' => array(),
'#pre_render' => array('drupal_pre_render_styles'),
- '#group_callback' => 'drupal_group_css',
- '#aggregate_callback' => 'drupal_aggregate_css',
);
$types['scripts'] = array(
'#items' => array(),
'#pre_render' => array('drupal_pre_render_scripts'),
- '#group_callback' => 'drupal_group_js',
- '#aggregate_callback' => 'drupal_aggregate_js',
);
// Input elements.
diff --git a/core/tests/Drupal/Tests/Core/Asset/CssCollectionRendererUnitTest.php b/core/tests/Drupal/Tests/Core/Asset/CssCollectionRendererUnitTest.php
index 5bc9537..cd97a61 100644
--- a/core/tests/Drupal/Tests/Core/Asset/CssCollectionRendererUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Asset/CssCollectionRendererUnitTest.php
@@ -563,7 +563,7 @@ function testRenderInvalidType() {
'type' => 'internal',
'media' => 'all',
'preprocess' => TRUE,
- 'browsers' => $browsers_default,
+ 'browsers' => array(),
'data' => 'http://example.com/popular.js'
);
$this->renderer->render($css_group);